LaunchpadControllerTests.js 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. const SandboxedModule = require('sandboxed-module')
  14. const { expect } = require('chai')
  15. const sinon = require('sinon')
  16. const MockResponse = require('../../../../../test/unit/src/helpers/MockResponse')
  17. const modulePath = require('path').join(
  18. __dirname,
  19. '../../../app/src/LaunchpadController.js'
  20. )
  21. describe('LaunchpadController', function () {
  22. beforeEach(function () {
  23. this.user = {
  24. _id: '323123',
  25. first_name: 'fn',
  26. last_name: 'ln',
  27. save: sinon.stub().callsArgWith(0),
  28. }
  29. this.User = {}
  30. this.LaunchpadController = SandboxedModule.require(modulePath, {
  31. requires: {
  32. '@overleaf/settings': (this.Settings = {
  33. adminPrivilegeAvailable: true,
  34. }),
  35. '@overleaf/metrics': (this.Metrics = {}),
  36. '../../../../app/src/Features/User/UserRegistrationHandler':
  37. (this.UserRegistrationHandler = {
  38. promises: {},
  39. }),
  40. '../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler =
  41. { promises: {} }),
  42. '../../../../app/src/Features/User/UserGetter': (this.UserGetter = {
  43. promises: {},
  44. }),
  45. '../../../../app/src/models/User': { User: this.User },
  46. '../../../../app/src/Features/Authentication/AuthenticationController':
  47. (this.AuthenticationController = {}),
  48. '../../../../app/src/Features/Authentication/AuthenticationManager':
  49. (this.AuthenticationManager = {}),
  50. '../../../../app/src/Features/Authentication/SessionManager':
  51. (this.SessionManager = {}),
  52. },
  53. })
  54. this.email = 'bob@smith.com'
  55. this.req = {
  56. query: {},
  57. body: {},
  58. session: {},
  59. }
  60. this.res = new MockResponse()
  61. this.res.locals = {
  62. translate(key) {
  63. return key
  64. },
  65. }
  66. this.next = sinon.stub()
  67. })
  68. describe('launchpadPage', function () {
  69. beforeEach(function () {
  70. this._atLeastOneAdminExists = sinon.stub(
  71. this.LaunchpadController,
  72. '_atLeastOneAdminExists'
  73. )
  74. return (this.AuthenticationController.setRedirectInSession = sinon.stub())
  75. })
  76. afterEach(function () {
  77. return this._atLeastOneAdminExists.restore()
  78. })
  79. describe('when the user is not logged in', function () {
  80. beforeEach(function () {
  81. this.SessionManager.getSessionUser = sinon.stub().returns(null)
  82. })
  83. describe('when there are no admins', function () {
  84. beforeEach(function () {
  85. this._atLeastOneAdminExists.resolves(false)
  86. return this.LaunchpadController.launchpadPage(
  87. this.req,
  88. this.res,
  89. this.next
  90. )
  91. })
  92. it('should render the launchpad page', function () {
  93. const viewPath = require('path').join(
  94. __dirname,
  95. '../../../app/views/launchpad'
  96. )
  97. this.res.render.callCount.should.equal(1)
  98. return this.res.render
  99. .calledWith(viewPath, {
  100. adminUserExists: false,
  101. authMethod: 'local',
  102. })
  103. .should.equal(true)
  104. })
  105. })
  106. describe('when there is at least one admin', function () {
  107. beforeEach(function () {
  108. this._atLeastOneAdminExists.resolves(true)
  109. return this.LaunchpadController.launchpadPage(
  110. this.req,
  111. this.res,
  112. this.next
  113. )
  114. })
  115. it('should redirect to login page', function () {
  116. this.AuthenticationController.setRedirectInSession.callCount.should.equal(
  117. 1
  118. )
  119. this.res.redirect.calledWith('/login').should.equal(true)
  120. })
  121. it('should not render the launchpad page', function () {
  122. return this.res.render.callCount.should.equal(0)
  123. })
  124. })
  125. })
  126. describe('when the user is logged in', function () {
  127. beforeEach(function () {
  128. this.user = {
  129. _id: 'abcd',
  130. email: 'abcd@example.com',
  131. }
  132. this.SessionManager.getSessionUser = sinon.stub().returns(this.user)
  133. this._atLeastOneAdminExists.resolves(true)
  134. })
  135. describe('when the user is an admin', function () {
  136. beforeEach(function () {
  137. this.UserGetter.promises.getUser = sinon
  138. .stub()
  139. .resolves({ isAdmin: true })
  140. return this.LaunchpadController.launchpadPage(
  141. this.req,
  142. this.res,
  143. this.next
  144. )
  145. })
  146. it('should render the launchpad page', function () {
  147. const viewPath = require('path').join(
  148. __dirname,
  149. '../../../app/views/launchpad'
  150. )
  151. this.res.render.callCount.should.equal(1)
  152. this.res.render
  153. .calledWith(viewPath, {
  154. wsUrl: undefined,
  155. adminUserExists: true,
  156. authMethod: 'local',
  157. })
  158. .should.equal(true)
  159. })
  160. })
  161. describe('when the user is not an admin', function () {
  162. beforeEach(function () {
  163. this.UserGetter.promises.getUser = sinon
  164. .stub()
  165. .resolves({ isAdmin: false })
  166. return this.LaunchpadController.launchpadPage(
  167. this.req,
  168. this.res,
  169. this.next
  170. )
  171. })
  172. it('should redirect to restricted page', function () {
  173. this.res.redirect.callCount.should.equal(1)
  174. return this.res.redirect.calledWith('/restricted').should.equal(true)
  175. })
  176. })
  177. })
  178. })
  179. describe('_atLeastOneAdminExists', function () {
  180. describe('when there are no admins', function () {
  181. beforeEach(function () {
  182. return (this.UserGetter.promises.getUser = sinon.stub().resolves(null))
  183. })
  184. it('should callback with false', async function () {
  185. const exists = await this.LaunchpadController._atLeastOneAdminExists()
  186. expect(exists).to.equal(false)
  187. })
  188. })
  189. describe('when there are some admins', function () {
  190. beforeEach(function () {
  191. return (this.UserGetter.promises.getUser = sinon
  192. .stub()
  193. .resolves({ _id: 'abcd' }))
  194. })
  195. it('should callback with true', async function () {
  196. const exists = await this.LaunchpadController._atLeastOneAdminExists()
  197. expect(exists).to.equal(true)
  198. })
  199. })
  200. describe('when getUser produces an error', function () {
  201. beforeEach(function () {
  202. return (this.UserGetter.promises.getUser = sinon
  203. .stub()
  204. .rejects(new Error('woops')))
  205. })
  206. it('should produce an error', async function () {
  207. await expect(this.LaunchpadController._atLeastOneAdminExists()).rejected
  208. })
  209. })
  210. })
  211. describe('sendTestEmail', function () {
  212. beforeEach(function () {
  213. this.EmailHandler.promises.sendEmail = sinon.stub().resolves()
  214. this.req.body.email = 'someone@example.com'
  215. })
  216. it('should produce a 200 response', async function () {
  217. await this.LaunchpadController.sendTestEmail(
  218. this.req,
  219. this.res,
  220. this.next
  221. )
  222. this.res.json.calledWith({ message: 'email_sent' }).should.equal(true)
  223. })
  224. it('should not call next with an error', function () {
  225. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  226. return this.next.callCount.should.equal(0)
  227. })
  228. it('should have called sendEmail', async function () {
  229. await this.LaunchpadController.sendTestEmail(
  230. this.req,
  231. this.res,
  232. this.next
  233. )
  234. this.EmailHandler.promises.sendEmail.callCount.should.equal(1)
  235. return this.EmailHandler.promises.sendEmail
  236. .calledWith('testEmail')
  237. .should.equal(true)
  238. })
  239. describe('when sendEmail produces an error', function () {
  240. beforeEach(function () {
  241. return (this.EmailHandler.promises.sendEmail = sinon
  242. .stub()
  243. .rejects(new Error('woops')))
  244. })
  245. it('should call next with an error', function (done) {
  246. this.next = sinon.stub().callsFake(err => {
  247. expect(err).to.be.instanceof(Error)
  248. this.next.callCount.should.equal(1)
  249. done()
  250. })
  251. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  252. })
  253. })
  254. describe('when no email address is supplied', function () {
  255. beforeEach(function () {
  256. return (this.req.body.email = undefined)
  257. })
  258. it('should produce a 400 response', function () {
  259. this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
  260. this.res.status.calledWith(400).should.equal(true)
  261. this.res.json
  262. .calledWith({
  263. message: 'no email address supplied',
  264. })
  265. .should.equal(true)
  266. })
  267. })
  268. })
  269. describe('registerAdmin', function () {
  270. beforeEach(function () {
  271. return (this._atLeastOneAdminExists = sinon.stub(
  272. this.LaunchpadController,
  273. '_atLeastOneAdminExists'
  274. ))
  275. })
  276. afterEach(function () {
  277. return this._atLeastOneAdminExists.restore()
  278. })
  279. describe('when all goes well', function () {
  280. beforeEach(function () {
  281. this._atLeastOneAdminExists.resolves(false)
  282. this.email = 'someone@example.com'
  283. this.password = 'a_really_bad_password'
  284. this.req.body.email = this.email
  285. this.req.body.password = this.password
  286. this.user = {
  287. _id: 'abcdef',
  288. email: this.email,
  289. }
  290. this.UserRegistrationHandler.promises.registerNewUser = sinon
  291. .stub()
  292. .resolves(this.user)
  293. this.User.updateOne = sinon
  294. .stub()
  295. .returns({ exec: sinon.stub().resolves() })
  296. this.AuthenticationController.setRedirectInSession = sinon.stub()
  297. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  298. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  299. return this.LaunchpadController.registerAdmin(
  300. this.req,
  301. this.res,
  302. this.next
  303. )
  304. })
  305. it('should send back a json response', function () {
  306. this.res.json.callCount.should.equal(1)
  307. expect(this.res.json).to.have.been.calledWith({ redir: '/launchpad' })
  308. })
  309. it('should have checked for existing admins', function () {
  310. return this._atLeastOneAdminExists.callCount.should.equal(1)
  311. })
  312. it('should have called registerNewUser', function () {
  313. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  314. 1
  315. )
  316. return this.UserRegistrationHandler.promises.registerNewUser
  317. .calledWith({ email: this.email, password: this.password })
  318. .should.equal(true)
  319. })
  320. it('should have updated the user to make them an admin', function () {
  321. this.User.updateOne.callCount.should.equal(1)
  322. return this.User.updateOne
  323. .calledWithMatch(
  324. { _id: this.user._id },
  325. {
  326. $set: {
  327. isAdmin: true,
  328. emails: [
  329. { email: this.user.email, reversedHostname: 'moc.elpmaxe' },
  330. ],
  331. },
  332. }
  333. )
  334. .should.equal(true)
  335. })
  336. })
  337. describe('when no email is supplied', function () {
  338. beforeEach(function () {
  339. this._atLeastOneAdminExists.resolves(false)
  340. this.email = undefined
  341. this.password = 'a_really_bad_password'
  342. this.req.body.email = this.email
  343. this.req.body.password = this.password
  344. this.user = {
  345. _id: 'abcdef',
  346. email: this.email,
  347. }
  348. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  349. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  350. this.AuthenticationController.setRedirectInSession = sinon.stub()
  351. return this.LaunchpadController.registerAdmin(
  352. this.req,
  353. this.res,
  354. this.next
  355. )
  356. })
  357. it('should send a 400 response', function () {
  358. this.res.sendStatus.callCount.should.equal(1)
  359. return this.res.sendStatus.calledWith(400).should.equal(true)
  360. })
  361. it('should not check for existing admins', function () {
  362. return this._atLeastOneAdminExists.callCount.should.equal(0)
  363. })
  364. it('should not call registerNewUser', function () {
  365. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  366. 0
  367. )
  368. })
  369. })
  370. describe('when no password is supplied', function () {
  371. beforeEach(function () {
  372. this._atLeastOneAdminExists.resolves(false)
  373. this.email = 'someone@example.com'
  374. this.password = undefined
  375. this.req.body.email = this.email
  376. this.req.body.password = this.password
  377. this.user = {
  378. _id: 'abcdef',
  379. email: this.email,
  380. }
  381. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  382. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  383. this.AuthenticationController.setRedirectInSession = sinon.stub()
  384. return this.LaunchpadController.registerAdmin(
  385. this.req,
  386. this.res,
  387. this.next
  388. )
  389. })
  390. it('should send a 400 response', function () {
  391. this.res.sendStatus.callCount.should.equal(1)
  392. return this.res.sendStatus.calledWith(400).should.equal(true)
  393. })
  394. it('should not check for existing admins', function () {
  395. return this._atLeastOneAdminExists.callCount.should.equal(0)
  396. })
  397. it('should not call registerNewUser', function () {
  398. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  399. 0
  400. )
  401. })
  402. })
  403. describe('when an invalid email is supplied', function () {
  404. beforeEach(function () {
  405. this._atLeastOneAdminExists.resolves(false)
  406. this.email = 'someone@example.com'
  407. this.password = 'invalid password'
  408. this.req.body.email = this.email
  409. this.req.body.password = this.password
  410. this.user = {
  411. _id: 'abcdef',
  412. email: this.email,
  413. }
  414. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  415. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  416. this.AuthenticationController.setRedirectInSession = sinon.stub()
  417. this.AuthenticationManager.validateEmail = sinon
  418. .stub()
  419. .returns(new Error('bad email'))
  420. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  421. return this.LaunchpadController.registerAdmin(
  422. this.req,
  423. this.res,
  424. this.next
  425. )
  426. })
  427. it('should send a 400 response', function () {
  428. this.res.status.callCount.should.equal(1)
  429. this.res.status.calledWith(400).should.equal(true)
  430. return this.res.json.calledWith({
  431. message: { type: 'error', text: 'bad email' },
  432. })
  433. })
  434. it('should not call registerNewUser', function () {
  435. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  436. 0
  437. )
  438. })
  439. })
  440. describe('when an invalid password is supplied', function () {
  441. beforeEach(function () {
  442. this._atLeastOneAdminExists.resolves(false)
  443. this.email = 'someone@example.com'
  444. this.password = 'invalid password'
  445. this.req.body.email = this.email
  446. this.req.body.password = this.password
  447. this.user = {
  448. _id: 'abcdef',
  449. email: this.email,
  450. }
  451. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  452. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  453. this.AuthenticationController.setRedirectInSession = sinon.stub()
  454. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  455. this.AuthenticationManager.validatePassword = sinon
  456. .stub()
  457. .returns(new Error('bad password'))
  458. return this.LaunchpadController.registerAdmin(
  459. this.req,
  460. this.res,
  461. this.next
  462. )
  463. })
  464. it('should send a 400 response', function () {
  465. this.res.status.callCount.should.equal(1)
  466. this.res.status.calledWith(400).should.equal(true)
  467. return this.res.json.calledWith({
  468. message: { type: 'error', text: 'bad password' },
  469. })
  470. })
  471. it('should not call registerNewUser', function () {
  472. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  473. 0
  474. )
  475. })
  476. })
  477. describe('when there are already existing admins', function () {
  478. beforeEach(function () {
  479. this._atLeastOneAdminExists.resolves(true)
  480. this.email = 'someone@example.com'
  481. this.password = 'a_really_bad_password'
  482. this.req.body.email = this.email
  483. this.req.body.password = this.password
  484. this.user = {
  485. _id: 'abcdef',
  486. email: this.email,
  487. }
  488. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  489. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  490. this.AuthenticationController.setRedirectInSession = sinon.stub()
  491. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  492. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  493. return this.LaunchpadController.registerAdmin(
  494. this.req,
  495. this.res,
  496. this.next
  497. )
  498. })
  499. it('should send a 403 response', function () {
  500. this.res.status.callCount.should.equal(1)
  501. return this.res.status.calledWith(403).should.equal(true)
  502. })
  503. it('should not call registerNewUser', function () {
  504. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  505. 0
  506. )
  507. })
  508. })
  509. describe('when checking admins produces an error', function () {
  510. beforeEach(function () {
  511. this._atLeastOneAdminExists.rejects(new Error('woops'))
  512. this.email = 'someone@example.com'
  513. this.password = 'a_really_bad_password'
  514. this.req.body.email = this.email
  515. this.req.body.password = this.password
  516. this.user = {
  517. _id: 'abcdef',
  518. email: this.email,
  519. }
  520. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  521. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  522. this.AuthenticationController.setRedirectInSession = sinon.stub()
  523. return this.LaunchpadController.registerAdmin(
  524. this.req,
  525. this.res,
  526. this.next
  527. )
  528. })
  529. it('should call next with an error', function () {
  530. this.next.callCount.should.equal(1)
  531. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  532. })
  533. it('should have checked for existing admins', function () {
  534. return this._atLeastOneAdminExists.callCount.should.equal(1)
  535. })
  536. it('should not call registerNewUser', function () {
  537. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  538. 0
  539. )
  540. })
  541. })
  542. describe('when registerNewUser produces an error', function () {
  543. beforeEach(function () {
  544. this._atLeastOneAdminExists.resolves(false)
  545. this.email = 'someone@example.com'
  546. this.password = 'a_really_bad_password'
  547. this.req.body.email = this.email
  548. this.req.body.password = this.password
  549. this.user = {
  550. _id: 'abcdef',
  551. email: this.email,
  552. }
  553. this.UserRegistrationHandler.promises.registerNewUser = sinon
  554. .stub()
  555. .rejects(new Error('woops'))
  556. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  557. this.AuthenticationController.setRedirectInSession = sinon.stub()
  558. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  559. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  560. return this.LaunchpadController.registerAdmin(
  561. this.req,
  562. this.res,
  563. this.next
  564. )
  565. })
  566. it('should call next with an error', function () {
  567. this.next.callCount.should.equal(1)
  568. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  569. })
  570. it('should have checked for existing admins', function () {
  571. return this._atLeastOneAdminExists.callCount.should.equal(1)
  572. })
  573. it('should have called registerNewUser', function () {
  574. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  575. 1
  576. )
  577. return this.UserRegistrationHandler.promises.registerNewUser
  578. .calledWith({ email: this.email, password: this.password })
  579. .should.equal(true)
  580. })
  581. it('should not call update', function () {
  582. return this.User.updateOne.callCount.should.equal(0)
  583. })
  584. })
  585. describe('when user update produces an error', function () {
  586. beforeEach(function () {
  587. this._atLeastOneAdminExists.resolves(false)
  588. this.email = 'someone@example.com'
  589. this.password = 'a_really_bad_password'
  590. this.req.body.email = this.email
  591. this.req.body.password = this.password
  592. this.user = {
  593. _id: 'abcdef',
  594. email: this.email,
  595. }
  596. this.UserRegistrationHandler.promises.registerNewUser = sinon
  597. .stub()
  598. .resolves(this.user)
  599. this.User.updateOne = sinon.stub().returns({
  600. exec: sinon.stub().rejects(new Error('woops')),
  601. })
  602. this.AuthenticationController.setRedirectInSession = sinon.stub()
  603. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  604. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  605. return this.LaunchpadController.registerAdmin(
  606. this.req,
  607. this.res,
  608. this.next
  609. )
  610. })
  611. it('should call next with an error', function () {
  612. this.next.callCount.should.equal(1)
  613. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  614. })
  615. it('should have checked for existing admins', function () {
  616. return this._atLeastOneAdminExists.callCount.should.equal(1)
  617. })
  618. it('should have called registerNewUser', function () {
  619. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  620. 1
  621. )
  622. return this.UserRegistrationHandler.promises.registerNewUser
  623. .calledWith({ email: this.email, password: this.password })
  624. .should.equal(true)
  625. })
  626. })
  627. describe('when overleaf', function () {
  628. beforeEach(function () {
  629. this.Settings.overleaf = { one: 1 }
  630. this._atLeastOneAdminExists.resolves(false)
  631. this.email = 'someone@example.com'
  632. this.password = 'a_really_bad_password'
  633. this.req.body.email = this.email
  634. this.req.body.password = this.password
  635. this.user = {
  636. _id: 'abcdef',
  637. email: this.email,
  638. }
  639. this.UserRegistrationHandler.promises.registerNewUser = sinon
  640. .stub()
  641. .resolves(this.user)
  642. this.User.updateOne = sinon
  643. .stub()
  644. .returns({ exec: sinon.stub().resolves() })
  645. this.AuthenticationController.setRedirectInSession = sinon.stub()
  646. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  647. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  648. this.UserGetter.promises.getUser = sinon
  649. .stub()
  650. .resolves({ _id: '1234' })
  651. return this.LaunchpadController.registerAdmin(
  652. this.req,
  653. this.res,
  654. this.next
  655. )
  656. })
  657. it('should send back a json response', function () {
  658. this.res.json.callCount.should.equal(1)
  659. expect(this.res.json).to.have.been.calledWith({ redir: '/launchpad' })
  660. })
  661. it('should have checked for existing admins', function () {
  662. return this._atLeastOneAdminExists.callCount.should.equal(1)
  663. })
  664. it('should have called registerNewUser', function () {
  665. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  666. 1
  667. )
  668. return this.UserRegistrationHandler.promises.registerNewUser
  669. .calledWith({ email: this.email, password: this.password })
  670. .should.equal(true)
  671. })
  672. it('should have updated the user to make them an admin', function () {
  673. return this.User.updateOne
  674. .calledWith(
  675. { _id: this.user._id },
  676. {
  677. $set: {
  678. isAdmin: true,
  679. emails: [
  680. { email: this.user.email, reversedHostname: 'moc.elpmaxe' },
  681. ],
  682. },
  683. }
  684. )
  685. .should.equal(true)
  686. })
  687. })
  688. })
  689. describe('registerExternalAuthAdmin', function () {
  690. beforeEach(function () {
  691. this.Settings.ldap = { one: 1 }
  692. return (this._atLeastOneAdminExists = sinon.stub(
  693. this.LaunchpadController,
  694. '_atLeastOneAdminExists'
  695. ))
  696. })
  697. afterEach(function () {
  698. return this._atLeastOneAdminExists.restore()
  699. })
  700. describe('when all goes well', function () {
  701. beforeEach(function () {
  702. this._atLeastOneAdminExists.resolves(false)
  703. this.email = 'someone@example.com'
  704. this.req.body.email = this.email
  705. this.user = {
  706. _id: 'abcdef',
  707. email: this.email,
  708. }
  709. this.UserRegistrationHandler.promises.registerNewUser = sinon
  710. .stub()
  711. .resolves(this.user)
  712. this.User.updateOne = sinon
  713. .stub()
  714. .returns({ exec: sinon.stub().resolves() })
  715. this.AuthenticationController.setRedirectInSession = sinon.stub()
  716. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  717. this.req,
  718. this.res,
  719. this.next
  720. )
  721. })
  722. it('should send back a json response', function () {
  723. this.res.json.callCount.should.equal(1)
  724. return expect(this.res.json.lastCall.args[0].email).to.equal(this.email)
  725. })
  726. it('should have checked for existing admins', function () {
  727. return this._atLeastOneAdminExists.callCount.should.equal(1)
  728. })
  729. it('should have called registerNewUser', function () {
  730. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  731. 1
  732. )
  733. return this.UserRegistrationHandler.promises.registerNewUser
  734. .calledWith({
  735. email: this.email,
  736. password: 'password_here',
  737. first_name: this.email,
  738. last_name: '',
  739. })
  740. .should.equal(true)
  741. })
  742. it('should have updated the user to make them an admin', function () {
  743. this.User.updateOne.callCount.should.equal(1)
  744. return this.User.updateOne
  745. .calledWith(
  746. { _id: this.user._id },
  747. {
  748. $set: {
  749. isAdmin: true,
  750. emails: [
  751. { email: this.user.email, reversedHostname: 'moc.elpmaxe' },
  752. ],
  753. },
  754. }
  755. )
  756. .should.equal(true)
  757. })
  758. it('should have set a redirect in session', function () {
  759. this.AuthenticationController.setRedirectInSession.callCount.should.equal(
  760. 1
  761. )
  762. return this.AuthenticationController.setRedirectInSession
  763. .calledWith(this.req, '/launchpad')
  764. .should.equal(true)
  765. })
  766. })
  767. describe('when the authMethod is invalid', function () {
  768. beforeEach(function () {
  769. this._atLeastOneAdminExists.resolves(false)
  770. this.email = undefined
  771. this.req.body.email = this.email
  772. this.user = {
  773. _id: 'abcdef',
  774. email: this.email,
  775. }
  776. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  777. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  778. this.AuthenticationController.setRedirectInSession = sinon.stub()
  779. return this.LaunchpadController.registerExternalAuthAdmin(
  780. 'NOTAVALIDAUTHMETHOD'
  781. )(this.req, this.res, this.next)
  782. })
  783. it('should send a 403 response', function () {
  784. this.res.sendStatus.callCount.should.equal(1)
  785. return this.res.sendStatus.calledWith(403).should.equal(true)
  786. })
  787. it('should not check for existing admins', function () {
  788. return this._atLeastOneAdminExists.callCount.should.equal(0)
  789. })
  790. it('should not call registerNewUser', function () {
  791. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  792. 0
  793. )
  794. })
  795. })
  796. describe('when no email is supplied', function () {
  797. beforeEach(function () {
  798. this._atLeastOneAdminExists.resolves(false)
  799. this.email = undefined
  800. this.req.body.email = this.email
  801. this.user = {
  802. _id: 'abcdef',
  803. email: this.email,
  804. }
  805. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  806. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  807. this.AuthenticationController.setRedirectInSession = sinon.stub()
  808. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  809. this.req,
  810. this.res,
  811. this.next
  812. )
  813. })
  814. it('should send a 400 response', function () {
  815. this.res.sendStatus.callCount.should.equal(1)
  816. return this.res.sendStatus.calledWith(400).should.equal(true)
  817. })
  818. it('should not check for existing admins', function () {
  819. return this._atLeastOneAdminExists.callCount.should.equal(0)
  820. })
  821. it('should not call registerNewUser', function () {
  822. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  823. 0
  824. )
  825. })
  826. })
  827. describe('when there are already existing admins', function () {
  828. beforeEach(function () {
  829. this._atLeastOneAdminExists.resolves(true)
  830. this.email = 'someone@example.com'
  831. this.req.body.email = this.email
  832. this.user = {
  833. _id: 'abcdef',
  834. email: this.email,
  835. }
  836. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  837. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  838. this.AuthenticationController.setRedirectInSession = sinon.stub()
  839. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  840. this.req,
  841. this.res,
  842. this.next
  843. )
  844. })
  845. it('should send a 403 response', function () {
  846. this.res.sendStatus.callCount.should.equal(1)
  847. return this.res.sendStatus.calledWith(403).should.equal(true)
  848. })
  849. it('should not call registerNewUser', function () {
  850. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  851. 0
  852. )
  853. })
  854. })
  855. describe('when checking admins produces an error', function () {
  856. beforeEach(function () {
  857. this._atLeastOneAdminExists.rejects(new Error('woops'))
  858. this.email = 'someone@example.com'
  859. this.req.body.email = this.email
  860. this.user = {
  861. _id: 'abcdef',
  862. email: this.email,
  863. }
  864. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  865. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  866. this.AuthenticationController.setRedirectInSession = sinon.stub()
  867. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  868. this.req,
  869. this.res,
  870. this.next
  871. )
  872. })
  873. it('should call next with an error', function () {
  874. this.next.callCount.should.equal(1)
  875. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  876. })
  877. it('should have checked for existing admins', function () {
  878. return this._atLeastOneAdminExists.callCount.should.equal(1)
  879. })
  880. it('should not call registerNewUser', function () {
  881. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  882. 0
  883. )
  884. })
  885. })
  886. describe('when registerNewUser produces an error', function () {
  887. beforeEach(function () {
  888. this._atLeastOneAdminExists.resolves(false)
  889. this.email = 'someone@example.com'
  890. this.req.body.email = this.email
  891. this.user = {
  892. _id: 'abcdef',
  893. email: this.email,
  894. }
  895. this.UserRegistrationHandler.promises.registerNewUser = sinon
  896. .stub()
  897. .rejects(new Error('woops'))
  898. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  899. this.AuthenticationController.setRedirectInSession = sinon.stub()
  900. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  901. this.req,
  902. this.res,
  903. this.next
  904. )
  905. })
  906. it('should call next with an error', function () {
  907. this.next.callCount.should.equal(1)
  908. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  909. })
  910. it('should have checked for existing admins', function () {
  911. return this._atLeastOneAdminExists.callCount.should.equal(1)
  912. })
  913. it('should have called registerNewUser', function () {
  914. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  915. 1
  916. )
  917. return this.UserRegistrationHandler.promises.registerNewUser
  918. .calledWith({
  919. email: this.email,
  920. password: 'password_here',
  921. first_name: this.email,
  922. last_name: '',
  923. })
  924. .should.equal(true)
  925. })
  926. it('should not call update', function () {
  927. return this.User.updateOne.callCount.should.equal(0)
  928. })
  929. })
  930. describe('when user update produces an error', function () {
  931. beforeEach(function () {
  932. this._atLeastOneAdminExists.resolves(false)
  933. this.email = 'someone@example.com'
  934. this.req.body.email = this.email
  935. this.user = {
  936. _id: 'abcdef',
  937. email: this.email,
  938. }
  939. this.UserRegistrationHandler.promises.registerNewUser = sinon
  940. .stub()
  941. .resolves(this.user)
  942. this.User.updateOne = sinon.stub().returns({
  943. exec: sinon.stub().rejects(new Error('woops')),
  944. })
  945. this.AuthenticationController.setRedirectInSession = sinon.stub()
  946. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  947. this.req,
  948. this.res,
  949. this.next
  950. )
  951. })
  952. it('should call next with an error', function () {
  953. this.next.callCount.should.equal(1)
  954. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  955. })
  956. it('should have checked for existing admins', function () {
  957. return this._atLeastOneAdminExists.callCount.should.equal(1)
  958. })
  959. it('should have called registerNewUser', function () {
  960. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  961. 1
  962. )
  963. return this.UserRegistrationHandler.promises.registerNewUser
  964. .calledWith({
  965. email: this.email,
  966. password: 'password_here',
  967. first_name: this.email,
  968. last_name: '',
  969. })
  970. .should.equal(true)
  971. })
  972. })
  973. })
  974. })