mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-08 19:50:47 +00:00
Use Error classes, and ensure invited_emails is cleared on new invite
This commit is contained in:
parent
b716f59442
commit
155102df64
4 changed files with 62 additions and 50 deletions
|
@ -56,7 +56,7 @@ V1HistoryNotSyncedError.prototype.__proto___ = Error.prototype
|
|||
|
||||
ProjectHistoryDisabledError = (message) ->
|
||||
error = new Error(message)
|
||||
error.name = "ProjectHistoryDisabledError "
|
||||
error.name = "ProjectHistoryDisabledError"
|
||||
error.__proto__ = ProjectHistoryDisabledError.prototype
|
||||
return error
|
||||
ProjectHistoryDisabledError.prototype.__proto___ = Error.prototype
|
||||
|
|
|
@ -11,7 +11,7 @@ module.exports =
|
|||
email = req.body.email
|
||||
|
||||
TeamInvitesHandler.createInvite teamManagerId, email, (err, invite) ->
|
||||
return handleError(err, req, res, next) if err?
|
||||
return next(err) if err?
|
||||
inviteView = { user:
|
||||
{ email: invite.email, sentAt: invite.sentAt, invite: true }
|
||||
}
|
||||
|
@ -22,13 +22,13 @@ module.exports =
|
|||
userId = AuthenticationController.getLoggedInUserId(req)
|
||||
|
||||
TeamInvitesHandler.getInvite token, (err, invite, teamSubscription) ->
|
||||
return handleError(err, req, res, next) if err?
|
||||
return next(err) if err?
|
||||
|
||||
if !invite
|
||||
return ErrorController.notFound(req, res, next)
|
||||
|
||||
SubscriptionLocator.getUsersSubscription userId, (err, personalSubscription) ->
|
||||
return handleError(err, req, res, next) if err?
|
||||
return next(err) if err?
|
||||
|
||||
res.render "subscriptions/team/invite",
|
||||
inviterName: invite.inviterName
|
||||
|
@ -41,8 +41,7 @@ module.exports =
|
|||
userId = AuthenticationController.getLoggedInUserId(req)
|
||||
|
||||
TeamInvitesHandler.acceptInvite token, userId, (err, results) ->
|
||||
return handleError(err, req, res, next) if err?
|
||||
|
||||
return next(err) if err?
|
||||
res.sendStatus 204
|
||||
|
||||
revokeInvite: (req, res) ->
|
||||
|
@ -50,12 +49,5 @@ module.exports =
|
|||
teamManagerId = AuthenticationController.getLoggedInUserId(req)
|
||||
|
||||
TeamInvitesHandler.revokeInvite teamManagerId, email, (err, results) ->
|
||||
return handleError(err, req, res, next) if err?
|
||||
|
||||
return next(err) if err?
|
||||
res.sendStatus 204
|
||||
|
||||
handleError = (err, req, res, next) ->
|
||||
if err.teamNotFound or err.inviteNoLongerValid
|
||||
ErrorController.notFound(req, res, next)
|
||||
else
|
||||
next(err)
|
||||
|
|
|
@ -14,12 +14,15 @@ SubscriptionUpdater = require("./SubscriptionUpdater")
|
|||
LimitationsManager = require("./LimitationsManager")
|
||||
|
||||
EmailHandler = require("../Email/EmailHandler")
|
||||
EmailHelper = require("../Helpers/EmailHelper")
|
||||
|
||||
Errors = require "../Errors/Errors"
|
||||
|
||||
module.exports = TeamInvitesHandler =
|
||||
getInvite: (token, callback) ->
|
||||
Subscription.findOne 'teamInvites.token': token, (err, subscription) ->
|
||||
return callback(err) if err?
|
||||
return callback(teamNotFound: true) unless subscription?
|
||||
return callback(new Errors.NotFoundError('team not found')) unless subscription?
|
||||
|
||||
invite = subscription.teamInvites.find (i) -> i.token == token
|
||||
return callback(null, invite, subscription)
|
||||
|
@ -37,7 +40,9 @@ module.exports = TeamInvitesHandler =
|
|||
else
|
||||
inviterName = teamManager.email
|
||||
|
||||
createInvite(subscription, email, inviterName, callback)
|
||||
removeLegacyInvite subscription.id, email, (error) ->
|
||||
return callback(error) if error?
|
||||
createInvite(subscription, email, inviterName, callback)
|
||||
|
||||
createDomainInvite: (user, licence, callback) ->
|
||||
logger.log {licence, email: user.email}, "Creating domain team invite"
|
||||
|
@ -51,7 +56,7 @@ module.exports = TeamInvitesHandler =
|
|||
logger.log {userId}, "Accepting invite"
|
||||
TeamInvitesHandler.getInvite token, (err, invite, subscription) ->
|
||||
return callback(err) if err?
|
||||
return callback(inviteNoLongerValid: true) unless invite?
|
||||
return callback(new Errors.NotFoundError('invite not found')) unless invite?
|
||||
|
||||
SubscriptionUpdater.addUserToGroup subscription.admin_id, userId, (err) ->
|
||||
return callback(err) if err?
|
||||
|
@ -82,8 +87,7 @@ createInvite = (subscription, email, inviterName, callback) ->
|
|||
return callback(error) if error?
|
||||
return callback(reason) unless possible
|
||||
|
||||
# TODO: use standard way to canonalise email addresses
|
||||
email = email.trim().toLowerCase()
|
||||
email = EmailHelper.parseEmail(email)
|
||||
|
||||
invite = subscription.teamInvites.find (invite) -> invite.email == email
|
||||
|
||||
|
@ -110,18 +114,24 @@ createInvite = (subscription, email, inviterName, callback) ->
|
|||
return callback(error, invite)
|
||||
|
||||
removeInviteFromTeam = (subscriptionId, email, callback) ->
|
||||
email = email.trim().toLowerCase()
|
||||
|
||||
email = EmailHelper.parseEmail(email)
|
||||
searchConditions = { _id: new ObjectId(subscriptionId.toString()) }
|
||||
|
||||
removeInvite = { $pull: { teamInvites: { email: email } } }
|
||||
removeLegacyInvite = { $pull: { invited_emails: email } }
|
||||
logger.log {subscriptionId, email, searchConditions, removeInvite}, 'removeInviteFromTeam'
|
||||
|
||||
async.series [
|
||||
(cb) -> Subscription.update(searchConditions, removeInvite, cb),
|
||||
(cb) -> Subscription.update(searchConditions, removeLegacyInvite, cb),
|
||||
(cb) -> removeLegacyInvite(subscriptionId, email, cb),
|
||||
], callback
|
||||
|
||||
removeLegacyInvite = (subscriptionId, email, callback) ->
|
||||
Subscription.update({
|
||||
_id: new ObjectId(subscriptionId.toString())
|
||||
}, {
|
||||
$pull: {
|
||||
invited_emails: EmailHelper.parseEmail(email)
|
||||
}
|
||||
}, callback)
|
||||
|
||||
checkIfInviteIsPossible = (subscription, email, callback = (error, possible, reason) -> ) ->
|
||||
unless subscription.groupPlan
|
||||
|
|
|
@ -6,6 +6,7 @@ querystring = require 'querystring'
|
|||
modulePath = "../../../../app/js/Features/Subscription/TeamInvitesHandler"
|
||||
|
||||
ObjectId = require("mongojs").ObjectId
|
||||
Errors = require("../../../../app/js/Features/Errors/Errors")
|
||||
|
||||
describe "TeamInvitesHandler", ->
|
||||
beforeEach ->
|
||||
|
@ -13,13 +14,13 @@ describe "TeamInvitesHandler", ->
|
|||
id: "666666",
|
||||
first_name: "Daenerys"
|
||||
last_name: "Targaryen"
|
||||
email: "daenerys@motherofdragons.com"
|
||||
email: "daenerys@example.com"
|
||||
}
|
||||
|
||||
@token = "aaaaaaaaaaaaaaaaaaaaaa"
|
||||
|
||||
@teamInvite = {
|
||||
email: "jorah@mormont.org",
|
||||
email: "jorah@example.com",
|
||||
token: @token,
|
||||
}
|
||||
|
||||
|
@ -83,6 +84,7 @@ describe "TeamInvitesHandler", ->
|
|||
"./SubscriptionUpdater": @SubscriptionUpdater
|
||||
"./LimitationsManager": @LimitationsManager
|
||||
"../Email/EmailHandler": @EmailHandler
|
||||
"../Errors/Errors": Errors
|
||||
|
||||
describe "getInvite", ->
|
||||
it "returns the invite if there's one", (done) ->
|
||||
|
@ -96,25 +98,25 @@ describe "TeamInvitesHandler", ->
|
|||
@Subscription.findOne = sinon.stub().yields(null, null)
|
||||
|
||||
@TeamInvitesHandler.getInvite @token, (err, invite, subscription) ->
|
||||
expect(err).to.deep.eq(teamNotFound: true)
|
||||
expect(err).to.be.instanceof(Errors.NotFoundError)
|
||||
done()
|
||||
|
||||
describe "createInvite", ->
|
||||
it "adds the team invite to the subscription", (done) ->
|
||||
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@nightwatch.com", (err, invite) =>
|
||||
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
||||
expect(err).to.eq(null)
|
||||
expect(invite.token).to.eq(@newToken)
|
||||
expect(invite.email).to.eq("john.snow@nightwatch.com")
|
||||
expect(invite.inviterName).to.eq("Daenerys Targaryen (daenerys@motherofdragons.com)")
|
||||
expect(invite.email).to.eq("john.snow@example.com")
|
||||
expect(invite.inviterName).to.eq("Daenerys Targaryen (daenerys@example.com)")
|
||||
expect(@subscription.teamInvites).to.deep.include(invite)
|
||||
done()
|
||||
|
||||
it "sends an email", (done) ->
|
||||
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@nightwatch.com", (err, invite) =>
|
||||
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
||||
@EmailHandler.sendEmail.calledWith("verifyEmailToJoinTeam",
|
||||
sinon.match({
|
||||
to: "john.snow@nightwatch.com",
|
||||
inviterName: "Daenerys Targaryen (daenerys@motherofdragons.com)",
|
||||
to: "john.snow@example.com",
|
||||
inviterName: "Daenerys Targaryen (daenerys@example.com)",
|
||||
acceptInviteUrl: "http://example.com/subscription/invites/#{@newToken}/"
|
||||
})
|
||||
).should.equal true
|
||||
|
@ -136,6 +138,14 @@ describe "TeamInvitesHandler", ->
|
|||
|
||||
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()
|
||||
|
||||
describe "createDomainInvite", ->
|
||||
beforeEach ->
|
||||
@licence =
|
||||
|
@ -143,13 +153,13 @@ describe "TeamInvitesHandler", ->
|
|||
name: "Team Daenerys"
|
||||
|
||||
@user =
|
||||
email: "John.Snow@nightwatch.com"
|
||||
email: "John.Snow@example.com"
|
||||
|
||||
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@nightwatch.com")
|
||||
expect(invite.email).to.eq("john.snow@example.com")
|
||||
expect(invite.inviterName).to.eq("Team Daenerys")
|
||||
expect(@subscription.teamInvites).to.deep.include(invite)
|
||||
done()
|
||||
|
@ -158,7 +168,7 @@ describe "TeamInvitesHandler", ->
|
|||
@TeamInvitesHandler.createDomainInvite @user, @licence, (err, invite) =>
|
||||
@EmailHandler.sendEmail.calledWith("verifyEmailToJoinTeam",
|
||||
sinon.match({
|
||||
to: "john.snow@nightwatch.com"
|
||||
to: "john.snow@example.com"
|
||||
inviterName: "Team Daenerys"
|
||||
acceptInviteUrl: "http://example.com/subscription/invites/#{@newToken}/"
|
||||
})
|
||||
|
@ -171,15 +181,15 @@ describe "TeamInvitesHandler", ->
|
|||
id: "123456789",
|
||||
first_name: "Tyrion",
|
||||
last_name: "Lannister",
|
||||
email: "tyrion@lannister.com"
|
||||
email: "tyrion@example.com"
|
||||
}
|
||||
|
||||
@UserGetter.getUserByAnyEmail.withArgs(@user.email).yields(null, @user)
|
||||
|
||||
@subscription.teamInvites.push({
|
||||
email: "john.snow@nightwatch.com",
|
||||
email: "john.snow@example.com",
|
||||
token: "dddddddd",
|
||||
inviterName: "Daenerys Targaryen (daenerys@motherofdragons.com)"
|
||||
inviterName: "Daenerys Targaryen (daenerys@example.com)"
|
||||
})
|
||||
|
||||
it "adds the user to the team", (done) ->
|
||||
|
@ -191,37 +201,37 @@ describe "TeamInvitesHandler", ->
|
|||
@TeamInvitesHandler.acceptInvite "dddddddd", @user.id, =>
|
||||
@Subscription.update.calledWith(
|
||||
{ _id: new ObjectId("55153a8014829a865bbf700d") },
|
||||
{ '$pull': { teamInvites: { email: 'john.snow@nightwatch.com' } } }
|
||||
{ '$pull': { teamInvites: { email: 'john.snow@example.com' } } }
|
||||
).should.eq true
|
||||
done()
|
||||
|
||||
describe "revokeInvite", ->
|
||||
it "removes the team invite from the subscription", (done) ->
|
||||
@TeamInvitesHandler.revokeInvite @manager.id, "jorah@mormont.org", =>
|
||||
@TeamInvitesHandler.revokeInvite @manager.id, "jorah@example.com", =>
|
||||
@Subscription.update.calledWith(
|
||||
{ _id: new ObjectId("55153a8014829a865bbf700d") },
|
||||
{ '$pull': { teamInvites: { email: "jorah@mormont.org" } } }
|
||||
{ '$pull': { teamInvites: { email: "jorah@example.com" } } }
|
||||
).should.eq true
|
||||
|
||||
@Subscription.update.calledWith(
|
||||
{ _id: new ObjectId("55153a8014829a865bbf700d") },
|
||||
{ '$pull': { invited_emails: "jorah@mormont.org" } }
|
||||
{ '$pull': { invited_emails: "jorah@example.com" } }
|
||||
).should.eq true
|
||||
done()
|
||||
|
||||
describe "createTeamInvitesForLegacyInvitedEmail", (done) ->
|
||||
beforeEach ->
|
||||
@subscription.invited_emails = ["eddard@stark.com", "robert@stark.com"]
|
||||
@subscription.invited_emails = ["eddard@example.com", "robert@example.com"]
|
||||
@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@stark.com", (err, invite) =>
|
||||
@TeamInvitesHandler.createTeamInvitesForLegacyInvitedEmail "eddard@example.com", (err, invite) =>
|
||||
expect(err).not.to.exist
|
||||
|
||||
@TeamInvitesHandler.createInvite.calledWith(
|
||||
@subscription.admin_id,
|
||||
"eddard@stark.com"
|
||||
"eddard@example.com"
|
||||
).should.eq true
|
||||
|
||||
@TeamInvitesHandler.createInvite.callCount.should.eq 1
|
||||
|
@ -231,13 +241,13 @@ describe "TeamInvitesHandler", ->
|
|||
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@nightwatch.com", (err, invite) =>
|
||||
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
||||
expect(err).to.deep.equal(limitReached: true)
|
||||
done()
|
||||
|
||||
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@nightwatch.com", (err, invite) =>
|
||||
@TeamInvitesHandler.createInvite @manager.id, "John.Snow@example.com", (err, invite) =>
|
||||
expect(err).to.deep.equal(wrongPlan: true)
|
||||
done()
|
||||
|
||||
|
@ -245,13 +255,13 @@ describe "TeamInvitesHandler", ->
|
|||
member = {
|
||||
id: "1a2b",
|
||||
_id: "1a2b",
|
||||
email: "tyrion@lannister.com"
|
||||
email: "tyrion@example.com"
|
||||
}
|
||||
|
||||
@subscription.member_ids = [member.id]
|
||||
@UserGetter.getUserByAnyEmail.withArgs(member.email).yields(null, member)
|
||||
|
||||
@TeamInvitesHandler.createInvite @manager.id, "tyrion@lannister.com", (err, invite) =>
|
||||
@TeamInvitesHandler.createInvite @manager.id, "tyrion@example.com", (err, invite) =>
|
||||
expect(err).to.deep.equal(alreadyInTeam: true)
|
||||
expect(invite).not.to.exist
|
||||
done()
|
||||
|
|
Loading…
Add table
Reference in a new issue