Use team invites to join domain licensed teams

This commit is contained in:
Alberto Fernández Capel 2018-05-31 16:15:47 +01:00
parent 39c8595c27
commit d262de14d6
10 changed files with 109 additions and 118 deletions

View file

@ -0,0 +1,47 @@
SubscriptionGroupHandler = require("./SubscriptionGroupHandler")
logger = require("logger-sharelatex")
SubscriptionLocator = require("./SubscriptionLocator")
ErrorsController = require("../Errors/ErrorController")
SubscriptionDomainHandler = require("./SubscriptionDomainHandler")
AuthenticationController = require('../Authentication/AuthenticationController')
TeamInvitesHandler = require('./TeamInvitesHandler')
async = require("async")
module.exports =
join: (req, res)->
user = AuthenticationController.getSessionUser(req)
licence = SubscriptionDomainHandler.getLicenceUserCanJoin(user)
if !licence?
return ErrorsController.notFound(req, res)
jobs =
partOfGroup: (cb)->
SubscriptionGroupHandler.isUserPartOfGroup user.id, licence.group_subscription_id, cb
subscription: (cb)->
SubscriptionLocator.getUsersSubscription user.id, cb
async.series jobs, (err, results)->
{ partOfGroup, subscription } = results
if partOfGroup
return res.redirect("/user/subscription/custom_account")
else
res.render "subscriptions/domain/join",
title: "Group Invitation"
group_subscription_id: licence.group_subscription_id
licenceName: licence.name
has_personal_subscription: subscription?
createInvite: (req, res)->
user = AuthenticationController.getSessionUser(req)
licence = SubscriptionDomainHandler.getLicenceUserCanJoin(user)
if !licence?
return ErrorsController.notFound(req, res)
TeamInvitesHandler.createDomainInvite user, licence, (err) ->
if err?
res.sendStatus 500
else
res.sendStatus 200

View file

@ -1,45 +0,0 @@
SubscriptionGroupHandler = require("./SubscriptionGroupHandler")
logger = require("logger-sharelatex")
SubscriptionLocator = require("./SubscriptionLocator")
ErrorsController = require("../Errors/ErrorController")
SubscriptionDomainHandler = require("./SubscriptionDomainHandler")
AuthenticationController = require('../Authentication/AuthenticationController')
async = require("async")
module.exports =
newInvite: (req, res)->
group_subscription_id = req.params.subscription_id
user_id = AuthenticationController.getLoggedInUserId(req)
licence = SubscriptionDomainHandler.findDomainLicenceBySubscriptionId(group_subscription_id)
if !licence?
return ErrorsController.notFound(req, res)
jobs =
partOfGroup: (cb)->
SubscriptionGroupHandler.isUserPartOfGroup user_id, licence.group_subscription_id, cb
subscription: (cb)->
SubscriptionLocator.getUsersSubscription user_id, cb
async.series jobs, (err, results)->
{partOfGroup, subscription} = results
if partOfGroup
return res.redirect("/user/subscription/custom_account")
else
res.render "subscriptions/group/join",
title: "Group Invitation"
group_subscription_id:group_subscription_id
licenceName:licence.name
has_personal_subscription: subscription?
createInvite: (req, res)->
subscription_id = req.params.subscription_id
currentUser = AuthenticationController.getSessionUser(req)
if !currentUser?
logger.err {subscription_id}, "error getting current user"
return res.sendStatus 500
licence = SubscriptionDomainHandler.findDomainLicenceBySubscriptionId(subscription_id)
if !licence?
return ErrorsController.notFound(req, res)
SubscriptionGroupHandler.sendVerificationEmail subscription_id, licence.name, currentUser.email, (err)->
if err?
res.sendStatus 500
else
res.sendStatus 200

View file

@ -15,7 +15,7 @@ module.exports = SubscriptionDomainHandler =
getDomainLicencePage: (user)->
licence = SubscriptionDomainHandler._findDomainLicence(user.email)
if licence?.verifyEmail
return "/user/subscription/#{licence.subscription_id}/group/invited"
return "/user/subscription/domain/join"
else
return undefined

View file

@ -1,7 +1,7 @@
AuthenticationController = require('../Authentication/AuthenticationController')
SubscriptionController = require('./SubscriptionController')
SubscriptionGroupController = require './SubscriptionGroupController'
DomainSubscriptionController = require './DomainSubscriptionController'
DomainLicenceController = require './DomainLicenceController'
TeamInvitesController = require './TeamInvitesController'
Settings = require "settings-sharelatex"
@ -38,8 +38,8 @@ module.exports =
TeamInvitesController.revokeInvite
# Routes to join a domain licence team
webRouter.get '/user/subscription/:subscription_id/group/join', AuthenticationController.requireLogin(), DomainSubscriptionController.newInvite
webRouter.post '/user/subscription/:subscription_id/group/join', AuthenticationController.requireLogin(), DomainSubscriptionController.createInvite
webRouter.get '/user/subscription/domain/join', AuthenticationController.requireLogin(), DomainLicenceController.join
webRouter.post '/user/subscription/domain/join', AuthenticationController.requireLogin(), DomainLicenceController.createInvite
#recurly callback
publicApiRouter.post '/user/subscription/callback', SubscriptionController.recurlyNotificationParser, SubscriptionController.recurlyCallback

View file

@ -2,6 +2,7 @@ settings = require "settings-sharelatex"
logger = require("logger-sharelatex")
TeamInvitesHandler = require('./TeamInvitesHandler')
AuthenticationController = require("../Authentication/AuthenticationController")
SubscriptionLocator = require("./SubscriptionLocator")
ErrorController = require("../Errors/ErrorController")
module.exports =
@ -20,19 +21,20 @@ module.exports =
token = req.params.token
userId = AuthenticationController.getLoggedInUserId(req)
TeamInvitesHandler.getInviteDetails token, userId, (err, results) ->
TeamInvitesHandler.getInvite token, (err, invite, teamSubscription) ->
next(err) if err?
{ invite, personalSubscription, inviterName } = results
unless invite?
return ErrorController.notFound(req, res, next)
res.render "subscriptions/group/team_invite",
inviterName: inviterName
inviteToken: invite.token
hasPersonalSubscription: personalSubscription?
appName: settings.appName
SubscriptionLocator.getUsersSubscription userId, (err, personalSubscription) ->
return callback(err) if err?
res.render "subscriptions/team/invite",
inviterName: invite.inviterName
inviteToken: invite.token
hasPersonalSubscription: personalSubscription?
appName: settings.appName
acceptInvite: (req, res, next) ->

View file

@ -19,47 +19,39 @@ module.exports = TeamInvitesHandler =
getInvites: (subscriptionId, callback) ->
TeamInvite.find(subscriptionId: subscriptionId, callback)
createInvite: (teamManagerId, email, callback) ->
getInvite: (token, callback) ->
Subscription.findOne 'teamInvites.token': token, (err, subscription) ->
return callback(err, subscription) if err?
return callback(teamNotFound: true) unless subscription?
invite = subscription.teamInvites.find (i) -> i.token == token
return callback(null, invite, subscription)
createManagerInvite: (teamManagerId, email, callback) ->
UserLocator.findById teamManagerId, (error, teamManager) ->
return callback(error) if error?
SubscriptionLocator.getUsersSubscription teamManagerId, (error, subscription) ->
return callback(error) if error?
if LimitationsManager.teamHasReachedMemberLimit(subscription)
return callback(limitReached: true)
if teamManager.first_name and teamManager.last_name
inviterName = "#{teamManager.first_name} #{teamManager.last_name} (#{teamManager.email})"
else
inviterName = teamManager.email
existingInvite = subscription.teamInvites.find (invite) -> invite.email == email
TeamInvitesHandler.createInvite(subscription, email, inviterName, callback)
if existingInvite
return callback(alreadyInvited: true)
inviterName = TeamInvitesHandler.inviterName(teamManager)
token = crypto.randomBytes(32).toString("hex")
invite = {
email: email,
token: token,
sentAt: new Date(),
}
subscription.teamInvites.push(invite)
subscription.save (error) ->
return callback(error) if error?
# TODO: use standard way to canonalise email addresses
opts =
to: email.trim().toLowerCase()
inviterName: inviterName
acceptInviteUrl: "#{settings.siteUrl}/subscription/invites/#{token}/"
EmailHandler.sendEmail "verifyEmailToJoinTeam", opts, (error) ->
return callback(error, invite)
createDomainInvite: (user, licence, callback) ->
SubscriptionLocator.getSubscription licence.subscription_id, (error, subscription) ->
return callback(error) if error?
TeamInvitesHandler.createInvite(subscription, user.email, licence.name, callback)
acceptInvite: (token, userId, callback) ->
TeamInvitesHandler.getInviteAndManager token, (err, invite, subscription, teamManager) ->
TeamInvitesHandler.getInvite token, (err, invite, subscription) ->
return callback(err) if err?
return callback(inviteNoLongerValid: true) unless invite? and teamManager?
return callback(inviteNoLongerValid: true) unless invite?
SubscriptionUpdater.addUserToGroup teamManager, userId, (err) ->
SubscriptionUpdater.addUserToGroup subscription.admin_id, userId, (err) ->
return callback(err) if err?
TeamInvitesHandler.removeInviteFromTeam(subscription.id, invite.email, callback)
@ -70,45 +62,39 @@ module.exports = TeamInvitesHandler =
TeamInvitesHandler.removeInviteFromTeam(teamSubscription.id, email, callback)
getInviteDetails: (token, userId, callback) ->
TeamInvitesHandler.getInviteAndManager token, (err, invite, teamSubscription, teamManager) ->
return callback(err) if err?
createInvite: (subscription, email, inviterName, callback) ->
if LimitationsManager.teamHasReachedMemberLimit(subscription)
return callback(limitReached: true)
SubscriptionLocator.getUsersSubscription userId, (err, personalSubscription) ->
return callback(err) if err?
existingInvite = subscription.teamInvites.find (invite) -> invite.email == email
return callback(null , {
invite: invite,
personalSubscription: personalSubscription,
team: teamSubscription,
inviterName: TeamInvitesHandler.inviterName(teamManager),
teamManager: teamManager
})
if existingInvite
return callback(alreadyInvited: true)
getInviteAndManager: (token, callback) ->
TeamInvitesHandler.getInvite token, (err, invite, teamSubscription) ->
return callback(err) if err?
token = crypto.randomBytes(32).toString("hex")
UserLocator.findById teamSubscription.admin_id, (err, teamManager) ->
return callback(err, invite, teamSubscription, teamManager)
invite = {
email: email,
token: token,
inviterName: inviterName,
sentAt: new Date(),
}
getInvite: (token, callback) ->
Subscription.findOne 'teamInvites.token': token, (err, subscription) ->
return callback(err, subscription) if err?
return callback(teamNotFound: true) unless subscription?
subscription.teamInvites.push(invite)
invite = subscription.teamInvites.find (i) -> i.token == token
return callback(null, invite, subscription)
subscription.save (error) ->
return callback(error) if error?
# TODO: use standard way to canonalise email addresses
opts =
to: email.trim().toLowerCase()
inviterName: inviterName
acceptInviteUrl: "#{settings.siteUrl}/subscription/invites/#{token}/"
EmailHandler.sendEmail "verifyEmailToJoinTeam", opts, (error) ->
return callback(error, invite)
removeInviteFromTeam: (subscriptionId, email, callback) ->
searchConditions = { _id: new ObjectId(subscriptionId.toString()) }
updateOp = { $pull: { teamInvites: { email: email.trim().toLowerCase() } } }
Subscription.update(searchConditions, updateOp, callback)
inviterName: (teamManager) ->
if teamManager.first_name and teamManager.last_name
"#{teamManager.first_name} #{teamManager.last_name} (#{teamManager.email})"
else
teamManager.email

View file

@ -7,6 +7,7 @@ ObjectId = Schema.ObjectId
TeamInviteSchema = new Schema
email : { type: String, required: true }
token : { type: String }
inviterName : { type: String }
sentAt : { type: Date }
mongoose.model 'TeamInvite', TeamInviteSchema

View file

@ -25,7 +25,7 @@ define [
$scope.joinGroup = ->
$scope.view = "requestSent"
$scope.inflight = true
request = $http.post "/user/subscription/#{group_subscription_id}/group/join", {_csrf:window.csrfToken}
request = $http.post "/user/subscription/domain/join", {_csrf:window.csrfToken}
request.then (response)->
{ status } = response
$scope.inflight = false