LaunchpadControllerTests.js 37 KB

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