2018-06-01 06:23:25 -04:00
|
|
|
SandboxedModule = require('sandboxed-module')
|
|
|
|
should = require('chai').should()
|
|
|
|
sinon = require 'sinon'
|
2018-06-01 10:37:09 -04:00
|
|
|
expect = require("chai").expect
|
2018-06-01 06:23:25 -04:00
|
|
|
querystring = require 'querystring'
|
|
|
|
modulePath = "../../../../app/js/Features/Subscription/TeamInvitesHandler"
|
|
|
|
|
2018-06-01 10:37:09 -04:00
|
|
|
ObjectId = require("mongojs").ObjectId
|
2018-06-11 09:20:35 -04:00
|
|
|
Errors = require("../../../../app/js/Features/Errors/Errors")
|
2018-06-01 10:37:09 -04:00
|
|
|
|
2018-06-01 06:23:25 -04:00
|
|
|
describe "TeamInvitesHandler", ->
|
2018-06-01 10:37:09 -04:00
|
|
|
beforeEach ->
|
|
|
|
@manager = {
|
|
|
|
id: "666666",
|
|
|
|
first_name: "Daenerys"
|
|
|
|
last_name: "Targaryen"
|
2018-06-11 09:20:35 -04:00
|
|
|
email: "daenerys@example.com"
|
2018-06-01 10:37:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@token = "aaaaaaaaaaaaaaaaaaaaaa"
|
|
|
|
|
|
|
|
@teamInvite = {
|
2018-06-11 09:20:35 -04:00
|
|
|
email: "jorah@example.com",
|
2018-06-01 10:37:09 -04:00
|
|
|
token: @token,
|
|
|
|
}
|
|
|
|
|
|
|
|
@subscription = {
|
|
|
|
id: "55153a8014829a865bbf700d",
|
|
|
|
admin_id: @manager.id,
|
2018-06-08 04:58:51 -04:00
|
|
|
groupPlan: true,
|
|
|
|
member_ids: [],
|
|
|
|
teamInvites: [ @teamInvite ],
|
|
|
|
save: sinon.stub().yields(null),
|
2018-06-01 10:37:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@SubscriptionLocator = {
|
|
|
|
getUsersSubscription: sinon.stub(),
|
|
|
|
getSubscription: sinon.stub().yields(null, @subscription)
|
|
|
|
}
|
|
|
|
|
2018-06-01 11:50:00 -04:00
|
|
|
@UserGetter = {
|
2018-06-07 07:49:46 -04:00
|
|
|
getUser: sinon.stub().yields(),
|
|
|
|
getUserByAnyEmail: sinon.stub().yields()
|
2018-06-01 10:37:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@SubscriptionUpdater = {
|
|
|
|
addUserToGroup: sinon.stub().yields()
|
|
|
|
}
|
|
|
|
|
|
|
|
@LimitationsManager = {
|
|
|
|
teamHasReachedMemberLimit: sinon.stub().returns(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Subscription = {
|
|
|
|
findOne: sinon.stub().yields()
|
|
|
|
update: sinon.stub().yields()
|
|
|
|
}
|
|
|
|
|
|
|
|
@EmailHandler = {
|
|
|
|
sendEmail: sinon.stub().yields(null)
|
|
|
|
}
|
|
|
|
|
|
|
|
@newToken = "bbbbbbbbb"
|
|
|
|
|
|
|
|
@crypto = {
|
|
|
|
randomBytes: =>
|
|
|
|
toString: sinon.stub().returns(@newToken)
|
|
|
|
}
|
|
|
|
|
2018-06-01 11:50:00 -04:00
|
|
|
@UserGetter.getUser.withArgs(@manager.id).yields(null, @manager)
|
2018-06-07 07:49:46 -04:00
|
|
|
@UserGetter.getUserByAnyEmail.withArgs(@manager.email).yields(null, @manager)
|
|
|
|
|
2018-06-01 10:37:09 -04:00
|
|
|
@SubscriptionLocator.getUsersSubscription.yields(null, @subscription)
|
|
|
|
@Subscription.findOne.yields(null, @subscription)
|
|
|
|
|
|
|
|
@TeamInvitesHandler = SandboxedModule.require modulePath, requires:
|
|
|
|
"logger-sharelatex": { log: -> }
|
|
|
|
"crypto": @crypto
|
|
|
|
"settings-sharelatex": { siteUrl: "http://example.com" }
|
|
|
|
"../../models/TeamInvite": { TeamInvite: @TeamInvite = {} }
|
|
|
|
"../../models/Subscription": { Subscription: @Subscription }
|
2018-06-01 11:50:00 -04:00
|
|
|
"../User/UserGetter": @UserGetter
|
2018-06-01 10:37:09 -04:00
|
|
|
"./SubscriptionLocator": @SubscriptionLocator
|
|
|
|
"./SubscriptionUpdater": @SubscriptionUpdater
|
|
|
|
"./LimitationsManager": @LimitationsManager
|
|
|
|
"../Email/EmailHandler": @EmailHandler
|
2018-06-11 09:20:35 -04:00
|
|
|
"../Errors/Errors": Errors
|
2018-06-01 10:37:09 -04:00
|
|
|
|
|
|
|
describe "getInvite", ->
|
|
|
|
it "returns the invite if there's one", (done) ->
|
|
|
|
@TeamInvitesHandler.getInvite @token, (err, invite, subscription) =>
|
|
|
|
expect(err).to.eq(null)
|
|
|
|
expect(invite).to.deep.eq(@teamInvite)
|
|
|
|
expect(subscription).to.deep.eq(@subscription)
|
|
|
|
done()
|
|
|
|
|
|
|
|
it "returns teamNotFound if there's none", (done) ->
|
|
|
|
@Subscription.findOne = sinon.stub().yields(null, null)
|
|
|
|
|
|
|
|
@TeamInvitesHandler.getInvite @token, (err, invite, subscription) ->
|
2018-06-11 09:20:35 -04:00
|
|
|
expect(err).to.be.instanceof(Errors.NotFoundError)
|
2018-06-01 10:37:09 -04:00
|
|
|
done()
|
|
|
|
|
2018-06-07 10:35:18 -04:00
|
|
|
describe "createInvite", ->
|
2018-06-01 10:37:09 -04:00
|
|
|
it "adds the team invite to the subscription", (done) ->
|
2018-06-11 09:20:35 -04:00
|
|
|
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
2018-06-01 10:37:09 -04:00
|
|
|
expect(err).to.eq(null)
|
|
|
|
expect(invite.token).to.eq(@newToken)
|
2018-06-11 09:20:35 -04:00
|
|
|
expect(invite.email).to.eq("john.snow@example.com")
|
|
|
|
expect(invite.inviterName).to.eq("Daenerys Targaryen (daenerys@example.com)")
|
2018-06-01 10:37:09 -04:00
|
|
|
expect(@subscription.teamInvites).to.deep.include(invite)
|
|
|
|
done()
|
|
|
|
|
|
|
|
it "sends an email", (done) ->
|
2018-06-11 09:20:35 -04:00
|
|
|
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
2018-06-01 10:37:09 -04:00
|
|
|
@EmailHandler.sendEmail.calledWith("verifyEmailToJoinTeam",
|
|
|
|
sinon.match({
|
2018-06-11 09:20:35 -04:00
|
|
|
to: "john.snow@example.com",
|
|
|
|
inviterName: "Daenerys Targaryen (daenerys@example.com)",
|
2018-06-01 10:37:09 -04:00
|
|
|
acceptInviteUrl: "http://example.com/subscription/invites/#{@newToken}/"
|
|
|
|
})
|
|
|
|
).should.equal true
|
|
|
|
done()
|
|
|
|
|
2018-06-06 10:13:49 -04:00
|
|
|
it "refreshes the existing invite if the email has already been invited", (done) ->
|
|
|
|
originalInvite = Object.assign({}, @teamInvite)
|
|
|
|
|
2018-06-07 10:35:18 -04:00
|
|
|
@TeamInvitesHandler.createInvite @manager.id, originalInvite.email, (err, invite) =>
|
2018-06-06 10:13:49 -04:00
|
|
|
expect(err).to.eq(null)
|
|
|
|
expect(invite).to.exist
|
|
|
|
|
|
|
|
expect(@subscription.teamInvites.length).to.eq 1
|
|
|
|
expect(@subscription.teamInvites).to.deep.include invite
|
|
|
|
|
|
|
|
expect(invite.email).to.eq originalInvite.email
|
|
|
|
|
|
|
|
@subscription.save.calledOnce.should.eq true
|
|
|
|
|
|
|
|
done()
|
|
|
|
|
2018-06-11 09:20:35 -04:00
|
|
|
it "removes any legacy invite from the subscription", (done) ->
|
|
|
|
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
|
|
|
@Subscription.update.calledWith(
|
|
|
|
{ _id: new ObjectId("55153a8014829a865bbf700d") },
|
|
|
|
{ '$pull': { invited_emails: "john.snow@example.com" } }
|
|
|
|
).should.eq true
|
|
|
|
done()
|
|
|
|
|
2018-06-01 10:37:09 -04:00
|
|
|
describe "createDomainInvite", ->
|
|
|
|
beforeEach ->
|
|
|
|
@licence =
|
|
|
|
subscription_id: @subscription.id
|
|
|
|
name: "Team Daenerys"
|
|
|
|
|
|
|
|
@user =
|
2018-06-11 09:20:35 -04:00
|
|
|
email: "John.Snow@example.com"
|
2018-06-01 10:37:09 -04:00
|
|
|
|
|
|
|
it "adds the team invite to the subscription", (done) ->
|
|
|
|
@TeamInvitesHandler.createDomainInvite @user, @licence, (err, invite) =>
|
|
|
|
expect(err).to.eq(null)
|
|
|
|
expect(invite.token).to.eq(@newToken)
|
2018-06-11 09:20:35 -04:00
|
|
|
expect(invite.email).to.eq("john.snow@example.com")
|
2018-06-01 10:37:09 -04:00
|
|
|
expect(invite.inviterName).to.eq("Team Daenerys")
|
|
|
|
expect(@subscription.teamInvites).to.deep.include(invite)
|
|
|
|
done()
|
|
|
|
|
|
|
|
it "sends an email", (done) ->
|
|
|
|
@TeamInvitesHandler.createDomainInvite @user, @licence, (err, invite) =>
|
|
|
|
@EmailHandler.sendEmail.calledWith("verifyEmailToJoinTeam",
|
|
|
|
sinon.match({
|
2018-06-11 09:20:35 -04:00
|
|
|
to: "john.snow@example.com"
|
2018-06-01 10:37:09 -04:00
|
|
|
inviterName: "Team Daenerys"
|
|
|
|
acceptInviteUrl: "http://example.com/subscription/invites/#{@newToken}/"
|
|
|
|
})
|
|
|
|
).should.equal true
|
|
|
|
done()
|
|
|
|
|
2018-06-18 09:18:23 -04:00
|
|
|
describe "importInvite", ->
|
|
|
|
beforeEach ->
|
|
|
|
@sentAt = new Date()
|
|
|
|
|
|
|
|
it "can imports an invite from v1", ->
|
|
|
|
@TeamInvitesHandler.importInvite @subscription, "A-Team", "hannibal@a-team.org",
|
|
|
|
"secret", @sentAt, (error) =>
|
|
|
|
expect(error).not.to.exist
|
|
|
|
|
|
|
|
@subscription.save.calledOnce.should.eq true
|
|
|
|
|
|
|
|
invite = @subscription.teamInvites.find (i) -> i.email == "hannibal@a-team.org"
|
|
|
|
expect(invite.token).to.eq("secret")
|
|
|
|
expect(invite.sentAt).to.eq(@sentAt)
|
|
|
|
|
|
|
|
|
2018-06-01 10:37:09 -04:00
|
|
|
describe "acceptInvite", ->
|
|
|
|
beforeEach ->
|
|
|
|
@user = {
|
|
|
|
id: "123456789",
|
|
|
|
first_name: "Tyrion",
|
|
|
|
last_name: "Lannister",
|
2018-06-11 09:20:35 -04:00
|
|
|
email: "tyrion@example.com"
|
2018-06-01 10:37:09 -04:00
|
|
|
}
|
|
|
|
|
2018-06-07 07:49:46 -04:00
|
|
|
@UserGetter.getUserByAnyEmail.withArgs(@user.email).yields(null, @user)
|
2018-06-01 10:37:09 -04:00
|
|
|
|
|
|
|
@subscription.teamInvites.push({
|
2018-06-11 09:20:35 -04:00
|
|
|
email: "john.snow@example.com",
|
2018-06-01 10:37:09 -04:00
|
|
|
token: "dddddddd",
|
2018-06-11 09:20:35 -04:00
|
|
|
inviterName: "Daenerys Targaryen (daenerys@example.com)"
|
2018-06-01 10:37:09 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
it "adds the user to the team", (done) ->
|
|
|
|
@TeamInvitesHandler.acceptInvite "dddddddd", @user.id, =>
|
|
|
|
@SubscriptionUpdater.addUserToGroup.calledWith(@manager.id, @user.id).should.eq true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it "removes the invite from the subscription", (done) ->
|
|
|
|
@TeamInvitesHandler.acceptInvite "dddddddd", @user.id, =>
|
|
|
|
@Subscription.update.calledWith(
|
|
|
|
{ _id: new ObjectId("55153a8014829a865bbf700d") },
|
2018-06-11 09:20:35 -04:00
|
|
|
{ '$pull': { teamInvites: { email: 'john.snow@example.com' } } }
|
2018-06-01 10:37:09 -04:00
|
|
|
).should.eq true
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe "revokeInvite", ->
|
|
|
|
it "removes the team invite from the subscription", (done) ->
|
2018-06-11 09:20:35 -04:00
|
|
|
@TeamInvitesHandler.revokeInvite @manager.id, "jorah@example.com", =>
|
2018-06-01 10:37:09 -04:00
|
|
|
@Subscription.update.calledWith(
|
|
|
|
{ _id: new ObjectId("55153a8014829a865bbf700d") },
|
2018-06-11 09:20:35 -04:00
|
|
|
{ '$pull': { teamInvites: { email: "jorah@example.com" } } }
|
2018-06-01 10:37:09 -04:00
|
|
|
).should.eq true
|
2018-06-07 11:22:38 -04:00
|
|
|
|
|
|
|
@Subscription.update.calledWith(
|
|
|
|
{ _id: new ObjectId("55153a8014829a865bbf700d") },
|
2018-06-11 09:20:35 -04:00
|
|
|
{ '$pull': { invited_emails: "jorah@example.com" } }
|
2018-06-07 11:22:38 -04:00
|
|
|
).should.eq true
|
2018-06-01 10:37:09 -04:00
|
|
|
done()
|
2018-06-01 06:23:25 -04:00
|
|
|
|
2018-06-06 07:35:13 -04:00
|
|
|
describe "createTeamInvitesForLegacyInvitedEmail", (done) ->
|
|
|
|
beforeEach ->
|
2018-06-11 09:20:35 -04:00
|
|
|
@subscription.invited_emails = ["eddard@example.com", "robert@example.com"]
|
2018-06-07 10:35:18 -04:00
|
|
|
@TeamInvitesHandler.createInvite = sinon.stub().yields(null)
|
2018-06-06 07:35:13 -04:00
|
|
|
@SubscriptionLocator.getGroupsWithEmailInvite = sinon.stub().yields(null, [@subscription])
|
|
|
|
|
|
|
|
it "sends an invitation email to addresses in the legacy invited_emails field", (done) ->
|
2018-06-11 09:20:35 -04:00
|
|
|
@TeamInvitesHandler.createTeamInvitesForLegacyInvitedEmail "eddard@example.com", (err, invite) =>
|
2018-06-06 07:35:13 -04:00
|
|
|
expect(err).not.to.exist
|
|
|
|
|
2018-06-07 10:35:18 -04:00
|
|
|
@TeamInvitesHandler.createInvite.calledWith(
|
2018-06-06 07:35:13 -04:00
|
|
|
@subscription.admin_id,
|
2018-06-11 09:20:35 -04:00
|
|
|
"eddard@example.com"
|
2018-06-06 07:35:13 -04:00
|
|
|
).should.eq true
|
|
|
|
|
2018-06-07 10:35:18 -04:00
|
|
|
@TeamInvitesHandler.createInvite.callCount.should.eq 1
|
2018-06-06 07:35:13 -04:00
|
|
|
|
|
|
|
done()
|
2018-06-06 10:13:49 -04:00
|
|
|
|
2018-06-01 10:37:09 -04:00
|
|
|
describe "validation", ->
|
|
|
|
it "doesn't create an invite if the team limit has been reached", (done) ->
|
|
|
|
@LimitationsManager.teamHasReachedMemberLimit = sinon.stub().returns(true)
|
2018-06-11 09:20:35 -04:00
|
|
|
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
2018-06-01 10:37:09 -04:00
|
|
|
expect(err).to.deep.equal(limitReached: true)
|
|
|
|
done()
|
2018-06-01 06:23:25 -04:00
|
|
|
|
2018-06-08 04:58:51 -04:00
|
|
|
it "doesn't create an invite if the subscription is not in a group plan", (done) ->
|
|
|
|
@subscription.groupPlan = false
|
2018-06-11 09:20:35 -04:00
|
|
|
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
2018-06-08 04:58:51 -04:00
|
|
|
expect(err).to.deep.equal(wrongPlan: true)
|
|
|
|
done()
|
|
|
|
|
2018-06-07 07:49:46 -04:00
|
|
|
it "doesn't create an invite if the user is already part of the team", (done) ->
|
2018-06-01 10:37:09 -04:00
|
|
|
member = {
|
|
|
|
id: "1a2b",
|
2018-06-07 07:49:46 -04:00
|
|
|
_id: "1a2b",
|
2018-06-11 09:20:35 -04:00
|
|
|
email: "tyrion@example.com"
|
2018-06-01 10:37:09 -04:00
|
|
|
}
|
2018-06-01 06:23:25 -04:00
|
|
|
|
2018-06-01 10:37:09 -04:00
|
|
|
@subscription.member_ids = [member.id]
|
2018-06-07 07:49:46 -04:00
|
|
|
@UserGetter.getUserByAnyEmail.withArgs(member.email).yields(null, member)
|
2018-06-01 06:23:25 -04:00
|
|
|
|
2018-06-11 09:20:35 -04:00
|
|
|
@TeamInvitesHandler.createInvite @manager.id, "tyrion@example.com", (err, invite) =>
|
2018-06-01 10:37:09 -04:00
|
|
|
expect(err).to.deep.equal(alreadyInTeam: true)
|
|
|
|
expect(invite).not.to.exist
|
|
|
|
done()
|