diff --git a/services/web/app/src/Features/Email/EmailBuilder.js b/services/web/app/src/Features/Email/EmailBuilder.js index dbee3c7005..b3dc813c51 100644 --- a/services/web/app/src/Features/Email/EmailBuilder.js +++ b/services/web/app/src/Features/Email/EmailBuilder.js @@ -437,6 +437,64 @@ templates.inviteNewUserToJoinManagedUsers = ctaTemplate({ }, }) +templates.surrenderAccountForManagedUsers = ctaTemplate({ + subject(opts) { + const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin')) + + const toGroupName = opts.groupName ? ` to ${opts.groupName}` : '' + + return `You’ve been invited by ${admin} to transfer management of your ${settings.appName} account${toGroupName}` + }, + title(opts) { + const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin')) + + const toGroupName = opts.groupName ? ` to ${opts.groupName}` : '' + + return `You’ve been invited by ${admin} to transfer management of your ${settings.appName} account${toGroupName}` + }, + message(opts, isPlainText) { + const admin = _.escape(_formatUserNameAndEmail(opts.admin, 'an admin')) + + const groupName = opts.groupName ?? `a group managed by ${admin}` + + // TODO update with actual wiki link once created + const managedUsersLink = EmailMessageHelper.displayLink( + 'user account management', + `${settings.siteUrl}/learn/how-to/Managed_Users`, + isPlainText + ) + + return [ + `Your ${settings.appName} account ${_.escape( + opts.to + )} is part of ${groupName} and your group administrator has now enabled ${managedUsersLink}. This will ensure that projects aren’t lost when someone leaves the group.`, + ] + }, + secondaryMessage(opts, isPlainText) { + const transferProjectOwnershipLink = EmailMessageHelper.displayLink( + 'change project owner', + `${settings.siteUrl}/learn/how-to/How_to_Transfer_Project_Ownership`, + isPlainText + ) + + return [ + `What does this mean for you?`, + `If you accept, you’ll transfer the management of your ${settings.appName} account to the owner of the group subscription, who will then have admin rights over your account and control over your stuff.`, + `If you have personal projects in your ${settings.appName} account that you want to keep separate, that’s not a problem. You can set up another account under a personal email address and change the ownership of your personal projects to the new account. Find out how to ${transferProjectOwnershipLink}.`, + `If you think this invitation has been sent in error please contact your group administrator.`, + ] + }, + ctaURL(opts) { + return opts.acceptInviteUrl + }, + ctaText(opts) { + return 'Accept invitation' + }, + greeting() { + return '' + }, +}) + templates.testEmail = ctaTemplate({ subject() { return `A Test Email from ${settings.appName}` diff --git a/services/web/app/src/Features/Subscription/ManagedUsersHandler.js b/services/web/app/src/Features/Subscription/ManagedUsersHandler.js index 967e59b0a9..4365b93975 100644 --- a/services/web/app/src/Features/Subscription/ManagedUsersHandler.js +++ b/services/web/app/src/Features/Subscription/ManagedUsersHandler.js @@ -10,6 +10,8 @@ const { } = 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 @@ -36,6 +38,8 @@ async function enableManagedUsers(subscriptionId) { // update the subscription to use the new policy subscription.groupPolicy = groupPolicy._id await subscription.save() + + await _sendEmailToGroupMembers(subscriptionId) } /** @@ -145,6 +149,45 @@ async function enrollInSubscription(userId, subscription) { } } +/** + * 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, + } + 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,