TokenAccessControllerTests.coffee 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. should = require('chai').should()
  2. SandboxedModule = require('sandboxed-module')
  3. assert = require('assert')
  4. path = require('path')
  5. sinon = require('sinon')
  6. modulePath = path.join __dirname, "../../../../app/js/Features/TokenAccess/TokenAccessController"
  7. expect = require("chai").expect
  8. ObjectId = require("mongojs").ObjectId
  9. MockRequest = require('../helpers/MockRequest')
  10. MockResponse = require('../helpers/MockResponse')
  11. Errors = require "../../../../app/js/Features/Errors/Errors.js"
  12. describe "TokenAccessController", ->
  13. beforeEach ->
  14. @readOnlyToken = 'somereadonlytoken'
  15. @readAndWriteToken = '42somereadandwritetoken'
  16. @projectId = ObjectId()
  17. @ownerId = 'owner'
  18. @project =
  19. _id: @projectId
  20. publicAccesLevel: 'tokenBased'
  21. tokens:
  22. readOnly: @readOnlyToken
  23. readAndWrite: @readAndWriteToken
  24. owner_ref: @ownerId
  25. @userId = ObjectId()
  26. @TokenAccessController = SandboxedModule.require modulePath, requires:
  27. '../Project/ProjectController': @ProjectController = {}
  28. '../Authentication/AuthenticationController': @AuthenticationController = {}
  29. './TokenAccessHandler': @TokenAccessHandler = {
  30. getV1DocPublishedInfo: sinon.stub().yields(null, {
  31. allow: true
  32. })
  33. getV1DocInfo: sinon.stub().yields(null, {
  34. exists: true
  35. exported: false
  36. })
  37. }
  38. '../../infrastructure/Features': @Features = {
  39. hasFeature: sinon.stub().returns(false)
  40. }
  41. 'logger-sharelatex': {log: sinon.stub(), err: sinon.stub()}
  42. 'settings-sharelatex': {
  43. overleaf:
  44. host: 'http://overleaf.test:5000'
  45. }
  46. '../V1/V1Api': @V1Api = {
  47. request: sinon.stub().callsArgWith(1, null, {}, { allow: true })
  48. }
  49. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  50. describe 'readAndWriteToken', ->
  51. beforeEach ->
  52. describe 'when all goes well', ->
  53. beforeEach ->
  54. @req = new MockRequest()
  55. @res = new MockResponse()
  56. @next = sinon.stub()
  57. @req.params['read_and_write_token'] = @readAndWriteToken
  58. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  59. .callsArgWith(1, null, @project, true)
  60. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  61. .callsArgWith(2, null)
  62. @ProjectController.loadEditor = sinon.stub()
  63. @AuthenticationController.setRedirectInSession = sinon.stub()
  64. @TokenAccessController.readAndWriteToken @req, @res, @next
  65. it 'should try to find a project with this token', (done) ->
  66. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  67. .to.equal 1
  68. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  69. .to.equal true
  70. done()
  71. it 'should add the user to the project with read-write access', (done) ->
  72. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  73. .to.equal 1
  74. expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
  75. @userId.toString(), @projectId
  76. ))
  77. .to.equal true
  78. done()
  79. it 'should pass control to loadEditor', (done) ->
  80. expect(@req.params.Project_id).to.equal @projectId.toString()
  81. expect(@ProjectController.loadEditor.callCount).to.equal 1
  82. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  83. done()
  84. describe 'when the user is already the owner', ->
  85. beforeEach ->
  86. @req = new MockRequest()
  87. @res = new MockResponse()
  88. @next = sinon.stub()
  89. @req.params['read_and_write_token'] = @readAndWriteToken
  90. @project.owner_ref = @userId
  91. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  92. .callsArgWith(1, null, @project, true)
  93. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  94. .callsArgWith(2, null)
  95. @ProjectController.loadEditor = sinon.stub()
  96. @TokenAccessController.readAndWriteToken @req, @res, @next
  97. it 'should try to find a project with this token', (done) ->
  98. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  99. .to.equal 1
  100. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  101. .to.equal true
  102. done()
  103. it 'should not add the user to the project with read-write access', (done) ->
  104. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  105. .to.equal 0
  106. done()
  107. it 'should pass control to loadEditor', (done) ->
  108. expect(@req.params.Project_id).to.equal @projectId.toString()
  109. expect(@ProjectController.loadEditor.callCount).to.equal 1
  110. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  111. done()
  112. describe 'when there is no user', ->
  113. beforeEach ->
  114. @AuthenticationController.getLoggedInUserId =
  115. sinon.stub().returns(null)
  116. describe 'when anonymous read-write access is enabled', ->
  117. beforeEach ->
  118. @TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = true
  119. @req = new MockRequest()
  120. @res = new MockResponse()
  121. @next = sinon.stub()
  122. @req.params['read_and_write_token'] = @readAndWriteToken
  123. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  124. .callsArgWith(1, null, @project, true)
  125. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  126. .callsArgWith(2, null)
  127. @ProjectController.loadEditor = sinon.stub()
  128. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  129. @TokenAccessController.readAndWriteToken @req, @res, @next
  130. it 'should not add the user to the project with read-write access', (done) ->
  131. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  132. .to.equal 0
  133. done()
  134. it 'should give the user session token access', (done) ->
  135. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  136. .to.equal 1
  137. expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
  138. @req, @projectId, @readAndWriteToken
  139. ))
  140. .to.equal true
  141. done()
  142. it 'should pass control to loadEditor', (done) ->
  143. expect(@req.params.Project_id).to.equal @projectId.toString()
  144. expect(@ProjectController.loadEditor.callCount).to.equal 1
  145. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  146. done()
  147. describe 'when anonymous read-write access is not enabled', ->
  148. beforeEach ->
  149. @TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = false
  150. @req = new MockRequest()
  151. @res = new MockResponse()
  152. @res.redirect = sinon.stub()
  153. @next = sinon.stub()
  154. @req.params['read_and_write_token'] = @readAndWriteToken
  155. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  156. .callsArgWith(1, null, @project, true)
  157. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  158. .callsArgWith(2, null)
  159. @ProjectController.loadEditor = sinon.stub()
  160. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  161. @AuthenticationController.setRedirectInSession = sinon.stub()
  162. @TokenAccessController.readAndWriteToken @req, @res, @next
  163. it 'should not add the user to the project with read-write access', (done) ->
  164. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  165. .to.equal 0
  166. done()
  167. it 'should give the user session token access', (done) ->
  168. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  169. .to.equal 0
  170. done()
  171. it 'should not pass control to loadEditor', (done) ->
  172. expect(@ProjectController.loadEditor.callCount).to.equal 0
  173. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  174. done()
  175. it 'should set redirect in session', (done) ->
  176. expect(@AuthenticationController.setRedirectInSession.callCount).to.equal 1
  177. expect(@AuthenticationController.setRedirectInSession.calledWith(@req)).to.equal true
  178. done()
  179. it 'should redirect to restricted page', (done) ->
  180. expect(@res.redirect.callCount).to.equal 1
  181. expect(@res.redirect.calledWith('/restricted')).to.equal true
  182. done()
  183. describe 'when findProject produces an error', ->
  184. beforeEach ->
  185. @req = new MockRequest()
  186. @res = new MockResponse()
  187. @next = sinon.stub()
  188. @req.params['read_and_write_token'] = @readAndWriteToken
  189. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  190. .callsArgWith(1, new Error('woops'))
  191. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  192. .callsArgWith(2, null)
  193. @ProjectController.loadEditor = sinon.stub()
  194. @TokenAccessController.readAndWriteToken @req, @res, @next
  195. it 'should try to find a project with this token', (done) ->
  196. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  197. .to.equal 1
  198. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  199. .to.equal true
  200. done()
  201. it 'should not add the user to the project with read-write access', (done) ->
  202. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  203. .to.equal 0
  204. done()
  205. it 'should not pass control to loadEditor', (done) ->
  206. expect(@ProjectController.loadEditor.callCount).to.equal 0
  207. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  208. done()
  209. it 'should call next with an error', (done) ->
  210. expect(@next.callCount).to.equal 1
  211. expect(@next.lastCall.args[0]).to.be.instanceof Error
  212. done()
  213. describe 'when findProject does not find a project', ->
  214. beforeEach ->
  215. describe 'when user is present', ->
  216. beforeEach ->
  217. @AuthenticationController.getLoggedInUserId =
  218. sinon.stub().returns(@userId.toString())
  219. describe 'when project does not exist', ->
  220. beforeEach ->
  221. @req = new MockRequest()
  222. @req.url = '/123abc'
  223. @res = new MockResponse()
  224. @res.redirect = sinon.stub()
  225. @res.render = sinon.stub()
  226. @next = sinon.stub()
  227. @req.params['read_and_write_token'] = '123abc'
  228. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  229. .callsArgWith(1, null, null, false)
  230. describe 'when project was not exported from v1', ->
  231. beforeEach ->
  232. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  233. exists: true
  234. exported: false
  235. })
  236. @TokenAccessController.readAndWriteToken @req, @res, @next
  237. it 'should redirect to v1', (done) ->
  238. expect(@res.redirect.callCount).to.equal 1
  239. expect(@res.redirect.calledWith(
  240. 302,
  241. '/sign_in_to_v1?return_to=/123abc'
  242. )).to.equal true
  243. done()
  244. describe 'when project was not exported from v1 but forcing import to v2', ->
  245. beforeEach ->
  246. @Features.hasFeature.returns(true)
  247. describe 'with project name', ->
  248. beforeEach ->
  249. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  250. exists: true
  251. exported: false
  252. has_owner: true
  253. name: 'A title'
  254. has_assignment: false
  255. brand_info: null
  256. })
  257. @TokenAccessController.readAndWriteToken @req, @res, @next
  258. it 'should render v2-import page with name', (done) ->
  259. expect(@res.render.calledWith(
  260. 'project/v2-import',
  261. {
  262. projectId: '123abc'
  263. name: 'A title'
  264. hasOwner: true
  265. hasAssignment: false
  266. brandInfo: null
  267. }
  268. )).to.equal true
  269. done()
  270. describe 'with project owner', ->
  271. beforeEach ->
  272. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  273. exists: true
  274. exported: false
  275. has_owner: true
  276. name: 'A title'
  277. has_assignment: false
  278. brand_info: null
  279. })
  280. @TokenAccessController.readAndWriteToken @req, @res, @next
  281. it 'should render v2-import page', (done) ->
  282. expect(@res.render.calledWith(
  283. 'project/v2-import',
  284. {
  285. projectId: '123abc'
  286. hasOwner: true
  287. name: 'A title'
  288. hasAssignment: false
  289. brandInfo: null
  290. }
  291. )).to.equal true
  292. done()
  293. describe 'without project owner', ->
  294. beforeEach ->
  295. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  296. exists: true
  297. exported: false
  298. has_owner: false
  299. name: 'A title'
  300. has_assignment: false
  301. brand_info: null
  302. })
  303. @TokenAccessController.readAndWriteToken @req, @res, @next
  304. it 'should render v2-import page', (done) ->
  305. expect(@res.render.calledWith(
  306. 'project/v2-import',
  307. {
  308. projectId: '123abc',
  309. hasOwner: false
  310. name: 'A title',
  311. hasAssignment: false,
  312. brandInfo: null
  313. }
  314. )).to.equal true
  315. done()
  316. describe 'with assignment', ->
  317. beforeEach ->
  318. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  319. exists: true
  320. exported: false
  321. has_owner: false
  322. name: 'A title'
  323. has_assignment: true
  324. brand_info: null
  325. })
  326. @TokenAccessController.readAndWriteToken @req, @res, @next
  327. it 'should render v2-import page', (done) ->
  328. expect(@res.render.calledWith(
  329. 'project/v2-import',
  330. {
  331. projectId: '123abc',
  332. hasOwner: false
  333. name: 'A title',
  334. hasAssignment: true,
  335. brandInfo: null
  336. }
  337. )).to.equal true
  338. done()
  339. describe 'with brand info', ->
  340. beforeEach ->
  341. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  342. exists: true
  343. exported: false
  344. has_owner: false
  345. name: 'A title'
  346. has_assignment: false
  347. brand_info: 'wellcome'
  348. })
  349. @TokenAccessController.readAndWriteToken @req, @res, @next
  350. it 'should render v2-import page', (done) ->
  351. expect(@res.render.calledWith(
  352. 'project/v2-import',
  353. {
  354. projectId: '123abc',
  355. hasOwner: false
  356. name: 'A title',
  357. hasAssignment: false,
  358. brandInfo: 'wellcome'
  359. }
  360. )).to.equal true
  361. done()
  362. describe 'with anonymous user', ->
  363. beforeEach ->
  364. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
  365. @TokenAccessController.readAndWriteToken @req, @res, @next
  366. it 'should render anonymous import status page', (done) ->
  367. expect(@res.render.callCount).to.equal 1
  368. expect(@res.render.calledWith(
  369. 'project/v2-import',
  370. { loginRedirect: '/123abc' }
  371. )).to.equal true
  372. done()
  373. describe 'when project was exported from v1', ->
  374. beforeEach ->
  375. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  376. exists: true
  377. exported: true
  378. })
  379. @TokenAccessController.readAndWriteToken @req, @res, @next
  380. it 'should call next with a not-found error', (done) ->
  381. expect(@next.callCount).to.equal 1
  382. done()
  383. describe 'when token access is off, but user has higher access anyway', ->
  384. beforeEach ->
  385. @req = new MockRequest()
  386. @res = new MockResponse()
  387. @res.redirect = sinon.stub()
  388. @next = sinon.stub()
  389. @req.params['read_and_write_token'] = @readAndWriteToken
  390. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  391. .callsArgWith(1, null, null, true)
  392. @TokenAccessHandler.findProjectWithHigherAccess =
  393. sinon.stub()
  394. .callsArgWith(2, null, @project)
  395. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  396. .callsArgWith(2, null)
  397. @ProjectController.loadEditor = sinon.stub()
  398. @TokenAccessController.readAndWriteToken @req, @res, @next
  399. it 'should try to find a project with this token', (done) ->
  400. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  401. .to.equal 1
  402. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken
  403. .calledWith(@readAndWriteToken)
  404. ).to.equal true
  405. done()
  406. it 'should check if user has higher access to the token project', (done) ->
  407. expect(
  408. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  409. ).to.equal 1
  410. done()
  411. it 'should not add the user to the project with read-write access', (done) ->
  412. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  413. .to.equal 0
  414. done()
  415. it 'should not pass control to loadEditor', (done) ->
  416. expect(@ProjectController.loadEditor.callCount).to.equal 0
  417. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  418. done()
  419. it 'should not call next with a not-found error', (done) ->
  420. expect(@next.callCount).to.equal 0
  421. done()
  422. it 'should redirect to the canonical project url', (done) ->
  423. expect(@res.redirect.callCount).to.equal 1
  424. expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
  425. done()
  426. describe 'when higher access is not available', ->
  427. beforeEach ->
  428. @req = new MockRequest()
  429. @res = new MockResponse()
  430. @next = sinon.stub()
  431. @req.params['read_and_write_token'] = @readAndWriteToken
  432. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  433. .callsArgWith(1, null, null, true)
  434. @TokenAccessHandler.findProjectWithHigherAccess =
  435. sinon.stub()
  436. .callsArgWith(2, null, null)
  437. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  438. .callsArgWith(2, null)
  439. @ProjectController.loadEditor = sinon.stub()
  440. @TokenAccessController.readAndWriteToken @req, @res, @next
  441. it 'should try to find a project with this token', (done) ->
  442. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  443. .to.equal 1
  444. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
  445. @readAndWriteToken
  446. )).to.equal true
  447. done()
  448. it 'should check if user has higher access to the token project', (done) ->
  449. expect(
  450. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  451. ).to.equal 1
  452. done()
  453. it 'should not add the user to the project with read-write access', (done) ->
  454. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  455. .to.equal 0
  456. done()
  457. it 'should not pass control to loadEditor', (done) ->
  458. expect(@ProjectController.loadEditor.callCount).to.equal 0
  459. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  460. done()
  461. it 'should call next with a not-found error', (done) ->
  462. expect(@next.callCount).to.equal 1
  463. expect(@next.lastCall.args[0]).to.be.instanceof Error
  464. done()
  465. describe 'when adding user to project produces an error', ->
  466. beforeEach ->
  467. @req = new MockRequest()
  468. @res = new MockResponse()
  469. @next = sinon.stub()
  470. @req.params['read_and_write_token'] = @readAndWriteToken
  471. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  472. .callsArgWith(1, null, @project, true)
  473. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  474. .callsArgWith(2, new Error('woops'))
  475. @ProjectController.loadEditor = sinon.stub()
  476. @TokenAccessController.readAndWriteToken @req, @res, @next
  477. it 'should try to find a project with this token', (done) ->
  478. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  479. .to.equal 1
  480. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  481. .to.equal true
  482. done()
  483. it 'should add the user to the project with read-write access', (done) ->
  484. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  485. .to.equal 1
  486. expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
  487. @userId.toString(), @projectId
  488. ))
  489. .to.equal true
  490. done()
  491. it 'should not pass control to loadEditor', (done) ->
  492. expect(@ProjectController.loadEditor.callCount).to.equal 0
  493. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  494. done()
  495. it 'should call next with an error', (done) ->
  496. expect(@next.callCount).to.equal 1
  497. expect(@next.lastCall.args[0]).to.be.instanceof Error
  498. done()
  499. describe 'readOnlyToken', ->
  500. beforeEach ->
  501. @TokenAccessHandler.checkV1Access = sinon.stub().callsArgWith(1, null, true)
  502. describe 'when access not allowed by v1 api', ->
  503. beforeEach ->
  504. @req = new MockRequest()
  505. @res = new MockResponse()
  506. @res.redirect = sinon.stub()
  507. @next = sinon.stub()
  508. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  509. .callsArgWith(1, null, @project, true)
  510. @TokenAccessHandler.getV1DocPublishedInfo = sinon.stub().yields(null, {
  511. allow: false
  512. published_path: 'doc-url'
  513. })
  514. @TokenAccessController.readOnlyToken @req, @res, @next
  515. it 'should redirect to doc-url', ->
  516. expect(@res.redirect.calledWith('doc-url')).to.equal true
  517. describe 'with a user', ->
  518. beforeEach ->
  519. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  520. describe 'when all goes well', ->
  521. beforeEach ->
  522. @req = new MockRequest()
  523. @res = new MockResponse()
  524. @next = sinon.stub()
  525. @req.params['read_only_token'] = @readOnlyToken
  526. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  527. .callsArgWith(1, null, @project, true)
  528. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  529. .callsArgWith(2, null)
  530. @ProjectController.loadEditor = sinon.stub()
  531. @TokenAccessController.readOnlyToken @req, @res, @next
  532. it 'should try to find a project with this token', (done) ->
  533. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  534. .to.equal 1
  535. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  536. .to.equal true
  537. done()
  538. it 'should add the user to the project with read-only access', (done) ->
  539. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  540. .to.equal 1
  541. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  542. @userId.toString(), @projectId
  543. ))
  544. .to.equal true
  545. done()
  546. it 'should pass control to loadEditor', (done) ->
  547. expect(@req.params.Project_id).to.equal @projectId.toString()
  548. expect(@ProjectController.loadEditor.callCount).to.equal 1
  549. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  550. done()
  551. describe 'when the user is already the owner', ->
  552. beforeEach ->
  553. @req = new MockRequest()
  554. @res = new MockResponse()
  555. @next = sinon.stub()
  556. @req.params['read_only_token'] = @readOnlyToken
  557. @project.owner_ref = @userId
  558. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  559. .callsArgWith(1, null, @project, true)
  560. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  561. .callsArgWith(2, null)
  562. @ProjectController.loadEditor = sinon.stub()
  563. @TokenAccessController.readOnlyToken @req, @res, @next
  564. it 'should try to find a project with this token', (done) ->
  565. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  566. .to.equal 1
  567. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  568. .to.equal true
  569. done()
  570. it 'should not add the user to the project with read-only access', (done) ->
  571. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  572. .to.equal 0
  573. done()
  574. it 'should pass control to loadEditor', (done) ->
  575. expect(@req.params.Project_id).to.equal @projectId.toString()
  576. expect(@ProjectController.loadEditor.callCount).to.equal 1
  577. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  578. done()
  579. describe 'when findProject produces an error', ->
  580. beforeEach ->
  581. @req = new MockRequest()
  582. @res = new MockResponse()
  583. @next = sinon.stub()
  584. @req.params['read_only_token'] = @readOnlyToken
  585. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  586. .callsArgWith(1, new Error('woops'))
  587. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  588. .callsArgWith(2, null)
  589. @ProjectController.loadEditor = sinon.stub()
  590. @TokenAccessController.readOnlyToken @req, @res, @next
  591. it 'should try to find a project with this token', (done) ->
  592. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  593. .to.equal 1
  594. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  595. .to.equal true
  596. done()
  597. it 'should not add the user to the project with read-only access', (done) ->
  598. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  599. .to.equal 0
  600. done()
  601. it 'should not pass control to loadEditor', (done) ->
  602. expect(@ProjectController.loadEditor.callCount).to.equal 0
  603. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  604. done()
  605. it 'should call next with an error', (done) ->
  606. expect(@next.callCount).to.equal 1
  607. expect(@next.lastCall.args[0]).to.be.instanceof Error
  608. done()
  609. describe 'when findProject does not find a project', ->
  610. describe 'when project does not exist', ->
  611. beforeEach ->
  612. @req = new MockRequest()
  613. @res = new MockResponse()
  614. @res.redirect = sinon.stub()
  615. @next = sinon.stub()
  616. @req.params['read_only_token'] = 'abcd'
  617. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  618. .callsArgWith(1, null, null, false)
  619. @TokenAccessHandler.checkV1ProjectExported = sinon.stub()
  620. .callsArgWith(1, null, false)
  621. @TokenAccessController.readOnlyToken @req, @res, @next
  622. it 'should redirect to v1', (done) ->
  623. expect(@res.redirect.callCount).to.equal 1
  624. expect(@res.redirect.calledWith(
  625. 302,
  626. '/sign_in_to_v1?return_to=/read/abcd'
  627. )).to.equal true
  628. done()
  629. describe 'when project was not exported from v1 but forcing import to v2', ->
  630. beforeEach ->
  631. @Features.hasFeature.returns(true)
  632. @req = new MockRequest()
  633. @res = new MockResponse()
  634. @res.render = sinon.stub()
  635. @next = sinon.stub()
  636. @req.params['read_only_token'] = 'abcd'
  637. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  638. .callsArgWith(1, null, null, false)
  639. describe 'with project name', ->
  640. beforeEach ->
  641. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  642. exists: true
  643. exported: false
  644. has_owner: true
  645. name: 'A title'
  646. has_assignment: false
  647. brand_info: null
  648. })
  649. @TokenAccessController.readOnlyToken @req, @res, @next
  650. it 'should render v2-import page with name', (done) ->
  651. expect(@res.render.calledWith(
  652. 'project/v2-import',
  653. {
  654. projectId: 'abcd'
  655. name: 'A title'
  656. hasOwner: true
  657. hasAssignment: false
  658. brandInfo: null
  659. }
  660. )).to.equal true
  661. done()
  662. describe 'with project owner', ->
  663. beforeEach ->
  664. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  665. exists: true
  666. exported: false
  667. has_owner: true
  668. name: 'A title'
  669. has_assignment: false
  670. brand_info: null
  671. })
  672. @TokenAccessController.readOnlyToken @req, @res, @next
  673. it 'should render v2-import page', (done) ->
  674. expect(@res.render.calledWith(
  675. 'project/v2-import',
  676. {
  677. projectId: 'abcd',
  678. hasOwner: true
  679. name: 'A title'
  680. hasAssignment: false
  681. brandInfo: null
  682. }
  683. )).to.equal true
  684. done()
  685. describe 'without project owner', ->
  686. beforeEach ->
  687. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  688. exists: true
  689. exported: false
  690. has_owner: false
  691. name: 'A title'
  692. has_assignment: false
  693. brand_info: null
  694. })
  695. @TokenAccessController.readOnlyToken @req, @res, @next
  696. it 'should render v2-import page', (done) ->
  697. expect(@res.render.calledWith(
  698. 'project/v2-import',
  699. {
  700. projectId: 'abcd',
  701. hasOwner: false
  702. name: 'A title'
  703. hasAssignment: false
  704. brandInfo: null
  705. }
  706. )).to.equal true
  707. done()
  708. describe 'with assignment', ->
  709. beforeEach ->
  710. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  711. exists: true
  712. exported: false
  713. has_owner: false
  714. name: 'A title'
  715. has_assignment: true
  716. brand_info: null
  717. })
  718. @TokenAccessController.readOnlyToken @req, @res, @next
  719. it 'should render v2-import page', (done) ->
  720. expect(@res.render.calledWith(
  721. 'project/v2-import',
  722. {
  723. projectId: 'abcd',
  724. hasOwner: false
  725. name: 'A title'
  726. hasAssignment: true
  727. brandInfo: null
  728. }
  729. )).to.equal true
  730. done()
  731. describe 'with brand info', ->
  732. beforeEach ->
  733. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  734. exists: true
  735. exported: false
  736. has_owner: false
  737. name: 'A title'
  738. has_assignment: false
  739. brand_info: 'f1000'
  740. })
  741. @TokenAccessController.readOnlyToken @req, @res, @next
  742. it 'should render v2-import page', (done) ->
  743. expect(@res.render.calledWith(
  744. 'project/v2-import',
  745. {
  746. projectId: 'abcd',
  747. hasOwner: false
  748. name: 'A title'
  749. hasAssignment: false
  750. brandInfo: 'f1000'
  751. }
  752. )).to.equal true
  753. done()
  754. describe 'when project was exported from v1', ->
  755. beforeEach ->
  756. @req = new MockRequest()
  757. @res = new MockResponse()
  758. @res.redirect = sinon.stub()
  759. @next = sinon.stub()
  760. @req.params['read_only_token'] = 'abcd'
  761. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  762. .callsArgWith(1, null, null, false)
  763. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  764. allow: true
  765. exists: true
  766. exported: true
  767. })
  768. @TokenAccessController.readOnlyToken @req, @res, @next
  769. it 'should call next with a not-found error', (done) ->
  770. expect(@next.callCount).to.equal 1
  771. done()
  772. describe 'when token access is off, but user has higher access anyway', ->
  773. beforeEach ->
  774. @req = new MockRequest()
  775. @res = new MockResponse()
  776. @res.redirect = sinon.stub()
  777. @next = sinon.stub()
  778. @req.params['read_and_write_token'] = @readAndWriteToken
  779. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  780. .callsArgWith(1, null, null, true)
  781. @TokenAccessHandler.findProjectWithHigherAccess =
  782. sinon.stub()
  783. .callsArgWith(2, null, @project)
  784. @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
  785. .callsArgWith(2, null)
  786. @ProjectController.loadEditor = sinon.stub()
  787. @TokenAccessController.readAndWriteToken @req, @res, @next
  788. it 'should try to find a project with this token', (done) ->
  789. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  790. .to.equal 1
  791. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
  792. .to.equal true
  793. done()
  794. it 'should check if user has higher access to the token project', (done) ->
  795. expect(
  796. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  797. ).to.equal 1
  798. done()
  799. it 'should not add the user to the project with read-write access', (done) ->
  800. expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
  801. .to.equal 0
  802. done()
  803. it 'should not pass control to loadEditor', (done) ->
  804. expect(@ProjectController.loadEditor.callCount).to.equal 0
  805. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  806. done()
  807. it 'should not call next with a not-found error', (done) ->
  808. expect(@next.callCount).to.equal 0
  809. done()
  810. it 'should redirect to the canonical project url', (done) ->
  811. expect(@res.redirect.callCount).to.equal 1
  812. expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
  813. done()
  814. describe 'when higher access is not available', ->
  815. beforeEach ->
  816. @req = new MockRequest()
  817. @res = new MockResponse()
  818. @next = sinon.stub()
  819. @req.params['read_and_write_token'] = @readAndWriteToken
  820. @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
  821. .callsArgWith(1, null, null, true)
  822. @TokenAccessHandler.findProjectWithHigherAccess =
  823. sinon.stub()
  824. .callsArgWith(2, null, null)
  825. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  826. .callsArgWith(2, null)
  827. @ProjectController.loadEditor = sinon.stub()
  828. @TokenAccessController.readAndWriteToken @req, @res, @next
  829. it 'should try to find a project with this token', (done) ->
  830. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
  831. .to.equal 1
  832. expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
  833. @readAndWriteToken
  834. )).to.equal true
  835. done()
  836. it 'should check if user has higher access to the token project', (done) ->
  837. expect(
  838. @TokenAccessHandler.findProjectWithHigherAccess.callCount
  839. ).to.equal 1
  840. done()
  841. it 'should not add the user to the project with read-write access', (done) ->
  842. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  843. .to.equal 0
  844. done()
  845. it 'should not pass control to loadEditor', (done) ->
  846. expect(@ProjectController.loadEditor.callCount).to.equal 0
  847. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  848. done()
  849. it 'should call next with a not-found error', (done) ->
  850. expect(@next.callCount).to.equal 1
  851. expect(@next.lastCall.args[0]).to.be.instanceof Error
  852. done()
  853. describe 'when adding user to project produces an error', ->
  854. beforeEach ->
  855. @req = new MockRequest()
  856. @res = new MockResponse()
  857. @next = sinon.stub()
  858. @req.params['read_only_token'] = @readOnlyToken
  859. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  860. .callsArgWith(1, null, @project, true)
  861. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  862. .callsArgWith(2, new Error('woops'))
  863. @ProjectController.loadEditor = sinon.stub()
  864. @TokenAccessController.readOnlyToken @req, @res, @next
  865. it 'should try to find a project with this token', (done) ->
  866. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  867. .to.equal 1
  868. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  869. .to.equal true
  870. done()
  871. it 'should add the user to the project with read-only access', (done) ->
  872. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  873. .to.equal 1
  874. expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
  875. @userId.toString(), @projectId
  876. ))
  877. .to.equal true
  878. done()
  879. it 'should not pass control to loadEditor', (done) ->
  880. expect(@ProjectController.loadEditor.callCount).to.equal 0
  881. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  882. done()
  883. it 'should call next with an error', (done) ->
  884. expect(@next.callCount).to.equal 1
  885. expect(@next.lastCall.args[0]).to.be.instanceof Error
  886. done()
  887. describe 'anonymous', ->
  888. beforeEach ->
  889. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
  890. @TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
  891. describe 'when all goes well', ->
  892. beforeEach ->
  893. @req = new MockRequest()
  894. @res = new MockResponse()
  895. @next = sinon.stub()
  896. @req.params['read_only_token'] = @readOnlyToken
  897. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  898. .callsArgWith(1, null, @project, true)
  899. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  900. .callsArgWith(2, null)
  901. @ProjectController.loadEditor = sinon.stub()
  902. @TokenAccessController.readOnlyToken @req, @res, @next
  903. it 'should try to find a project with this token', (done) ->
  904. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  905. .to.equal 1
  906. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  907. .to.equal true
  908. done()
  909. it 'should give the user session read-only access', (done) ->
  910. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  911. .to.equal 1
  912. expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
  913. @req, @projectId, @readOnlyToken
  914. ))
  915. .to.equal true
  916. done()
  917. it 'should not add the user to the project with read-only access', (done) ->
  918. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  919. .to.equal 0
  920. done()
  921. it 'should pass control to loadEditor', (done) ->
  922. expect(@req.params.Project_id).to.equal @projectId.toString()
  923. expect(@req._anonymousAccessToken).to.equal @readOnlyToken
  924. expect(@ProjectController.loadEditor.callCount).to.equal 1
  925. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
  926. done()
  927. describe 'when findProject produces an error', ->
  928. beforeEach ->
  929. @req = new MockRequest()
  930. @res = new MockResponse()
  931. @next = sinon.stub()
  932. @req.params['read_only_token'] = @readOnlyToken
  933. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  934. .callsArgWith(1, new Error('woops'))
  935. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  936. .callsArgWith(2, null)
  937. @ProjectController.loadEditor = sinon.stub()
  938. @TokenAccessController.readOnlyToken @req, @res, @next
  939. it 'should try to find a project with this token', (done) ->
  940. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  941. .to.equal 1
  942. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  943. .to.equal true
  944. done()
  945. it 'should not give the user session read-only access', (done) ->
  946. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  947. .to.equal 0
  948. done()
  949. it 'should not add the user to the project with read-only access', (done) ->
  950. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  951. .to.equal 0
  952. done()
  953. it 'should not pass control to loadEditor', (done) ->
  954. expect(@ProjectController.loadEditor.callCount).to.equal 0
  955. expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
  956. done()
  957. it 'should call next with an error', (done) ->
  958. expect(@next.callCount).to.equal 1
  959. expect(@next.lastCall.args[0]).to.be.instanceof Error
  960. done()
  961. describe 'when findProject does not find a project', ->
  962. beforeEach ->
  963. @req = new MockRequest()
  964. @res = new MockResponse()
  965. @res.redirect = sinon.stub()
  966. @next = sinon.stub()
  967. @req.params['read_only_token'] = @readOnlyToken
  968. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
  969. @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
  970. .callsArgWith(1, null, false)
  971. @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
  972. describe 'when project does not exist', ->
  973. beforeEach ->
  974. @TokenAccessController.readOnlyToken @req, @res, @next
  975. it 'should try to find a project with this token', (done) ->
  976. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
  977. .to.equal 1
  978. expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
  979. .to.equal true
  980. done()
  981. it 'should not give the user session read-only access', (done) ->
  982. expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
  983. .to.equal 0
  984. done()
  985. it 'should not add the user to the project with read-only access', (done) ->
  986. expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
  987. .to.equal 0
  988. done()
  989. describe 'when project was exported to v2', ->
  990. beforeEach ->
  991. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  992. exists: true
  993. exported: true
  994. })
  995. @TokenAccessController.readOnlyToken @req, @res, @next
  996. it 'should call next with not found error', (done) ->
  997. expect(@next.callCount).to.equal 1
  998. expect(@next.calledWith(new Errors.NotFoundError())).to.equal true
  999. done()
  1000. describe 'when project was not exported to v2', ->
  1001. beforeEach ->
  1002. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  1003. exists: true
  1004. exported: false
  1005. })
  1006. @TokenAccessController.readOnlyToken @req, @res, @next
  1007. it 'should redirect to v1', (done) ->
  1008. expect(@res.redirect.callCount).to.equal 1
  1009. expect(@res.redirect.calledWith(
  1010. 302,
  1011. "/sign_in_to_v1?return_to=/read/#{@readOnlyToken}"
  1012. )).to.equal true
  1013. done()
  1014. describe 'anonymous user', ->
  1015. beforeEach ->
  1016. @AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
  1017. describe 'when project was not exported to v2', ->
  1018. beforeEach ->
  1019. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  1020. exists: true
  1021. exported: false
  1022. })
  1023. @TokenAccessController.readOnlyToken @req, @res, @next
  1024. it 'should redirect to v1', (done) ->
  1025. expect(@res.redirect.callCount).to.equal 1
  1026. expect(@res.redirect.calledWith(
  1027. 302,
  1028. "/sign_in_to_v1?return_to=/read/#{@readOnlyToken}"
  1029. )).to.equal true
  1030. done()
  1031. describe 'force-import-to-v2 flag is on', ->
  1032. beforeEach ->
  1033. @res.render = sinon.stub()
  1034. @Features.hasFeature.returns(true)
  1035. describe 'when project was not exported to v2', ->
  1036. beforeEach ->
  1037. @TokenAccessHandler.getV1DocInfo = sinon.stub().yields(null, {
  1038. exists: true
  1039. exported: false
  1040. })
  1041. @TokenAccessController.readOnlyToken @req, @res, @next
  1042. it 'should render anonymous import status page', (done) ->
  1043. expect(@res.render.callCount).to.equal 1
  1044. expect(@res.render.calledWith(
  1045. 'project/v2-import',
  1046. { loginRedirect: "/read/#{@readOnlyToken}" }
  1047. )).to.equal true
  1048. done()