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
}