mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #18294 from overleaf/jpa-td-invite-details
[web] avoid content reflection via query parameter on register page GitOrigin-RevId: 43e7ba6069e0d9f3f12e5e9e680b5960b0673782
This commit is contained in:
parent
105d67bd04
commit
dfe587f297
12 changed files with 143 additions and 96 deletions
|
@ -522,7 +522,7 @@ const AuthenticationController = {
|
||||||
_redirectToLoginOrRegisterPage(req, res) {
|
_redirectToLoginOrRegisterPage(req, res) {
|
||||||
if (
|
if (
|
||||||
req.query.zipUrl != null ||
|
req.query.zipUrl != null ||
|
||||||
req.query.project_name != null ||
|
req.session.sharedProjectData ||
|
||||||
req.path === '/user/subscription/new'
|
req.path === '/user/subscription/new'
|
||||||
) {
|
) {
|
||||||
AuthenticationController._redirectToRegisterPage(req, res)
|
AuthenticationController._redirectToRegisterPage(req, res)
|
||||||
|
|
|
@ -5,13 +5,7 @@ const Settings = require('@overleaf/settings')
|
||||||
|
|
||||||
const CollaboratorsEmailHandler = {
|
const CollaboratorsEmailHandler = {
|
||||||
_buildInviteUrl(project, invite) {
|
_buildInviteUrl(project, invite) {
|
||||||
return (
|
return `${Settings.siteUrl}/project/${project._id}/invite/token/${invite.token}`
|
||||||
`${Settings.siteUrl}/project/${project._id}/invite/token/${invite.token}?` +
|
|
||||||
[
|
|
||||||
`project_name=${encodeURIComponent(project.name)}`,
|
|
||||||
`user_first_name=${encodeURIComponent(project.owner_ref.first_name)}`,
|
|
||||||
].join('&')
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async notifyUserOfProjectInvite(projectId, email, invite, sendingUser) {
|
async notifyUserOfProjectInvite(projectId, email, invite, sendingUser) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ const { RateLimiter } = require('../../infrastructure/RateLimiter')
|
||||||
const { expressify } = require('@overleaf/promise-utils')
|
const { expressify } = require('@overleaf/promise-utils')
|
||||||
const ProjectAuditLogHandler = require('../Project/ProjectAuditLogHandler')
|
const ProjectAuditLogHandler = require('../Project/ProjectAuditLogHandler')
|
||||||
const Errors = require('../Errors/Errors')
|
const Errors = require('../Errors/Errors')
|
||||||
|
const AuthenticationController = require('../Authentication/AuthenticationController')
|
||||||
|
|
||||||
// This rate limiter allows a different number of requests depending on the
|
// This rate limiter allows a different number of requests depending on the
|
||||||
// number of callaborators a user is allowed. This is implemented by providing
|
// number of callaborators a user is allowed. This is implemented by providing
|
||||||
|
@ -234,23 +235,26 @@ const CollaboratorsInviteController = {
|
||||||
const projectId = req.params.Project_id
|
const projectId = req.params.Project_id
|
||||||
const { token } = req.params
|
const { token } = req.params
|
||||||
const _renderInvalidPage = function () {
|
const _renderInvalidPage = function () {
|
||||||
|
res.status(404)
|
||||||
logger.debug({ projectId }, 'invite not valid, rendering not-valid page')
|
logger.debug({ projectId }, 'invite not valid, rendering not-valid page')
|
||||||
res.render('project/invite/not-valid', { title: 'Invalid Invite' })
|
res.render('project/invite/not-valid', { title: 'Invalid Invite' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the user is already a member of the project
|
// check if the user is already a member of the project
|
||||||
const currentUser = SessionManager.getSessionUser(req.session)
|
const currentUser = SessionManager.getSessionUser(req.session)
|
||||||
const isMember =
|
if (currentUser) {
|
||||||
await CollaboratorsGetter.promises.isUserInvitedMemberOfProject(
|
const isMember =
|
||||||
currentUser._id,
|
await CollaboratorsGetter.promises.isUserInvitedMemberOfProject(
|
||||||
projectId
|
currentUser._id,
|
||||||
)
|
projectId
|
||||||
if (isMember) {
|
)
|
||||||
logger.debug(
|
if (isMember) {
|
||||||
{ projectId, userId: currentUser._id },
|
logger.debug(
|
||||||
'user is already a member of this project, redirecting'
|
{ projectId, userId: currentUser._id },
|
||||||
)
|
'user is already a member of this project, redirecting'
|
||||||
return res.redirect(`/project/${projectId}`)
|
)
|
||||||
|
return res.redirect(`/project/${projectId}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the invite
|
// get the invite
|
||||||
|
@ -284,6 +288,18 @@ const CollaboratorsInviteController = {
|
||||||
return _renderInvalidPage()
|
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
|
// finally render the invite
|
||||||
res.render('project/invite/show', {
|
res.render('project/invite/show', {
|
||||||
invite,
|
invite,
|
||||||
|
|
|
@ -26,6 +26,10 @@ const rateLimiters = {
|
||||||
points: 200,
|
points: 200,
|
||||||
duration: 60 * 10,
|
duration: 60 * 10,
|
||||||
}),
|
}),
|
||||||
|
viewProjectInvite: new RateLimiter('view-project-invite', {
|
||||||
|
points: 20,
|
||||||
|
duration: 60,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -128,7 +132,7 @@ module.exports = {
|
||||||
'collaboration',
|
'collaboration',
|
||||||
'project-invite'
|
'project-invite'
|
||||||
),
|
),
|
||||||
AuthenticationController.requireLogin(),
|
RateLimiterMiddleware.rateLimit(rateLimiters.viewProjectInvite),
|
||||||
CollaboratorsInviteController.viewInvite,
|
CollaboratorsInviteController.viewInvite,
|
||||||
AnalyticsRegistrationSourceMiddleware.clearSource()
|
AnalyticsRegistrationSourceMiddleware.clearSource()
|
||||||
)
|
)
|
||||||
|
|
|
@ -80,6 +80,17 @@ const _buildPortalTemplatesList = affiliations => {
|
||||||
return portalTemplates
|
return portalTemplates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanupSession(req) {
|
||||||
|
// cleanup redirects at the end of the redirect chain
|
||||||
|
delete req.session.postCheckoutRedirect
|
||||||
|
delete req.session.postLoginRedirect
|
||||||
|
delete req.session.postOnboardingRedirect
|
||||||
|
|
||||||
|
// cleanup details from register page
|
||||||
|
delete req.session.sharedProjectData
|
||||||
|
delete req.session.templateData
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("express").Request} req
|
* @param {import("express").Request} req
|
||||||
* @param {import("express").Response} res
|
* @param {import("express").Response} res
|
||||||
|
@ -87,10 +98,7 @@ const _buildPortalTemplatesList = affiliations => {
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function projectListPage(req, res, next) {
|
async function projectListPage(req, res, next) {
|
||||||
// cleanup redirects at the end of the redirect chain
|
cleanupSession(req)
|
||||||
delete req.session.postCheckoutRedirect
|
|
||||||
delete req.session.postLoginRedirect
|
|
||||||
delete req.session.postOnboardingRedirect
|
|
||||||
|
|
||||||
// can have two values:
|
// can have two values:
|
||||||
// - undefined - when there's no "saas" feature or couldn't get subscription data
|
// - undefined - when there's no "saas" feature or couldn't get subscription data
|
||||||
|
|
|
@ -211,10 +211,7 @@ const UserPagesController = {
|
||||||
accountSuspended: expressify(accountSuspended),
|
accountSuspended: expressify(accountSuspended),
|
||||||
|
|
||||||
registerPage(req, res) {
|
registerPage(req, res) {
|
||||||
const sharedProjectData = {
|
const sharedProjectData = req.session.sharedProjectData || {}
|
||||||
project_name: req.query.project_name,
|
|
||||||
user_first_name: req.query.user_first_name,
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTemplateData = {}
|
const newTemplateData = {}
|
||||||
if (req.session.templateData != null) {
|
if (req.session.templateData != null) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ const User = require('./helpers/User')
|
||||||
const settings = require('@overleaf/settings')
|
const settings = require('@overleaf/settings')
|
||||||
const CollaboratorsEmailHandler = require('../../../app/src/Features/Collaborators/CollaboratorsEmailHandler')
|
const CollaboratorsEmailHandler = require('../../../app/src/Features/Collaborators/CollaboratorsEmailHandler')
|
||||||
const Features = require('../../../app/src/infrastructure/Features')
|
const Features = require('../../../app/src/infrastructure/Features')
|
||||||
|
const cheerio = require('cheerio')
|
||||||
|
|
||||||
const createInvite = (sendingUser, projectId, email, callback) => {
|
const createInvite = (sendingUser, projectId, email, callback) => {
|
||||||
sendingUser.getCsrfToken(err => {
|
sendingUser.getCsrfToken(err => {
|
||||||
|
@ -107,24 +108,6 @@ const tryAcceptInvite = (user, invite, callback) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const tryRegisterUser = (user, email, callback) => {
|
|
||||||
user.getCsrfToken(error => {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
user.request.post(
|
|
||||||
{
|
|
||||||
url: '/register',
|
|
||||||
json: {
|
|
||||||
email,
|
|
||||||
password: 'some_weird_password',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
callback
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const tryFollowLoginLink = (user, loginLink, callback) => {
|
const tryFollowLoginLink = (user, loginLink, callback) => {
|
||||||
user.getCsrfToken(error => {
|
user.getCsrfToken(error => {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
@ -220,7 +203,7 @@ const expectInvalidInvitePage = (user, link, callback) => {
|
||||||
// view invalid invite
|
// view invalid invite
|
||||||
tryFollowInviteLink(user, link, (err, response, body) => {
|
tryFollowInviteLink(user, link, (err, response, body) => {
|
||||||
expect(err).not.to.exist
|
expect(err).not.to.exist
|
||||||
expect(response.statusCode).to.equal(200)
|
expect(response.statusCode).to.equal(404)
|
||||||
expect(body).to.match(/<title>Invalid Invite - .*<\/title>/)
|
expect(body).to.match(/<title>Invalid Invite - .*<\/title>/)
|
||||||
callback()
|
callback()
|
||||||
})
|
})
|
||||||
|
@ -232,7 +215,15 @@ const expectInviteRedirectToRegister = (user, link, callback) => {
|
||||||
expect(err).not.to.exist
|
expect(err).not.to.exist
|
||||||
expect(response.statusCode).to.equal(302)
|
expect(response.statusCode).to.equal(302)
|
||||||
expect(response.headers.location).to.match(/^\/register.*$/)
|
expect(response.headers.location).to.match(/^\/register.*$/)
|
||||||
callback()
|
|
||||||
|
user.getSession((err, session) => {
|
||||||
|
if (err) return callback(err)
|
||||||
|
expect(session.sharedProjectData).deep.equals({
|
||||||
|
project_name: PROJECT_NAME,
|
||||||
|
user_first_name: OWNER_NAME,
|
||||||
|
})
|
||||||
|
callback()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,11 +244,26 @@ const expectLoginRedirectToInvite = (user, link, callback) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const expectRegistrationRedirectToInvite = (user, email, link, callback) => {
|
const expectRegistrationRedirectToInvite = (user, link, callback) => {
|
||||||
tryRegisterUser(user, email, (err, response) => {
|
user.register((err, _user, response) => {
|
||||||
expect(err).not.to.exist
|
expect(err).not.to.exist
|
||||||
expect(response.statusCode).to.equal(200)
|
expect(response.statusCode).to.equal(200)
|
||||||
callback()
|
|
||||||
|
if (response.body.redir === '/registration/try-premium') {
|
||||||
|
user.request.get('/registration/onboarding', (err, response) => {
|
||||||
|
if (err) return callback(err)
|
||||||
|
expect(response.statusCode).to.equal(200)
|
||||||
|
const dom = cheerio.load(response.body)
|
||||||
|
const skipUrl = dom('meta[name="ol-skipUrl"]')[0].attribs.content
|
||||||
|
expect(new URL(skipUrl, settings.siteUrl).href).to.equal(
|
||||||
|
new URL(link, settings.siteUrl).href
|
||||||
|
)
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
expect(response.body.redir).to.equal(link)
|
||||||
|
callback()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,19 +307,26 @@ const expectInvitesInJoinProjectCount = (user, projectId, count, callback) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line mocha/no-skipped-tests
|
const PROJECT_NAME = 'project name for sharing test'
|
||||||
describe.skip('ProjectInviteTests', function () {
|
const OWNER_NAME = 'sending user name'
|
||||||
|
|
||||||
|
describe('ProjectInviteTests', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.sendingUser = new User()
|
this.sendingUser = new User()
|
||||||
this.user = new User()
|
this.user = new User()
|
||||||
this.site_admin = new User({ email: 'admin@example.com' })
|
this.site_admin = new User({ email: `admin+${Math.random()}@example.com` })
|
||||||
this.email = 'smoketestuser@example.com'
|
this.email = `smoketestuser+${Math.random()}@example.com`
|
||||||
this.projectName = 'sharing test'
|
|
||||||
Async.series(
|
Async.series(
|
||||||
[
|
[
|
||||||
cb => this.user.ensureUserExists(cb),
|
|
||||||
cb => this.sendingUser.login(cb),
|
cb => this.sendingUser.login(cb),
|
||||||
cb => this.sendingUser.setFeatures({ collaborators: 10 }, cb),
|
cb => this.sendingUser.setFeatures({ collaborators: 10 }, cb),
|
||||||
|
cb =>
|
||||||
|
this.sendingUser.mongoUpdate(
|
||||||
|
{
|
||||||
|
$set: { first_name: OWNER_NAME },
|
||||||
|
},
|
||||||
|
cb
|
||||||
|
),
|
||||||
cb =>
|
cb =>
|
||||||
this.sendingUser.setFeaturesOverride(
|
this.sendingUser.setFeaturesOverride(
|
||||||
{
|
{
|
||||||
|
@ -328,15 +341,11 @@ describe.skip('ProjectInviteTests', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('creating invites', function () {
|
describe('creating invites', function () {
|
||||||
beforeEach(function () {
|
|
||||||
this.projectName = 'wat'
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('creating two invites', function () {
|
describe('creating two invites', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
createProject(
|
createProject(
|
||||||
this.sendingUser,
|
this.sendingUser,
|
||||||
this.projectName,
|
PROJECT_NAME,
|
||||||
(err, projectId, project) => {
|
(err, projectId, project) => {
|
||||||
expect(err).not.to.exist
|
expect(err).not.to.exist
|
||||||
this.projectId = projectId
|
this.projectId = projectId
|
||||||
|
@ -504,7 +513,7 @@ describe.skip('ProjectInviteTests', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
createProjectAndInvite(
|
createProjectAndInvite(
|
||||||
this.sendingUser,
|
this.sendingUser,
|
||||||
this.projectName,
|
PROJECT_NAME,
|
||||||
this.email,
|
this.email,
|
||||||
(err, project, invite, link) => {
|
(err, project, invite, link) => {
|
||||||
expect(err).not.to.exist
|
expect(err).not.to.exist
|
||||||
|
@ -657,12 +666,7 @@ describe.skip('ProjectInviteTests', function () {
|
||||||
[
|
[
|
||||||
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
|
cb => expectInviteRedirectToRegister(this.user, this.link, cb),
|
||||||
cb =>
|
cb =>
|
||||||
expectRegistrationRedirectToInvite(
|
expectRegistrationRedirectToInvite(this.user, this.link, cb),
|
||||||
this.user,
|
|
||||||
'some_email@example.com',
|
|
||||||
this.link,
|
|
||||||
cb
|
|
||||||
),
|
|
||||||
cb => expectInvitePage(this.user, this.link, cb),
|
cb => expectInvitePage(this.user, this.link, cb),
|
||||||
cb => expectAcceptInviteAndRedirect(this.user, this.invite, cb),
|
cb => expectAcceptInviteAndRedirect(this.user, this.invite, cb),
|
||||||
cb => expectProjectAccess(this.user, this.invite.projectId, cb),
|
cb => expectProjectAccess(this.user, this.invite.projectId, cb),
|
||||||
|
@ -689,21 +693,13 @@ describe.skip('ProjectInviteTests', function () {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should display invalid-invite if the user registers a new account', function (done) {
|
it('should display invalid-invite right away', function (done) {
|
||||||
const badLink = this.link.replace(
|
const badLink = this.link.replace(
|
||||||
this.invite.token,
|
this.invite.token,
|
||||||
'not_a_real_token'
|
'not_a_real_token'
|
||||||
)
|
)
|
||||||
Async.series(
|
Async.series(
|
||||||
[
|
[
|
||||||
cb => expectInviteRedirectToRegister(this.user, badLink, cb),
|
|
||||||
cb =>
|
|
||||||
expectRegistrationRedirectToInvite(
|
|
||||||
this.user,
|
|
||||||
'some_email@example.com',
|
|
||||||
badLink,
|
|
||||||
cb
|
|
||||||
),
|
|
||||||
cb => expectInvalidInvitePage(this.user, badLink, cb),
|
cb => expectInvalidInvitePage(this.user, badLink, cb),
|
||||||
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb),
|
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb),
|
||||||
],
|
],
|
||||||
|
@ -713,6 +709,10 @@ describe.skip('ProjectInviteTests', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('login workflow with valid token', function () {
|
describe('login workflow with valid token', function () {
|
||||||
|
beforeEach(function (done) {
|
||||||
|
this.user.ensureUserExists(done)
|
||||||
|
})
|
||||||
|
|
||||||
it('should redirect to the register page', function (done) {
|
it('should redirect to the register page', function (done) {
|
||||||
Async.series(
|
Async.series(
|
||||||
[
|
[
|
||||||
|
@ -762,20 +762,13 @@ describe.skip('ProjectInviteTests', function () {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should show the invalid-invite page once the user has logged in', function (done) {
|
it('should show the invalid-invite page right away', function (done) {
|
||||||
const badLink = this.link.replace(
|
const badLink = this.link.replace(
|
||||||
this.invite.token,
|
this.invite.token,
|
||||||
'not_a_real_token'
|
'not_a_real_token'
|
||||||
)
|
)
|
||||||
Async.series(
|
Async.series(
|
||||||
[
|
[
|
||||||
cb => {
|
|
||||||
return expectInviteRedirectToRegister(this.user, badLink, cb)
|
|
||||||
},
|
|
||||||
cb => {
|
|
||||||
return expectLoginPage(this.user, cb)
|
|
||||||
},
|
|
||||||
cb => expectLoginRedirectToInvite(this.user, badLink, cb),
|
|
||||||
cb => expectInvalidInvitePage(this.user, badLink, cb),
|
cb => expectInvalidInvitePage(this.user, badLink, cb),
|
||||||
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb),
|
cb => expectNoProjectAccess(this.user, this.invite.projectId, cb),
|
||||||
],
|
],
|
||||||
|
|
|
@ -336,7 +336,7 @@ class User {
|
||||||
return callback(error)
|
return callback(error)
|
||||||
}
|
}
|
||||||
this.setExtraAttributes(user)
|
this.setExtraAttributes(user)
|
||||||
callback(null, user)
|
callback(null, user, response)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -906,7 +906,10 @@ describe('AuthenticationController', function () {
|
||||||
|
|
||||||
describe('they have been invited to a project', function () {
|
describe('they have been invited to a project', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.req.query.project_name = 'something'
|
this.req.session.sharedProjectData = {
|
||||||
|
project_name: 'something',
|
||||||
|
user_first_name: 'else',
|
||||||
|
}
|
||||||
this.SessionManager.isUserLoggedIn = sinon.stub().returns(false)
|
this.SessionManager.isUserLoggedIn = sinon.stub().returns(false)
|
||||||
this.middleware(this.req, this.res, this.next)
|
this.middleware(this.req, this.res, this.next)
|
||||||
})
|
})
|
||||||
|
|
|
@ -92,6 +92,10 @@ describe('CollaboratorsInviteController', function () {
|
||||||
addEntryInBackground: sinon.stub(),
|
addEntryInBackground: sinon.stub(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.AuthenticationController = {
|
||||||
|
setRedirectInSession: sinon.stub(),
|
||||||
|
}
|
||||||
|
|
||||||
this.CollaboratorsInviteController = SandboxedModule.require(MODULE_PATH, {
|
this.CollaboratorsInviteController = SandboxedModule.require(MODULE_PATH, {
|
||||||
requires: {
|
requires: {
|
||||||
'../Project/ProjectGetter': this.ProjectGetter,
|
'../Project/ProjectGetter': this.ProjectGetter,
|
||||||
|
@ -105,6 +109,8 @@ describe('CollaboratorsInviteController', function () {
|
||||||
'../Authentication/SessionManager': this.SessionManager,
|
'../Authentication/SessionManager': this.SessionManager,
|
||||||
'@overleaf/settings': this.settings,
|
'@overleaf/settings': this.settings,
|
||||||
'../../infrastructure/RateLimiter': this.RateLimiter,
|
'../../infrastructure/RateLimiter': this.RateLimiter,
|
||||||
|
'../Authentication/AuthenticationController':
|
||||||
|
this.AuthenticationController,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -626,6 +632,35 @@ describe('CollaboratorsInviteController', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when not logged in', function () {
|
||||||
|
beforeEach(function (done) {
|
||||||
|
this.SessionManager.getSessionUser.returns(null)
|
||||||
|
|
||||||
|
this.res.callback = () => done()
|
||||||
|
this.CollaboratorsInviteController.viewInvite(
|
||||||
|
this.req,
|
||||||
|
this.res,
|
||||||
|
this.next
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('should not check member status', function () {
|
||||||
|
expect(this.CollaboratorsGetter.promises.isUserInvitedMemberOfProject)
|
||||||
|
.to.not.have.been.called
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should set redirect back to invite', function () {
|
||||||
|
expect(
|
||||||
|
this.AuthenticationController.setRedirectInSession
|
||||||
|
).to.have.been.calledWith(this.req)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should redirect to the register page', function () {
|
||||||
|
expect(this.res.render).to.not.have.been.called
|
||||||
|
expect(this.res.redirect).to.have.been.calledOnce
|
||||||
|
expect(this.res.redirect).to.have.been.calledWith('/register')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('when user is already a member of the project', function () {
|
describe('when user is already a member of the project', function () {
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
this.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.resolves(
|
this.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.resolves(
|
||||||
|
|
|
@ -537,12 +537,7 @@ describe('EmailBuilder', function () {
|
||||||
}
|
}
|
||||||
this.projectName = 'Top Secret'
|
this.projectName = 'Top Secret'
|
||||||
this.opts = {
|
this.opts = {
|
||||||
inviteUrl:
|
inviteUrl: `${this.settings.siteUrl}/project/projectId123/invite/token/aToken123`,
|
||||||
`${this.settings.siteUrl}/project/projectId123/invite/token/aToken123?` +
|
|
||||||
[
|
|
||||||
`project_name=${encodeURIComponent(this.projectName)}`,
|
|
||||||
`user_first_name=${encodeURIComponent(this.owner.name)}`,
|
|
||||||
].join('&'),
|
|
||||||
owner: {
|
owner: {
|
||||||
email: this.owner.email,
|
email: this.owner.email,
|
||||||
},
|
},
|
||||||
|
|
|
@ -119,8 +119,10 @@ describe('UserPagesController', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should set sharedProjectData', function (done) {
|
it('should set sharedProjectData', function (done) {
|
||||||
this.req.query.project_name = 'myProject'
|
this.req.session.sharedProjectData = {
|
||||||
this.req.query.user_first_name = 'user_first_name_here'
|
project_name: 'myProject',
|
||||||
|
user_first_name: 'user_first_name_here',
|
||||||
|
}
|
||||||
|
|
||||||
this.res.callback = () => {
|
this.res.callback = () => {
|
||||||
this.res.renderedVariables.sharedProjectData.project_name.should.equal(
|
this.res.renderedVariables.sharedProjectData.project_name.should.equal(
|
||||||
|
|
Loading…
Reference in a new issue