diff --git a/services/web/app/coffee/Features/Subscription/LimitationsManager.coffee b/services/web/app/coffee/Features/Subscription/LimitationsManager.coffee index f09dde2453..9b5137392f 100644 --- a/services/web/app/coffee/Features/Subscription/LimitationsManager.coffee +++ b/services/web/app/coffee/Features/Subscription/LimitationsManager.coffee @@ -6,7 +6,7 @@ Settings = require("settings-sharelatex") CollaboratorsHandler = require("../Collaborators/CollaboratorsHandler") CollaboratorsInvitesHandler = require("../Collaborators/CollaboratorsInviteHandler") -module.exports = +module.exports = LimitationsManager = allowedNumberOfCollaboratorsInProject: (project_id, callback) -> ProjectGetter.getProject project_id, owner_ref: true, (error, project) => return callback(error) if error? @@ -56,7 +56,7 @@ module.exports = callback err, subscriptions.length > 0, subscriptions teamHasReachedMemberLimit: (subscription) -> - currentTotal = (subscription.member_ids or []).length + (subscription.team_invites or []).length + currentTotal = (subscription.member_ids or []).length + (subscription.teamInvites or []).length return currentTotal >= subscription.membersLimit hasGroupMembersLimitReached: (user_id, callback = (err, limitReached, subscription)->)-> @@ -67,7 +67,6 @@ module.exports = if !subscription? logger.err user_id:user_id, "no subscription found for user" return callback("no subscription found") - currentTotal = (subscription.member_ids or []).length + (subscription.invited_emails or []).length - limitReached = currentTotal >= subscription.membersLimit - logger.log user_id:user_id, limitReached:limitReached, currentTotal: currentTotal, membersLimit: subscription.membersLimit, "checking if subscription members limit has been reached" + + limitReached = LimitationsManager.teamHasReachedMemberLimit(subscription) callback(err, limitReached, subscription) diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee index ffb5c6e832..8e84f1fb0b 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee @@ -33,14 +33,6 @@ module.exports = return res.sendStatus 500 res.send() - removeEmailInviteFromGroup: (req, res)-> - adminUserId = AuthenticationController.getLoggedInUserId(req) - email = req.params.email - logger.log {adminUserId, email}, "removing email invite from group subscription" - SubscriptionGroupHandler.removeEmailInviteFromGroup adminUserId, email, (err)-> - return next(error) if error? - res.send() - removeSelfFromGroup: (req, res)-> adminUserId = req.query.admin_user_id userToRemove_id = AuthenticationController.getLoggedInUserId(req) diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionGroupHandler.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionGroupHandler.coffee index d893bff7a1..b34dacc3e6 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionGroupHandler.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionGroupHandler.coffee @@ -33,7 +33,7 @@ module.exports = SubscriptionGroupHandler = userViewModel = buildUserViewModel(user) callback(err, userViewModel) else - SubscriptionUpdater.addEmailInviteToGroup adminUserId, newEmail, (err) -> + TeamInvitesHandler.createManagerInvite adminUserId, newEmail, (err) -> return callback(err) if err? userViewModel = buildEmailInviteViewModel(newEmail) callback(err, userViewModel) @@ -41,16 +41,11 @@ module.exports = SubscriptionGroupHandler = removeUserFromGroup: (adminUser_id, userToRemove_id, callback)-> SubscriptionUpdater.removeUserFromGroup adminUser_id, userToRemove_id, callback - removeEmailInviteFromGroup: (adminUser_id, email, callback) -> - SubscriptionUpdater.removeEmailInviteFromGroup adminUser_id, email, callback - getPopulatedListOfMembers: (adminUser_id, callback)-> SubscriptionLocator.getUsersSubscription adminUser_id, (err, subscription)-> return callback(err) if err? users = [] - for email in subscription.invited_emails or [] - users.push buildEmailInviteViewModel(email) for teamInvite in subscription.teamInvites or [] users.push buildEmailInviteViewModel(teamInvite.email) @@ -86,37 +81,6 @@ module.exports = SubscriptionGroupHandler = completeJoinUrl: "#{settings.siteUrl}/user/subscription/#{subscription_id}/group/complete-join?token=#{token}" EmailHandler.sendEmail "completeJoinGroupAccount", opts, callback - processGroupVerification: (userEmail, subscription_id, token, callback)-> - logger.log userEmail:userEmail, subscription_id:subscription_id, "processing group verification for user" - OneTimeTokenHandler.getValueFromTokenAndExpire token, (err, token_subscription_id)-> - if err? or subscription_id != token_subscription_id - logger.err userEmail:userEmail, token:token, "token value not found for processing group verification" - return callback("token_not_found") - SubscriptionLocator.getSubscription subscription_id, (err, subscription)-> - if err? - logger.err err:err, subscription:subscription, userEmail:userEmail, subscription_id:subscription_id, "error getting subscription" - return callback(err) - if !subscription? - logger.warn subscription_id:subscription_id, userEmail:userEmail, "no subscription found" - return callback() - SubscriptionGroupHandler.addUserToGroup subscription?.admin_id, userEmail, callback - - convertEmailInvitesToMemberships: (email, user_id, callback = (err) ->) -> - SubscriptionLocator.getGroupsWithEmailInvite email, (err, groups = []) -> - return callback(err) if err? - logger.log {email, user_id, groups}, "found groups to convert from email invite to member" - jobs = [] - for group in groups - do (group) -> - jobs.push (cb) -> - SubscriptionUpdater.removeEmailInviteFromGroup group.admin_id, email, (err) -> - return cb(err) if err? - SubscriptionUpdater.addUserToGroup group.admin_id, user_id, (err) -> - return cb(err) if err? - logger.log {group_id: group._id, user_id, email}, "converted email invite to group membership" - return cb() - async.series jobs, callback - buildUserViewModel = (user)-> u = email: user.email diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionLocator.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionLocator.coffee index 33376f504b..b0a6a5b021 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionLocator.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionLocator.coffee @@ -32,4 +32,4 @@ module.exports = Subscription.find {member_ids: user_id}, {_id:1, planCode:1}, callback getGroupsWithEmailInvite: (email, callback) -> - Subscription.find { invited_emails: email }, callback \ No newline at end of file + Subscription.find { teamInvites: { email: email } }, callback diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee index cf4bd73be9..e512a1c3dd 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee @@ -24,7 +24,6 @@ module.exports = webRouter.post '/subscription/group/user', AuthenticationController.requireLogin(), SubscriptionGroupController.addUserToGroup webRouter.get '/subscription/group/export', AuthenticationController.requireLogin(), SubscriptionGroupController.exportGroupCsv webRouter.delete '/subscription/group/user/:user_id', AuthenticationController.requireLogin(), SubscriptionGroupController.removeUserFromGroup - webRouter.delete '/subscription/group/email/:email', AuthenticationController.requireLogin(), SubscriptionGroupController.removeEmailInviteFromGroup webRouter.delete '/subscription/group/user', AuthenticationController.requireLogin(), SubscriptionGroupController.removeSelfFromGroup # Team invites diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee index cb5c39d122..16dc5adf25 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee @@ -26,28 +26,20 @@ module.exports = SubscriptionUpdater = addUserToGroup: (adminUser_id, user_id, callback)-> logger.log adminUser_id:adminUser_id, user_id:user_id, "adding user into mongo subscription" - searchOps = + searchOps = admin_id: adminUser_id - insertOperation = + insertOperation = "$addToSet": {member_ids:user_id} Subscription.findAndModify searchOps, insertOperation, (err, subscription)-> if err? logger.err err:err, searchOps:searchOps, insertOperation:insertOperation, "error findy and modify add user to group" return callback(err) FeaturesUpdater.refreshFeatures user_id, callback - - addEmailInviteToGroup: (adminUser_id, email, callback) -> - logger.log {adminUser_id, email}, "adding email into mongo subscription" - searchOps = - admin_id: adminUser_id - insertOperation = - "$addToSet": {invited_emails: email} - Subscription.findAndModify searchOps, insertOperation, callback removeUserFromGroup: (adminUser_id, user_id, callback)-> - searchOps = + searchOps = admin_id: adminUser_id - removeOperation = + removeOperation = "$pull": {member_ids:user_id} Subscription.update searchOps, removeOperation, (err)-> if err? @@ -55,13 +47,6 @@ module.exports = SubscriptionUpdater = return callback(err) FeaturesUpdater.refreshFeatures user_id, callback - removeEmailInviteFromGroup: (adminUser_id, email, callback)-> - Subscription.update { - admin_id: adminUser_id - }, "$pull": { - invited_emails: email - }, callback - deleteSubscription: (subscription_id, callback = (error) ->) -> SubscriptionLocator.getSubscription subscription_id, (err, subscription) -> return callback(err) if err? diff --git a/services/web/app/coffee/Features/Subscription/TeamInvitesController.coffee b/services/web/app/coffee/Features/Subscription/TeamInvitesController.coffee index ef1d90aa6a..565cdffcf1 100644 --- a/services/web/app/coffee/Features/Subscription/TeamInvitesController.coffee +++ b/services/web/app/coffee/Features/Subscription/TeamInvitesController.coffee @@ -10,7 +10,7 @@ module.exports = teamManagerId = AuthenticationController.getLoggedInUserId(req) email = req.body.email - TeamInvitesHandler.createInvite teamManagerId, email, (err, invite) -> + TeamInvitesHandler.createManagerInvite teamManagerId, email, (err, invite) -> return handleError(err, req, res, next) if err? inviteView = { user: { email: invite.email, sentAt: invite.sentAt, holdingAccount: true } diff --git a/services/web/app/coffee/Features/Subscription/TeamInvitesHandler.coffee b/services/web/app/coffee/Features/Subscription/TeamInvitesHandler.coffee index 4a4cf37357..37c99bafbe 100644 --- a/services/web/app/coffee/Features/Subscription/TeamInvitesHandler.coffee +++ b/services/web/app/coffee/Features/Subscription/TeamInvitesHandler.coffee @@ -1,5 +1,6 @@ logger = require("logger-sharelatex") crypto = require("crypto") +async = require("async") settings = require("settings-sharelatex") ObjectId = require("mongojs").ObjectId @@ -15,19 +16,16 @@ LimitationsManager = require("./LimitationsManager") EmailHandler = require("../Email/EmailHandler") module.exports = TeamInvitesHandler = - - getInvites: (subscriptionId, callback) -> - TeamInvite.find(subscriptionId: subscriptionId, callback) - getInvite: (token, callback) -> Subscription.findOne 'teamInvites.token': token, (err, subscription) -> - return callback(err, subscription) if err? + return callback(err) 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) -> + logger.log {teamManagerId, email}, "Creating manager team invite" UserLocator.findById teamManagerId, (error, teamManager) -> return callback(error) if error? @@ -39,14 +37,16 @@ module.exports = TeamInvitesHandler = else inviterName = teamManager.email - TeamInvitesHandler.createInvite(subscription, email, inviterName, callback) + createInvite(subscription, email, inviterName, callback) createDomainInvite: (user, licence, callback) -> + logger.log {licence, email: user.email}, "Creating domain team invite" SubscriptionLocator.getSubscription licence.subscription_id, (error, subscription) -> return callback(error) if error? - TeamInvitesHandler.createInvite(subscription, user.email, licence.name, callback) + createInvite(subscription, user.email, licence.name, callback) acceptInvite: (token, userId, callback) -> + logger.log {userId}, "Accepting invite" TeamInvitesHandler.getInvite token, (err, invite, subscription) -> return callback(err) if err? return callback(inviteNoLongerValid: true) unless invite? @@ -54,22 +54,19 @@ module.exports = TeamInvitesHandler = SubscriptionUpdater.addUserToGroup subscription.admin_id, userId, (err) -> return callback(err) if err? - TeamInvitesHandler.removeInviteFromTeam(subscription.id, invite.email, callback) + removeInviteFromTeam(subscription.id, invite.email, callback) revokeInvite: (teamManagerId, email, callback) -> + logger.log {teamManagerId, email}, "Revoking invite" SubscriptionLocator.getUsersSubscription teamManagerId, (err, teamSubscription) -> return callback(err) if err? - TeamInvitesHandler.removeInviteFromTeam(teamSubscription.id, email, callback) + removeInviteFromTeam(teamSubscription.id, email, callback) - createInvite: (subscription, email, inviterName, callback) -> - if LimitationsManager.teamHasReachedMemberLimit(subscription) - return callback(limitReached: true) - - existingInvite = subscription.teamInvites.find (invite) -> invite.email == email - - if existingInvite - return callback(alreadyInvited: true) +createInvite = (subscription, email, inviterName, callback) -> + logger.log {subscriptionId: subscription.id, email, inviterName}, "Creating invite" + checkIfInviteIsPossible subscription, email, (error, possible, reason) -> + return callback(reason) unless possible? token = crypto.randomBytes(32).toString("hex") @@ -93,8 +90,30 @@ module.exports = TeamInvitesHandler = 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() } } } +removeInviteFromTeam = (subscriptionId, email, callback) -> + searchConditions = { _id: new ObjectId(subscriptionId.toString()) } + updateOp = { $pull: { teamInvites: { email: email.trim().toLowerCase() } } } - Subscription.update(searchConditions, updateOp, callback) + Subscription.update(searchConditions, updateOp, callback) + +checkIfInviteIsPossible = (subscription, email, callback = (error, possible, reason) -> ) -> + if LimitationsManager.teamHasReachedMemberLimit(subscription) + logger.log {subscriptionId: subscription.id}, "team has reached member limit" + return callback(null, false, limitReached: true) + + existingInvite = subscription.teamInvites.find (invite) -> invite.email == email + + if existingInvite + logger.log {subscriptionId: subscription.id, email}, "user already invited" + return callback(null, false, alreadyInvited: true) + + async.map subscription.member_ids, UserLocator.findById, (error, members) -> + return callback(error) if error? + + existingMember = members.find (member) -> member.email == email + + if existingMember + logger.log {subscriptionId: subscription.id, email}, "user already in team" + return callback(null, false, alreadyInTeam: true) + else + return callback(null, true) diff --git a/services/web/test/unit/coffee/Subscription/LimitationsManagerTests.coffee b/services/web/test/unit/coffee/Subscription/LimitationsManagerTests.coffee index 3e0cf4c499..63af90f62d 100644 --- a/services/web/test/unit/coffee/Subscription/LimitationsManagerTests.coffee +++ b/services/web/test/unit/coffee/Subscription/LimitationsManagerTests.coffee @@ -55,7 +55,7 @@ describe "LimitationsManager", -> it "should return the number of collaborators the user is allowed", -> @callback.calledWith(null, @user.features.collaborators).should.equal true - + describe "allowedNumberOfCollaboratorsForUser", -> describe "when the user has no features", -> beforeEach -> @@ -286,7 +286,9 @@ describe "LimitationsManager", -> @subscription = membersLimit: 3 member_ids: ["", ""] - invited_emails: ["bob@example.com"] + teamInvites: [ + { email: "bob@example.com", sentAt: new Date(), token: "hey" } + ] it "should return true if the limit is hit (including members and invites)", (done)-> @SubscriptionLocator.getUsersSubscription.callsArgWith(1, null, @subscription) diff --git a/services/web/test/unit/coffee/Subscription/SubscriptionGroupControllerTests.coffee b/services/web/test/unit/coffee/Subscription/SubscriptionGroupControllerTests.coffee index 09eab53063..086babd3e7 100644 --- a/services/web/test/unit/coffee/Subscription/SubscriptionGroupControllerTests.coffee +++ b/services/web/test/unit/coffee/Subscription/SubscriptionGroupControllerTests.coffee @@ -24,10 +24,8 @@ describe "SubscriptionGroupController", -> @GroupHandler = addUserToGroup: sinon.stub().callsArgWith(2, null, @user) removeUserFromGroup: sinon.stub().callsArgWith(2) - removeEmailInviteFromGroup: sinon.stub().callsArgWith(2) isUserPartOfGroup: sinon.stub() sendVerificationEmail:sinon.stub() - processGroupVerification:sinon.stub() getPopulatedListOfMembers: sinon.stub().callsArgWith(1, null, [@user]) @SubscriptionLocator = getUsersSubscription: sinon.stub().callsArgWith(1, null, @subscription) @AuthenticationController = @@ -80,16 +78,6 @@ describe "SubscriptionGroupController", -> done() @Controller.removeUserFromGroup @req, res - describe "removeEmailInviteFromGroup", -> - it "should use the admin id for the logged in user and take the email from the params", (done)-> - email = "jo@example.com" - @req.params = email: email - res = - send : => - @GroupHandler.removeEmailInviteFromGroup.calledWith(@adminUserId, email).should.equal true - done() - @Controller.removeEmailInviteFromGroup @req, res - describe "renderSubscriptionGroupAdminPage", -> it "should redirect you if you don't have a group account", (done)-> @subscription.groupPlan = false @@ -109,97 +97,6 @@ describe "SubscriptionGroupController", -> done() @Controller.renderSubscriptionGroupAdminPage @req, res - describe "renderGroupInvitePage", -> - describe "with a valid licence", -> - beforeEach -> - @SubscriptionDomainHandler.findDomainLicenceBySubscriptionId.returns({subscription_id:@subscription_id, adminUser_id:@adminUserId}) - - it "should render subscriptions/group/invite if not part of group", (done)-> - @GroupHandler.isUserPartOfGroup.callsArgWith(2, null, false) - res = - render : (pageName)=> - pageName.should.equal "subscriptions/group/invite" - done() - @Controller.renderGroupInvitePage @req, res - - it "should redirect to custom page if is already part of group", (done)-> - @GroupHandler.isUserPartOfGroup.callsArgWith(2, null, true) - res = - redirect : (location)=> - location.should.equal "/user/subscription/custom_account" - done() - @Controller.renderGroupInvitePage @req, res - - describe "without a valid licence", -> - beforeEach -> - @SubscriptionDomainHandler.findDomainLicenceBySubscriptionId.returns(undefined) - - it "should send a 500", (done)-> - @Controller.renderGroupInvitePage @req, {} - @ErrorsController.notFound.called.should.equal true - done() - - - - describe "beginJoinGroup", -> - describe "with a valid licence", -> - beforeEach -> - @licenceName = "get amazing licence" - @SubscriptionDomainHandler.findDomainLicenceBySubscriptionId.returns({name:@licenceName}) - @GroupHandler.sendVerificationEmail.callsArgWith(3) - - it "should ask the SubscriptionGroupHandler to send the verification email", (done)-> - res = - sendStatus : (statusCode)=> - statusCode.should.equal 200 - @GroupHandler.sendVerificationEmail.calledWith(@subscription_id, @licenceName, @user_email).should.equal true - done() - @Controller.beginJoinGroup @req, res - - describe "without a valid licence", -> - beforeEach -> - @SubscriptionDomainHandler.findDomainLicenceBySubscriptionId.returns(undefined) - - it "should send a 500", (done)-> - @Controller.beginJoinGroup @req, {} - @ErrorsController.notFound.called.should.equal true - done() - - - describe "completeJoin", -> - describe "with a valid licence", -> - beforeEach -> - @GroupHandler.processGroupVerification.callsArgWith(3) - @SubscriptionDomainHandler.findDomainLicenceBySubscriptionId.returns({name:@licenceName}) - - it "should redirect to the success page upon processGroupVerification", (done)-> - @req.query.token = @token - res = - redirect : (location)=> - @GroupHandler.processGroupVerification.calledWith(@user_email, @subscription_id, @token).should.equal true - location.should.equal "/user/subscription/#{@subscription_id}/group/successful-join" - done() - @Controller.completeJoin @req, res - - describe "without a valid licence", -> - - it "should send a 500", (done)-> - @SubscriptionDomainHandler.findDomainLicenceBySubscriptionId.returns(undefined) - @Controller.completeJoin @req, {} - @ErrorsController.notFound.called.should.equal true - done() - - it "should redirect to the invited page with querystring if token was not found", (done)-> - @SubscriptionDomainHandler.findDomainLicenceBySubscriptionId.returns({name:@licenceName}) - @req.query.token = @token - @GroupHandler.processGroupVerification.callsArgWith(3, "token_not_found") - res = - redirect : (location)=> - location.should.equal "/user/subscription/#{@subscription_id}/group/invited?expired=true" - done() - @Controller.completeJoin @req, res - - describe "exportGroupCsv", -> beforeEach -> diff --git a/services/web/test/unit/coffee/Subscription/SubscriptionGroupHandlerTests.coffee b/services/web/test/unit/coffee/Subscription/SubscriptionGroupHandlerTests.coffee index 1daf43bbd7..59471c68f8 100644 --- a/services/web/test/unit/coffee/Subscription/SubscriptionGroupHandlerTests.coffee +++ b/services/web/test/unit/coffee/Subscription/SubscriptionGroupHandlerTests.coffee @@ -19,19 +19,20 @@ describe "SubscriptionGroupHandler", -> admin_id:@adminUser_id _id:@subscription_id - @SubscriptionLocator = + @SubscriptionLocator = getUsersSubscription: sinon.stub() getSubscriptionByMemberIdAndId: sinon.stub() getSubscription: sinon.stub() - @UserCreator = + @UserCreator = getUserOrCreateHoldingAccount: sinon.stub().callsArgWith(1, null, @user) @SubscriptionUpdater = addUserToGroup: sinon.stub().callsArgWith(2) removeUserFromGroup: sinon.stub().callsArgWith(2) - addEmailInviteToGroup: sinon.stub().callsArgWith(2) - removeEmailInviteFromGroup: sinon.stub().callsArgWith(2) + + @TeamInvitesHandler = + createManagerInvite: sinon.stub().callsArgWith(2) @UserLocator = findById: sinon.stub() @@ -47,7 +48,7 @@ describe "SubscriptionGroupHandler", -> @EmailHandler = sendEmail:sinon.stub() - @settings = + @settings = siteUrl:"http://www.sharelatex.com" @readStub = sinon.stub() @@ -58,6 +59,7 @@ describe "SubscriptionGroupHandler", -> "logger-sharelatex": log:-> "../User/UserCreator": @UserCreator "./SubscriptionUpdater": @SubscriptionUpdater + "./TeamInvitesHandler": @TeamInvitesHandler "./SubscriptionLocator": @SubscriptionLocator "../User/UserLocator": @UserLocator "./LimitationsManager": @LimitationsManager @@ -65,7 +67,7 @@ describe "SubscriptionGroupHandler", -> "../Email/EmailHandler":@EmailHandler "settings-sharelatex":@settings "../Notifications/NotificationsBuilder": @NotificationsBuilder - "logger-sharelatex": + "logger-sharelatex": err:-> log:-> warn:-> @@ -75,7 +77,7 @@ describe "SubscriptionGroupHandler", -> beforeEach -> @LimitationsManager.hasGroupMembersLimitReached.callsArgWith(1, null, false, @subscription) @UserLocator.findByEmail.callsArgWith(1, null, @user) - + it "should find the user", (done)-> @Handler.addUserToGroup @adminUser_id, @newEmail, (err)=> @UserLocator.findByEmail.calledWith(@newEmail).should.equal true @@ -85,7 +87,7 @@ describe "SubscriptionGroupHandler", -> @Handler.addUserToGroup @adminUser_id, @newEmail, (err)=> @SubscriptionUpdater.addUserToGroup.calledWith(@adminUser_id, @user._id).should.equal true done() - + it "should not add the user to the group if the limit has been reached", (done)-> @LimitationsManager.hasGroupMembersLimitReached.callsArgWith(1, null, true, @subscription) @Handler.addUserToGroup @adminUser_id, @newEmail, (err)=> @@ -103,11 +105,11 @@ describe "SubscriptionGroupHandler", -> @NotificationsBuilder.groupPlan.calledWith(@user, {subscription_id:@subscription._id}).should.equal true @readStub.called.should.equal true done() - - it "should add an email invite if no user is found", (done) -> + + it "should add a team invite if no user is found", (done) -> @UserLocator.findByEmail.callsArgWith(1, null, null) @Handler.addUserToGroup @adminUser_id, @newEmail, (err)=> - @SubscriptionUpdater.addEmailInviteToGroup.calledWith(@adminUser_id, @newEmail).should.equal true + @TeamInvitesHandler.createManagerInvite.calledWith(@adminUser_id, @newEmail).should.equal true done() describe "removeUserFromGroup", -> @@ -148,15 +150,18 @@ describe "SubscriptionGroupHandler", -> assert.deepEqual users[1], {_id:@subscription.member_ids[1]} assert.deepEqual users[2], {_id:@subscription.member_ids[2]} done() - + it "should return any invited users", (done) -> - @subscription.invited_emails = ["jo@example.com", "charlie@example.com"] + @subscription.teamInvites = [ + { email: "jo@example.com" }, + { email: "charlie@example.com" } + ] @Handler.getPopulatedListOfMembers @adminUser_id, (err, users)=> users[0].email.should.equal "jo@example.com" users[0].holdingAccount.should.equal true users[1].email.should.equal "charlie@example.com" users[1].holdingAccount.should.equal true - users.length.should.equal @subscription.invited_emails.length + users.length.should.equal @subscription.teamInvites.length done() describe "isUserPartOfGroup", -> @@ -192,47 +197,3 @@ describe "SubscriptionGroupHandler", -> emailOpts.to.should.equal @email emailOpts.group_name.should.equal @licenceName done() - - describe "processGroupVerification", -> - beforeEach -> - @token = "31dDAd2Da" - @SubscriptionLocator.getSubscription.callsArgWith(1, null, @subscription) - @Handler.addUserToGroup = sinon.stub().callsArgWith(2) - - it "should addUserToGroup", (done)-> - @OneTimeTokenHandler.getValueFromTokenAndExpire.callsArgWith(1, null, @subscription_id) - @Handler.processGroupVerification @email, @subscription_id, @token, (err)=> - @Handler.addUserToGroup.calledWith(@adminUser_id, @email).should.equal true - done() - - it "should return token_not_found error if it couldn't get the token", (done)-> - @OneTimeTokenHandler.getValueFromTokenAndExpire.callsArgWith(1) - @Handler.processGroupVerification @email, @subscription_id, @token, (err)=> - err.should.equal "token_not_found" - done() - - describe "convertEmailInvitesToMemberships", -> - beforeEach -> - @SubscriptionLocator.getGroupsWithEmailInvite = sinon.stub().yields(null, @groups = [{ admin_id: "group-1" }, { admin_id: "group-2" }]) - - it "should get groups with the email address invited to", (done) -> - @Handler.convertEmailInvitesToMemberships @email, @user_id, (err) => - @SubscriptionLocator.getGroupsWithEmailInvite.calledWith(@email).should.equal true - done() - - it "should remove the email from each group", (done) -> - @Handler.convertEmailInvitesToMemberships @email, @user_id, (err) => - for group in @groups - @SubscriptionUpdater.removeEmailInviteFromGroup - .calledWith(group.admin_id, @email) - .should.equal true - done() - - it "should add the user to each group", (done) -> - @Handler.convertEmailInvitesToMemberships @email, @user_id, (err) => - for group in @groups - @SubscriptionUpdater.addUserToGroup - .calledWith(group.admin_id, @user_id) - .should.equal true - done() - diff --git a/services/web/test/unit/coffee/Subscription/TeamInvitesHandlerTests.coffee b/services/web/test/unit/coffee/Subscription/TeamInvitesHandlerTests.coffee new file mode 100644 index 0000000000..f640887e88 --- /dev/null +++ b/services/web/test/unit/coffee/Subscription/TeamInvitesHandlerTests.coffee @@ -0,0 +1,22 @@ +SandboxedModule = require('sandboxed-module') +should = require('chai').should() +sinon = require 'sinon' +querystring = require 'querystring' +modulePath = "../../../../app/js/Features/Subscription/TeamInvitesHandler" + +describe "TeamInvitesHandler", -> + + describe "getInvite", -> + # TODO + + describe "createManagerInvite", -> + # TODO + + describe "createDomainInvite", -> + # TODO + + describe "acceptInvite", -> + # TODO + + describe "revokeInvite", -> + # TODO