From 720e5bdc4dec573a2b6001558bdfd0a4b14e5982 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 20 Nov 2023 09:25:38 +0000 Subject: [PATCH] Merge pull request #15726 from overleaf/ab-managed-users-module-cleanup [web] Managed users / Group SSO module cleanup GitOrigin-RevId: a24d3278667059248d9563afe44cafca5f87a7c0 --- .../Authorization/PermissionsController.js | 45 ++-- .../Subscription/ManagedUsersHandler.js | 210 ------------------ .../Subscription/ManagedUsersPolicy.js | 173 --------------- .../Subscription/SubscriptionLocator.js | 7 - .../Subscription/TeamInvitesController.js | 12 +- .../Subscription/TeamInvitesHandler.js | 6 +- .../manage-group-settings.stories.tsx | 99 --------- .../sso/disable-modal.stories.tsx | 37 --- .../subscription/sso/enable-modal.stories.tsx | 37 --- .../sso/sso-link-interstitial.stories.tsx | 27 --- .../frontend/stylesheets/_style_includes.less | 2 +- .../web/frontend/stylesheets/main-style.less | 2 +- ...managed-users.less => group-settings.less} | 0 .../acceptance/src/helpers/Subscription.js | 21 +- .../sso/group-settings-sso.spec.tsx | 2 +- .../Subscription/TeamInvitesHandlerTests.js | 10 +- 16 files changed, 58 insertions(+), 632 deletions(-) delete mode 100644 services/web/app/src/Features/Subscription/ManagedUsersHandler.js delete mode 100644 services/web/app/src/Features/Subscription/ManagedUsersPolicy.js delete mode 100644 services/web/frontend/stories/subscription/managed-users/manage-group-settings.stories.tsx delete mode 100644 services/web/frontend/stories/subscription/sso/disable-modal.stories.tsx delete mode 100644 services/web/frontend/stories/subscription/sso/enable-modal.stories.tsx delete mode 100644 services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx rename services/web/frontend/stylesheets/modules/{managed-users.less => group-settings.less} (100%) diff --git a/services/web/app/src/Features/Authorization/PermissionsController.js b/services/web/app/src/Features/Authorization/PermissionsController.js index eba0486326..258cf4a763 100644 --- a/services/web/app/src/Features/Authorization/PermissionsController.js +++ b/services/web/app/src/Features/Authorization/PermissionsController.js @@ -4,7 +4,7 @@ const { getUserCapabilities, getUserRestrictions, } = require('./PermissionsManager') -const ManagedUsersHandler = require('../Subscription/ManagedUsersHandler') +const Modules = require('../../infrastructure/Modules') /** * Function that returns middleware to add an `assertPermission` function to the request object to check if the user has a specific capability. @@ -26,19 +26,26 @@ function useCapabilities() { return next() } try { - // get the group policy applying to the user - const { groupPolicy, managedBy, isManagedGroupAdmin } = - await ManagedUsersHandler.promises.getEnrollmentForUser(req.user) - // attach the subscription ID to the request object - req.managedBy = managedBy - // attach the subscription admin status to the request object - req.isManagedGroupAdmin = isManagedGroupAdmin - // attach the new capabilities to the request object - for (const cap of getUserCapabilities(groupPolicy)) { - req.capabilitySet.add(cap) + const result = ( + await Modules.promises.hooks.fire( + 'getManagedUsersEnrollmentForUser', + req.user + ) + )[0] + if (result) { + // get the group policy applying to the user + const { groupPolicy, managedBy, isManagedGroupAdmin } = result + // attach the subscription ID to the request object + req.managedBy = managedBy + // attach the subscription admin status to the request object + req.isManagedGroupAdmin = isManagedGroupAdmin + // attach the new capabilities to the request object + for (const cap of getUserCapabilities(groupPolicy)) { + req.capabilitySet.add(cap) + } + // also attach the user's restrictions (the capabilities they don't have) + req.userRestrictions = getUserRestrictions(groupPolicy) } - // also attach the user's restrictions (the capabilities they don't have) - req.userRestrictions = getUserRestrictions(groupPolicy) next() } catch (error) { if (error instanceof UserNotFoundError) { @@ -69,10 +76,14 @@ function requirePermission(...requiredCapabilities) { return next(new Error('no user')) } try { - // get the group policy applying to the user - const { groupPolicy, managedUsersEnabled } = - await ManagedUsersHandler.promises.getEnrollmentForUser(req.user) - + const result = + ( + await Modules.promises.hooks.fire( + 'getManagedUsersEnrollmentForUser', + req.user + ) + )[0] || {} + const { groupPolicy, managedUsersEnabled } = result if (!managedUsersEnabled) { return next() } diff --git a/services/web/app/src/Features/Subscription/ManagedUsersHandler.js b/services/web/app/src/Features/Subscription/ManagedUsersHandler.js deleted file mode 100644 index b6015858d5..0000000000 --- a/services/web/app/src/Features/Subscription/ManagedUsersHandler.js +++ /dev/null @@ -1,210 +0,0 @@ -const { callbackify } = require('util') -const { Subscription } = require('../../models/Subscription') -const { GroupPolicy } = require('../../models/GroupPolicy') -const { User } = require('../../models/User') -const ManagedUsersPolicy = require('./ManagedUsersPolicy') -const OError = require('@overleaf/o-error') -const settings = require('@overleaf/settings') -const { - UserNotFoundError, - SubscriptionNotFoundError, -} = require('../Errors/Errors') -const UserGetter = require('../User/UserGetter') -const UserUpdater = require('../User/UserUpdater') -const EmailHandler = require('../Email/EmailHandler') -const logger = require('@overleaf/logger') - -/** - * This module contains functions for handling managed users in a - * group subscription. - */ - -/** - * Enables managed users for a given subscription by creating a new - * group policy with default settings for managed users and updating - * the subscription to use the new policy. - * @async - * @function - * @param {string} subscriptionId - The ID of the subscription to enable - * managed users for. - * @returns {Promise} - A Promise that resolves when the subscription - * has been updated with the new group policy. - */ -async function enableManagedUsers(subscriptionId) { - const subscription = await Subscription.findById(subscriptionId).exec() - - // create a new Group policy with the default settings for managed users - const policy = ManagedUsersPolicy.getDefaultPolicy() - const groupPolicy = new GroupPolicy(policy) - await groupPolicy.save() - // update the subscription to use the new policy - subscription.groupPolicy = groupPolicy._id - subscription.managedUsersEnabled = true - await subscription.save() - - await _sendEmailToGroupMembers(subscriptionId) -} - -/** - * Disables managed users for a given subscription by removing the - * group policy and deleting enrolment information for all managed users. - * @async - * @function - * @param {string} subscriptionId - The ID of the subscription to disable - * managed users for. - * @returns {Promise} - A Promise that resolves when the subscription and - * users have been updated. - */ -async function disableManagedUsers(subscriptionId) { - const subscription = await Subscription.findById(subscriptionId).exec() - for (const userId of subscription.member_ids || []) { - const user = await UserGetter.promises.getUser(userId, { enrollment: 1 }) - if ( - user.enrollment?.managedBy?.toString() === subscription._id.toString() - ) { - await UserUpdater.promises.updateUser(userId, { - $unset: { enrollment: 1 }, - }) - } - } - - subscription.groupPolicy = undefined - subscription.managedUsersEnabled = false - await subscription.save() -} - -/** - * Retrieves the group policy for a user enrolled in a managed group. - * @async - * @function - * @param {Object} requestedUser - The user object to retrieve the group policy for. - * @returns {Promise} - A Promise that resolves with the group policy - * and subscription objects for the user's enrollment, or null if it does not exist. - */ -async function getEnrollmentForUser(requestedUser) { - // Don't rely on the user being populated, it may be a session user without - // the enrollment property. Force the user to be loaded from mongo. - const user = await User.findById(requestedUser._id, 'enrollment') - if (!user) { - throw new UserNotFoundError({ info: { userId: requestedUser._id } }) - } - // Now we are sure the user exists and we have the full contents - if (user.enrollment?.managedBy == null) { - return {} - } - // retrieve the subscription and the group policy (without the _id field) - const subscription = await Subscription.findById(user.enrollment.managedBy) - .populate('groupPolicy', '-_id') - .exec() - if (!subscription) { - throw new SubscriptionNotFoundError({ - info: { subscriptionId: user.enrollment.managedBy, userId: user._id }, - }) - } - - // check whether the user is an admin of the subscription - const isManagedGroupAdmin = user._id.equals(subscription.admin_id) - - // return the group policy as a plain object (without the __v field) - const groupPolicy = subscription.groupPolicy.toObject({ - versionKey: false, - }) - - return { - groupPolicy, - managedUsersEnabled: subscription.managedUsersEnabled, - managedBy: user.enrollment.managedBy, - isManagedGroupAdmin, - } -} - -async function enrollInSubscription(userId, subscription) { - // check whether the user is already enrolled in a subscription - const user = await User.findOne( - { - _id: userId, - 'enrollment.managedBy': { $exists: true }, - }, - { _id: 1 } - ).exec() - if (user != null) { - throw new OError('User is already enrolled in a subscription', { - userId, - subscriptionId: subscription._id, - }) - } - // update the user to be enrolled in the subscription - const updatedUser = await User.findOneAndUpdate( - { _id: userId, 'enrollment.managedBy': { $exists: false } }, - { - enrollment: { - managedBy: subscription._id, - enrolledAt: new Date(), - }, - }, - { new: true } - ).exec() - // check whether the enrollment succeeded - if ( - !updatedUser || - !subscription.equals(updatedUser?.enrollment?.managedBy) - ) { - throw new OError('Failed to enroll user in subscription', { - userId, - subscriptionId: subscription._id, - }) - } -} - -/** - * Send email to all group members, irregardless of the member status. - * @async - * @function - * @param {string} subscriptionId - The ID of the subscription to enable - * managed users for. - * @returns {Promise} - A Promise that resolves when all the `sendEmail` function has been sent, - * irregardless of whether they're successful or failed. - */ -async function _sendEmailToGroupMembers(subscriptionId) { - const EMAIL_DELAY_IN_MS = 0 - - const subscription = await Subscription.findById(subscriptionId) - .populate('member_ids', 'email') - .populate('admin_id', ['first_name', 'last_name', 'email']) - .exec() - - // On failure, log the error and carry on so that one email failing does not prevent other emails sending - for (const recipient of subscription.member_ids) { - try { - const opts = { - to: recipient.email, - admin: subscription.admin_id, - groupName: subscription.teamName, - acceptInviteUrl: `${settings.siteUrl}/subscription/${subscriptionId}/enrollment/`, - } - EmailHandler.sendDeferredEmail( - 'surrenderAccountForManagedUsers', - opts, - EMAIL_DELAY_IN_MS - ) - } catch (err) { - logger.error( - { err, userId: recipient._id }, - 'could not send notification email to surrender account' - ) - } - } -} - -module.exports = { - promises: { - enableManagedUsers, - disableManagedUsers, - getEnrollmentForUser, - enrollInSubscription, - }, - enableManagedUsers: callbackify(enableManagedUsers), - getEnrollmentForUser: callbackify(getEnrollmentForUser), - enrollInSubscription: callbackify(enrollInSubscription), - disableManagedUsers: callbackify(disableManagedUsers), -} diff --git a/services/web/app/src/Features/Subscription/ManagedUsersPolicy.js b/services/web/app/src/Features/Subscription/ManagedUsersPolicy.js deleted file mode 100644 index 82b979ef38..0000000000 --- a/services/web/app/src/Features/Subscription/ManagedUsersPolicy.js +++ /dev/null @@ -1,173 +0,0 @@ -const { - registerCapability, - registerPolicy, -} = require('../Authorization/PermissionsManager') -const { getUsersSubscription, getGroupSubscriptionsMemberOf } = - require('./SubscriptionLocator').promises -const { subscriptionIsCanceledOrExpired } = require('./RecurlyClient') - -// This file defines the capabilities and policies that are used to -// determine what managed users can and cannot do. - -// Register the capability for a user to delete their own account. -registerCapability('delete-own-account', { default: true }) - -// Register the capability for a user to add a secondary email to their account. -registerCapability('add-secondary-email', { default: true }) - -// Register the capability for a user to add an affiliation to their account. -registerCapability('add-affiliation', { default: true }) - -// Register the capability for a user to endorse an email address. -registerCapability('endorse-email', { default: true }) - -// Register the capability for a user to sign in with Google to their account -registerCapability('link-google-sso', { default: true }) - -// Register the capability for a user to link other third party SSO to their account -registerCapability('link-other-third-party-sso', { default: true }) - -// Register the capability for a user to leave a managed group subscription. -registerCapability('leave-group-subscription', { default: true }) - -// Register the capability for a user to start a subscription. -registerCapability('start-subscription', { default: true }) - -// Register the capability for a user to join a subscription. -registerCapability('join-subscription', { default: true }) - -// Register the capability for a user to reactivate a subscription. -registerCapability('reactivate-subscription', { default: true }) - -// Register a policy to prevent a user deleting their own account. -registerPolicy('userCannotDeleteOwnAccount', { - 'delete-own-account': false, -}) - -// Register a policy to prevent a user having secondary email addresses on their account. -registerPolicy( - 'userCannotHaveSecondaryEmail', - { - 'add-secondary-email': false, - 'add-affiliation': false, - 'endorse-email': false, - }, - { - validator: async ({ user }) => { - // return true if the user does not have any secondary emails - return user.emails.length === 1 - }, - } -) - -// Register a policy to prevent a user leaving the group subscription they are managed by. -registerPolicy('userCannotLeaveManagingGroupSubscription', { - 'leave-group-subscription': false, -}) - -// Register a policy to prevent a user having third-party SSO linked to their account. -registerPolicy( - 'userCannotHaveGoogleSSO', - { 'link-google-sso': false }, - { - // return true if the user does not have Google SSO linked - validator: async ({ user }) => - !user.thirdPartyIdentifiers?.some( - identifier => identifier.providerId === 'google' - ), - } -) - -// Register a policy to prevent a user having third-party SSO linked to their account. -registerPolicy( - 'userCannotHaveOtherThirdPartySSO', - { 'link-other-third-party-sso': false }, - { - // return true if the user does not have any other third party SSO linked - validator: async ({ user }) => - !user.thirdPartyIdentifiers?.some( - identifier => identifier.providerId !== 'google' - ), - } -) - -// Register a policy to prevent a user having an active subscription or -// being a member of another group subscription. -registerPolicy( - 'userCannotHaveSubscription', - { - 'start-subscription': false, - 'join-subscription': false, - 'reactivate-subscription': false, - }, - { - validator: async ({ user, subscription }) => { - const usersSubscription = await getUsersSubscription(user) - - // The user can be enrolled if: - // 1. they do not have a subscription and are not a member of another subscription (apart from the managed group subscription) - // 2. they have a subscription and it is canceled or expired - // 3. they have a subscription and it is the subscription they are trying to join as a managed user - // The last case is to allow the admin to join their own subscription as a managed user - - const userHasSubscription = - Boolean(usersSubscription) && - !subscriptionIsCanceledOrExpired(usersSubscription) - - const userIsThisGroupAdmin = - Boolean(usersSubscription) && - usersSubscription._id.toString() === subscription._id.toString() - - const userMemberOfSubscriptions = await getGroupSubscriptionsMemberOf( - user - ) - - const isMemberOfOtherSubscriptions = userMemberOfSubscriptions.some( - sub => { - // ignore the subscription of the managed group itself - if (sub._id.toString() === subscription._id.toString()) { - return false - } - // ignore the user's own subscription - if ( - usersSubscription && - sub._id.toString() === usersSubscription._id.toString() - ) { - return false - } - return true - } - ) - - return ( - (!userHasSubscription || userIsThisGroupAdmin) && - !isMemberOfOtherSubscriptions - ) - }, - } -) - -/** - * Returns the default group policy for managed users. - * Managed users are users who are part of a group subscription, and are - * managed by the group policy. Managed users have limited functionality. - * This method returns an object with boolean values for each policy that - * indicates whether the policy is enforced or not. - * - * @returns {Object} An object with boolean values for each policy that indicates whether it is enforced or not. - * @function - */ -function getDefaultPolicy() { - return { - userCannotDeleteOwnAccount: true, - userCannotHaveSecondaryEmail: true, - userCannotHaveSubscription: true, - userCannotLeaveManagingGroupSubscription: true, - userCannotHaveGoogleSSO: false, // we want to allow google SSO by default - userCannotHaveOtherThirdPartySSO: true, - } -} - -module.exports = { - getDefaultPolicy, -} diff --git a/services/web/app/src/Features/Subscription/SubscriptionLocator.js b/services/web/app/src/Features/Subscription/SubscriptionLocator.js index c1b8fde703..52dddcc967 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionLocator.js +++ b/services/web/app/src/Features/Subscription/SubscriptionLocator.js @@ -2,7 +2,6 @@ const { promisify } = require('util') const { Subscription } = require('../../models/Subscription') const { DeletedSubscription } = require('../../models/DeletedSubscription') const logger = require('@overleaf/logger') -const { SSOConfig } = require('../../models/SSOConfig') require('./GroupPlansData') // make sure dynamic group plans are loaded const SubscriptionLocator = { @@ -133,11 +132,6 @@ const SubscriptionLocator = { }, } -async function hasSSOEnabled(subscription) { - const ssoConfig = await SSOConfig.findById(subscription.ssoConfig).exec() - return !!ssoConfig?.enabled -} - SubscriptionLocator.promises = { getUsersSubscription: promisify(SubscriptionLocator.getUsersSubscription), getUserIndividualSubscription: promisify( @@ -170,6 +164,5 @@ SubscriptionLocator.promises = { hasRecurlyGroupSubscription: promisify( SubscriptionLocator.hasRecurlyGroupSubscription ), - hasSSOEnabled, } module.exports = SubscriptionLocator diff --git a/services/web/app/src/Features/Subscription/TeamInvitesController.js b/services/web/app/src/Features/Subscription/TeamInvitesController.js index 8d8abba4a3..48a0cf9dff 100644 --- a/services/web/app/src/Features/Subscription/TeamInvitesController.js +++ b/services/web/app/src/Features/Subscription/TeamInvitesController.js @@ -84,9 +84,9 @@ async function viewInvite(req, res, next) { personalSubscription.recurlySubscription_id && personalSubscription.recurlySubscription_id !== '' - const groupSSOActive = await SubscriptionLocator.promises.hasSSOEnabled( - subscription - ) + const groupSSOActive = ( + await Modules.promises.hooks.fire('hasGroupSSOEnabled', subscription) + )?.[0] if (subscription?.groupPolicy) { if (!subscription.populated('groupPolicy')) { @@ -194,9 +194,9 @@ async function acceptInvite(req, res, next) { token, userId ) - const groupSSOActive = await SubscriptionLocator.promises.hasSSOEnabled( - subscription - ) + const groupSSOActive = ( + await Modules.promises.hooks.fire('hasGroupSSOEnabled', subscription) + )?.[0] res.json({ groupSSOActive }) } diff --git a/services/web/app/src/Features/Subscription/TeamInvitesHandler.js b/services/web/app/src/Features/Subscription/TeamInvitesHandler.js index c89f9257d7..ed8dc76f50 100644 --- a/services/web/app/src/Features/Subscription/TeamInvitesHandler.js +++ b/services/web/app/src/Features/Subscription/TeamInvitesHandler.js @@ -2,6 +2,7 @@ const logger = require('@overleaf/logger') const crypto = require('crypto') const settings = require('@overleaf/settings') +const Modules = require('../../infrastructure/Modules') const { ObjectId } = require('mongodb') const { Subscription } = require('../../models/Subscription') @@ -11,7 +12,6 @@ const UserGetter = require('../User/UserGetter') const SubscriptionLocator = require('./SubscriptionLocator') const SubscriptionUpdater = require('./SubscriptionUpdater') const LimitationsManager = require('./LimitationsManager') -const ManagedUsersHandler = require('./ManagedUsersHandler') const EmailHandler = require('../Email/EmailHandler') const EmailHelper = require('../Helpers/EmailHelper') @@ -22,7 +22,6 @@ const { callbackifyMultiResult, } = require('@overleaf/promise-utils') const NotificationsBuilder = require('../Notifications/NotificationsBuilder') -const Modules = require('../../infrastructure/Modules') async function getInvite(token) { const subscription = await Subscription.findOne({ @@ -74,7 +73,8 @@ async function acceptInvite(token, userId) { await SubscriptionUpdater.promises.addUserToGroup(subscription._id, userId) if (subscription.managedUsersEnabled) { - await ManagedUsersHandler.promises.enrollInSubscription( + await Modules.promises.hooks.fire( + 'enrollInManagedSubscription', userId, subscription ) diff --git a/services/web/frontend/stories/subscription/managed-users/manage-group-settings.stories.tsx b/services/web/frontend/stories/subscription/managed-users/manage-group-settings.stories.tsx deleted file mode 100644 index 8c428b1f94..0000000000 --- a/services/web/frontend/stories/subscription/managed-users/manage-group-settings.stories.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import GroupSettings from '../../../../modules/managed-users/frontend/js/components/group-settings' -import { useMeta } from '../../hooks/use-meta' -import useFetchMock from '../../hooks/use-fetch-mock' - -export const GroupSettingsWithManagedUsersDisabledAndNoSSOFeature = () => { - useMeta({ - 'ol-managedUsersEnabled': false, - 'ol-hasGroupSSOFeature': false, - }) - return -} - -export const GroupSettingsWithManagedUsersDisabledAndSSOFeature = () => { - useFetchMock(fetchMock => - fetchMock.get('express:/manage/groups/:id/settings/sso', {}) - ) - useMeta({ - 'ol-managedUsersEnabled': false, - 'ol-hasGroupSSOFeature': true, - }) - return -} - -export const GroupSettingsWithManagedUsersEnabledAndNoSSOFeature = () => { - useMeta({ - 'ol-managedUsersEnabled': true, - 'ol-hasGroupSSOFeature': false, - }) - return -} - -export const GroupSettingsWithManagedUsersEnabledAndSSOFeatureNotConfigured = - () => { - useMeta({ - 'ol-managedUsersEnabled': true, - 'ol-hasGroupSSOFeature': true, - }) - useFetchMock(fetchMock => { - fetchMock.get( - 'express:/manage/groups/:id/settings/sso', - {}, - { - delay: 500, - } - ) - }) - return - } - -export const GroupSettingsWithManagedUsersEnabledAndSSOFeatureConfigured = - () => { - const config = { - entryPoint: 'http://idp.example.com/entry_point', - certificate: - 'X1JQa2tWQmYzYlN1aUZORVhzZGpURVp3c0U4T3J3bWtjYVZsQ2h4MkRyRUpOVGtxV2hXcG9KbG1WZ2hYclB1YUVNeFVjM0pFZW5Zd1dQRzB5bldxWm5xYm5IdEJ5d1VGQlQ2RWJ1bHdQeJ0VmpoMkFUeHlIaE5KUVBqYm1iUlB1ckZjQnZzRzlZWW5RZVpYU3pKd3V3Z1l3cE5ZeE9XZkx5ZlVJZGVKQk5JkFUeHlIaE5KUV', - signatureAlgorithm: 'sha256', - userIdAttribute: 'email', - enabled: true, - } - useFetchMock(fetchMock => { - fetchMock.get('express:/manage/groups/:id/settings/sso', config, { - delay: 500, - }) - }) - - useMeta({ - 'ol-managedUsersEnabled': true, - 'ol-hasGroupSSOFeature': true, - }) - return - } - -export const GroupSettingsWithManagedUsersDisabledAndSSOFeatureConfigured = - () => { - const config = { - entryPoint: 'http://idp.example.com/entry_point', - certificate: - 'X1JQa2tWQmYzYlN1aUZORVhzZGpURVp3c0U4T3J3bWtjYVZsQ2h4MkRyRUpOVGtxV2hXcG9KbG1WZ2hYclB1YUVNeFVjM0pFZW5Zd1dQRzB5bldxWm5xYm5IdEJ5d1VGQlQ2RWJ1bHdQeJ0VmpoMkFUeHlIaE5KUVBqYm1iUlB1ckZjQnZzRzlZWW5RZVpYU3pKd3V3Z1l3cE5ZeE9XZkx5ZlVJZGVKQk5JkFUeHlIaE5KUV', - signatureAlgorithm: 'sha256', - userIdAttribute: 'email', - enabled: false, - } - useFetchMock(fetchMock => { - fetchMock.get('express:/manage/groups/:id/settings/sso', config, { - delay: 500, - }) - }) - - useMeta({ - 'ol-managedUsersEnabled': true, - 'ol-hasGroupSSOFeature': true, - }) - return - } - -export default { - title: 'Subscription / Managed Users', - component: GroupSettings, -} diff --git a/services/web/frontend/stories/subscription/sso/disable-modal.stories.tsx b/services/web/frontend/stories/subscription/sso/disable-modal.stories.tsx deleted file mode 100644 index 4e287979f4..0000000000 --- a/services/web/frontend/stories/subscription/sso/disable-modal.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import SSODisableModal, { - type SSODisableModalProps, -} from '../../../../modules/managed-users/frontend/js/components/modals/sso-disable-modal' -import useFetchMock from '../../hooks/use-fetch-mock' -import { useMeta } from '../../hooks/use-meta' - -export const DisableSSOModalDefault = (args: SSODisableModalProps) => { - useMeta({ 'ol-groupId': '123' }) - useFetchMock(fetchMock => { - fetchMock.post('express:/manage/groups/:id/settings/disableSSO', 200, { - delay: 500, - }) - }) - return -} - -export const DisableSSOModalError = (args: SSODisableModalProps) => { - useMeta({ 'ol-groupId': '123' }) - useFetchMock(fetchMock => { - fetchMock.post('express:/manage/groups/:id/settings/enableSSO', 500, { - delay: 500, - }) - }) - return -} - -export default { - title: 'Subscription / SSO / Disable Modal', - component: SSODisableModal, - args: { - show: true, - }, - argTypes: { - handleHide: { action: 'close modal' }, - onDisableSSO: { action: 'callback' }, - }, -} diff --git a/services/web/frontend/stories/subscription/sso/enable-modal.stories.tsx b/services/web/frontend/stories/subscription/sso/enable-modal.stories.tsx deleted file mode 100644 index ad5d82f139..0000000000 --- a/services/web/frontend/stories/subscription/sso/enable-modal.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import SSOEnableModal, { - type SSOEnableModalProps, -} from '../../../../modules/managed-users/frontend/js/components/modals/sso-enable-modal' -import useFetchMock from '../../hooks/use-fetch-mock' -import { useMeta } from '../../hooks/use-meta' - -export const EnableSSOModalDefault = (args: SSOEnableModalProps) => { - useMeta({ 'ol-groupId': '123' }) - useFetchMock(fetchMock => { - fetchMock.post('express:/manage/groups/:id/settings/enableSSO', 200, { - delay: 500, - }) - }) - return -} - -export const EnableSSOModalError = (args: SSOEnableModalProps) => { - useMeta({ 'ol-groupId': '123' }) - useFetchMock(fetchMock => { - fetchMock.post('express:/manage/groups/:id/settings/enableSSO', 500, { - delay: 500, - }) - }) - return -} - -export default { - title: 'Subscription / SSO / Enable Modal', - component: SSOEnableModal, - args: { - show: true, - }, - argTypes: { - handleHide: { action: 'close modal' }, - onEnableSSO: { action: 'callback' }, - }, -} diff --git a/services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx b/services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx deleted file mode 100644 index 3c86a6ea2a..0000000000 --- a/services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useMeta } from '../../hooks/use-meta' -import SSOLinkConfirm from '../../../../modules/managed-users/frontend/js/components/sso-link-confirm' - -export const LinkConfirmInterstitial = () => { - return -} - -export const LinkConfirmInterstitialWithError = () => { - useMeta({ 'ol-error': 'SAMLInvalidSignatureError' }) - return -} - -export default { - title: 'Subscription / SSO / Link', - component: SSOLinkConfirm, - decorators: [ - (Story: any) => { - useMeta({ 'ol-groupId': '123' }) - useMeta({ 'ol-email': 'user@example.com' }) - return ( -
- -
- ) - }, - ], -} diff --git a/services/web/frontend/stylesheets/_style_includes.less b/services/web/frontend/stylesheets/_style_includes.less index 0c10548b0b..8e15d35c86 100644 --- a/services/web/frontend/stylesheets/_style_includes.less +++ b/services/web/frontend/stylesheets/_style_includes.less @@ -111,7 +111,7 @@ // module styles // TODO: find a way for modules to add styles dynamically @import 'modules/symbol-palette.less'; -@import 'modules/managed-users.less'; +@import 'modules/group-settings.less'; @import 'modules/git-bridge-modal.less'; @import 'modules/admin-panel.less'; @import 'modules/overleaf-integration.less'; diff --git a/services/web/frontend/stylesheets/main-style.less b/services/web/frontend/stylesheets/main-style.less index 679f2b6d04..cf6a519c1e 100644 --- a/services/web/frontend/stylesheets/main-style.less +++ b/services/web/frontend/stylesheets/main-style.less @@ -144,5 +144,5 @@ @import 'modules/symbol-palette.less'; @import 'modules/admin-panel.less'; @import 'modules/git-bridge-modal.less'; -@import 'modules/managed-users.less'; +@import 'modules/group-settings.less'; @import 'modules/overleaf-integration.less'; diff --git a/services/web/frontend/stylesheets/modules/managed-users.less b/services/web/frontend/stylesheets/modules/group-settings.less similarity index 100% rename from services/web/frontend/stylesheets/modules/managed-users.less rename to services/web/frontend/stylesheets/modules/group-settings.less diff --git a/services/web/test/acceptance/src/helpers/Subscription.js b/services/web/test/acceptance/src/helpers/Subscription.js index 7de389efca..03badd4421 100644 --- a/services/web/test/acceptance/src/helpers/Subscription.js +++ b/services/web/test/acceptance/src/helpers/Subscription.js @@ -2,13 +2,13 @@ const { db, ObjectId } = require('../../../../app/src/infrastructure/mongodb') const { expect } = require('chai') const { promisify } = require('util') const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater') -const ManagedUsersHandler = require('../../../../app/src/Features/Subscription/ManagedUsersHandler') const PermissionsManager = require('../../../../app/src/Features/Authorization/PermissionsManager') -const SSOConfigManager = require('../../../../modules/managed-users/app/src/SSOConfigManager') +const SSOConfigManager = require('../../../../modules/group-settings/app/src/sso/SSOConfigManager') const SubscriptionModel = require('../../../../app/src/models/Subscription').Subscription const DeletedSubscriptionModel = require('../../../../app/src/models/DeletedSubscription').DeletedSubscription +const Modules = require('../../../../app/src/infrastructure/Modules') class Subscription { constructor(options = {}) { @@ -78,11 +78,17 @@ class Subscription { } enableManagedUsers(callback) { - ManagedUsersHandler.enableManagedUsers(this._id, callback) + Modules.hooks.fire('enableManagedUsers', this._id, callback) } getEnrollmentForUser(user, callback) { - ManagedUsersHandler.getEnrollmentForUser(user, callback) + Modules.hooks.fire( + 'getManagedUsersEnrollmentForUser', + user, + (error, [enrollment]) => { + callback(error, enrollment) + } + ) } getCapabilities(groupPolicy) { @@ -98,7 +104,12 @@ class Subscription { if (error) { return callback(error) } - ManagedUsersHandler.enrollInSubscription(user._id, subscription, callback) + Modules.hooks.fire( + 'enrollInManagedSubscription', + user._id, + subscription, + callback + ) }) } diff --git a/services/web/test/frontend/features/group-management/components/sso/group-settings-sso.spec.tsx b/services/web/test/frontend/features/group-management/components/sso/group-settings-sso.spec.tsx index 927d260814..4bbebec973 100644 --- a/services/web/test/frontend/features/group-management/components/sso/group-settings-sso.spec.tsx +++ b/services/web/test/frontend/features/group-management/components/sso/group-settings-sso.spec.tsx @@ -1,4 +1,4 @@ -import GroupSettingsSSORoot from '../../../../../../modules/managed-users/frontend/js/components/sso/group-settings-sso-root' +import GroupSettingsSSORoot from '../../../../../../modules/group-settings/frontend/js/components/sso/group-settings-sso-root' function GroupSettingsSSOComponent() { return ( diff --git a/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js b/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js index 19fad561f2..dd83437c4b 100644 --- a/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js +++ b/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js @@ -76,12 +76,6 @@ describe('TeamInvitesHandler', function () { }, } - this.ManagedUsersHandler = { - promises: { - enrollInSubscription: sinon.stub().resolves(), - }, - } - this.newToken = 'bbbbbbbbb' this.crypto = { @@ -128,7 +122,6 @@ describe('TeamInvitesHandler', function () { './SubscriptionUpdater': this.SubscriptionUpdater, './LimitationsManager': this.LimitationsManager, '../Email/EmailHandler': this.EmailHandler, - './ManagedUsersHandler': this.ManagedUsersHandler, '../Notifications/NotificationsBuilder': this.NotificationsBuilder, '../../infrastructure/Modules': (this.Modules = { promises: { hooks: { fire: sinon.stub().resolves() } }, @@ -393,7 +386,8 @@ describe('TeamInvitesHandler', function () { this.TeamInvitesHandler.acceptInvite('dddddddd', this.user.id, () => { sinon.assert.calledWith( - this.ManagedUsersHandler.promises.enrollInSubscription, + this.Modules.promises.hooks.fire, + 'enrollInManagedSubscription', this.user.id, this.subscription )