diff --git a/services/web/app/src/Features/Email/EmailBuilder.js b/services/web/app/src/Features/Email/EmailBuilder.js index 40abeeb1a7..7a97d272bd 100644 --- a/services/web/app/src/Features/Email/EmailBuilder.js +++ b/services/web/app/src/Features/Email/EmailBuilder.js @@ -360,6 +360,77 @@ templates.verifyEmailToJoinTeam = ctaTemplate({ }, }) +templates.verifyEmailToJoinManagedUsers = ctaTemplate({ + subject(opts) { + return `You’ve been invited by ${_.escape( + _formatUserNameAndEmail(opts.inviter, 'a collaborator') + )} to join an ${settings.appName} group subscription.` + }, + title(opts) { + return `You’ve been invited by ${_.escape( + _formatUserNameAndEmail(opts.inviter, 'a collaborator') + )} to join an ${settings.appName} group subscription.` + }, + message(opts) { + return [ + `By joining this group, you'll have access to ${settings.appName} premium features such as additional collaborators, greater maximum compile time, and real-time track changes.`, + ] + }, + secondaryMessage(opts) { + return [ + `User accounts in this group are managed by ${_.escape( + _formatUserNameAndEmail(opts.admin, 'an admin') + )}`, + `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 change project owner.`, + ] + }, + ctaURL(opts) { + return opts.acceptInviteUrl + }, + ctaText(opts) { + return 'Accept invitation' + }, + greeting() { + return '' + }, +}) + +templates.inviteNewUserToJoinManagedUsers = ctaTemplate({ + subject(opts) { + return `You’ve been invited by ${_.escape( + _formatUserNameAndEmail(opts.inviter, 'a collaborator') + )} to join an ${settings.appName} group subscription.` + }, + title(opts) { + return `You’ve been invited by ${_.escape( + _formatUserNameAndEmail(opts.inviter, 'a collaborator') + )} to join an ${settings.appName} group subscription.` + }, + message(opts) { + return [''] + }, + secondaryMessage(opts) { + return [ + `User accounts in this group are managed by ${_.escape( + _formatUserNameAndEmail(opts.admin, 'an admin') + )}`, + `If you accept the owner of the group subscription will have admin rights over your account and control over your stuff.`, + `What is ${settings.appName}?`, + `${settings.appName} is the collaborative online LaTeX editor loved by researchers and technical writers. With thousands of ready-to-use templates and an array of LaTeX learning resources you’ll be up and running in no time.`, + ] + }, + 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/SubscriptionLocator.js b/services/web/app/src/Features/Subscription/SubscriptionLocator.js index f83a4d323c..6f28796ffd 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionLocator.js +++ b/services/web/app/src/Features/Subscription/SubscriptionLocator.js @@ -40,6 +40,17 @@ const SubscriptionLocator = { .exec(callback) }, + getAdminEmailAndName(subscriptionId, callback) { + Subscription.findById(subscriptionId) + .populate('admin_id', ['email', 'first_name', 'last_name']) + .exec((err, subscription) => { + if (err) { + return callback(err) + } + callback(err, subscription?.admin_id) + }) + }, + hasRecurlyGroupSubscription(userOrId, callback) { const userId = SubscriptionLocator._getUserId(userOrId) Subscription.exists( @@ -111,6 +122,7 @@ SubscriptionLocator.promises = { SubscriptionLocator.getManagedGroupSubscriptions ), getMemberSubscriptions: promisify(SubscriptionLocator.getMemberSubscriptions), + getAdminEmailAndName: promisify(SubscriptionLocator.getAdminEmailAndName), getSubscription: promisify(SubscriptionLocator.getSubscription), getSubscriptionByMemberIdAndId: promisify( SubscriptionLocator.getSubscriptionByMemberIdAndId diff --git a/services/web/app/src/Features/Subscription/TeamInvitesHandler.js b/services/web/app/src/Features/Subscription/TeamInvitesHandler.js index 8a5967e6dc..913a1448c5 100644 --- a/services/web/app/src/Features/Subscription/TeamInvitesHandler.js +++ b/services/web/app/src/Features/Subscription/TeamInvitesHandler.js @@ -1,4 +1,5 @@ const logger = require('@overleaf/logger') +const OError = require('@overleaf/o-error') const crypto = require('crypto') const settings = require('@overleaf/settings') @@ -147,13 +148,50 @@ async function _createInvite(subscription, email, inviter) { await subscription.save() - const opts = { - to: email, - inviter, - acceptInviteUrl: `${settings.siteUrl}/subscription/invites/${invite.token}/`, - appName: settings.appName, + if (subscription.groupPolicy) { + let admin = {} + try { + admin = await SubscriptionLocator.promises.getAdminEmailAndName( + subscription._id + ) + } catch (error) { + logger.error( + OError.tag(error, 'error getting subscription admin email and name') + ) + } + + const user = await UserGetter.promises.getUserByAnyEmail(email) + + const opts = { + to: email, + admin, + inviter, + acceptInviteUrl: `${settings.siteUrl}/subscription/invites/${invite.token}/`, + appName: settings.appName, + } + + if (user) { + await EmailHandler.promises.sendEmail( + 'verifyEmailToJoinManagedUsers', + opts + ) + } else { + await EmailHandler.promises.sendEmail( + 'inviteNewUserToJoinManagedUsers', + opts + ) + } + } else { + const opts = { + to: email, + inviter, + acceptInviteUrl: `${settings.siteUrl}/subscription/invites/${invite.token}/`, + appName: settings.appName, + } + + await EmailHandler.promises.sendEmail('verifyEmailToJoinTeam', opts) } - await EmailHandler.promises.sendEmail('verifyEmailToJoinTeam', opts) + Object.assign(invite, { invite: true }) return invite }