[web] Remove promises exports from Controller modules (#22242)

* Remove promises object from CollaboratorsInviteController.mjs

* Define functions at root

* Remove mentions of undefined `revokeInviteForUser`

* Remove unused `doLogout`

* Remove promises object from UserController.js

* Remove unused `makeChangePreview`

* Remove promises object from SubscriptionController.js (`getRecommendedCurrency` and `getLatamCountryBannerDetails`)

* Remove promises object from CollabratecController.mjs

* Remove promises object from SSOController.mjs

* Remove promises object from ReferencesApiController.mjs

* Remove promises object from MetricsEmailController.mjs

* Remove promises object from InstitutionHubsController.mjs

* Remove promises object from DocumentUpdaterController.mjs

* Remove promises object from SubscriptionAdminController.mjs

* Fixup unit tests

* Add expects that controllers don't error

* Promisify `ensureAffiliationMiddleware`

GitOrigin-RevId: 311c8afa7d5c8e4f051408d305b6b4147a020edc
This commit is contained in:
Antoine Clausse 2025-01-17 09:06:05 +01:00 committed by Copybot
parent ae34c4b8cc
commit b9fb636f0b
9 changed files with 487 additions and 540 deletions

View file

@ -1,4 +1,3 @@
import { callbackify } from 'node:util'
import ProjectGetter from '../Project/ProjectGetter.js' import ProjectGetter from '../Project/ProjectGetter.js'
import LimitationsManager from '../Subscription/LimitationsManager.js' import LimitationsManager from '../Subscription/LimitationsManager.js'
import UserGetter from '../User/UserGetter.js' import UserGetter from '../User/UserGetter.js'
@ -34,336 +33,218 @@ const rateLimiter = new RateLimiter('invite-to-project-by-user-id', {
duration: 60 * 30, duration: 60 * 30,
}) })
const CollaboratorsInviteController = { async function getAllInvites(req, res) {
async getAllInvites(req, res) { const projectId = req.params.Project_id
const projectId = req.params.Project_id logger.debug({ projectId }, 'getting all active invites for project')
logger.debug({ projectId }, 'getting all active invites for project') const invites =
const invites = await CollaboratorsInviteGetter.promises.getAllInvites(projectId)
await CollaboratorsInviteGetter.promises.getAllInvites(projectId) res.json({ invites })
res.json({ invites }) }
},
async _checkShouldInviteEmail(email) { async function _checkShouldInviteEmail(email) {
if (Settings.restrictInvitesToExistingAccounts === true) { if (Settings.restrictInvitesToExistingAccounts === true) {
logger.debug({ email }, 'checking if user exists with this email') logger.debug({ email }, 'checking if user exists with this email')
const user = await UserGetter.promises.getUserByAnyEmail(email, { const user = await UserGetter.promises.getUserByAnyEmail(email, {
_id: 1, _id: 1,
})
const userExists = user?._id != null
return userExists
} else {
return true
}
},
async _checkRateLimit(userId) {
let collabLimit =
await LimitationsManager.promises.allowedNumberOfCollaboratorsForUser(
userId
)
if (collabLimit == null || collabLimit === 0) {
collabLimit = 1
} else if (collabLimit < 0 || collabLimit > 20) {
collabLimit = 20
}
// Consume enough points to hit the rate limit at 10 * collabLimit
const maxRequests = 10 * collabLimit
const points = Math.floor(RATE_LIMIT_POINTS / maxRequests)
try {
await rateLimiter.consume(userId, points, { method: 'userId' })
} catch (err) {
if (err instanceof Error) {
throw err
} else {
return false
}
}
return true
},
async inviteToProject(req, res) {
const projectId = req.params.Project_id
let { email, privileges } = req.body
const sendingUser = SessionManager.getSessionUser(req.session)
const sendingUserId = sendingUser._id
req.logger.addFields({ email, sendingUserId })
if (email === sendingUser.email) {
logger.debug(
{ projectId, email, sendingUserId },
'cannot invite yourself to project'
)
return res.json({ invite: null, error: 'cannot_invite_self' })
}
logger.debug({ projectId, email, sendingUserId }, 'inviting to project')
const project = await ProjectGetter.promises.getProject(projectId, {
owner_ref: 1,
}) })
const linkSharingChanges = const userExists = user?._id != null
await SplitTestHandler.promises.getAssignmentForUser( return userExists
project.owner_ref, } else {
'link-sharing-warning' return true
) }
}
let allowed = false async function _checkRateLimit(userId) {
if (linkSharingChanges?.variant === 'active') { let collabLimit =
// if link-sharing-warning is active, can always invite read-only collaborators await LimitationsManager.promises.allowedNumberOfCollaboratorsForUser(
if (privileges === PrivilegeLevels.READ_ONLY) { userId
allowed = true )
} else {
allowed = await LimitationsManager.promises.canAddXEditCollaborators( if (collabLimit == null || collabLimit === 0) {
projectId, collabLimit = 1
1 } else if (collabLimit < 0 || collabLimit > 20) {
) collabLimit = 20
} }
// Consume enough points to hit the rate limit at 10 * collabLimit
const maxRequests = 10 * collabLimit
const points = Math.floor(RATE_LIMIT_POINTS / maxRequests)
try {
await rateLimiter.consume(userId, points, { method: 'userId' })
} catch (err) {
if (err instanceof Error) {
throw err
} else { } else {
allowed = await LimitationsManager.promises.canAddXCollaborators( return false
}
}
return true
}
async function inviteToProject(req, res) {
const projectId = req.params.Project_id
let { email, privileges } = req.body
const sendingUser = SessionManager.getSessionUser(req.session)
const sendingUserId = sendingUser._id
req.logger.addFields({ email, sendingUserId })
if (email === sendingUser.email) {
logger.debug(
{ projectId, email, sendingUserId },
'cannot invite yourself to project'
)
return res.json({ invite: null, error: 'cannot_invite_self' })
}
logger.debug({ projectId, email, sendingUserId }, 'inviting to project')
const project = await ProjectGetter.promises.getProject(projectId, {
owner_ref: 1,
})
const linkSharingChanges =
await SplitTestHandler.promises.getAssignmentForUser(
project.owner_ref,
'link-sharing-warning'
)
let allowed = false
if (linkSharingChanges?.variant === 'active') {
// if link-sharing-warning is active, can always invite read-only collaborators
if (privileges === PrivilegeLevels.READ_ONLY) {
allowed = true
} else {
allowed = await LimitationsManager.promises.canAddXEditCollaborators(
projectId, projectId,
1 1
) )
} }
} else {
if (!allowed) { allowed = await LimitationsManager.promises.canAddXCollaborators(
logger.debug(
{ projectId, email, sendingUserId },
'not allowed to invite more users to project'
)
return res.json({ invite: null })
}
email = EmailHelper.parseEmail(email, true)
if (email == null || email === '') {
logger.debug({ projectId, email, sendingUserId }, 'invalid email address')
return res.status(400).json({ errorReason: 'invalid_email' })
}
const underRateLimit =
await CollaboratorsInviteController._checkRateLimit(sendingUserId)
if (!underRateLimit) {
return res.sendStatus(429)
}
const shouldAllowInvite =
await CollaboratorsInviteController._checkShouldInviteEmail(email)
if (!shouldAllowInvite) {
logger.debug(
{ email, projectId, sendingUserId },
'not allowed to send an invite to this email address'
)
return res.json({
invite: null,
error: 'cannot_invite_non_user',
})
}
const invite = await CollaboratorsInviteHandler.promises.inviteToProject(
projectId, projectId,
sendingUser, 1
email,
privileges
) )
}
if (!allowed) {
logger.debug(
{ projectId, email, sendingUserId },
'not allowed to invite more users to project'
)
return res.json({ invite: null })
}
email = EmailHelper.parseEmail(email, true)
if (email == null || email === '') {
logger.debug({ projectId, email, sendingUserId }, 'invalid email address')
return res.status(400).json({ errorReason: 'invalid_email' })
}
const underRateLimit =
await CollaboratorsInviteController._checkRateLimit(sendingUserId)
if (!underRateLimit) {
return res.sendStatus(429)
}
const shouldAllowInvite =
await CollaboratorsInviteController._checkShouldInviteEmail(email)
if (!shouldAllowInvite) {
logger.debug(
{ email, projectId, sendingUserId },
'not allowed to send an invite to this email address'
)
return res.json({
invite: null,
error: 'cannot_invite_non_user',
})
}
const invite = await CollaboratorsInviteHandler.promises.inviteToProject(
projectId,
sendingUser,
email,
privileges
)
ProjectAuditLogHandler.addEntryInBackground(
projectId,
'send-invite',
sendingUserId,
req.ip,
{
inviteId: invite._id,
privileges,
}
)
logger.debug({ projectId, email, sendingUserId }, 'invite created')
EditorRealTimeController.emitToRoom(projectId, 'project:membership:changed', {
invites: true,
})
res.json({ invite })
}
async function revokeInvite(req, res) {
const projectId = req.params.Project_id
const inviteId = req.params.invite_id
const user = SessionManager.getSessionUser(req.session)
logger.debug({ projectId, inviteId }, 'revoking invite')
const invite = await CollaboratorsInviteHandler.promises.revokeInvite(
projectId,
inviteId
)
if (invite != null) {
ProjectAuditLogHandler.addEntryInBackground( ProjectAuditLogHandler.addEntryInBackground(
projectId, projectId,
'send-invite', 'revoke-invite',
sendingUserId, user._id,
req.ip, req.ip,
{ {
inviteId: invite._id, inviteId: invite._id,
privileges, privileges: invite.privileges,
} }
) )
logger.debug({ projectId, email, sendingUserId }, 'invite created')
EditorRealTimeController.emitToRoom( EditorRealTimeController.emitToRoom(
projectId, projectId,
'project:membership:changed', 'project:membership:changed',
{ invites: true } { invites: true }
) )
res.json({ invite }) }
},
async revokeInvite(req, res) {
const projectId = req.params.Project_id
const inviteId = req.params.invite_id
const user = SessionManager.getSessionUser(req.session)
logger.debug({ projectId, inviteId }, 'revoking invite') res.sendStatus(204)
}
const invite = await CollaboratorsInviteHandler.promises.revokeInvite( async function generateNewInvite(req, res) {
const projectId = req.params.Project_id
const inviteId = req.params.invite_id
const user = SessionManager.getSessionUser(req.session)
logger.debug({ projectId, inviteId }, 'resending invite')
const sendingUser = SessionManager.getSessionUser(req.session)
const underRateLimit = await CollaboratorsInviteController._checkRateLimit(
sendingUser._id
)
if (!underRateLimit) {
return res.sendStatus(429)
}
const invite = await CollaboratorsInviteHandler.promises.generateNewInvite(
projectId,
sendingUser,
inviteId
)
EditorRealTimeController.emitToRoom(projectId, 'project:membership:changed', {
invites: true,
})
if (invite != null) {
ProjectAuditLogHandler.addEntryInBackground(
projectId, projectId,
inviteId 'resend-invite',
) user._id,
if (invite != null) {
ProjectAuditLogHandler.addEntryInBackground(
projectId,
'revoke-invite',
user._id,
req.ip,
{
inviteId: invite._id,
privileges: invite.privileges,
}
)
EditorRealTimeController.emitToRoom(
projectId,
'project:membership:changed',
{ invites: true }
)
}
res.sendStatus(204)
},
async generateNewInvite(req, res) {
const projectId = req.params.Project_id
const inviteId = req.params.invite_id
const user = SessionManager.getSessionUser(req.session)
logger.debug({ projectId, inviteId }, 'resending invite')
const sendingUser = SessionManager.getSessionUser(req.session)
const underRateLimit = await CollaboratorsInviteController._checkRateLimit(
sendingUser._id
)
if (!underRateLimit) {
return res.sendStatus(429)
}
const invite = await CollaboratorsInviteHandler.promises.generateNewInvite(
projectId,
sendingUser,
inviteId
)
EditorRealTimeController.emitToRoom(
projectId,
'project:membership:changed',
{ invites: true }
)
if (invite != null) {
ProjectAuditLogHandler.addEntryInBackground(
projectId,
'resend-invite',
user._id,
req.ip,
{
inviteId: invite._id,
privileges: invite.privileges,
}
)
res.sendStatus(201)
} else {
res.sendStatus(404)
}
},
async viewInvite(req, res) {
const projectId = req.params.Project_id
const { token } = req.params
const _renderInvalidPage = function () {
res.status(404)
logger.debug({ projectId }, 'invite not valid, rendering not-valid page')
res.render('project/invite/not-valid', { title: 'Invalid Invite' })
}
// check if the user is already a member of the project
const currentUser = SessionManager.getSessionUser(req.session)
if (currentUser) {
const isMember =
await CollaboratorsGetter.promises.isUserInvitedMemberOfProject(
currentUser._id,
projectId
)
if (isMember) {
logger.debug(
{ projectId, userId: currentUser._id },
'user is already a member of this project, redirecting'
)
return res.redirect(`/project/${projectId}`)
}
}
// get the invite
const invite = await CollaboratorsInviteGetter.promises.getInviteByToken(
projectId,
token
)
// check if invite is gone, or otherwise non-existent
if (invite == null) {
logger.debug({ projectId }, 'no invite found for this token')
return _renderInvalidPage()
}
// check the user who sent the invite exists
const owner = await UserGetter.promises.getUser(
{ _id: invite.sendingUserId },
{ email: 1, first_name: 1, last_name: 1 }
)
if (owner == null) {
logger.debug({ projectId }, 'no project owner found')
return _renderInvalidPage()
}
// fetch the project name
const project = await ProjectGetter.promises.getProject(projectId, {
name: 1,
})
if (project == null) {
logger.debug({ projectId }, 'no project found')
return _renderInvalidPage()
}
if (!currentUser) {
req.session.sharedProjectData = {
project_name: project.name,
user_first_name: owner.first_name,
}
AuthenticationController.setRedirectInSession(req)
return res.redirect('/register')
}
// cleanup if set for register page
delete req.session.sharedProjectData
// finally render the invite
res.render('project/invite/show', {
invite,
token,
project,
owner,
title: 'Project Invite',
})
},
async acceptInvite(req, res) {
const { Project_id: projectId, token } = req.params
const currentUser = SessionManager.getSessionUser(req.session)
logger.debug(
{ projectId, userId: currentUser._id },
'got request to accept invite'
)
const invite = await CollaboratorsInviteGetter.promises.getInviteByToken(
projectId,
token
)
if (invite == null) {
throw new Errors.NotFoundError('no matching invite found')
}
await ProjectAuditLogHandler.promises.addEntry(
projectId,
'accept-invite',
currentUser._id,
req.ip, req.ip,
{ {
inviteId: invite._id, inviteId: invite._id,
@ -371,48 +252,154 @@ const CollaboratorsInviteController = {
} }
) )
await CollaboratorsInviteHandler.promises.acceptInvite( res.sendStatus(201)
invite, } else {
projectId, res.sendStatus(404)
currentUser }
) }
await EditorRealTimeController.emitToRoom( async function viewInvite(req, res) {
projectId, const projectId = req.params.Project_id
'project:membership:changed', const { token } = req.params
{ invites: true, members: true } const _renderInvalidPage = function () {
) res.status(404)
AnalyticsManager.recordEventForUserInBackground( logger.debug({ projectId }, 'invite not valid, rendering not-valid page')
currentUser._id, res.render('project/invite/not-valid', { title: 'Invalid Invite' })
'project-invite-accept', }
{
projectId,
}
)
if (req.xhr) { // check if the user is already a member of the project
res.sendStatus(204) // Done async via project page notification const currentUser = SessionManager.getSessionUser(req.session)
} else { if (currentUser) {
res.redirect(`/project/${projectId}`) const isMember =
await CollaboratorsGetter.promises.isUserInvitedMemberOfProject(
currentUser._id,
projectId
)
if (isMember) {
logger.debug(
{ projectId, userId: currentUser._id },
'user is already a member of this project, redirecting'
)
return res.redirect(`/project/${projectId}`)
} }
}, }
// get the invite
const invite = await CollaboratorsInviteGetter.promises.getInviteByToken(
projectId,
token
)
// check if invite is gone, or otherwise non-existent
if (invite == null) {
logger.debug({ projectId }, 'no invite found for this token')
return _renderInvalidPage()
}
// check the user who sent the invite exists
const owner = await UserGetter.promises.getUser(
{ _id: invite.sendingUserId },
{ email: 1, first_name: 1, last_name: 1 }
)
if (owner == null) {
logger.debug({ projectId }, 'no project owner found')
return _renderInvalidPage()
}
// fetch the project name
const project = await ProjectGetter.promises.getProject(projectId, {
name: 1,
})
if (project == null) {
logger.debug({ projectId }, 'no project found')
return _renderInvalidPage()
}
if (!currentUser) {
req.session.sharedProjectData = {
project_name: project.name,
user_first_name: owner.first_name,
}
AuthenticationController.setRedirectInSession(req)
return res.redirect('/register')
}
// cleanup if set for register page
delete req.session.sharedProjectData
// finally render the invite
res.render('project/invite/show', {
invite,
token,
project,
owner,
title: 'Project Invite',
})
} }
export default { async function acceptInvite(req, res) {
promises: CollaboratorsInviteController, const { Project_id: projectId, token } = req.params
getAllInvites: expressify(CollaboratorsInviteController.getAllInvites), const currentUser = SessionManager.getSessionUser(req.session)
inviteToProject: expressify(CollaboratorsInviteController.inviteToProject), logger.debug(
revokeInvite: expressify(CollaboratorsInviteController.revokeInvite), { projectId, userId: currentUser._id },
revokeInviteForUser: expressify( 'got request to accept invite'
CollaboratorsInviteController.revokeInviteForUser )
),
generateNewInvite: expressify( const invite = await CollaboratorsInviteGetter.promises.getInviteByToken(
CollaboratorsInviteController.generateNewInvite projectId,
), token
viewInvite: expressify(CollaboratorsInviteController.viewInvite), )
acceptInvite: expressify(CollaboratorsInviteController.acceptInvite),
_checkShouldInviteEmail: callbackify( if (invite == null) {
CollaboratorsInviteController._checkShouldInviteEmail throw new Errors.NotFoundError('no matching invite found')
), }
_checkRateLimit: callbackify(CollaboratorsInviteController._checkRateLimit),
await ProjectAuditLogHandler.promises.addEntry(
projectId,
'accept-invite',
currentUser._id,
req.ip,
{
inviteId: invite._id,
privileges: invite.privileges,
}
)
await CollaboratorsInviteHandler.promises.acceptInvite(
invite,
projectId,
currentUser
)
await EditorRealTimeController.emitToRoom(
projectId,
'project:membership:changed',
{ invites: true, members: true }
)
AnalyticsManager.recordEventForUserInBackground(
currentUser._id,
'project-invite-accept',
{
projectId,
}
)
if (req.xhr) {
res.sendStatus(204) // Done async via project page notification
} else {
res.redirect(`/project/${projectId}`)
}
} }
const CollaboratorsInviteController = {
getAllInvites: expressify(getAllInvites),
inviteToProject: expressify(inviteToProject),
revokeInvite: expressify(revokeInvite),
generateNewInvite: expressify(generateNewInvite),
viewInvite: expressify(viewInvite),
acceptInvite: expressify(acceptInvite),
_checkShouldInviteEmail,
_checkRateLimit,
}
export default CollaboratorsInviteController

View file

@ -44,7 +44,4 @@ async function getDoc(req, res) {
export default { export default {
getDoc: expressify(getDoc), getDoc: expressify(getDoc),
promises: {
getDoc,
},
} }

View file

@ -544,7 +544,7 @@ async function redirectToHostedPage(req, res) {
res.redirect(url) res.redirect(url)
} }
async function _getRecommendedCurrency(req, res) { async function getRecommendedCurrency(req, res) {
const userId = SessionManager.getLoggedInUserId(req.session) const userId = SessionManager.getLoggedInUserId(req.session)
let ip = req.ip let ip = req.ip
if ( if (
@ -683,8 +683,6 @@ module.exports = {
purchaseAddon, purchaseAddon,
removeAddon, removeAddon,
makeChangePreview, makeChangePreview,
promises: { getRecommendedCurrency,
getRecommendedCurrency: _getRecommendedCurrency, getLatamCountryBannerDetails,
getLatamCountryBannerDetails,
},
} }

View file

@ -16,7 +16,7 @@ const HttpErrorHandler = require('../Errors/HttpErrorHandler')
const OError = require('@overleaf/o-error') const OError = require('@overleaf/o-error')
const EmailHandler = require('../Email/EmailHandler') const EmailHandler = require('../Email/EmailHandler')
const UrlHelper = require('../Helpers/UrlHelper') const UrlHelper = require('../Helpers/UrlHelper')
const { promisify, callbackify } = require('util') const { promisify } = require('util')
const { expressify } = require('@overleaf/promise-utils') const { expressify } = require('@overleaf/promise-utils')
const { const {
acceptsJson, acceptsJson,
@ -212,11 +212,7 @@ async function ensureAffiliationMiddleware(req, res, next) {
return next() return next()
} }
} }
try { await ensureAffiliation(user)
await ensureAffiliation(user)
} catch (error) {
return next(error)
}
return next() return next()
} }
@ -505,13 +501,9 @@ module.exports = {
subscribe: expressify(subscribe), subscribe: expressify(subscribe),
unsubscribe: expressify(unsubscribe), unsubscribe: expressify(unsubscribe),
updateUserSettings: expressify(updateUserSettings), updateUserSettings: expressify(updateUserSettings),
doLogout: callbackify(doLogout),
logout: expressify(logout), logout: expressify(logout),
expireDeletedUser: expressify(expireDeletedUser), expireDeletedUser: expressify(expireDeletedUser),
expireDeletedUsersAfterDuration: expressify(expireDeletedUsersAfterDuration), expireDeletedUsersAfterDuration: expressify(expireDeletedUsersAfterDuration),
promises: { ensureAffiliationMiddleware: expressify(ensureAffiliationMiddleware),
doLogout, ensureAffiliation,
ensureAffiliation,
ensureAffiliationMiddleware,
},
} }

View file

@ -314,7 +314,7 @@ async function initialize(webRouter, privateApiRouter, publicApiRouter) {
'/user/emails', '/user/emails',
AuthenticationController.requireLogin(), AuthenticationController.requireLogin(),
PermissionsController.useCapabilities(), PermissionsController.useCapabilities(),
UserController.promises.ensureAffiliationMiddleware, UserController.ensureAffiliationMiddleware,
UserEmailsController.list UserEmailsController.list
) )
webRouter.get( webRouter.get(

View file

@ -15,7 +15,7 @@ const query = {
async function _handleEnsureAffiliation(user) { async function _handleEnsureAffiliation(user) {
try { try {
await UserController.promises.ensureAffiliation(user) await UserController.ensureAffiliation(user)
console.log(`${user._id}`) console.log(`${user._id}`)
success.push(user._id) success.push(user._id)
} catch (error) { } catch (error) {

View file

@ -238,17 +238,17 @@ describe('CollaboratorsInviteController', function () {
}) })
describe('when all goes well', function (done) { describe('when all goes well', function (done) {
beforeEach(function (done) { beforeEach(async function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true)
this.CollaboratorsInviteController.promises._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.res.callback = () => done() this.CollaboratorsInviteController._checkRateLimit = sinon
this.CollaboratorsInviteController.inviteToProject( .stub()
.resolves(true)
await this.CollaboratorsInviteController.inviteToProject(
this.req, this.req,
this.res, this.res
done
) )
}) })
@ -269,10 +269,11 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should have called _checkShouldInviteEmail', function () { it('should have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
1 1
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail
this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.targetEmail) .calledWith(this.targetEmail)
.should.equal(true) .should.equal(true)
}) })
@ -322,9 +323,10 @@ describe('CollaboratorsInviteController', function () {
describe('readAndWrite collaborator', function () { describe('readAndWrite collaborator', function () {
beforeEach(function (done) { beforeEach(function (done) {
this.privileges = 'readAndWrite' this.privileges = 'readAndWrite'
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.res.callback = () => done() this.res.callback = () => done()
@ -343,10 +345,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should not have called _checkShouldInviteEmail', function () { it('should not have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
0 0
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.currentUser, this.targetEmail) .calledWith(this.currentUser, this.targetEmail)
.should.equal(false) .should.equal(false)
}) })
@ -364,9 +366,10 @@ describe('CollaboratorsInviteController', function () {
email: this.targetEmail, email: this.targetEmail,
privileges: (this.privileges = 'readOnly'), privileges: (this.privileges = 'readOnly'),
} }
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.res.callback = () => done() this.res.callback = () => done()
@ -391,10 +394,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should have called _checkShouldInviteEmail', function () { it('should have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
1 1
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.targetEmail) .calledWith(this.targetEmail)
.should.equal(true) .should.equal(true)
}) })
@ -438,9 +441,10 @@ describe('CollaboratorsInviteController', function () {
describe('when all goes well', function (done) { describe('when all goes well', function (done) {
beforeEach(function (done) { beforeEach(function (done) {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.res.callback = () => done() this.res.callback = () => done()
@ -468,10 +472,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should have called _checkShouldInviteEmail', function () { it('should have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
1 1
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.targetEmail) .calledWith(this.targetEmail)
.should.equal(true) .should.equal(true)
}) })
@ -513,9 +517,10 @@ describe('CollaboratorsInviteController', function () {
describe('when the user is not allowed to add more collaborators', function () { describe('when the user is not allowed to add more collaborators', function () {
beforeEach(function (done) { beforeEach(function (done) {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.LimitationsManager.promises.canAddXCollaborators.resolves(false) this.LimitationsManager.promises.canAddXCollaborators.resolves(false)
@ -533,10 +538,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should not have called _checkShouldInviteEmail', function () { it('should not have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
0 0
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.currentUser, this.targetEmail) .calledWith(this.currentUser, this.targetEmail)
.should.equal(false) .should.equal(false)
}) })
@ -550,9 +555,10 @@ describe('CollaboratorsInviteController', function () {
describe('when canAddXCollaborators produces an error', function () { describe('when canAddXCollaborators produces an error', function () {
beforeEach(function (done) { beforeEach(function (done) {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.LimitationsManager.promises.canAddXCollaborators.rejects( this.LimitationsManager.promises.canAddXCollaborators.rejects(
@ -572,10 +578,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should not have called _checkShouldInviteEmail', function () { it('should not have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
0 0
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.currentUser, this.targetEmail) .calledWith(this.currentUser, this.targetEmail)
.should.equal(false) .should.equal(false)
}) })
@ -589,9 +595,10 @@ describe('CollaboratorsInviteController', function () {
describe('when inviteToProject produces an error', function () { describe('when inviteToProject produces an error', function () {
beforeEach(function (done) { beforeEach(function (done) {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.CollaboratorsInviteHandler.promises.inviteToProject.rejects( this.CollaboratorsInviteHandler.promises.inviteToProject.rejects(
@ -620,10 +627,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should have called _checkShouldInviteEmail', function () { it('should have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
1 1
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.targetEmail) .calledWith(this.targetEmail)
.should.equal(true) .should.equal(true)
}) })
@ -645,9 +652,10 @@ describe('CollaboratorsInviteController', function () {
describe('when _checkShouldInviteEmail disallows the invite', function () { describe('when _checkShouldInviteEmail disallows the invite', function () {
beforeEach(function (done) { beforeEach(function (done) {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(false) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(false)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.res.callback = () => done() this.res.callback = () => done()
@ -667,10 +675,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should have called _checkShouldInviteEmail', function () { it('should have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
1 1
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.targetEmail) .calledWith(this.targetEmail)
.should.equal(true) .should.equal(true)
}) })
@ -684,9 +692,10 @@ describe('CollaboratorsInviteController', function () {
describe('when _checkShouldInviteEmail produces an error', function () { describe('when _checkShouldInviteEmail produces an error', function () {
beforeEach(function (done) { beforeEach(function (done) {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().rejects(new Error('woops')) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .rejects(new Error('woops'))
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.next.callsFake(() => done()) this.next.callsFake(() => done())
@ -703,10 +712,10 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should have called _checkShouldInviteEmail', function () { it('should have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
1 1
) )
this.CollaboratorsInviteController.promises._checkShouldInviteEmail this.CollaboratorsInviteController._checkShouldInviteEmail
.calledWith(this.targetEmail) .calledWith(this.targetEmail)
.should.equal(true) .should.equal(true)
}) })
@ -721,9 +730,10 @@ describe('CollaboratorsInviteController', function () {
describe('when the user invites themselves to the project', function () { describe('when the user invites themselves to the project', function () {
beforeEach(function () { beforeEach(function () {
this.req.body.email = this.currentUser.email this.req.body.email = this.currentUser.email
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
this.CollaboratorsInviteController.inviteToProject( this.CollaboratorsInviteController.inviteToProject(
@ -748,7 +758,7 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should not have called _checkShouldInviteEmail', function () { it('should not have called _checkShouldInviteEmail', function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail.callCount.should.equal( this.CollaboratorsInviteController._checkShouldInviteEmail.callCount.should.equal(
0 0
) )
}) })
@ -765,14 +775,14 @@ describe('CollaboratorsInviteController', function () {
}) })
describe('when _checkRateLimit returns false', function () { describe('when _checkRateLimit returns false', function () {
beforeEach(function (done) { beforeEach(async function () {
this.CollaboratorsInviteController.promises._checkShouldInviteEmail = this.CollaboratorsInviteController._checkShouldInviteEmail = sinon
sinon.stub().resolves(true) .stub()
this.CollaboratorsInviteController.promises._checkRateLimit = sinon .resolves(true)
this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(false) .resolves(false)
this.res.callback = () => done() await this.CollaboratorsInviteController.inviteToProject(
this.CollaboratorsInviteController.inviteToProject(
this.req, this.req,
this.res, this.res,
this.next this.next
@ -1281,7 +1291,7 @@ describe('CollaboratorsInviteController', function () {
Project_id: this.projectId, Project_id: this.projectId,
invite_id: this.invite._id.toString(), invite_id: this.invite._id.toString(),
} }
this.CollaboratorsInviteController.promises._checkRateLimit = sinon this.CollaboratorsInviteController._checkRateLimit = sinon
.stub() .stub()
.resolves(true) .resolves(true)
}) })
@ -1316,7 +1326,7 @@ describe('CollaboratorsInviteController', function () {
}) })
it('should check the rate limit', function () { it('should check the rate limit', function () {
this.CollaboratorsInviteController.promises._checkRateLimit.callCount.should.equal( this.CollaboratorsInviteController._checkRateLimit.callCount.should.equal(
1 1
) )
}) })
@ -1600,12 +1610,8 @@ describe('CollaboratorsInviteController', function () {
describe('when we should be restricting to existing accounts', function () { describe('when we should be restricting to existing accounts', function () {
beforeEach(function () { beforeEach(function () {
this.settings.restrictInvitesToExistingAccounts = true this.settings.restrictInvitesToExistingAccounts = true
this.call = callback => { this.call = () =>
this.CollaboratorsInviteController._checkShouldInviteEmail( this.CollaboratorsInviteController._checkShouldInviteEmail(this.email)
this.email,
callback
)
}
}) })
describe('when user account is present', function () { describe('when user account is present', function () {
@ -1614,12 +1620,12 @@ describe('CollaboratorsInviteController', function () {
this.UserGetter.promises.getUserByAnyEmail.resolves(this.user) this.UserGetter.promises.getUserByAnyEmail.resolves(this.user)
}) })
it('should callback with `true`', function (done) { it('should callback with `true`', async function () {
this.call((err, shouldAllow) => { const shouldAllow =
expect(err).to.equal(null) await this.CollaboratorsInviteController._checkShouldInviteEmail(
expect(shouldAllow).to.equal(true) this.email
done() )
}) expect(shouldAllow).to.equal(true)
}) })
}) })
@ -1629,25 +1635,22 @@ describe('CollaboratorsInviteController', function () {
this.UserGetter.promises.getUserByAnyEmail.resolves(this.user) this.UserGetter.promises.getUserByAnyEmail.resolves(this.user)
}) })
it('should callback with `false`', function (done) { it('should callback with `false`', async function () {
this.call((err, shouldAllow) => { const shouldAllow =
expect(err).to.equal(null) await this.CollaboratorsInviteController._checkShouldInviteEmail(
expect(shouldAllow).to.equal(false) this.email
done() )
}) expect(shouldAllow).to.equal(false)
}) })
it('should have called getUser', function (done) { it('should have called getUser', async function () {
this.call((err, shouldAllow) => { await this.CollaboratorsInviteController._checkShouldInviteEmail(
if (err) { this.email
return done(err) )
} this.UserGetter.promises.getUserByAnyEmail.callCount.should.equal(1)
this.UserGetter.promises.getUserByAnyEmail.callCount.should.equal(1) this.UserGetter.promises.getUserByAnyEmail
this.UserGetter.promises.getUserByAnyEmail .calledWith(this.email, { _id: 1 })
.calledWith(this.email, { _id: 1 }) .should.equal(true)
.should.equal(true)
done()
})
}) })
}) })
@ -1657,13 +1660,12 @@ describe('CollaboratorsInviteController', function () {
this.UserGetter.promises.getUserByAnyEmail.rejects(new Error('woops')) this.UserGetter.promises.getUserByAnyEmail.rejects(new Error('woops'))
}) })
it('should callback with an error', function (done) { it('should callback with an error', async function () {
this.call((err, shouldAllow) => { await expect(
expect(err).to.not.equal(null) this.CollaboratorsInviteController._checkShouldInviteEmail(
expect(err).to.be.instanceof(Error) this.email
expect(shouldAllow).to.equal(undefined) )
done() ).to.be.rejected
})
}) })
}) })
}) })
@ -1678,90 +1680,60 @@ describe('CollaboratorsInviteController', function () {
.resolves(17) .resolves(17)
}) })
it('should callback with `true` when rate limit under', function (done) { it('should callback with `true` when rate limit under', async function () {
this.CollaboratorsInviteController._checkRateLimit( const result = await this.CollaboratorsInviteController._checkRateLimit(
this.currentUserId, this.currentUserId
(err, result) => {
if (err) {
return done(err)
}
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId
)
result.should.equal(true)
done()
}
) )
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId
)
result.should.equal(true)
}) })
it('should callback with `false` when rate limit hit', function (done) { it('should callback with `false` when rate limit hit', async function () {
this.rateLimiter.consume.rejects({ remainingPoints: 0 }) this.rateLimiter.consume.rejects({ remainingPoints: 0 })
this.CollaboratorsInviteController._checkRateLimit( const result = await this.CollaboratorsInviteController._checkRateLimit(
this.currentUserId
)
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId
)
result.should.equal(false)
})
it('should allow 10x the collaborators', async function () {
await this.CollaboratorsInviteController._checkRateLimit(
this.currentUserId
)
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId, this.currentUserId,
(err, result) => { Math.floor(40000 / 170)
if (err) {
return done(err)
}
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId
)
result.should.equal(false)
done()
}
) )
}) })
it('should allow 10x the collaborators', function (done) { it('should allow 200 requests when collaborators is -1', async function () {
this.CollaboratorsInviteController._checkRateLimit(
this.currentUserId,
(err, result) => {
if (err) {
return done(err)
}
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId,
Math.floor(40000 / 170)
)
done()
}
)
})
it('should allow 200 requests when collaborators is -1', function (done) {
this.LimitationsManager.promises.allowedNumberOfCollaboratorsForUser this.LimitationsManager.promises.allowedNumberOfCollaboratorsForUser
.withArgs(this.currentUserId) .withArgs(this.currentUserId)
.resolves(-1) .resolves(-1)
this.CollaboratorsInviteController._checkRateLimit( await this.CollaboratorsInviteController._checkRateLimit(
this.currentUserId
)
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId, this.currentUserId,
(err, result) => { Math.floor(40000 / 200)
if (err) {
return done(err)
}
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId,
Math.floor(40000 / 200)
)
done()
}
) )
}) })
it('should allow 10 requests when user has no collaborators set', function (done) { it('should allow 10 requests when user has no collaborators set', async function () {
this.LimitationsManager.promises.allowedNumberOfCollaboratorsForUser this.LimitationsManager.promises.allowedNumberOfCollaboratorsForUser
.withArgs(this.currentUserId) .withArgs(this.currentUserId)
.resolves(null) .resolves(null)
this.CollaboratorsInviteController._checkRateLimit( await this.CollaboratorsInviteController._checkRateLimit(
this.currentUserId
)
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId, this.currentUserId,
(err, result) => { Math.floor(40000 / 10)
if (err) {
return done(err)
}
expect(this.rateLimiter.consume).to.have.been.calledWith(
this.currentUserId,
Math.floor(40000 / 10)
)
done()
}
) )
}) })
}) })

View file

@ -38,6 +38,7 @@ describe('DocumentUpdaterController', function () {
} }
this.lines = ['test', '', 'testing'] this.lines = ['test', '', 'testing']
this.res = new MockResponse() this.res = new MockResponse()
this.next = sinon.stub()
this.doc = { name: 'myfile.tex' } this.doc = { name: 'myfile.tex' }
}) })
@ -53,8 +54,7 @@ describe('DocumentUpdaterController', function () {
}) })
it('should call the document updater handler with the project_id and doc_id', async function () { it('should call the document updater handler with the project_id and doc_id', async function () {
await this.controller.promises.getDoc(this.req, this.res) await this.controller.getDoc(this.req, this.res, this.next)
expect( expect(
this.DocumentUpdaterHandler.promises.getDocument this.DocumentUpdaterHandler.promises.getDocument
).to.have.been.calledOnceWith( ).to.have.been.calledOnceWith(
@ -65,13 +65,14 @@ describe('DocumentUpdaterController', function () {
}) })
it('should return the content', async function () { it('should return the content', async function () {
await this.controller.promises.getDoc(this.req, this.res) await this.controller.getDoc(this.req, this.res)
expect(this.next).to.not.have.been.called
expect(this.res.statusCode).to.equal(200) expect(this.res.statusCode).to.equal(200)
expect(this.res.body).to.equal('test\n\ntesting') expect(this.res.body).to.equal('test\n\ntesting')
}) })
it('should find the doc in the project', async function () { it('should find the doc in the project', async function () {
await this.controller.promises.getDoc(this.req, this.res) await this.controller.getDoc(this.req, this.res)
expect( expect(
this.ProjectLocator.promises.findElement this.ProjectLocator.promises.findElement
).to.have.been.calledOnceWith({ ).to.have.been.calledOnceWith({
@ -82,7 +83,7 @@ describe('DocumentUpdaterController', function () {
}) })
it('should set the Content-Disposition header', async function () { it('should set the Content-Disposition header', async function () {
await this.controller.promises.getDoc(this.req, this.res) await this.controller.getDoc(this.req, this.res)
expect(this.res.setContentDisposition).to.have.been.calledWith( expect(this.res.setContentDisposition).to.have.been.calledWith(
'attachment', 'attachment',
{ filename: this.doc.name } { filename: this.doc.name }

View file

@ -916,7 +916,7 @@ describe('UserController', function () {
describe('ensureAffiliationMiddleware', function () { describe('ensureAffiliationMiddleware', function () {
describe('without affiliations feature', function () { describe('without affiliations feature', function () {
beforeEach(async function () { beforeEach(async function () {
await this.UserController.promises.ensureAffiliationMiddleware( await this.UserController.ensureAffiliationMiddleware(
this.req, this.req,
this.res, this.res,
this.next this.next
@ -938,7 +938,7 @@ describe('UserController', function () {
describe('without ensureAffiliation query parameter', function () { describe('without ensureAffiliation query parameter', function () {
beforeEach(async function () { beforeEach(async function () {
this.Features.hasFeature.withArgs('affiliations').returns(true) this.Features.hasFeature.withArgs('affiliations').returns(true)
await this.UserController.promises.ensureAffiliationMiddleware( await this.UserController.ensureAffiliationMiddleware(
this.req, this.req,
this.res, this.res,
this.next this.next
@ -968,7 +968,7 @@ describe('UserController', function () {
] ]
this.Features.hasFeature.withArgs('affiliations').returns(true) this.Features.hasFeature.withArgs('affiliations').returns(true)
this.req.query.ensureAffiliation = true this.req.query.ensureAffiliation = true
await this.UserController.promises.ensureAffiliationMiddleware( await this.UserController.ensureAffiliationMiddleware(
this.req, this.req,
this.res, this.res,
this.next this.next
@ -1005,7 +1005,7 @@ describe('UserController', function () {
this.Features.hasFeature.withArgs('affiliations').returns(true) this.Features.hasFeature.withArgs('affiliations').returns(true)
this.req.query.ensureAffiliation = true this.req.query.ensureAffiliation = true
this.req.assertPermission = sinon.stub() this.req.assertPermission = sinon.stub()
await this.UserController.promises.ensureAffiliationMiddleware( await this.UserController.ensureAffiliationMiddleware(
this.req, this.req,
this.res, this.res,
this.next this.next
@ -1047,7 +1047,7 @@ describe('UserController', function () {
this.Features.hasFeature.withArgs('affiliations').returns(true) this.Features.hasFeature.withArgs('affiliations').returns(true)
this.req.query.ensureAffiliation = true this.req.query.ensureAffiliation = true
this.req.assertPermission = sinon.stub() this.req.assertPermission = sinon.stub()
await this.UserController.promises.ensureAffiliationMiddleware( await this.UserController.ensureAffiliationMiddleware(
this.req, this.req,
this.res, this.res,
this.next this.next
@ -1089,7 +1089,7 @@ describe('UserController', function () {
this.Features.hasFeature.withArgs('affiliations').returns(true) this.Features.hasFeature.withArgs('affiliations').returns(true)
this.req.query.ensureAffiliation = true this.req.query.ensureAffiliation = true
this.req.assertPermission = sinon.stub() this.req.assertPermission = sinon.stub()
await this.UserController.promises.ensureAffiliationMiddleware( await this.UserController.ensureAffiliationMiddleware(
this.req, this.req,
this.res, this.res,
this.next this.next