| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- const sinon = require('sinon')
- const assertCalledWith = sinon.assert.calledWith
- const assertNotCalled = sinon.assert.notCalled
- const chai = require('chai')
- const { assert } = chai
- const modulePath = '../../../../app/src/Features/User/UserEmailsController.js'
- const SandboxedModule = require('sandboxed-module')
- const MockRequest = require('../helpers/MockRequest')
- const Errors = require('../../../../app/src/Features/Errors/Errors')
- describe('UserEmailsController', function() {
- beforeEach(function() {
- this.req = new MockRequest()
- this.user = { _id: 'mock-user-id' }
- this.UserGetter = { getUserFullEmails: sinon.stub() }
- this.AuthenticationController = {
- getLoggedInUserId: sinon.stub().returns(this.user._id),
- setInSessionUser: sinon.stub()
- }
- this.Features = {
- hasFeature: sinon.stub()
- }
- this.UserUpdater = {
- addEmailAddress: sinon.stub(),
- removeEmailAddress: sinon.stub(),
- setDefaultEmailAddress: sinon.stub(),
- updateV1AndSetDefaultEmailAddress: sinon.stub()
- }
- this.EmailHelper = { parseEmail: sinon.stub() }
- this.endorseAffiliation = sinon.stub().yields()
- this.InstitutionsAPI = {
- endorseAffiliation: this.endorseAffiliation,
- getInstitutionViaDomain: sinon
- .stub()
- .withArgs('overleaf.com')
- .resolves({ sso_enabled: true })
- .withArgs('example.com')
- .resolves({ sso_enabled: false })
- }
- this.UserEmailsController = SandboxedModule.require(modulePath, {
- globals: {
- console: console
- },
- requires: {
- '../Authentication/AuthenticationController': this
- .AuthenticationController,
- '../../infrastructure/Features': this.Features,
- './UserGetter': this.UserGetter,
- './UserUpdater': this.UserUpdater,
- '../Helpers/EmailHelper': this.EmailHelper,
- './UserEmailsConfirmationHandler': (this.UserEmailsConfirmationHandler = {}),
- '../Institutions/InstitutionsAPI': this.InstitutionsAPI,
- '../Errors/Errors': Errors,
- 'logger-sharelatex': {
- log() {
- console.log(arguments)
- },
- err() {}
- }
- }
- })
- })
- describe('List', function() {
- beforeEach(function() {})
- it('lists emails', function(done) {
- const fullEmails = [{ some: 'data' }]
- this.UserGetter.getUserFullEmails.callsArgWith(1, null, fullEmails)
- this.UserEmailsController.list(this.req, {
- json: response => {
- assert.deepEqual(response, fullEmails)
- assertCalledWith(this.UserGetter.getUserFullEmails, this.user._id)
- done()
- }
- })
- })
- })
- describe('Add', function() {
- beforeEach(function() {
- this.newEmail = 'new_email@baz.com'
- this.req.body = {
- email: this.newEmail,
- university: { name: 'University Name' },
- department: 'Department',
- role: 'Role'
- }
- this.EmailHelper.parseEmail.returns(this.newEmail)
- this.UserEmailsConfirmationHandler.sendConfirmationEmail = sinon
- .stub()
- .yields()
- this.UserUpdater.addEmailAddress.callsArgWith(3, null)
- })
- it('adds new email', function(done) {
- this.UserEmailsController.add(this.req, {
- sendStatus: code => {
- code.should.equal(204)
- assertCalledWith(this.EmailHelper.parseEmail, this.newEmail)
- assertCalledWith(
- this.UserUpdater.addEmailAddress,
- this.user._id,
- this.newEmail
- )
- const affiliationOptions = this.UserUpdater.addEmailAddress.lastCall
- .args[2]
- Object.keys(affiliationOptions).length.should.equal(3)
- affiliationOptions.university.should.equal(this.req.body.university)
- affiliationOptions.department.should.equal(this.req.body.department)
- affiliationOptions.role.should.equal(this.req.body.role)
- done()
- }
- })
- })
- it('sends an email confirmation', function(done) {
- this.UserEmailsController.add(this.req, {
- sendStatus: code => {
- code.should.equal(204)
- assertCalledWith(
- this.UserEmailsConfirmationHandler.sendConfirmationEmail,
- this.user._id,
- this.newEmail
- )
- done()
- }
- })
- })
- it('handles email parse error', function(done) {
- this.EmailHelper.parseEmail.returns(null)
- this.UserEmailsController.add(this.req, {
- sendStatus: code => {
- code.should.equal(422)
- assertNotCalled(this.UserUpdater.addEmailAddress)
- done()
- }
- })
- })
- })
- describe('remove', function() {
- beforeEach(function() {
- this.email = 'email_to_remove@bar.com'
- this.req.body.email = this.email
- this.EmailHelper.parseEmail.returns(this.email)
- })
- it('removes email', function(done) {
- this.UserUpdater.removeEmailAddress.callsArgWith(2, null)
- this.UserEmailsController.remove(this.req, {
- sendStatus: code => {
- code.should.equal(200)
- assertCalledWith(this.EmailHelper.parseEmail, this.email)
- assertCalledWith(
- this.UserUpdater.removeEmailAddress,
- this.user._id,
- this.email
- )
- done()
- }
- })
- })
- it('handles email parse error', function(done) {
- this.EmailHelper.parseEmail.returns(null)
- this.UserEmailsController.remove(this.req, {
- sendStatus: code => {
- code.should.equal(422)
- assertNotCalled(this.UserUpdater.removeEmailAddress)
- done()
- }
- })
- })
- })
- describe('setDefault', function() {
- beforeEach(function() {
- this.email = 'email_to_set_default@bar.com'
- this.req.body.email = this.email
- this.EmailHelper.parseEmail.returns(this.email)
- this.AuthenticationController.setInSessionUser.returns(null)
- })
- it('sets default email', function(done) {
- this.UserUpdater.setDefaultEmailAddress.yields()
- this.UserEmailsController.setDefault(this.req, {
- sendStatus: code => {
- code.should.equal(200)
- assertCalledWith(this.EmailHelper.parseEmail, this.email)
- assertCalledWith(
- this.AuthenticationController.setInSessionUser,
- this.req,
- { email: this.email }
- )
- assertCalledWith(
- this.UserUpdater.setDefaultEmailAddress,
- this.user._id,
- this.email
- )
- done()
- }
- })
- })
- it('handles email parse error', function(done) {
- this.EmailHelper.parseEmail.returns(null)
- this.UserEmailsController.setDefault(this.req, {
- sendStatus: code => {
- code.should.equal(422)
- assertNotCalled(this.UserUpdater.setDefaultEmailAddress)
- done()
- }
- })
- })
- })
- describe('endorse', function() {
- beforeEach(function() {
- this.email = 'email_to_endorse@bar.com'
- this.req.body.email = this.email
- this.EmailHelper.parseEmail.returns(this.email)
- })
- it('endorses affiliation', function(done) {
- this.req.body.role = 'Role'
- this.req.body.department = 'Department'
- this.UserEmailsController.endorse(this.req, {
- sendStatus: code => {
- code.should.equal(204)
- assertCalledWith(
- this.endorseAffiliation,
- this.user._id,
- this.email,
- 'Role',
- 'Department'
- )
- done()
- }
- })
- })
- })
- describe('confirm', function() {
- beforeEach(function() {
- this.UserEmailsConfirmationHandler.confirmEmailFromToken = sinon
- .stub()
- .yields()
- this.res = {
- sendStatus: sinon.stub(),
- json: sinon.stub()
- }
- this.res.status = sinon.stub().returns(this.res)
- this.next = sinon.stub()
- this.token = 'mock-token'
- this.req.body = { token: this.token }
- })
- describe('successfully', function() {
- beforeEach(function() {
- this.UserEmailsController.confirm(this.req, this.res, this.next)
- })
- it('should confirm the email from the token', function() {
- this.UserEmailsConfirmationHandler.confirmEmailFromToken
- .calledWith(this.token)
- .should.equal(true)
- })
- it('should return a 200 status', function() {
- this.res.sendStatus.calledWith(200).should.equal(true)
- })
- })
- describe('without a token', function() {
- beforeEach(function() {
- this.req.body.token = null
- this.UserEmailsController.confirm(this.req, this.res, this.next)
- })
- it('should return a 422 status', function() {
- this.res.status.calledWith(422).should.equal(true)
- })
- })
- describe('when confirming fails', function() {
- beforeEach(function() {
- this.UserEmailsConfirmationHandler.confirmEmailFromToken = sinon
- .stub()
- .yields(new Errors.NotFoundError('not found'))
- this.UserEmailsController.confirm(this.req, this.res, this.next)
- })
- it('should return a 404 error code with a message', function() {
- this.res.status.calledWith(404).should.equal(true)
- this.res.json
- .calledWith({
- message: this.req.i18n.translate('confirmation_token_invalid')
- })
- .should.equal(true)
- })
- })
- })
- describe('resendConfirmation', function() {
- beforeEach(function() {
- this.req = {
- body: {}
- }
- this.res = {
- sendStatus: sinon.stub()
- }
- this.next = sinon.stub()
- this.UserEmailsConfirmationHandler.sendConfirmationEmail = sinon
- .stub()
- .yields()
- })
- describe('when institution SSO is released', function() {
- beforeEach(function() {
- this.Features.hasFeature.withArgs('saml').returns(true)
- })
- describe('for an institution SSO email', function() {
- beforeEach(function() {
- this.req.body.email = 'with-sso@overleaf.com'
- })
- it('should not send the email', function() {
- this.UserEmailsController.resendConfirmation(
- this.req,
- this.res,
- () => {
- this.UserEmailsConfirmationHandler.sendConfirmationEmail.should
- .not.have.been.called.once
- }
- )
- })
- })
- describe('for a non-institution SSO email', function() {
- beforeEach(function() {
- this.req.body.email = 'without-sso@example.com'
- })
- it('should send the email', function() {
- this.UserEmailsController.resendConfirmation(
- this.req,
- this.res,
- () => {
- this.UserEmailsConfirmationHandler.sendConfirmationEmail.should
- .have.been.called.once
- }
- )
- })
- })
- })
- describe('when institution SSO is not released', function() {
- beforeEach(function() {
- this.Features.hasFeature.withArgs('saml').returns(false)
- })
- describe('for an institution SSO email', function() {
- beforeEach(function() {
- this.req.body.email = 'with-sso@overleaf.com'
- })
- it('should send the email', function() {
- this.UserEmailsController.resendConfirmation(
- this.req,
- this.res,
- () => {
- this.UserEmailsConfirmationHandler.sendConfirmationEmail.should
- .have.been.called.once
- }
- )
- })
- })
- describe('for a non-institution SSO email', function() {
- beforeEach(function() {
- this.req.body.email = 'without-sso@example.com'
- })
- it('should send the email', function() {
- this.UserEmailsController.resendConfirmation(
- this.req,
- this.res,
- () => {
- this.UserEmailsConfirmationHandler.sendConfirmationEmail.should
- .have.been.called.once
- }
- )
- })
- })
- })
- })
- })
|