LaunchpadControllerTests.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  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: [{ email: this.user.email }],
  329. },
  330. }
  331. )
  332. .should.equal(true)
  333. })
  334. })
  335. describe('when no email is supplied', function () {
  336. beforeEach(function () {
  337. this._atLeastOneAdminExists.resolves(false)
  338. this.email = undefined
  339. this.password = 'a_really_bad_password'
  340. this.req.body.email = this.email
  341. this.req.body.password = this.password
  342. this.user = {
  343. _id: 'abcdef',
  344. email: this.email,
  345. }
  346. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  347. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  348. this.AuthenticationController.setRedirectInSession = sinon.stub()
  349. return this.LaunchpadController.registerAdmin(
  350. this.req,
  351. this.res,
  352. this.next
  353. )
  354. })
  355. it('should send a 400 response', function () {
  356. this.res.sendStatus.callCount.should.equal(1)
  357. return this.res.sendStatus.calledWith(400).should.equal(true)
  358. })
  359. it('should not check for existing admins', function () {
  360. return this._atLeastOneAdminExists.callCount.should.equal(0)
  361. })
  362. it('should not call registerNewUser', function () {
  363. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  364. 0
  365. )
  366. })
  367. })
  368. describe('when no password is supplied', function () {
  369. beforeEach(function () {
  370. this._atLeastOneAdminExists.resolves(false)
  371. this.email = 'someone@example.com'
  372. this.password = undefined
  373. this.req.body.email = this.email
  374. this.req.body.password = this.password
  375. this.user = {
  376. _id: 'abcdef',
  377. email: this.email,
  378. }
  379. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  380. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  381. this.AuthenticationController.setRedirectInSession = sinon.stub()
  382. return this.LaunchpadController.registerAdmin(
  383. this.req,
  384. this.res,
  385. this.next
  386. )
  387. })
  388. it('should send a 400 response', function () {
  389. this.res.sendStatus.callCount.should.equal(1)
  390. return this.res.sendStatus.calledWith(400).should.equal(true)
  391. })
  392. it('should not check for existing admins', function () {
  393. return this._atLeastOneAdminExists.callCount.should.equal(0)
  394. })
  395. it('should not call registerNewUser', function () {
  396. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  397. 0
  398. )
  399. })
  400. })
  401. describe('when an invalid email is supplied', function () {
  402. beforeEach(function () {
  403. this._atLeastOneAdminExists.resolves(false)
  404. this.email = 'someone@example.com'
  405. this.password = 'invalid password'
  406. this.req.body.email = this.email
  407. this.req.body.password = this.password
  408. this.user = {
  409. _id: 'abcdef',
  410. email: this.email,
  411. }
  412. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  413. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  414. this.AuthenticationController.setRedirectInSession = sinon.stub()
  415. this.AuthenticationManager.validateEmail = sinon
  416. .stub()
  417. .returns(new Error('bad email'))
  418. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  419. return this.LaunchpadController.registerAdmin(
  420. this.req,
  421. this.res,
  422. this.next
  423. )
  424. })
  425. it('should send a 400 response', function () {
  426. this.res.status.callCount.should.equal(1)
  427. this.res.status.calledWith(400).should.equal(true)
  428. return this.res.json.calledWith({
  429. message: { type: 'error', text: 'bad email' },
  430. })
  431. })
  432. it('should not call registerNewUser', function () {
  433. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  434. 0
  435. )
  436. })
  437. })
  438. describe('when an invalid password is supplied', function () {
  439. beforeEach(function () {
  440. this._atLeastOneAdminExists.resolves(false)
  441. this.email = 'someone@example.com'
  442. this.password = 'invalid password'
  443. this.req.body.email = this.email
  444. this.req.body.password = this.password
  445. this.user = {
  446. _id: 'abcdef',
  447. email: this.email,
  448. }
  449. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  450. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  451. this.AuthenticationController.setRedirectInSession = sinon.stub()
  452. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  453. this.AuthenticationManager.validatePassword = sinon
  454. .stub()
  455. .returns(new Error('bad password'))
  456. return this.LaunchpadController.registerAdmin(
  457. this.req,
  458. this.res,
  459. this.next
  460. )
  461. })
  462. it('should send a 400 response', function () {
  463. this.res.status.callCount.should.equal(1)
  464. this.res.status.calledWith(400).should.equal(true)
  465. return this.res.json.calledWith({
  466. message: { type: 'error', text: 'bad password' },
  467. })
  468. })
  469. it('should not call registerNewUser', function () {
  470. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  471. 0
  472. )
  473. })
  474. })
  475. describe('when there are already existing admins', function () {
  476. beforeEach(function () {
  477. this._atLeastOneAdminExists.resolves(true)
  478. this.email = 'someone@example.com'
  479. this.password = 'a_really_bad_password'
  480. this.req.body.email = this.email
  481. this.req.body.password = this.password
  482. this.user = {
  483. _id: 'abcdef',
  484. email: this.email,
  485. }
  486. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  487. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  488. this.AuthenticationController.setRedirectInSession = sinon.stub()
  489. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  490. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  491. return this.LaunchpadController.registerAdmin(
  492. this.req,
  493. this.res,
  494. this.next
  495. )
  496. })
  497. it('should send a 403 response', function () {
  498. this.res.status.callCount.should.equal(1)
  499. return this.res.status.calledWith(403).should.equal(true)
  500. })
  501. it('should not call registerNewUser', function () {
  502. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  503. 0
  504. )
  505. })
  506. })
  507. describe('when checking admins produces an error', function () {
  508. beforeEach(function () {
  509. this._atLeastOneAdminExists.rejects(new Error('woops'))
  510. this.email = 'someone@example.com'
  511. this.password = 'a_really_bad_password'
  512. this.req.body.email = this.email
  513. this.req.body.password = this.password
  514. this.user = {
  515. _id: 'abcdef',
  516. email: this.email,
  517. }
  518. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  519. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  520. this.AuthenticationController.setRedirectInSession = sinon.stub()
  521. return this.LaunchpadController.registerAdmin(
  522. this.req,
  523. this.res,
  524. this.next
  525. )
  526. })
  527. it('should call next with an error', function () {
  528. this.next.callCount.should.equal(1)
  529. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  530. })
  531. it('should have checked for existing admins', function () {
  532. return this._atLeastOneAdminExists.callCount.should.equal(1)
  533. })
  534. it('should not call registerNewUser', function () {
  535. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  536. 0
  537. )
  538. })
  539. })
  540. describe('when registerNewUser produces an error', function () {
  541. beforeEach(function () {
  542. this._atLeastOneAdminExists.resolves(false)
  543. this.email = 'someone@example.com'
  544. this.password = 'a_really_bad_password'
  545. this.req.body.email = this.email
  546. this.req.body.password = this.password
  547. this.user = {
  548. _id: 'abcdef',
  549. email: this.email,
  550. }
  551. this.UserRegistrationHandler.promises.registerNewUser = sinon
  552. .stub()
  553. .rejects(new Error('woops'))
  554. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  555. this.AuthenticationController.setRedirectInSession = sinon.stub()
  556. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  557. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  558. return this.LaunchpadController.registerAdmin(
  559. this.req,
  560. this.res,
  561. this.next
  562. )
  563. })
  564. it('should call next with an error', function () {
  565. this.next.callCount.should.equal(1)
  566. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  567. })
  568. it('should have checked for existing admins', function () {
  569. return this._atLeastOneAdminExists.callCount.should.equal(1)
  570. })
  571. it('should have called registerNewUser', function () {
  572. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  573. 1
  574. )
  575. return this.UserRegistrationHandler.promises.registerNewUser
  576. .calledWith({ email: this.email, password: this.password })
  577. .should.equal(true)
  578. })
  579. it('should not call update', function () {
  580. return this.User.updateOne.callCount.should.equal(0)
  581. })
  582. })
  583. describe('when user update produces an error', function () {
  584. beforeEach(function () {
  585. this._atLeastOneAdminExists.resolves(false)
  586. this.email = 'someone@example.com'
  587. this.password = 'a_really_bad_password'
  588. this.req.body.email = this.email
  589. this.req.body.password = this.password
  590. this.user = {
  591. _id: 'abcdef',
  592. email: this.email,
  593. }
  594. this.UserRegistrationHandler.promises.registerNewUser = sinon
  595. .stub()
  596. .resolves(this.user)
  597. this.User.updateOne = sinon.stub().returns({
  598. exec: sinon.stub().rejects(new Error('woops')),
  599. })
  600. this.AuthenticationController.setRedirectInSession = sinon.stub()
  601. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  602. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  603. return this.LaunchpadController.registerAdmin(
  604. this.req,
  605. this.res,
  606. this.next
  607. )
  608. })
  609. it('should call next with an error', function () {
  610. this.next.callCount.should.equal(1)
  611. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  612. })
  613. it('should have checked for existing admins', function () {
  614. return this._atLeastOneAdminExists.callCount.should.equal(1)
  615. })
  616. it('should have called registerNewUser', function () {
  617. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  618. 1
  619. )
  620. return this.UserRegistrationHandler.promises.registerNewUser
  621. .calledWith({ email: this.email, password: this.password })
  622. .should.equal(true)
  623. })
  624. })
  625. describe('when overleaf', function () {
  626. beforeEach(function () {
  627. this.Settings.overleaf = { one: 1 }
  628. this.Settings.createV1AccountOnLogin = true
  629. this._atLeastOneAdminExists.resolves(false)
  630. this.email = 'someone@example.com'
  631. this.password = 'a_really_bad_password'
  632. this.req.body.email = this.email
  633. this.req.body.password = this.password
  634. this.user = {
  635. _id: 'abcdef',
  636. email: this.email,
  637. }
  638. this.UserRegistrationHandler.promises.registerNewUser = sinon
  639. .stub()
  640. .resolves(this.user)
  641. this.User.updateOne = sinon
  642. .stub()
  643. .returns({ exec: sinon.stub().resolves() })
  644. this.AuthenticationController.setRedirectInSession = sinon.stub()
  645. this.AuthenticationManager.validateEmail = sinon.stub().returns(null)
  646. this.AuthenticationManager.validatePassword = sinon.stub().returns(null)
  647. this.UserGetter.promises.getUser = sinon
  648. .stub()
  649. .resolves({ _id: '1234' })
  650. return this.LaunchpadController.registerAdmin(
  651. this.req,
  652. this.res,
  653. this.next
  654. )
  655. })
  656. it('should send back a json response', function () {
  657. this.res.json.callCount.should.equal(1)
  658. expect(this.res.json).to.have.been.calledWith({ redir: '/launchpad' })
  659. })
  660. it('should have checked for existing admins', function () {
  661. return this._atLeastOneAdminExists.callCount.should.equal(1)
  662. })
  663. it('should have called registerNewUser', function () {
  664. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  665. 1
  666. )
  667. return this.UserRegistrationHandler.promises.registerNewUser
  668. .calledWith({ email: this.email, password: this.password })
  669. .should.equal(true)
  670. })
  671. it('should have updated the user to make them an admin', function () {
  672. return this.User.updateOne
  673. .calledWith(
  674. { _id: this.user._id },
  675. {
  676. $set: {
  677. isAdmin: true,
  678. emails: [{ email: this.user.email }],
  679. },
  680. }
  681. )
  682. .should.equal(true)
  683. })
  684. })
  685. })
  686. describe('registerExternalAuthAdmin', function () {
  687. beforeEach(function () {
  688. this.Settings.ldap = { one: 1 }
  689. return (this._atLeastOneAdminExists = sinon.stub(
  690. this.LaunchpadController,
  691. '_atLeastOneAdminExists'
  692. ))
  693. })
  694. afterEach(function () {
  695. return this._atLeastOneAdminExists.restore()
  696. })
  697. describe('when all goes well', function () {
  698. beforeEach(function () {
  699. this._atLeastOneAdminExists.resolves(false)
  700. this.email = 'someone@example.com'
  701. this.req.body.email = this.email
  702. this.user = {
  703. _id: 'abcdef',
  704. email: this.email,
  705. }
  706. this.UserRegistrationHandler.promises.registerNewUser = sinon
  707. .stub()
  708. .resolves(this.user)
  709. this.User.updateOne = sinon
  710. .stub()
  711. .returns({ exec: sinon.stub().resolves() })
  712. this.AuthenticationController.setRedirectInSession = sinon.stub()
  713. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  714. this.req,
  715. this.res,
  716. this.next
  717. )
  718. })
  719. it('should send back a json response', function () {
  720. this.res.json.callCount.should.equal(1)
  721. return expect(this.res.json.lastCall.args[0].email).to.equal(this.email)
  722. })
  723. it('should have checked for existing admins', function () {
  724. return this._atLeastOneAdminExists.callCount.should.equal(1)
  725. })
  726. it('should have called registerNewUser', function () {
  727. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  728. 1
  729. )
  730. return this.UserRegistrationHandler.promises.registerNewUser
  731. .calledWith({
  732. email: this.email,
  733. password: 'password_here',
  734. first_name: this.email,
  735. last_name: '',
  736. })
  737. .should.equal(true)
  738. })
  739. it('should have updated the user to make them an admin', function () {
  740. this.User.updateOne.callCount.should.equal(1)
  741. return this.User.updateOne
  742. .calledWith(
  743. { _id: this.user._id },
  744. {
  745. $set: { isAdmin: true },
  746. emails: [{ email: this.user.email }],
  747. }
  748. )
  749. .should.equal(true)
  750. })
  751. it('should have set a redirect in session', function () {
  752. this.AuthenticationController.setRedirectInSession.callCount.should.equal(
  753. 1
  754. )
  755. return this.AuthenticationController.setRedirectInSession
  756. .calledWith(this.req, '/launchpad')
  757. .should.equal(true)
  758. })
  759. })
  760. describe('when the authMethod is invalid', function () {
  761. beforeEach(function () {
  762. this._atLeastOneAdminExists.resolves(false)
  763. this.email = undefined
  764. this.req.body.email = this.email
  765. this.user = {
  766. _id: 'abcdef',
  767. email: this.email,
  768. }
  769. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  770. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  771. this.AuthenticationController.setRedirectInSession = sinon.stub()
  772. return this.LaunchpadController.registerExternalAuthAdmin(
  773. 'NOTAVALIDAUTHMETHOD'
  774. )(this.req, this.res, this.next)
  775. })
  776. it('should send a 403 response', function () {
  777. this.res.sendStatus.callCount.should.equal(1)
  778. return this.res.sendStatus.calledWith(403).should.equal(true)
  779. })
  780. it('should not check for existing admins', function () {
  781. return this._atLeastOneAdminExists.callCount.should.equal(0)
  782. })
  783. it('should not call registerNewUser', function () {
  784. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  785. 0
  786. )
  787. })
  788. })
  789. describe('when no email is supplied', function () {
  790. beforeEach(function () {
  791. this._atLeastOneAdminExists.resolves(false)
  792. this.email = undefined
  793. this.req.body.email = this.email
  794. this.user = {
  795. _id: 'abcdef',
  796. email: this.email,
  797. }
  798. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  799. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  800. this.AuthenticationController.setRedirectInSession = sinon.stub()
  801. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  802. this.req,
  803. this.res,
  804. this.next
  805. )
  806. })
  807. it('should send a 400 response', function () {
  808. this.res.sendStatus.callCount.should.equal(1)
  809. return this.res.sendStatus.calledWith(400).should.equal(true)
  810. })
  811. it('should not check for existing admins', function () {
  812. return this._atLeastOneAdminExists.callCount.should.equal(0)
  813. })
  814. it('should not call registerNewUser', function () {
  815. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  816. 0
  817. )
  818. })
  819. })
  820. describe('when there are already existing admins', function () {
  821. beforeEach(function () {
  822. this._atLeastOneAdminExists.resolves(true)
  823. this.email = 'someone@example.com'
  824. this.req.body.email = this.email
  825. this.user = {
  826. _id: 'abcdef',
  827. email: this.email,
  828. }
  829. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  830. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  831. this.AuthenticationController.setRedirectInSession = sinon.stub()
  832. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  833. this.req,
  834. this.res,
  835. this.next
  836. )
  837. })
  838. it('should send a 403 response', function () {
  839. this.res.sendStatus.callCount.should.equal(1)
  840. return this.res.sendStatus.calledWith(403).should.equal(true)
  841. })
  842. it('should not call registerNewUser', function () {
  843. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  844. 0
  845. )
  846. })
  847. })
  848. describe('when checking admins produces an error', function () {
  849. beforeEach(function () {
  850. this._atLeastOneAdminExists.rejects(new Error('woops'))
  851. this.email = 'someone@example.com'
  852. this.req.body.email = this.email
  853. this.user = {
  854. _id: 'abcdef',
  855. email: this.email,
  856. }
  857. this.UserRegistrationHandler.promises.registerNewUser = sinon.stub()
  858. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  859. this.AuthenticationController.setRedirectInSession = sinon.stub()
  860. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  861. this.req,
  862. this.res,
  863. this.next
  864. )
  865. })
  866. it('should call next with an error', function () {
  867. this.next.callCount.should.equal(1)
  868. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  869. })
  870. it('should have checked for existing admins', function () {
  871. return this._atLeastOneAdminExists.callCount.should.equal(1)
  872. })
  873. it('should not call registerNewUser', function () {
  874. return this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  875. 0
  876. )
  877. })
  878. })
  879. describe('when registerNewUser produces an error', function () {
  880. beforeEach(function () {
  881. this._atLeastOneAdminExists.resolves(false)
  882. this.email = 'someone@example.com'
  883. this.req.body.email = this.email
  884. this.user = {
  885. _id: 'abcdef',
  886. email: this.email,
  887. }
  888. this.UserRegistrationHandler.promises.registerNewUser = sinon
  889. .stub()
  890. .rejects(new Error('woops'))
  891. this.User.updateOne = sinon.stub().returns({ exec: sinon.stub() })
  892. this.AuthenticationController.setRedirectInSession = sinon.stub()
  893. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  894. this.req,
  895. this.res,
  896. this.next
  897. )
  898. })
  899. it('should call next with an error', function () {
  900. this.next.callCount.should.equal(1)
  901. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  902. })
  903. it('should have checked for existing admins', function () {
  904. return this._atLeastOneAdminExists.callCount.should.equal(1)
  905. })
  906. it('should have called registerNewUser', function () {
  907. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  908. 1
  909. )
  910. return this.UserRegistrationHandler.promises.registerNewUser
  911. .calledWith({
  912. email: this.email,
  913. password: 'password_here',
  914. first_name: this.email,
  915. last_name: '',
  916. })
  917. .should.equal(true)
  918. })
  919. it('should not call update', function () {
  920. return this.User.updateOne.callCount.should.equal(0)
  921. })
  922. })
  923. describe('when user update produces an error', function () {
  924. beforeEach(function () {
  925. this._atLeastOneAdminExists.resolves(false)
  926. this.email = 'someone@example.com'
  927. this.req.body.email = this.email
  928. this.user = {
  929. _id: 'abcdef',
  930. email: this.email,
  931. }
  932. this.UserRegistrationHandler.promises.registerNewUser = sinon
  933. .stub()
  934. .resolves(this.user)
  935. this.User.updateOne = sinon.stub().returns({
  936. exec: sinon.stub().rejects(new Error('woops')),
  937. })
  938. this.AuthenticationController.setRedirectInSession = sinon.stub()
  939. return this.LaunchpadController.registerExternalAuthAdmin('ldap')(
  940. this.req,
  941. this.res,
  942. this.next
  943. )
  944. })
  945. it('should call next with an error', function () {
  946. this.next.callCount.should.equal(1)
  947. return expect(this.next.lastCall.args[0]).to.be.instanceof(Error)
  948. })
  949. it('should have checked for existing admins', function () {
  950. return this._atLeastOneAdminExists.callCount.should.equal(1)
  951. })
  952. it('should have called registerNewUser', function () {
  953. this.UserRegistrationHandler.promises.registerNewUser.callCount.should.equal(
  954. 1
  955. )
  956. return this.UserRegistrationHandler.promises.registerNewUser
  957. .calledWith({
  958. email: this.email,
  959. password: 'password_here',
  960. first_name: this.email,
  961. last_name: '',
  962. })
  963. .should.equal(true)
  964. })
  965. })
  966. })
  967. })