| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- const { expect } = require('chai')
- const { ObjectId } = require('mongodb')
- const Path = require('path')
- const fs = require('fs')
- const { Project } = require('../../../app/src/models/Project')
- const ProjectGetter = require('../../../app/src/Features/Project/ProjectGetter.js')
- const User = require('./helpers/User')
- const MockDocStoreApiClass = require('./mocks/MockDocstoreApi')
- const MockDocUpdaterApiClass = require('./mocks/MockDocUpdaterApi')
- let MockDocStoreApi, MockDocUpdaterApi
- before(function () {
- MockDocUpdaterApi = MockDocUpdaterApiClass.instance()
- MockDocStoreApi = MockDocStoreApiClass.instance()
- })
- describe('ProjectStructureChanges', function () {
- let owner
- beforeEach(function (done) {
- owner = new User()
- owner.login(done)
- })
- function createExampleProject(owner, callback) {
- owner.createProject(
- 'example-project',
- { template: 'example' },
- (error, projectId) => {
- if (error) {
- return callback(error)
- }
- ProjectGetter.getProject(projectId, (error, project) => {
- if (error) {
- return callback(error)
- }
- const rootFolderId = project.rootFolder[0]._id.toString()
- callback(null, projectId, rootFolderId)
- })
- }
- )
- }
- function createExampleDoc(owner, projectId, callback) {
- ProjectGetter.getProject(projectId, (error, project) => {
- if (error) {
- return callback(error)
- }
- owner.request.post(
- {
- uri: `project/${projectId}/doc`,
- json: {
- name: 'new.tex',
- parent_folder_id: project.rootFolder[0]._id,
- },
- },
- (error, res, body) => {
- if (error) {
- return callback(error)
- }
- if (res.statusCode < 200 || res.statusCode >= 300) {
- return callback(new Error(`failed to add doc ${res.statusCode}`))
- }
- callback(null, body._id)
- }
- )
- })
- }
- function createExampleFolder(owner, projectId, callback) {
- owner.request.post(
- {
- uri: `project/${projectId}/folder`,
- json: {
- name: 'foo',
- },
- },
- (error, res, body) => {
- if (error) {
- return callback(error)
- }
- if (res.statusCode < 200 || res.statusCode >= 300) {
- return callback(new Error(`failed to add doc ${res.statusCode}`))
- }
- callback(null, body._id)
- }
- )
- }
- function uploadExampleProject(owner, zipFilename, options, callback) {
- if (typeof options === 'function') {
- callback = options
- options = {}
- }
- const zipFile = fs.createReadStream(
- Path.resolve(Path.join(__dirname, '..', 'files', zipFilename))
- )
- owner.request.post(
- {
- uri: 'project/new/upload',
- formData: {
- qqfile: zipFile,
- },
- },
- (error, res, body) => {
- if (error) {
- return callback(error)
- }
- if (
- !options.allowBadStatus &&
- (res.statusCode < 200 || res.statusCode >= 300)
- ) {
- return new Error(`failed to upload project ${res.statusCode}`)
- }
- callback(null, JSON.parse(body).project_id, res)
- }
- )
- }
- function deleteItem(owner, projectId, type, itemId, callback) {
- owner.deleteItemInProject(projectId, type, itemId, callback)
- }
- describe('uploading a project with a name', function () {
- let exampleProjectId
- const testProjectName = 'wombat'
- beforeEach(function (done) {
- uploadExampleProject(
- owner,
- 'test_project_with_name.zip',
- (err, projectId) => {
- if (err) {
- return done(err)
- }
- exampleProjectId = projectId
- done()
- }
- )
- })
- it('should set the project name from the zip contents', function (done) {
- ProjectGetter.getProject(exampleProjectId, (error, project) => {
- expect(error).not.to.exist
- expect(project.name).to.equal(testProjectName)
- done()
- })
- })
- })
- describe('uploading a project with an invalid name', function () {
- let exampleProjectId
- const testProjectMatch = /^bad[^\\]+name$/
- beforeEach(function (done) {
- uploadExampleProject(
- owner,
- 'test_project_with_invalid_name.zip',
- (error, projectId) => {
- if (error) {
- return done(error)
- }
- exampleProjectId = projectId
- done()
- }
- )
- })
- it('should set the project name from the zip contents', function (done) {
- ProjectGetter.getProject(exampleProjectId, (error, project) => {
- expect(error).not.to.exist
- expect(project.name).to.match(testProjectMatch)
- done()
- })
- })
- })
- describe('uploading an empty zipfile', function () {
- let res
- beforeEach(function (done) {
- uploadExampleProject(
- owner,
- 'test_project_empty.zip',
- { allowBadStatus: true },
- (err, projectId, response) => {
- if (err) {
- return done(err)
- }
- res = response
- done()
- }
- )
- })
- it('should fail with 422 error', function () {
- expect(res.statusCode).to.equal(422)
- })
- })
- describe('uploading a zipfile containing only empty directories', function () {
- let res
- beforeEach(function (done) {
- uploadExampleProject(
- owner,
- 'test_project_with_empty_folder.zip',
- { allowBadStatus: true },
- (err, projectId, response) => {
- if (err) {
- return done(err)
- }
- res = response
- done()
- }
- )
- })
- it('should fail with 422 error', function () {
- expect(res.statusCode).to.equal(422)
- })
- })
- describe('uploading a project with a shared top-level folder', function () {
- let exampleProjectId
- beforeEach(function (done) {
- uploadExampleProject(
- owner,
- 'test_project_with_shared_top_level_folder.zip',
- (err, projectId) => {
- if (err) {
- return done(err)
- }
- exampleProjectId = projectId
- done()
- }
- )
- })
- it('should not create the top-level folder', function (done) {
- ProjectGetter.getProject(exampleProjectId, (error, project) => {
- expect(error).not.to.exist
- expect(project.rootFolder[0].folders.length).to.equal(0)
- expect(project.rootFolder[0].docs.length).to.equal(2)
- done()
- })
- })
- })
- describe('uploading a project with backslashes in the path names', function () {
- let exampleProjectId
- beforeEach(function (done) {
- uploadExampleProject(
- owner,
- 'test_project_with_backslash_in_filename.zip',
- (err, projectId) => {
- if (err) {
- return done(err)
- }
- exampleProjectId = projectId
- done()
- }
- )
- })
- it('should treat the backslash as a directory separator', function (done) {
- ProjectGetter.getProject(exampleProjectId, (error, project) => {
- expect(error).not.to.exist
- expect(project.rootFolder[0].folders[0].name).to.equal('styles')
- expect(project.rootFolder[0].folders[0].docs[0].name).to.equal('ao.sty')
- done()
- })
- })
- })
- describe('deleting docs', function () {
- beforeEach(function (done) {
- createExampleProject(owner, (err, projectId) => {
- if (err) {
- return done(err)
- }
- this.exampleProjectId = projectId
- createExampleFolder(owner, projectId, (err, folderId) => {
- if (err) {
- return done(err)
- }
- this.exampleFolderId = folderId
- createExampleDoc(owner, projectId, (err, docId) => {
- if (err) {
- return done(err)
- }
- this.exampleDocId = docId
- MockDocUpdaterApi.reset()
- ProjectGetter.getProject(
- this.exampleProjectId,
- (error, project) => {
- if (error) {
- throw error
- }
- this.project0 = project
- done()
- }
- )
- })
- })
- })
- })
- it('should pass the doc name to docstore', function (done) {
- deleteItem(
- owner,
- this.exampleProjectId,
- 'doc',
- this.exampleDocId,
- error => {
- if (error) return done(error)
- expect(
- MockDocStoreApi.getDeletedDocs(this.exampleProjectId)
- ).to.deep.equal([{ _id: this.exampleDocId, name: 'new.tex' }])
- done()
- }
- )
- })
- describe('when rootDoc_id matches doc being deleted', function () {
- beforeEach(function (done) {
- Project.updateOne(
- { _id: this.exampleProjectId },
- { $set: { rootDoc_id: this.exampleDocId } },
- done
- )
- })
- it('should clear rootDoc_id', function (done) {
- deleteItem(
- owner,
- this.exampleProjectId,
- 'doc',
- this.exampleDocId,
- () => {
- ProjectGetter.getProject(
- this.exampleProjectId,
- (error, project) => {
- if (error) {
- throw error
- }
- expect(project.rootDoc_id).to.be.undefined
- done()
- }
- )
- }
- )
- })
- })
- describe('when rootDoc_id does not match doc being deleted', function () {
- beforeEach(function (done) {
- this.exampleRootDocId = new ObjectId()
- Project.updateOne(
- { _id: this.exampleProjectId },
- { $set: { rootDoc_id: this.exampleRootDocId } },
- done
- )
- })
- it('should not clear rootDoc_id', function (done) {
- deleteItem(
- owner,
- this.exampleProjectId,
- 'doc',
- this.exampleDocId,
- () => {
- ProjectGetter.getProject(
- this.exampleProjectId,
- (error, project) => {
- if (error) {
- throw error
- }
- expect(project.rootDoc_id.toString()).to.equal(
- this.exampleRootDocId.toString()
- )
- done()
- }
- )
- }
- )
- })
- })
- })
- })
|