2019-05-29 05:21:06 -04:00
|
|
|
/* eslint-disable
|
|
|
|
handle-callback-err,
|
|
|
|
max-len,
|
|
|
|
no-return-assign,
|
|
|
|
no-unused-vars,
|
|
|
|
*/
|
|
|
|
// TODO: This file was created by bulk-decaffeinate.
|
|
|
|
// Fix any style issues and re-enable lint.
|
|
|
|
/*
|
|
|
|
* decaffeinate suggestions:
|
|
|
|
* DS101: Remove unnecessary use of Array.from
|
|
|
|
* DS102: Remove unnecessary code created because of implicit returns
|
|
|
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
|
|
*/
|
|
|
|
const should = require('chai').should()
|
|
|
|
const modulePath = '../../../../app/src/Features/Project/ProjectDetailsHandler'
|
|
|
|
const Errors = require('../../../../app/src/Features/Errors/Errors')
|
|
|
|
const SandboxedModule = require('sandboxed-module')
|
|
|
|
const sinon = require('sinon')
|
|
|
|
const { assert } = require('chai')
|
|
|
|
const { expect } = require('chai')
|
|
|
|
require('chai').should()
|
|
|
|
|
|
|
|
describe('ProjectDetailsHandler', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.project_id = '321l3j1kjkjl'
|
|
|
|
this.user_id = 'user-id-123'
|
|
|
|
this.project = {
|
|
|
|
name: 'project',
|
|
|
|
description: 'this is a great project',
|
|
|
|
something: 'should not exist',
|
|
|
|
compiler: 'latexxxxxx',
|
|
|
|
owner_ref: this.user_id
|
|
|
|
}
|
|
|
|
this.user = { features: 'mock-features' }
|
|
|
|
this.ProjectGetter = {
|
|
|
|
getProjectWithoutDocLines: sinon
|
|
|
|
.stub()
|
|
|
|
.callsArgWith(1, null, this.project),
|
|
|
|
getProject: sinon.stub().callsArgWith(2, null, this.project)
|
|
|
|
}
|
|
|
|
this.ProjectModel = {
|
|
|
|
update: sinon.stub(),
|
|
|
|
findOne: sinon.stub()
|
|
|
|
}
|
|
|
|
this.UserGetter = { getUser: sinon.stub().callsArgWith(1, null, this.user) }
|
|
|
|
this.tpdsUpdateSender = { moveEntity: sinon.stub().callsArgWith(1) }
|
|
|
|
this.ProjectEntityHandler = {
|
|
|
|
flushProjectToThirdPartyDataStore: sinon.stub().callsArg(1)
|
|
|
|
}
|
|
|
|
this.CollaboratorsHandler = {
|
|
|
|
removeUserFromProject: sinon.stub().callsArg(2)
|
|
|
|
}
|
|
|
|
return (this.handler = SandboxedModule.require(modulePath, {
|
|
|
|
requires: {
|
|
|
|
'./ProjectGetter': this.ProjectGetter,
|
|
|
|
'../../models/Project': {
|
|
|
|
Project: this.ProjectModel
|
|
|
|
},
|
|
|
|
'../User/UserGetter': this.UserGetter,
|
|
|
|
'../ThirdPartyDataStore/TpdsUpdateSender': this.tpdsUpdateSender,
|
|
|
|
'./ProjectEntityHandler': this.ProjectEntityHandler,
|
|
|
|
'../Collaborators/CollaboratorsHandler': this.CollaboratorsHandler,
|
|
|
|
'logger-sharelatex': {
|
|
|
|
log() {},
|
|
|
|
err() {}
|
|
|
|
},
|
|
|
|
'./ProjectTokenGenerator': (this.ProjectTokenGenerator = {}),
|
|
|
|
'settings-sharelatex': (this.settings = {
|
|
|
|
defaultFeatures: 'default-features'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('getDetails', function() {
|
|
|
|
it('should find the project and owner', function(done) {
|
|
|
|
return this.handler.getDetails(this.project_id, (err, details) => {
|
|
|
|
details.name.should.equal(this.project.name)
|
|
|
|
details.description.should.equal(this.project.description)
|
|
|
|
details.compiler.should.equal(this.project.compiler)
|
|
|
|
details.features.should.equal(this.user.features)
|
|
|
|
assert.equal(details.something, undefined)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should find overleaf metadata if it exists', function(done) {
|
|
|
|
this.project.overleaf = { id: 'id' }
|
|
|
|
return this.handler.getDetails(this.project_id, (err, details) => {
|
|
|
|
details.overleaf.should.equal(this.project.overleaf)
|
|
|
|
assert.equal(details.something, undefined)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return an error for a non-existent project', function(done) {
|
|
|
|
this.ProjectGetter.getProject.callsArg(2, null, null)
|
|
|
|
const err = new Errors.NotFoundError('project not found')
|
|
|
|
return this.handler.getDetails(
|
|
|
|
'0123456789012345678901234',
|
|
|
|
(error, details) => {
|
|
|
|
err.should.eql(error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return the default features if no owner found', function(done) {
|
|
|
|
this.UserGetter.getUser.callsArgWith(1, null, null)
|
|
|
|
return this.handler.getDetails(this.project_id, (err, details) => {
|
|
|
|
details.features.should.equal(this.settings.defaultFeatures)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should return the error', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
const error = 'some error'
|
|
|
|
this.ProjectGetter.getProject.callsArgWith(2, error)
|
|
|
|
return this.handler.getDetails(this.project_id, err => {
|
|
|
|
err.should.equal(error)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('transferOwnership', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.handler.generateUniqueName = sinon
|
|
|
|
.stub()
|
|
|
|
.callsArgWith(2, null, 'teapot')
|
|
|
|
return this.ProjectModel.update.callsArgWith(2)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("should return a not found error if the project can't be found", function(done) {
|
|
|
|
this.ProjectGetter.getProject.callsArgWith(2)
|
|
|
|
return this.handler.transferOwnership('abc', '123', function(err) {
|
|
|
|
err.should.exist
|
|
|
|
err.name.should.equal('NotFoundError')
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it("should return a not found error if the user can't be found", function(done) {
|
|
|
|
this.ProjectGetter.getProject.callsArgWith(2)
|
|
|
|
return this.handler.transferOwnership('abc', '123', function(err) {
|
|
|
|
err.should.exist
|
|
|
|
err.name.should.equal('NotFoundError')
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return an error if user cannot be removed as collaborator ', function(done) {
|
|
|
|
const errorMessage = 'user-cannot-be-removed'
|
|
|
|
this.CollaboratorsHandler.removeUserFromProject.callsArgWith(
|
|
|
|
2,
|
|
|
|
errorMessage
|
|
|
|
)
|
|
|
|
return this.handler.transferOwnership('abc', '123', function(err) {
|
|
|
|
err.should.exist
|
|
|
|
err.should.equal(errorMessage)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should transfer ownership of the project', function(done) {
|
|
|
|
return this.handler.transferOwnership('abc', '123', () => {
|
|
|
|
sinon.assert.calledWith(
|
|
|
|
this.ProjectModel.update,
|
|
|
|
{ _id: 'abc' },
|
|
|
|
sinon.match({ $set: { name: 'teapot' } })
|
|
|
|
)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it("should remove the user from the project's collaborators", function(done) {
|
|
|
|
return this.handler.transferOwnership('abc', '123', () => {
|
|
|
|
sinon.assert.calledWith(
|
|
|
|
this.CollaboratorsHandler.removeUserFromProject,
|
|
|
|
'abc',
|
|
|
|
'123'
|
|
|
|
)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should flush the project to tpds', function(done) {
|
|
|
|
return this.handler.transferOwnership('abc', '123', () => {
|
|
|
|
sinon.assert.calledWith(
|
|
|
|
this.ProjectEntityHandler.flushProjectToThirdPartyDataStore,
|
|
|
|
'abc'
|
|
|
|
)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should generate a unique name for the project', function(done) {
|
|
|
|
return this.handler.transferOwnership('abc', '123', () => {
|
|
|
|
sinon.assert.calledWith(
|
|
|
|
this.handler.generateUniqueName,
|
|
|
|
'123',
|
|
|
|
this.project.name
|
|
|
|
)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should append the supplied suffix to the project name, if passed', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return this.handler.transferOwnership('abc', '123', ' wombat', () => {
|
|
|
|
sinon.assert.calledWith(
|
|
|
|
this.handler.generateUniqueName,
|
|
|
|
'123',
|
|
|
|
`${this.project.name} wombat`
|
|
|
|
)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('getProjectDescription', function() {
|
|
|
|
it('should make a call to mongo just for the description', function(done) {
|
|
|
|
this.ProjectGetter.getProject.callsArgWith(2)
|
|
|
|
return this.handler.getProjectDescription(
|
|
|
|
this.project_id,
|
|
|
|
(err, description) => {
|
|
|
|
this.ProjectGetter.getProject
|
|
|
|
.calledWith(this.project_id, { description: true })
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should return what the mongo call returns', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
const err = 'error'
|
|
|
|
const description = 'cool project'
|
|
|
|
this.ProjectGetter.getProject.callsArgWith(2, err, { description })
|
|
|
|
return this.handler.getProjectDescription(
|
|
|
|
this.project_id,
|
|
|
|
(returnedErr, returnedDescription) => {
|
|
|
|
err.should.equal(returnedErr)
|
|
|
|
description.should.equal(returnedDescription)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('setProjectDescription', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
return (this.description = 'updated teh description')
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should update the project detials', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
this.ProjectModel.update.callsArgWith(2)
|
|
|
|
return this.handler.setProjectDescription(
|
|
|
|
this.project_id,
|
|
|
|
this.description,
|
|
|
|
() => {
|
|
|
|
this.ProjectModel.update
|
|
|
|
.calledWith(
|
|
|
|
{ _id: this.project_id },
|
|
|
|
{ description: this.description }
|
|
|
|
)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('renameProject', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.handler.validateProjectName = sinon.stub().yields()
|
|
|
|
this.ProjectModel.update.callsArgWith(2)
|
|
|
|
return (this.newName = 'new name here')
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should update the project with the new name', function(done) {
|
|
|
|
const newName = 'new name here'
|
|
|
|
return this.handler.renameProject(this.project_id, this.newName, () => {
|
|
|
|
this.ProjectModel.update
|
|
|
|
.calledWith({ _id: this.project_id }, { name: this.newName })
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should tell the tpdsUpdateSender', function(done) {
|
|
|
|
return this.handler.renameProject(this.project_id, this.newName, () => {
|
|
|
|
this.tpdsUpdateSender.moveEntity
|
|
|
|
.calledWith({
|
|
|
|
project_id: this.project_id,
|
|
|
|
project_name: this.project.name,
|
|
|
|
newProjectName: this.newName
|
|
|
|
})
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should not do anything with an invalid name', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
this.handler.validateProjectName = sinon
|
|
|
|
.stub()
|
|
|
|
.yields(new Error('invalid name'))
|
|
|
|
return this.handler.renameProject(this.project_id, this.newName, () => {
|
|
|
|
this.tpdsUpdateSender.moveEntity.called.should.equal(false)
|
|
|
|
this.ProjectModel.update.called.should.equal(false)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('validateProjectName', function() {
|
|
|
|
it('should reject undefined names', function(done) {
|
|
|
|
return this.handler.validateProjectName(undefined, function(error) {
|
|
|
|
expect(error).to.exist
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should reject empty names', function(done) {
|
|
|
|
return this.handler.validateProjectName('', function(error) {
|
|
|
|
expect(error).to.exist
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should reject names with /s', function(done) {
|
|
|
|
return this.handler.validateProjectName('foo/bar', function(error) {
|
|
|
|
expect(error).to.exist
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should reject names with \\s', function(done) {
|
|
|
|
return this.handler.validateProjectName('foo\\bar', function(error) {
|
|
|
|
expect(error).to.exist
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should reject long names', function(done) {
|
|
|
|
return this.handler.validateProjectName(
|
|
|
|
new Array(1000).join('a'),
|
|
|
|
function(error) {
|
|
|
|
expect(error).to.exist
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should accept normal names', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return this.handler.validateProjectName('foobar', function(error) {
|
|
|
|
expect(error).to.not.exist
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('ensureProjectNameIsUnique', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.result = {
|
|
|
|
owned: [
|
|
|
|
{ _id: 1, name: 'name' },
|
|
|
|
{ _id: 2, name: 'name1' },
|
|
|
|
{ _id: 3, name: 'name11' },
|
|
|
|
{ _id: 100, name: 'numeric' }
|
|
|
|
],
|
|
|
|
readAndWrite: [{ _id: 4, name: 'name2' }, { _id: 5, name: 'name22' }],
|
|
|
|
readOnly: [{ _id: 6, name: 'name3' }, { _id: 7, name: 'name33' }],
|
|
|
|
tokenReadAndWrite: [
|
|
|
|
{ _id: 8, name: 'name4' },
|
|
|
|
{ _id: 9, name: 'name44' }
|
|
|
|
],
|
|
|
|
tokenReadOnly: [
|
|
|
|
{ _id: 10, name: 'name5' },
|
|
|
|
{ _id: 11, name: 'name55' },
|
|
|
|
{ _id: 12, name: 'x'.repeat(15) }
|
|
|
|
]
|
|
|
|
}
|
|
|
|
for (let i of Array.from(
|
|
|
|
[
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
3,
|
|
|
|
4,
|
|
|
|
5,
|
|
|
|
6,
|
|
|
|
7,
|
|
|
|
8,
|
|
|
|
9,
|
|
|
|
10,
|
|
|
|
11,
|
|
|
|
12,
|
|
|
|
13,
|
|
|
|
14,
|
|
|
|
15,
|
|
|
|
16,
|
|
|
|
17,
|
|
|
|
18,
|
|
|
|
19,
|
|
|
|
20
|
|
|
|
].concat([30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40])
|
|
|
|
)) {
|
|
|
|
this.result.owned.push({ _id: 100 + i, name: `numeric (${i})` })
|
|
|
|
}
|
|
|
|
return (this.ProjectGetter.findAllUsersProjects = sinon
|
|
|
|
.stub()
|
|
|
|
.callsArgWith(2, null, this.result))
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should leave a unique name unchanged', function(done) {
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'unique-name',
|
|
|
|
['-test-suffix'],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('unique-name')
|
|
|
|
expect(changed).to.equal(false)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should append a suffix to an existing name', function(done) {
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'name1',
|
|
|
|
['-test-suffix'],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('name1-test-suffix')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should fallback to a second suffix when needed', function(done) {
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'name1',
|
|
|
|
['1', '-test-suffix'],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('name1-test-suffix')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should truncate the name when append a suffix if the result is too long', function(done) {
|
|
|
|
this.handler.MAX_PROJECT_NAME_LENGTH = 20
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'x'.repeat(15),
|
|
|
|
['-test-suffix'],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('x'.repeat(8) + '-test-suffix')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should use a numeric index if no suffix is supplied', function(done) {
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'name1',
|
|
|
|
[],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('name1 (1)')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should use a numeric index if all suffixes are exhausted', function(done) {
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'name',
|
|
|
|
['1', '11'],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('name (1)')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should find the next lowest available numeric index for the base name', function(done) {
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'numeric',
|
|
|
|
[],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('numeric (21)')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should find the next available numeric index when a numeric index is already present', function(done) {
|
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'numeric (5)',
|
|
|
|
[],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('numeric (21)')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should not find a numeric index lower than the one already present', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return this.handler.ensureProjectNameIsUnique(
|
|
|
|
this.user_id,
|
|
|
|
'numeric (31)',
|
|
|
|
[],
|
|
|
|
function(error, name, changed) {
|
|
|
|
expect(name).to.equal('numeric (41)')
|
|
|
|
expect(changed).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('fixProjectName', function() {
|
|
|
|
it('should change empty names to Untitled', function() {
|
|
|
|
return expect(this.handler.fixProjectName('')).to.equal('Untitled')
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should replace / with -', function() {
|
|
|
|
return expect(this.handler.fixProjectName('foo/bar')).to.equal('foo-bar')
|
|
|
|
})
|
|
|
|
|
|
|
|
it("should replace \\ with ''", function() {
|
|
|
|
return expect(this.handler.fixProjectName('foo \\ bar')).to.equal(
|
|
|
|
'foo bar'
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should truncate long names', function() {
|
|
|
|
return expect(
|
|
|
|
this.handler.fixProjectName(new Array(1000).join('a'))
|
|
|
|
).to.equal('a'.repeat(150))
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should accept normal names', function() {
|
2019-05-29 05:21:06 -04:00
|
|
|
return expect(this.handler.fixProjectName('foobar')).to.equal('foobar')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('setPublicAccessLevel', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.ProjectModel.update.callsArgWith(2)
|
|
|
|
return (this.accessLevel = 'readOnly')
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should update the project with the new level', function(done) {
|
|
|
|
return this.handler.setPublicAccessLevel(
|
|
|
|
this.project_id,
|
|
|
|
this.accessLevel,
|
|
|
|
() => {
|
|
|
|
this.ProjectModel.update
|
|
|
|
.calledWith(
|
|
|
|
{ _id: this.project_id },
|
|
|
|
{ publicAccesLevel: this.accessLevel }
|
|
|
|
)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should not produce an error', function(done) {
|
|
|
|
return this.handler.setPublicAccessLevel(
|
|
|
|
this.project_id,
|
|
|
|
this.accessLevel,
|
|
|
|
err => {
|
|
|
|
expect(err).to.not.exist
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
describe('when update produces an error', function() {
|
2019-05-29 05:21:06 -04:00
|
|
|
beforeEach(function() {
|
|
|
|
return this.ProjectModel.update.callsArgWith(2, new Error('woops'))
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should produce an error', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return this.handler.setPublicAccessLevel(
|
|
|
|
this.project_id,
|
|
|
|
this.accessLevel,
|
|
|
|
err => {
|
|
|
|
expect(err).to.exist
|
|
|
|
expect(err).to.be.instanceof(Error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
describe('ensureTokensArePresent', function() {
|
2019-05-29 05:21:06 -04:00
|
|
|
beforeEach(function() {})
|
|
|
|
|
|
|
|
describe('when the project has tokens', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.project = {
|
|
|
|
_id: this.project_id,
|
|
|
|
tokens: {
|
|
|
|
readOnly: 'aaa',
|
|
|
|
readAndWrite: '42bbb',
|
|
|
|
readAndWritePrefix: '42'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.ProjectGetter.getProject = sinon
|
|
|
|
.stub()
|
|
|
|
.callsArgWith(2, null, this.project)
|
|
|
|
return (this.ProjectModel.update = sinon.stub())
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should get the project', function(done) {
|
|
|
|
return this.handler.ensureTokensArePresent(
|
|
|
|
this.project_id,
|
|
|
|
(err, tokens) => {
|
|
|
|
expect(this.ProjectGetter.getProject.callCount).to.equal(1)
|
|
|
|
expect(
|
|
|
|
this.ProjectGetter.getProject.calledWith(this.project_id, {
|
|
|
|
tokens: 1
|
|
|
|
})
|
|
|
|
).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should not update the project with new tokens', function(done) {
|
|
|
|
return this.handler.ensureTokensArePresent(
|
|
|
|
this.project_id,
|
|
|
|
(err, tokens) => {
|
|
|
|
expect(this.ProjectModel.update.callCount).to.equal(0)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should produce the tokens without error', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return this.handler.ensureTokensArePresent(
|
|
|
|
this.project_id,
|
|
|
|
(err, tokens) => {
|
|
|
|
expect(err).to.not.exist
|
|
|
|
expect(tokens).to.deep.equal(this.project.tokens)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
describe('when tokens are missing', function() {
|
2019-05-29 05:21:06 -04:00
|
|
|
beforeEach(function() {
|
|
|
|
this.project = { _id: this.project_id }
|
|
|
|
this.ProjectGetter.getProject = sinon
|
|
|
|
.stub()
|
|
|
|
.callsArgWith(2, null, this.project)
|
|
|
|
this.readOnlyToken = 'abc'
|
|
|
|
this.readAndWriteToken = '42def'
|
|
|
|
this.readAndWriteTokenPrefix = '42'
|
|
|
|
this.ProjectTokenGenerator.generateUniqueReadOnlyToken = sinon
|
|
|
|
.stub()
|
|
|
|
.callsArgWith(0, null, this.readOnlyToken)
|
|
|
|
this.ProjectTokenGenerator.readAndWriteToken = sinon.stub().returns({
|
|
|
|
token: this.readAndWriteToken,
|
|
|
|
numericPrefix: this.readAndWriteTokenPrefix
|
|
|
|
})
|
|
|
|
return (this.ProjectModel.update = sinon.stub().callsArgWith(2, null))
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should get the project', function(done) {
|
|
|
|
return this.handler.ensureTokensArePresent(
|
|
|
|
this.project_id,
|
|
|
|
(err, tokens) => {
|
|
|
|
expect(this.ProjectGetter.getProject.callCount).to.equal(1)
|
|
|
|
expect(
|
|
|
|
this.ProjectGetter.getProject.calledWith(this.project_id, {
|
|
|
|
tokens: 1
|
|
|
|
})
|
|
|
|
).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should update the project with new tokens', function(done) {
|
|
|
|
return this.handler.ensureTokensArePresent(
|
|
|
|
this.project_id,
|
|
|
|
(err, tokens) => {
|
|
|
|
expect(
|
|
|
|
this.ProjectTokenGenerator.generateUniqueReadOnlyToken.callCount
|
|
|
|
).to.equal(1)
|
|
|
|
expect(
|
|
|
|
this.ProjectTokenGenerator.readAndWriteToken.callCount
|
|
|
|
).to.equal(1)
|
|
|
|
expect(this.ProjectModel.update.callCount).to.equal(1)
|
|
|
|
expect(
|
|
|
|
this.ProjectModel.update.calledWith(
|
|
|
|
{ _id: this.project_id },
|
|
|
|
{
|
|
|
|
$set: {
|
|
|
|
tokens: {
|
|
|
|
readOnly: this.readOnlyToken,
|
|
|
|
readAndWrite: this.readAndWriteToken,
|
|
|
|
readAndWritePrefix: this.readAndWriteTokenPrefix
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-06-21 09:46:09 -04:00
|
|
|
it('should produce the tokens without error', function(done) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return this.handler.ensureTokensArePresent(
|
|
|
|
this.project_id,
|
|
|
|
(err, tokens) => {
|
|
|
|
expect(err).to.not.exist
|
|
|
|
expect(tokens).to.deep.equal({
|
|
|
|
readOnly: this.readOnlyToken,
|
|
|
|
readAndWrite: this.readAndWriteToken,
|
|
|
|
readAndWritePrefix: this.readAndWriteTokenPrefix
|
|
|
|
})
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|