overleaf/services/web/test/unit/coffee/Subscription/TeamInvitesHandlerTests.coffee

285 lines
9.2 KiB
CoffeeScript
Raw Normal View History

2018-06-01 10:23:25 +00:00
SandboxedModule = require('sandboxed-module')
should = require('chai').should()
sinon = require 'sinon'
2018-06-01 14:37:09 +00:00
expect = require("chai").expect
2018-06-01 10:23:25 +00:00
querystring = require 'querystring'
modulePath = "../../../../app/js/Features/Subscription/TeamInvitesHandler"
2018-06-01 14:37:09 +00:00
ObjectId = require("mongojs").ObjectId
Errors = require("../../../../app/js/Features/Errors/Errors")
2018-06-01 14:37:09 +00:00
2018-06-01 10:23:25 +00:00
describe "TeamInvitesHandler", ->
2018-06-01 14:37:09 +00:00
beforeEach ->
@manager = {
id: "666666",
first_name: "Daenerys"
last_name: "Targaryen"
email: "daenerys@example.com"
2018-06-01 14:37:09 +00:00
}
@token = "aaaaaaaaaaaaaaaaaaaaaa"
@teamInvite = {
email: "jorah@example.com",
2018-06-01 14:37:09 +00:00
token: @token,
}
@subscription = {
id: "55153a8014829a865bbf700d",
_id: new ObjectId("55153a8014829a865bbf700d"),
2018-06-01 14:37:09 +00:00
admin_id: @manager.id,
groupPlan: true,
member_ids: [],
teamInvites: [ @teamInvite ],
save: sinon.stub().yields(null),
2018-06-01 14:37:09 +00:00
}
@SubscriptionLocator = {
getUsersSubscription: sinon.stub(),
getSubscription: sinon.stub().yields(null, @subscription)
}
@UserGetter = {
getUser: sinon.stub().yields(),
getUserByAnyEmail: sinon.stub().yields()
2018-06-01 14:37:09 +00: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)
}
@UserGetter.getUser.withArgs(@manager.id).yields(null, @manager)
@UserGetter.getUserByAnyEmail.withArgs(@manager.email).yields(null, @manager)
2018-06-01 14:37:09 +00: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 }
"../User/UserGetter": @UserGetter
2018-06-01 14:37:09 +00:00
"./SubscriptionLocator": @SubscriptionLocator
"./SubscriptionUpdater": @SubscriptionUpdater
"./LimitationsManager": @LimitationsManager
"../Email/EmailHandler": @EmailHandler
"../Errors/Errors": Errors
2018-06-01 14:37:09 +00: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) ->
expect(err).to.be.instanceof(Errors.NotFoundError)
2018-06-01 14:37:09 +00:00
done()
2018-06-07 14:35:18 +00:00
describe "createInvite", ->
2018-06-01 14:37:09 +00:00
it "adds the team invite to the subscription", (done) ->
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
2018-06-01 14:37:09 +00:00
expect(err).to.eq(null)
expect(invite.token).to.eq(@newToken)
expect(invite.email).to.eq("john.snow@example.com")
expect(invite.inviterName).to.eq("Daenerys Targaryen (daenerys@example.com)")
2018-06-01 14:37:09 +00:00
expect(@subscription.teamInvites).to.deep.include(invite)
done()
it "sends an email", (done) ->
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
2018-06-01 14:37:09 +00:00
@EmailHandler.sendEmail.calledWith("verifyEmailToJoinTeam",
sinon.match({
to: "john.snow@example.com",
inviterName: "Daenerys Targaryen (daenerys@example.com)",
2018-06-01 14:37:09 +00:00
acceptInviteUrl: "http://example.com/subscription/invites/#{@newToken}/"
})
).should.equal true
done()
it "refreshes the existing invite if the email has already been invited", (done) ->
originalInvite = Object.assign({}, @teamInvite)
2018-06-07 14:35:18 +00:00
@TeamInvitesHandler.createInvite @manager.id, originalInvite.email, (err, invite) =>
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()
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 14:37:09 +00:00
describe "createDomainInvite", ->
beforeEach ->
@licence =
subscription_id: @subscription.id
name: "Team Daenerys"
@user =
email: "John.Snow@example.com"
2018-06-01 14:37:09 +00: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)
expect(invite.email).to.eq("john.snow@example.com")
2018-06-01 14:37:09 +00: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({
to: "john.snow@example.com"
2018-06-01 14:37:09 +00:00
inviterName: "Team Daenerys"
acceptInviteUrl: "http://example.com/subscription/invites/#{@newToken}/"
})
).should.equal true
done()
2018-06-18 13:18:23 +00: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 14:37:09 +00:00
describe "acceptInvite", ->
beforeEach ->
@user = {
id: "123456789",
first_name: "Tyrion",
last_name: "Lannister",
email: "tyrion@example.com"
2018-06-01 14:37:09 +00:00
}
@UserGetter.getUserByAnyEmail.withArgs(@user.email).yields(null, @user)
2018-06-01 14:37:09 +00:00
@subscription.teamInvites.push({
email: "john.snow@example.com",
2018-06-01 14:37:09 +00:00
token: "dddddddd",
inviterName: "Daenerys Targaryen (daenerys@example.com)"
2018-06-01 14:37:09 +00:00
})
it "adds the user to the team", (done) ->
@TeamInvitesHandler.acceptInvite "dddddddd", @user.id, =>
@SubscriptionUpdater.addUserToGroup.calledWith(@subscription._id, @user.id).should.eq true
2018-06-01 14:37:09 +00:00
done()
it "removes the invite from the subscription", (done) ->
@TeamInvitesHandler.acceptInvite "dddddddd", @user.id, =>
@Subscription.update.calledWith(
{ _id: new ObjectId("55153a8014829a865bbf700d") },
{ '$pull': { teamInvites: { email: 'john.snow@example.com' } } }
2018-06-01 14:37:09 +00:00
).should.eq true
done()
describe "revokeInvite", ->
it "removes the team invite from the subscription", (done) ->
@TeamInvitesHandler.revokeInvite @manager.id, "jorah@example.com", =>
2018-06-01 14:37:09 +00:00
@Subscription.update.calledWith(
{ _id: new ObjectId("55153a8014829a865bbf700d") },
{ '$pull': { teamInvites: { email: "jorah@example.com" } } }
2018-06-01 14:37:09 +00:00
).should.eq true
@Subscription.update.calledWith(
{ _id: new ObjectId("55153a8014829a865bbf700d") },
{ '$pull': { invited_emails: "jorah@example.com" } }
).should.eq true
2018-06-01 14:37:09 +00:00
done()
2018-06-01 10:23:25 +00:00
describe "createTeamInvitesForLegacyInvitedEmail", (done) ->
beforeEach ->
@subscription.invited_emails = ["eddard@example.com", "robert@example.com"]
2018-06-07 14:35:18 +00:00
@TeamInvitesHandler.createInvite = sinon.stub().yields(null)
@SubscriptionLocator.getGroupsWithEmailInvite = sinon.stub().yields(null, [@subscription])
it "sends an invitation email to addresses in the legacy invited_emails field", (done) ->
@TeamInvitesHandler.createTeamInvitesForLegacyInvitedEmail "eddard@example.com", (err, invite) =>
expect(err).not.to.exist
2018-06-07 14:35:18 +00:00
@TeamInvitesHandler.createInvite.calledWith(
@subscription.admin_id,
"eddard@example.com"
).should.eq true
2018-06-07 14:35:18 +00:00
@TeamInvitesHandler.createInvite.callCount.should.eq 1
done()
2018-06-01 14:37:09 +00:00
describe "validation", ->
it "doesn't create an invite if the team limit has been reached", (done) ->
@LimitationsManager.teamHasReachedMemberLimit = sinon.stub().returns(true)
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
2018-06-01 14:37:09 +00:00
expect(err).to.deep.equal(limitReached: true)
done()
2018-06-01 10:23:25 +00:00
it "doesn't create an invite if the subscription is not in a group plan", (done) ->
@subscription.groupPlan = false
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
expect(err).to.deep.equal(wrongPlan: true)
done()
it "doesn't create an invite if the user is already part of the team", (done) ->
2018-06-01 14:37:09 +00:00
member = {
id: "1a2b",
_id: "1a2b",
email: "tyrion@example.com"
2018-06-01 14:37:09 +00:00
}
2018-06-01 10:23:25 +00:00
2018-06-01 14:37:09 +00:00
@subscription.member_ids = [member.id]
@UserGetter.getUserByAnyEmail.withArgs(member.email).yields(null, member)
2018-06-01 10:23:25 +00:00
@TeamInvitesHandler.createInvite @manager.id, "tyrion@example.com", (err, invite) =>
2018-06-01 14:37:09 +00:00
expect(err).to.deep.equal(alreadyInTeam: true)
expect(invite).not.to.exist
done()