From 64ca8ce09405f5d81614619154a1dcfce6971e36 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 26 Jun 2023 08:43:56 +0100 Subject: [PATCH] Merge pull request #13530 from overleaf/bg-support-managed-users add backend support for managed users GitOrigin-RevId: 61d965949c864013be31206661d2d36b35dd37a1 --- .../Subscription/ManagedUsersHandler.js | 62 +++++++++++++++++++ .../Subscription/ManagedUsersPolicy.js | 23 +++++++ .../acceptance/src/helpers/Subscription.js | 13 ++++ .../web/test/acceptance/src/helpers/User.js | 8 +++ 4 files changed, 106 insertions(+) create mode 100644 services/web/app/src/Features/Subscription/ManagedUsersHandler.js create mode 100644 services/web/app/src/Features/Subscription/ManagedUsersPolicy.js diff --git a/services/web/app/src/Features/Subscription/ManagedUsersHandler.js b/services/web/app/src/Features/Subscription/ManagedUsersHandler.js new file mode 100644 index 0000000000..6d5b3e073c --- /dev/null +++ b/services/web/app/src/Features/Subscription/ManagedUsersHandler.js @@ -0,0 +1,62 @@ +const { callbackify } = require('util') +const { Subscription } = require('../../models/Subscription') +const { GroupPolicy } = require('../../models/GroupPolicy') +const ManagedUsersPolicy = require('./ManagedUsersPolicy') + +/** + * 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 + await subscription.save() +} + +/** + * Retrieves the group policy for a user enrolled in a managed group. + * @async + * @function + * @param {Object} user - The user object to retrieve the group policy for. + * @returns {Promise} - A Promise that resolves with the group policy + * object for the user's enrollment, or undefined if it does not exist. + */ +async function getGroupPolicyForUser(user) { + if (user.enrollment?.managedBy == null) { + return + } + const subscription = await Subscription.findById(user.enrollment.managedBy) + .populate('groupPolicy', '-_id') + .exec() + // return the group policy as a plain object without the _id and __v field + const groupPolicy = subscription?.groupPolicy.toObject({ + versionKey: false, + }) + return groupPolicy +} + +module.exports = { + promises: { + enableManagedUsers, + getGroupPolicyForUser, + }, + enableManagedUsers: callbackify(enableManagedUsers), + getGroupPolicyForUser: callbackify(getGroupPolicyForUser), +} diff --git a/services/web/app/src/Features/Subscription/ManagedUsersPolicy.js b/services/web/app/src/Features/Subscription/ManagedUsersPolicy.js new file mode 100644 index 0000000000..ced66a5563 --- /dev/null +++ b/services/web/app/src/Features/Subscription/ManagedUsersPolicy.js @@ -0,0 +1,23 @@ +/** + * 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, + userCannotAddSecondaryEmail: true, + userCannotHaveSubscription: true, + userCannotLeaveManagingGroupSubscription: true, + userCannotHaveThirdPartySSO: true, + } +} + +module.exports = { + getDefaultPolicy, +} diff --git a/services/web/test/acceptance/src/helpers/Subscription.js b/services/web/test/acceptance/src/helpers/Subscription.js index 8c5c9bf3c2..290356b307 100644 --- a/services/web/test/acceptance/src/helpers/Subscription.js +++ b/services/web/test/acceptance/src/helpers/Subscription.js @@ -1,6 +1,7 @@ const { db, ObjectId } = require('../../../../app/src/infrastructure/mongodb') const { expect } = require('chai') const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater') +const ManagedUsersHandler = require('../../../../app/src/Features/Subscription/ManagedUsersHandler') const SubscriptionModel = require('../../../../app/src/models/Subscription').Subscription const DeletedSubscriptionModel = @@ -43,6 +44,10 @@ class Subscription { db.subscriptions.findOne({ _id: ObjectId(this._id) }, callback) } + getWithGroupPolicy(callback) { + SubscriptionModel.findById(this._id).populate('groupPolicy').exec(callback) + } + setManagerIds(managerIds, callback) { return SubscriptionModel.findOneAndUpdate( { _id: ObjectId(this._id) }, @@ -55,6 +60,14 @@ class Subscription { SubscriptionUpdater.refreshUsersFeatures(this, callback) } + enableManagedUsers(callback) { + ManagedUsersHandler.enableManagedUsers(this._id, callback) + } + + getGroupPolicyForUser(user, callback) { + ManagedUsersHandler.getGroupPolicyForUser(user, callback) + } + expectDeleted(deleterData, callback) { DeletedSubscriptionModel.find( { 'subscription._id': this._id }, diff --git a/services/web/test/acceptance/src/helpers/User.js b/services/web/test/acceptance/src/helpers/User.js index 0409669727..3b5db84efa 100644 --- a/services/web/test/acceptance/src/helpers/User.js +++ b/services/web/test/acceptance/src/helpers/User.js @@ -205,6 +205,14 @@ class User { ) } + enrollInSubscription(subscription, callback) { + UserModel.updateOne( + { _id: this.id }, + { 'enrollment.managedBy': subscription._id }, + callback + ) + } + logout(callback) { this.getCsrfToken(error => { if (error != null) {