overleaf/services/web/test/UnitTests/coffee/TokenAccess/TokenAccessControllerTests.coffee
Shane Kilkelly 5df4556e9c Set redirect when bouncing away from token route
This ensures that when the user logs in they will be redirected back
to this token, the page they wanted to access in the first place.
2017-11-15 13:30:40 +00:00

740 lines
28 KiB
CoffeeScript

should = require('chai').should()
SandboxedModule = require('sandboxed-module')
assert = require('assert')
path = require('path')
sinon = require('sinon')
modulePath = path.join __dirname, "../../../../app/js/Features/TokenAccess/TokenAccessController"
expect = require("chai").expect
ObjectId = require("mongojs").ObjectId
MockRequest = require('../helpers/MockRequest')
MockResponse = require('../helpers/MockResponse')
Errors = require "../../../../app/js/Features/Errors/Errors.js"
describe "TokenAccessController", ->
beforeEach ->
@readOnlyToken = 'somereadonlytoken'
@readAndWriteToken = '42somereadandwritetoken'
@projectId = ObjectId()
@ownerId = 'owner'
@project =
_id: @projectId
publicAccesLevel: 'tokenBased'
tokens:
readOnly: @readOnlyToken
readAndWrite: @readAndWriteToken
owner_ref: @ownerId
@userId = ObjectId()
@TokenAccessController = SandboxedModule.require modulePath, requires:
'../Project/ProjectController': @ProjectController = {}
'../Authentication/AuthenticationController': @AuthenticationController = {}
'./TokenAccessHandler': @TokenAccessHandler = {}
'logger-sharelatex': {log: sinon.stub(), err: sinon.stub()}
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
describe 'readAndWriteToken', ->
beforeEach ->
describe 'when all goes well', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@AuthenticationController._setRedirectInSession = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
.to.equal true
done()
it 'should add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 1
expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
@userId.toString(), @projectId
))
.to.equal true
done()
it 'should pass control to loadEditor', (done) ->
expect(@req.params.Project_id).to.equal @projectId.toString()
expect(@ProjectController.loadEditor.callCount).to.equal 1
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
done()
describe 'when the user is already the owner', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@project.owner_ref = @userId
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
.to.equal true
done()
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 0
done()
it 'should pass control to loadEditor', (done) ->
expect(@req.params.Project_id).to.equal @projectId.toString()
expect(@ProjectController.loadEditor.callCount).to.equal 1
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
done()
describe 'when there is no user', ->
beforeEach ->
@AuthenticationController.getLoggedInUserId =
sinon.stub().returns(null)
describe 'when anonymous read-write access is enabled', ->
beforeEach ->
@TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = true
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 0
done()
it 'should give the user session token access', (done) ->
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
.to.equal 1
expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
@req, @projectId, @readAndWriteToken
))
.to.equal true
done()
it 'should pass control to loadEditor', (done) ->
expect(@req.params.Project_id).to.equal @projectId.toString()
expect(@ProjectController.loadEditor.callCount).to.equal 1
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
done()
describe 'when anonymous read-write access is not enabled', ->
beforeEach ->
@TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = false
@req = new MockRequest()
@res = new MockResponse()
@res.redirect = sinon.stub()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
@AuthenticationController._setRedirectInSession = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 0
done()
it 'should give the user session token access', (done) ->
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should set redirect in session', (done) ->
expect(@AuthenticationController._setRedirectInSession.callCount).to.equal 1
expect(@AuthenticationController._setRedirectInSession.calledWith(@req)).to.equal true
done()
it 'should redirect to restricted page', (done) ->
expect(@res.redirect.callCount).to.equal 1
expect(@res.redirect.calledWith('/restricted')).to.equal true
done()
describe 'when findProject produces an error', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, new Error('woops'))
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
.to.equal true
done()
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should call next with an error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()
describe 'when findProject does not find a project', ->
beforeEach ->
describe 'when user is present', ->
beforeEach ->
@AuthenticationController.getLoggedInUserId =
sinon.stub().returns(@userId.toString())
describe 'when token access is off, but user has higher access anyway', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@res.redirect = sinon.stub()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, null)
@TokenAccessHandler.findProjectWithHigherAccess =
sinon.stub()
.callsArgWith(2, null, @project)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken
.calledWith(@readAndWriteToken)
).to.equal true
done()
it 'should check if user has higher access to the token project', (done) ->
expect(
@TokenAccessHandler.findProjectWithHigherAccess.callCount
).to.equal 1
done()
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should not call next with a not-found error', (done) ->
expect(@next.callCount).to.equal 0
done()
it 'should redirect to the canonical project url', (done) ->
expect(@res.redirect.callCount).to.equal 1
expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
done()
describe 'when higher access is not available', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, null)
@TokenAccessHandler.findProjectWithHigherAccess =
sinon.stub()
.callsArgWith(2, null, null)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
@readAndWriteToken
)).to.equal true
done()
it 'should check if user has higher access to the token project', (done) ->
expect(
@TokenAccessHandler.findProjectWithHigherAccess.callCount
).to.equal 1
done()
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should call next with a not-found error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()
describe 'when adding user to project produces an error', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, new Error('woops'))
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
.to.equal true
done()
it 'should add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 1
expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
@userId.toString(), @projectId
))
.to.equal true
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should call next with an error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()
describe 'readOnlyToken', ->
beforeEach ->
describe 'with a user', ->
beforeEach ->
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
describe 'when all goes well', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_only_token'] = @readOnlyToken
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readOnlyToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
.to.equal true
done()
it 'should add the user to the project with read-only access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 1
expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
@userId.toString(), @projectId
))
.to.equal true
done()
it 'should pass control to loadEditor', (done) ->
expect(@req.params.Project_id).to.equal @projectId.toString()
expect(@ProjectController.loadEditor.callCount).to.equal 1
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
done()
describe 'when the user is already the owner', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_only_token'] = @readOnlyToken
@project.owner_ref = @userId
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readOnlyToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
.to.equal true
done()
it 'should not add the user to the project with read-only access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 0
done()
it 'should pass control to loadEditor', (done) ->
expect(@req.params.Project_id).to.equal @projectId.toString()
expect(@ProjectController.loadEditor.callCount).to.equal 1
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
done()
describe 'when findProject produces an error', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_only_token'] = @readOnlyToken
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
.callsArgWith(1, new Error('woops'))
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readOnlyToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
.to.equal true
done()
it 'should not add the user to the project with read-only access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should call next with an error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()
##
describe 'when findProject does not find a project', ->
beforeEach ->
describe 'when token access is off, but user has higher access anyway', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@res.redirect = sinon.stub()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, null)
@TokenAccessHandler.findProjectWithHigherAccess =
sinon.stub()
.callsArgWith(2, null, @project)
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
.to.equal true
done()
it 'should check if user has higher access to the token project', (done) ->
expect(
@TokenAccessHandler.findProjectWithHigherAccess.callCount
).to.equal 1
done()
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should not call next with a not-found error', (done) ->
expect(@next.callCount).to.equal 0
done()
it 'should redirect to the canonical project url', (done) ->
expect(@res.redirect.callCount).to.equal 1
expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
done()
describe 'when higher access is not available', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_and_write_token'] = @readAndWriteToken
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
.callsArgWith(1, null, null)
@TokenAccessHandler.findProjectWithHigherAccess =
sinon.stub()
.callsArgWith(2, null, null)
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readAndWriteToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
@readAndWriteToken
)).to.equal true
done()
it 'should check if user has higher access to the token project', (done) ->
expect(
@TokenAccessHandler.findProjectWithHigherAccess.callCount
).to.equal 1
done()
it 'should not add the user to the project with read-write access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should call next with a not-found error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()
describe 'when adding user to project produces an error', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_only_token'] = @readOnlyToken
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, new Error('woops'))
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readOnlyToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
.to.equal true
done()
it 'should add the user to the project with read-only access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 1
expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
@userId.toString(), @projectId
))
.to.equal true
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should call next with an error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()
describe 'anonymous', ->
beforeEach ->
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
describe 'when all goes well', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_only_token'] = @readOnlyToken
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
.callsArgWith(1, null, @project)
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readOnlyToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
.to.equal true
done()
it 'should give the user session read-only access', (done) ->
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
.to.equal 1
expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
@req, @projectId, @readOnlyToken
))
.to.equal true
done()
it 'should not add the user to the project with read-only access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 0
done()
it 'should pass control to loadEditor', (done) ->
expect(@req.params.Project_id).to.equal @projectId.toString()
expect(@req._anonymousAccessToken).to.equal @readOnlyToken
expect(@ProjectController.loadEditor.callCount).to.equal 1
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
done()
describe 'when findProject produces an error', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_only_token'] = @readOnlyToken
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
.callsArgWith(1, new Error('woops'))
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readOnlyToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
.to.equal true
done()
it 'should not give the user session read-only access', (done) ->
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
.to.equal 0
done()
it 'should not add the user to the project with read-only access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should call next with an error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()
describe 'when findProject does not find a project', ->
beforeEach ->
@req = new MockRequest()
@res = new MockResponse()
@next = sinon.stub()
@req.params['read_only_token'] = @readOnlyToken
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
.callsArgWith(1, null, null)
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
.callsArgWith(2, null)
@ProjectController.loadEditor = sinon.stub()
@TokenAccessController.readOnlyToken @req, @res, @next
it 'should try to find a project with this token', (done) ->
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
.to.equal 1
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
.to.equal true
done()
it 'should not give the user session read-only access', (done) ->
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
.to.equal 0
done()
it 'should not pass control to loadEditor', (done) ->
expect(@ProjectController.loadEditor.callCount).to.equal 0
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
done()
it 'should not add the user to the project with read-only access', (done) ->
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
.to.equal 0
done()
it 'should call next with a not-found error', (done) ->
expect(@next.callCount).to.equal 1
expect(@next.lastCall.args[0]).to.be.instanceof Error
done()