mirror of
https://github.com/overleaf/overleaf.git
synced 2024-09-23 02:55:13 -04:00
289 lines
7.6 KiB
JavaScript
289 lines
7.6 KiB
JavaScript
|
/* eslint-disable
|
||
|
handle-callback-err,
|
||
|
max-len,
|
||
|
no-unused-vars,
|
||
|
*/
|
||
|
// TODO: This file was created by bulk-decaffeinate.
|
||
|
// Fix any style issues and re-enable lint.
|
||
|
/*
|
||
|
* decaffeinate suggestions:
|
||
|
* DS102: Remove unnecessary code created because of implicit returns
|
||
|
* DS207: Consider shorter variations of null checks
|
||
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||
|
*/
|
||
|
let TeamInvitesHandler
|
||
|
const logger = require('logger-sharelatex')
|
||
|
const crypto = require('crypto')
|
||
|
const async = require('async')
|
||
|
|
||
|
const settings = require('settings-sharelatex')
|
||
|
const { ObjectId } = require('mongojs')
|
||
|
|
||
|
const { TeamInvite } = require('../../models/TeamInvite')
|
||
|
const { Subscription } = require('../../models/Subscription')
|
||
|
|
||
|
const UserGetter = require('../User/UserGetter')
|
||
|
const SubscriptionLocator = require('./SubscriptionLocator')
|
||
|
const SubscriptionUpdater = require('./SubscriptionUpdater')
|
||
|
const LimitationsManager = require('./LimitationsManager')
|
||
|
|
||
|
const EmailHandler = require('../Email/EmailHandler')
|
||
|
const EmailHelper = require('../Helpers/EmailHelper')
|
||
|
|
||
|
const Errors = require('../Errors/Errors')
|
||
|
|
||
|
module.exports = TeamInvitesHandler = {
|
||
|
getInvite(token, callback) {
|
||
|
return Subscription.findOne({ 'teamInvites.token': token }, function(
|
||
|
err,
|
||
|
subscription
|
||
|
) {
|
||
|
if (err != null) {
|
||
|
return callback(err)
|
||
|
}
|
||
|
if (subscription == null) {
|
||
|
return callback(new Errors.NotFoundError('team not found'))
|
||
|
}
|
||
|
|
||
|
const invite = subscription.teamInvites.find(i => i.token === token)
|
||
|
return callback(null, invite, subscription)
|
||
|
})
|
||
|
},
|
||
|
|
||
|
createInvite(teamManagerId, subscription, email, callback) {
|
||
|
email = EmailHelper.parseEmail(email)
|
||
|
if (email == null) {
|
||
|
return callback(new Error('invalid email'))
|
||
|
}
|
||
|
logger.log({ teamManagerId, email }, 'Creating manager team invite')
|
||
|
return UserGetter.getUser(teamManagerId, function(error, teamManager) {
|
||
|
let inviterName
|
||
|
if (error != null) {
|
||
|
return callback(error)
|
||
|
}
|
||
|
|
||
|
if (teamManager.first_name && teamManager.last_name) {
|
||
|
inviterName = `${teamManager.first_name} ${teamManager.last_name} (${
|
||
|
teamManager.email
|
||
|
})`
|
||
|
} else {
|
||
|
inviterName = teamManager.email
|
||
|
}
|
||
|
|
||
|
return removeLegacyInvite(subscription.id, email, function(error) {
|
||
|
if (error != null) {
|
||
|
return callback(error)
|
||
|
}
|
||
|
return createInvite(subscription, email, inviterName, callback)
|
||
|
})
|
||
|
})
|
||
|
},
|
||
|
|
||
|
importInvite(subscription, inviterName, email, token, sentAt, callback) {
|
||
|
return checkIfInviteIsPossible(subscription, email, function(
|
||
|
error,
|
||
|
possible,
|
||
|
reason
|
||
|
) {
|
||
|
if (error != null) {
|
||
|
return callback(error)
|
||
|
}
|
||
|
if (!possible) {
|
||
|
return callback(reason)
|
||
|
}
|
||
|
|
||
|
subscription.teamInvites.push({
|
||
|
email,
|
||
|
inviterName,
|
||
|
token,
|
||
|
sentAt
|
||
|
})
|
||
|
|
||
|
return subscription.save(callback)
|
||
|
})
|
||
|
},
|
||
|
|
||
|
acceptInvite(token, userId, callback) {
|
||
|
logger.log({ userId }, 'Accepting invite')
|
||
|
return TeamInvitesHandler.getInvite(token, function(
|
||
|
err,
|
||
|
invite,
|
||
|
subscription
|
||
|
) {
|
||
|
if (err != null) {
|
||
|
return callback(err)
|
||
|
}
|
||
|
if (invite == null) {
|
||
|
return callback(new Errors.NotFoundError('invite not found'))
|
||
|
}
|
||
|
|
||
|
return SubscriptionUpdater.addUserToGroup(
|
||
|
subscription._id,
|
||
|
userId,
|
||
|
function(err) {
|
||
|
if (err != null) {
|
||
|
return callback(err)
|
||
|
}
|
||
|
|
||
|
return removeInviteFromTeam(subscription.id, invite.email, callback)
|
||
|
}
|
||
|
)
|
||
|
})
|
||
|
},
|
||
|
|
||
|
revokeInvite(teamManagerId, subscription, email, callback) {
|
||
|
email = EmailHelper.parseEmail(email)
|
||
|
if (email == null) {
|
||
|
return callback(new Error('invalid email'))
|
||
|
}
|
||
|
logger.log({ teamManagerId, email }, 'Revoking invite')
|
||
|
return removeInviteFromTeam(subscription.id, email, callback)
|
||
|
},
|
||
|
|
||
|
// Legacy method to allow a user to receive a confirmation email if their
|
||
|
// email is in Subscription.invited_emails when they join. We'll remove this
|
||
|
// after a short while.
|
||
|
createTeamInvitesForLegacyInvitedEmail(email, callback) {
|
||
|
return SubscriptionLocator.getGroupsWithEmailInvite(email, function(
|
||
|
err,
|
||
|
teams
|
||
|
) {
|
||
|
if (err != null) {
|
||
|
return callback(err)
|
||
|
}
|
||
|
|
||
|
return async.map(
|
||
|
teams,
|
||
|
(team, cb) =>
|
||
|
TeamInvitesHandler.createInvite(team.admin_id, team, email, cb),
|
||
|
callback
|
||
|
)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var createInvite = function(subscription, email, inviterName, callback) {
|
||
|
logger.log(
|
||
|
{ subscriptionId: subscription.id, email, inviterName },
|
||
|
'Creating invite'
|
||
|
)
|
||
|
return checkIfInviteIsPossible(subscription, email, function(
|
||
|
error,
|
||
|
possible,
|
||
|
reason
|
||
|
) {
|
||
|
if (error != null) {
|
||
|
return callback(error)
|
||
|
}
|
||
|
if (!possible) {
|
||
|
return callback(reason)
|
||
|
}
|
||
|
|
||
|
let invite = subscription.teamInvites.find(invite => invite.email === email)
|
||
|
|
||
|
if (invite == null) {
|
||
|
invite = {
|
||
|
email,
|
||
|
inviterName,
|
||
|
token: crypto.randomBytes(32).toString('hex'),
|
||
|
sentAt: new Date()
|
||
|
}
|
||
|
subscription.teamInvites.push(invite)
|
||
|
} else {
|
||
|
invite.sentAt = new Date()
|
||
|
}
|
||
|
|
||
|
return subscription.save(function(error) {
|
||
|
if (error != null) {
|
||
|
return callback(error)
|
||
|
}
|
||
|
|
||
|
const opts = {
|
||
|
to: email,
|
||
|
inviterName,
|
||
|
acceptInviteUrl: `${settings.siteUrl}/subscription/invites/${
|
||
|
invite.token
|
||
|
}/`,
|
||
|
appName: settings.appName
|
||
|
}
|
||
|
return EmailHandler.sendEmail('verifyEmailToJoinTeam', opts, error =>
|
||
|
callback(error, invite)
|
||
|
)
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
|
||
|
var removeInviteFromTeam = function(subscriptionId, email, callback) {
|
||
|
const searchConditions = { _id: new ObjectId(subscriptionId.toString()) }
|
||
|
const removeInvite = { $pull: { teamInvites: { email } } }
|
||
|
logger.log(
|
||
|
{ subscriptionId, email, searchConditions, removeInvite },
|
||
|
'removeInviteFromTeam'
|
||
|
)
|
||
|
|
||
|
return async.series(
|
||
|
[
|
||
|
cb => Subscription.update(searchConditions, removeInvite, cb),
|
||
|
cb => removeLegacyInvite(subscriptionId, email, cb)
|
||
|
],
|
||
|
callback
|
||
|
)
|
||
|
}
|
||
|
|
||
|
var removeLegacyInvite = (subscriptionId, email, callback) =>
|
||
|
Subscription.update(
|
||
|
{
|
||
|
_id: new ObjectId(subscriptionId.toString())
|
||
|
},
|
||
|
{
|
||
|
$pull: {
|
||
|
invited_emails: email
|
||
|
}
|
||
|
},
|
||
|
callback
|
||
|
)
|
||
|
|
||
|
var checkIfInviteIsPossible = function(subscription, email, callback) {
|
||
|
if (callback == null) {
|
||
|
callback = function(error, possible, reason) {}
|
||
|
}
|
||
|
if (!subscription.groupPlan) {
|
||
|
logger.log(
|
||
|
{ subscriptionId: subscription.id },
|
||
|
'can not add members to a subscription that is not in a group plan'
|
||
|
)
|
||
|
return callback(null, false, { wrongPlan: true })
|
||
|
}
|
||
|
|
||
|
if (LimitationsManager.teamHasReachedMemberLimit(subscription)) {
|
||
|
logger.log(
|
||
|
{ subscriptionId: subscription.id },
|
||
|
'team has reached member limit'
|
||
|
)
|
||
|
return callback(null, false, { limitReached: true })
|
||
|
}
|
||
|
|
||
|
return UserGetter.getUserByAnyEmail(email, function(error, existingUser) {
|
||
|
if (error != null) {
|
||
|
return callback(error)
|
||
|
}
|
||
|
if (existingUser == null) {
|
||
|
return callback(null, true)
|
||
|
}
|
||
|
|
||
|
const existingMember = subscription.member_ids.find(
|
||
|
memberId => memberId.toString() === existingUser._id.toString()
|
||
|
)
|
||
|
|
||
|
if (existingMember) {
|
||
|
logger.log(
|
||
|
{ subscriptionId: subscription.id, email },
|
||
|
'user already in team'
|
||
|
)
|
||
|
return callback(null, false, { alreadyInTeam: true })
|
||
|
} else {
|
||
|
return callback(null, true)
|
||
|
}
|
||
|
})
|
||
|
}
|