TeamInvitesHandler.coffee 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. logger = require("logger-sharelatex")
  2. crypto = require("crypto")
  3. async = require("async")
  4. settings = require("settings-sharelatex")
  5. ObjectId = require("mongojs").ObjectId
  6. TeamInvite = require("../../models/TeamInvite").TeamInvite
  7. Subscription = require("../../models/Subscription").Subscription
  8. UserGetter = require("../User/UserGetter")
  9. SubscriptionLocator = require("./SubscriptionLocator")
  10. SubscriptionUpdater = require("./SubscriptionUpdater")
  11. LimitationsManager = require("./LimitationsManager")
  12. EmailHandler = require("../Email/EmailHandler")
  13. module.exports = TeamInvitesHandler =
  14. getInvite: (token, callback) ->
  15. Subscription.findOne 'teamInvites.token': token, (err, subscription) ->
  16. return callback(err) if err?
  17. return callback(teamNotFound: true) unless subscription?
  18. invite = subscription.teamInvites.find (i) -> i.token == token
  19. return callback(null, invite, subscription)
  20. createManagerInvite: (teamManagerId, email, callback) ->
  21. logger.log {teamManagerId, email}, "Creating manager team invite"
  22. UserGetter.getUser teamManagerId, (error, teamManager) ->
  23. return callback(error) if error?
  24. SubscriptionLocator.getUsersSubscription teamManagerId, (error, subscription) ->
  25. return callback(error) if error?
  26. if teamManager.first_name and teamManager.last_name
  27. inviterName = "#{teamManager.first_name} #{teamManager.last_name} (#{teamManager.email})"
  28. else
  29. inviterName = teamManager.email
  30. createInvite(subscription, email, inviterName, callback)
  31. createDomainInvite: (user, licence, callback) ->
  32. logger.log {licence, email: user.email}, "Creating domain team invite"
  33. SubscriptionLocator.getSubscription licence.subscription_id, (error, subscription) ->
  34. return callback(error) if error?
  35. createInvite(subscription, user.email, licence.name, callback)
  36. acceptInvite: (token, userId, callback) ->
  37. logger.log {userId}, "Accepting invite"
  38. TeamInvitesHandler.getInvite token, (err, invite, subscription) ->
  39. return callback(err) if err?
  40. return callback(inviteNoLongerValid: true) unless invite?
  41. SubscriptionUpdater.addUserToGroup subscription.admin_id, userId, (err) ->
  42. return callback(err) if err?
  43. removeInviteFromTeam(subscription.id, invite.email, callback)
  44. revokeInvite: (teamManagerId, email, callback) ->
  45. logger.log {teamManagerId, email}, "Revoking invite"
  46. SubscriptionLocator.getUsersSubscription teamManagerId, (err, teamSubscription) ->
  47. return callback(err) if err?
  48. removeInviteFromTeam(teamSubscription.id, email, callback)
  49. # Legacy method to allow a user to receive a confirmation email if their
  50. # email is in Subscription.invited_emails when they join. We'll remove this
  51. # after a short while.
  52. createTeamInvitesForLegacyInvitedEmail: (email, callback) ->
  53. SubscriptionLocator.getGroupsWithEmailInvite email, (err, teams) ->
  54. return callback(err) if err?
  55. async.map teams,
  56. (team, cb) -> TeamInvitesHandler.createManagerInvite(team.admin_id, email, cb)
  57. , callback
  58. createInvite = (subscription, email, inviterName, callback) ->
  59. logger.log {subscriptionId: subscription.id, email, inviterName}, "Creating invite"
  60. checkIfInviteIsPossible subscription, email, (error, possible, reason) ->
  61. return callback(error) if error?
  62. return callback(reason) unless possible
  63. # TODO: use standard way to canonalise email addresses
  64. email = email.trim().toLowerCase()
  65. invite = subscription.teamInvites.find (invite) -> invite.email == email
  66. if !invite?
  67. invite = {
  68. email: email
  69. inviterName: inviterName
  70. token: crypto.randomBytes(32).toString("hex")
  71. sentAt: new Date()
  72. }
  73. subscription.teamInvites.push(invite)
  74. else
  75. invite.sentAt = new Date()
  76. subscription.save (error) ->
  77. return callback(error) if error?
  78. opts =
  79. to: email
  80. inviterName: inviterName
  81. acceptInviteUrl: "#{settings.siteUrl}/subscription/invites/#{invite.token}/"
  82. appName: settings.appName
  83. EmailHandler.sendEmail "verifyEmailToJoinTeam", opts, (error) ->
  84. return callback(error, invite)
  85. removeInviteFromTeam = (subscriptionId, email, callback) ->
  86. searchConditions = { _id: new ObjectId(subscriptionId.toString()) }
  87. updateOp = { $pull: { teamInvites: { email: email.trim().toLowerCase() } } }
  88. Subscription.update(searchConditions, updateOp, callback)
  89. checkIfInviteIsPossible = (subscription, email, callback = (error, possible, reason) -> ) ->
  90. if LimitationsManager.teamHasReachedMemberLimit(subscription)
  91. logger.log {subscriptionId: subscription.id}, "team has reached member limit"
  92. return callback(null, false, limitReached: true)
  93. async.map subscription.member_ids, UserGetter.getUser, (error, members) ->
  94. return callback(error) if error?
  95. existingMember = members.find (member) -> member.email == email
  96. if existingMember
  97. logger.log {subscriptionId: subscription.id, email}, "user already in team"
  98. return callback(null, false, alreadyInTeam: true)
  99. else
  100. return callback(null, true)