mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #2639 from overleaf/em-convert-doc-to-file
Endpoint for converting a doc to a file GitOrigin-RevId: 0a3bd46a7a78537b0f64dc577402277cbe81fecb
This commit is contained in:
parent
693100358c
commit
2627595040
9 changed files with 1011 additions and 615 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
const HttpErrors = require('@overleaf/o-error/http')
|
||||||
const ProjectDeleter = require('../Project/ProjectDeleter')
|
const ProjectDeleter = require('../Project/ProjectDeleter')
|
||||||
const EditorController = require('./EditorController')
|
const EditorController = require('./EditorController')
|
||||||
const ProjectGetter = require('../Project/ProjectGetter')
|
const ProjectGetter = require('../Project/ProjectGetter')
|
||||||
|
@ -11,6 +12,7 @@ const PrivilegeLevels = require('../Authorization/PrivilegeLevels')
|
||||||
const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
|
const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
|
||||||
const AuthenticationController = require('../Authentication/AuthenticationController')
|
const AuthenticationController = require('../Authentication/AuthenticationController')
|
||||||
const Errors = require('../Errors/Errors')
|
const Errors = require('../Errors/Errors')
|
||||||
|
const ProjectEntityUpdateHandler = require('../Project/ProjectEntityUpdateHandler')
|
||||||
const { expressify } = require('../../util/promises')
|
const { expressify } = require('../../util/promises')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -23,6 +25,7 @@ module.exports = {
|
||||||
deleteFile: expressify(deleteFile),
|
deleteFile: expressify(deleteFile),
|
||||||
deleteFolder: expressify(deleteFolder),
|
deleteFolder: expressify(deleteFolder),
|
||||||
deleteEntity: expressify(deleteEntity),
|
deleteEntity: expressify(deleteEntity),
|
||||||
|
convertDocToFile: expressify(convertDocToFile),
|
||||||
_nameIsAcceptableLength
|
_nameIsAcceptableLength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,3 +224,25 @@ async function deleteEntity(req, res, next) {
|
||||||
)
|
)
|
||||||
res.sendStatus(204)
|
res.sendStatus(204)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function convertDocToFile(req, res, next) {
|
||||||
|
const projectId = req.params.Project_id
|
||||||
|
const docId = req.params.entity_id
|
||||||
|
const { userId } = req.body
|
||||||
|
try {
|
||||||
|
const fileRef = await ProjectEntityUpdateHandler.promises.convertDocToFile(
|
||||||
|
projectId,
|
||||||
|
docId,
|
||||||
|
userId
|
||||||
|
)
|
||||||
|
res.json({ fileId: fileRef._id.toString() })
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof Errors.NotFoundError) {
|
||||||
|
throw new HttpErrors.NotFoundError({
|
||||||
|
info: { public: { message: 'Document not found' } }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ const EditorHttpController = require('./EditorHttpController')
|
||||||
const AuthenticationController = require('../Authentication/AuthenticationController')
|
const AuthenticationController = require('../Authentication/AuthenticationController')
|
||||||
const AuthorizationMiddleware = require('../Authorization/AuthorizationMiddleware')
|
const AuthorizationMiddleware = require('../Authorization/AuthorizationMiddleware')
|
||||||
const RateLimiterMiddleware = require('../Security/RateLimiterMiddleware')
|
const RateLimiterMiddleware = require('../Security/RateLimiterMiddleware')
|
||||||
|
const { Joi, validate } = require('../../infrastructure/Validation')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
apply(webRouter, apiRouter) {
|
apply(webRouter, apiRouter) {
|
||||||
|
@ -54,6 +55,16 @@ module.exports = {
|
||||||
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
|
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
|
||||||
EditorHttpController.deleteFolder
|
EditorHttpController.deleteFolder
|
||||||
)
|
)
|
||||||
|
apiRouter.post(
|
||||||
|
'/project/:Project_id/doc/:entity_id/convert-to-file',
|
||||||
|
AuthenticationController.httpAuth,
|
||||||
|
validate({
|
||||||
|
body: Joi.object({
|
||||||
|
userId: Joi.objectId().required()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
EditorHttpController.convertDocToFile
|
||||||
|
)
|
||||||
|
|
||||||
// Called by the real-time API to load up the current project state.
|
// Called by the real-time API to load up the current project state.
|
||||||
// This is a post request because it's more than just a getting of data. We take actions
|
// This is a post request because it's more than just a getting of data. We take actions
|
||||||
|
|
|
@ -224,6 +224,7 @@ module.exports = ProjectEntityHandler
|
||||||
module.exports.promises = promisifyAll(ProjectEntityHandler, {
|
module.exports.promises = promisifyAll(ProjectEntityHandler, {
|
||||||
multiResult: {
|
multiResult: {
|
||||||
getAllEntities: ['docs', 'files'],
|
getAllEntities: ['docs', 'files'],
|
||||||
getAllEntitiesFromProject: ['docs', 'files']
|
getAllEntitiesFromProject: ['docs', 'files'],
|
||||||
|
getDoc: ['lines', 'rev', 'version', 'ranges']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -47,6 +47,7 @@ module.exports = {
|
||||||
'path',
|
'path',
|
||||||
'newProject'
|
'newProject'
|
||||||
]),
|
]),
|
||||||
|
replaceDocWithFile: callbackify(replaceDocWithFile),
|
||||||
mkdirp: callbackifyMultiResult(wrapWithLock(mkdirp), [
|
mkdirp: callbackifyMultiResult(wrapWithLock(mkdirp), [
|
||||||
'newFolders',
|
'newFolders',
|
||||||
'folder'
|
'folder'
|
||||||
|
@ -81,6 +82,7 @@ module.exports = {
|
||||||
addFile: wrapWithLock(addFile),
|
addFile: wrapWithLock(addFile),
|
||||||
addFolder: wrapWithLock(addFolder),
|
addFolder: wrapWithLock(addFolder),
|
||||||
replaceFileWithNew: wrapWithLock(replaceFileWithNew),
|
replaceFileWithNew: wrapWithLock(replaceFileWithNew),
|
||||||
|
replaceDocWithFile: wrapWithLock(replaceDocWithFile),
|
||||||
mkdirp: wrapWithLock(mkdirp),
|
mkdirp: wrapWithLock(mkdirp),
|
||||||
moveEntity: wrapWithLock(moveEntity),
|
moveEntity: wrapWithLock(moveEntity),
|
||||||
deleteEntity: wrapWithLock(deleteEntity),
|
deleteEntity: wrapWithLock(deleteEntity),
|
||||||
|
@ -186,6 +188,33 @@ async function replaceFileWithNew(projectId, fileId, newFileRef) {
|
||||||
return { oldFileRef: fileRef, project, path, newProject }
|
return { oldFileRef: fileRef, project, path, newProject }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function replaceDocWithFile(projectId, docId, fileRef) {
|
||||||
|
const project = await ProjectGetter.promises.getProjectWithoutLock(
|
||||||
|
projectId,
|
||||||
|
{ rootFolder: true, name: true, overleaf: true }
|
||||||
|
)
|
||||||
|
const { path } = await ProjectLocator.promises.findElement({
|
||||||
|
project,
|
||||||
|
element_id: docId,
|
||||||
|
type: 'doc'
|
||||||
|
})
|
||||||
|
const folderMongoPath = _getParentMongoPath(path.mongo)
|
||||||
|
const newProject = await Project.findOneAndUpdate(
|
||||||
|
{ _id: project._id },
|
||||||
|
{
|
||||||
|
$pull: {
|
||||||
|
[`${folderMongoPath}.docs`]: { _id: docId }
|
||||||
|
},
|
||||||
|
$push: {
|
||||||
|
[`${folderMongoPath}.fileRefs`]: fileRef
|
||||||
|
},
|
||||||
|
$inc: { version: 1 }
|
||||||
|
},
|
||||||
|
{ new: true }
|
||||||
|
).exec()
|
||||||
|
return newProject
|
||||||
|
}
|
||||||
|
|
||||||
async function mkdirp(projectId, path, options = {}) {
|
async function mkdirp(projectId, path, options = {}) {
|
||||||
// defaults to case insensitive paths, use options {exactCaseMatch:true}
|
// defaults to case insensitive paths, use options {exactCaseMatch:true}
|
||||||
// to make matching case-sensitive
|
// to make matching case-sensitive
|
||||||
|
@ -637,3 +666,14 @@ async function createNewFolderStructure(projectId, docUploads, fileUploads) {
|
||||||
}).withCause(err)
|
}).withCause(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a Mongo path to an entity, return the Mongo path to the parent folder
|
||||||
|
*/
|
||||||
|
function _getParentMongoPath(mongoPath) {
|
||||||
|
const segments = mongoPath.split('.')
|
||||||
|
if (segments.length <= 2) {
|
||||||
|
throw new Error('Root folder has no parents')
|
||||||
|
}
|
||||||
|
return segments.slice(0, -2).join('.')
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ const async = require('async')
|
||||||
const logger = require('logger-sharelatex')
|
const logger = require('logger-sharelatex')
|
||||||
const Settings = require('settings-sharelatex')
|
const Settings = require('settings-sharelatex')
|
||||||
const Path = require('path')
|
const Path = require('path')
|
||||||
|
const fs = require('fs')
|
||||||
const { Doc } = require('../../models/Doc')
|
const { Doc } = require('../../models/Doc')
|
||||||
const DocstoreManager = require('../Docstore/DocstoreManager')
|
const DocstoreManager = require('../Docstore/DocstoreManager')
|
||||||
const DocumentUpdaterHandler = require('../../Features/DocumentUpdater/DocumentUpdaterHandler')
|
const DocumentUpdaterHandler = require('../../Features/DocumentUpdater/DocumentUpdaterHandler')
|
||||||
|
@ -18,6 +19,9 @@ const ProjectUpdateHandler = require('./ProjectUpdateHandler')
|
||||||
const ProjectEntityMongoUpdateHandler = require('./ProjectEntityMongoUpdateHandler')
|
const ProjectEntityMongoUpdateHandler = require('./ProjectEntityMongoUpdateHandler')
|
||||||
const SafePath = require('./SafePath')
|
const SafePath = require('./SafePath')
|
||||||
const TpdsUpdateSender = require('../ThirdPartyDataStore/TpdsUpdateSender')
|
const TpdsUpdateSender = require('../ThirdPartyDataStore/TpdsUpdateSender')
|
||||||
|
const FileWriter = require('../../infrastructure/FileWriter')
|
||||||
|
const EditorRealTimeController = require('../Editor/EditorRealTimeController')
|
||||||
|
const { promisifyAll } = require('../../util/promises')
|
||||||
|
|
||||||
const LOCK_NAMESPACE = 'sequentialProjectStructureUpdateLock'
|
const LOCK_NAMESPACE = 'sequentialProjectStructureUpdateLock'
|
||||||
const VALID_ROOT_DOC_EXTENSIONS = Settings.validRootDocExtensions
|
const VALID_ROOT_DOC_EXTENSIONS = Settings.validRootDocExtensions
|
||||||
|
@ -1512,7 +1516,146 @@ const ProjectEntityUpdateHandler = {
|
||||||
})
|
})
|
||||||
|
|
||||||
async.series(jobs, callback)
|
async.series(jobs, callback)
|
||||||
}
|
},
|
||||||
|
|
||||||
|
convertDocToFile: wrapWithLock({
|
||||||
|
beforeLock(next) {
|
||||||
|
return function(projectId, docId, userId, callback) {
|
||||||
|
DocumentUpdaterHandler.deleteDoc(projectId, docId, err => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
ProjectLocator.findElement(
|
||||||
|
{ project_id: projectId, element_id: docId, type: 'doc' },
|
||||||
|
(err, doc, path) => {
|
||||||
|
const docPath = path.fileSystem
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
DocstoreManager.getDoc(projectId, docId, (err, docLines) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
FileWriter.writeLinesToDisk(
|
||||||
|
projectId,
|
||||||
|
docLines,
|
||||||
|
(err, fsPath) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
FileStoreHandler.uploadFileFromDisk(
|
||||||
|
projectId,
|
||||||
|
{ name: doc.name },
|
||||||
|
fsPath,
|
||||||
|
(err, fileStoreUrl, fileRef) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
fs.unlink(fsPath, err => {
|
||||||
|
if (err) {
|
||||||
|
logger.warn(
|
||||||
|
{ err, path: fsPath },
|
||||||
|
'failed to clean up temporary file'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
next(
|
||||||
|
projectId,
|
||||||
|
doc,
|
||||||
|
docPath,
|
||||||
|
fileRef,
|
||||||
|
fileStoreUrl,
|
||||||
|
userId,
|
||||||
|
callback
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
withLock(projectId, doc, path, fileRef, fileStoreUrl, userId, callback) {
|
||||||
|
ProjectEntityMongoUpdateHandler.replaceDocWithFile(
|
||||||
|
projectId,
|
||||||
|
doc._id,
|
||||||
|
fileRef,
|
||||||
|
(err, project) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
const projectHistoryId =
|
||||||
|
project.overleaf &&
|
||||||
|
project.overleaf.history &&
|
||||||
|
project.overleaf.history.id
|
||||||
|
DocumentUpdaterHandler.updateProjectStructure(
|
||||||
|
projectId,
|
||||||
|
projectHistoryId,
|
||||||
|
userId,
|
||||||
|
{
|
||||||
|
oldDocs: [{ doc, path }],
|
||||||
|
newFiles: [{ file: fileRef, path, url: fileStoreUrl }],
|
||||||
|
newProject: project
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
ProjectLocator.findElement(
|
||||||
|
{
|
||||||
|
project_id: projectId,
|
||||||
|
element_id: fileRef._id,
|
||||||
|
type: 'file'
|
||||||
|
},
|
||||||
|
(err, element, path, folder) => {
|
||||||
|
if (err) {
|
||||||
|
return callback(err)
|
||||||
|
}
|
||||||
|
EditorRealTimeController.emitToRoom(
|
||||||
|
projectId,
|
||||||
|
'removeEntity',
|
||||||
|
doc._id,
|
||||||
|
'convertDocToFile'
|
||||||
|
)
|
||||||
|
EditorRealTimeController.emitToRoom(
|
||||||
|
projectId,
|
||||||
|
'reciveNewFile',
|
||||||
|
folder._id,
|
||||||
|
fileRef,
|
||||||
|
'convertDocToFile',
|
||||||
|
null
|
||||||
|
)
|
||||||
|
callback(null, fileRef)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ProjectEntityUpdateHandler
|
module.exports = ProjectEntityUpdateHandler
|
||||||
|
module.exports.promises = promisifyAll(ProjectEntityUpdateHandler, {
|
||||||
|
without: ['isPathValidForRootDoc'],
|
||||||
|
multiResult: {
|
||||||
|
copyFileFromExistingProjectWithProject: ['fileRef', 'folderId'],
|
||||||
|
_addDocAndSendToTpds: ['result', 'project'],
|
||||||
|
addDoc: ['doc', 'folderId'],
|
||||||
|
addDocWithRanges: ['doc', 'folderId'],
|
||||||
|
_uploadFile: ['fileStoreUrl', 'fileRef'],
|
||||||
|
_addFileAndSendToTpds: ['result', 'project'],
|
||||||
|
addFile: ['fileRef', 'folderId'],
|
||||||
|
upsertDoc: ['doc', 'isNew'],
|
||||||
|
upsertFile: ['fileRef', 'isNew', 'oldFileRef'],
|
||||||
|
upsertDocWithPath: ['doc', 'isNew', 'newFolders', 'folder'],
|
||||||
|
upsertFileWithPath: ['fileRef', 'isNew', 'oldFile', 'newFolders', 'folder'],
|
||||||
|
mkdirp: ['newFolders', 'folder'],
|
||||||
|
mkdirpWithExactCase: ['newFolders', 'folder'],
|
||||||
|
addFolder: ['folder', 'parentFolderId']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
@ -10,15 +10,15 @@
|
||||||
* DS207: Consider shorter variations of null checks
|
* DS207: Consider shorter variations of null checks
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
let FileWriter
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const logger = require('logger-sharelatex')
|
const logger = require('logger-sharelatex')
|
||||||
const uuid = require('uuid')
|
const uuid = require('uuid')
|
||||||
const _ = require('underscore')
|
const _ = require('underscore')
|
||||||
const Settings = require('settings-sharelatex')
|
const Settings = require('settings-sharelatex')
|
||||||
const request = require('request')
|
const request = require('request')
|
||||||
|
const { promisifyAll } = require('../util/promises')
|
||||||
|
|
||||||
module.exports = FileWriter = {
|
const FileWriter = {
|
||||||
ensureDumpFolderExists(callback) {
|
ensureDumpFolderExists(callback) {
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
callback = function(error) {}
|
callback = function(error) {}
|
||||||
|
@ -123,3 +123,6 @@ module.exports = FileWriter = {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = FileWriter
|
||||||
|
module.exports.promises = promisifyAll(FileWriter)
|
||||||
|
|
|
@ -29,8 +29,9 @@ describe('EditorHttpController', function() {
|
||||||
_id: this.projectView._id,
|
_id: this.projectView._id,
|
||||||
owner: { _id: this.projectView.owner._id }
|
owner: { _id: this.projectView.owner._id }
|
||||||
}
|
}
|
||||||
this.doc = { mock: 'doc' }
|
this.doc = { _id: new ObjectId(), name: 'excellent-original-idea.tex' }
|
||||||
this.folder = { mock: 'folder' }
|
this.file = { _id: new ObjectId() }
|
||||||
|
this.folder = { _id: new ObjectId() }
|
||||||
|
|
||||||
this.parentFolderId = 'mock-folder-id'
|
this.parentFolderId = 'mock-folder-id'
|
||||||
this.req = { i18n: { translate: string => string } }
|
this.req = { i18n: { translate: string => string } }
|
||||||
|
@ -42,6 +43,7 @@ describe('EditorHttpController', function() {
|
||||||
}
|
}
|
||||||
this.next = sinon.stub()
|
this.next = sinon.stub()
|
||||||
this.token = null
|
this.token = null
|
||||||
|
this.docLines = ['hello', 'overleaf']
|
||||||
|
|
||||||
this.AuthorizationManager = {
|
this.AuthorizationManager = {
|
||||||
isRestrictedUser: sinon.stub().returns(false),
|
isRestrictedUser: sinon.stub().returns(false),
|
||||||
|
@ -82,6 +84,7 @@ describe('EditorHttpController', function() {
|
||||||
this.EditorController = {
|
this.EditorController = {
|
||||||
promises: {
|
promises: {
|
||||||
addDoc: sinon.stub().resolves(this.doc),
|
addDoc: sinon.stub().resolves(this.doc),
|
||||||
|
addFile: sinon.stub().resolves(this.file),
|
||||||
addFolder: sinon.stub().resolves(this.folder),
|
addFolder: sinon.stub().resolves(this.folder),
|
||||||
renameEntity: sinon.stub().resolves(),
|
renameEntity: sinon.stub().resolves(),
|
||||||
moveEntity: sinon.stub().resolves(),
|
moveEntity: sinon.stub().resolves(),
|
||||||
|
@ -113,6 +116,11 @@ describe('EditorHttpController', function() {
|
||||||
this.AuthenticationController = {
|
this.AuthenticationController = {
|
||||||
getLoggedInUserId: sinon.stub().returns(this.user._id)
|
getLoggedInUserId: sinon.stub().returns(this.user._id)
|
||||||
}
|
}
|
||||||
|
this.ProjectEntityUpdateHandler = {
|
||||||
|
promises: {
|
||||||
|
convertDocToFile: sinon.stub().resolves(this.file)
|
||||||
|
}
|
||||||
|
}
|
||||||
this.EditorHttpController = SandboxedModule.require(MODULE_PATH, {
|
this.EditorHttpController = SandboxedModule.require(MODULE_PATH, {
|
||||||
globals: {
|
globals: {
|
||||||
console: console
|
console: console
|
||||||
|
@ -132,6 +140,9 @@ describe('EditorHttpController', function() {
|
||||||
'../TokenAccess/TokenAccessHandler': this.TokenAccessHandler,
|
'../TokenAccess/TokenAccessHandler': this.TokenAccessHandler,
|
||||||
'../Authentication/AuthenticationController': this
|
'../Authentication/AuthenticationController': this
|
||||||
.AuthenticationController,
|
.AuthenticationController,
|
||||||
|
'../../infrastructure/FileWriter': this.FileWriter,
|
||||||
|
'../Project/ProjectEntityUpdateHandler': this
|
||||||
|
.ProjectEntityUpdateHandler,
|
||||||
'../Errors/Errors': Errors
|
'../Errors/Errors': Errors
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -496,4 +507,32 @@ describe('EditorHttpController', function() {
|
||||||
expect(this.res.sendStatus).to.have.been.calledWith(204)
|
expect(this.res.sendStatus).to.have.been.calledWith(204)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('convertDocToFile', function() {
|
||||||
|
beforeEach(function(done) {
|
||||||
|
this.req.params = {
|
||||||
|
Project_id: this.project._id.toString(),
|
||||||
|
entity_id: this.doc._id.toString()
|
||||||
|
}
|
||||||
|
this.req.body = { userId: this.user._id.toString() }
|
||||||
|
this.res.json.callsFake(() => done())
|
||||||
|
this.EditorHttpController.convertDocToFile(this.req, this.res)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert the doc to a file', function() {
|
||||||
|
expect(
|
||||||
|
this.ProjectEntityUpdateHandler.promises.convertDocToFile
|
||||||
|
).to.have.been.calledWith(
|
||||||
|
this.project._id.toString(),
|
||||||
|
this.doc._id.toString(),
|
||||||
|
this.user._id.toString()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return the file id in the response', function() {
|
||||||
|
expect(this.res.json).to.have.been.calledWith({
|
||||||
|
fileId: this.file._id.toString()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1089,4 +1089,27 @@ describe('ProjectEntityMongoUpdateHandler', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('replaceDocWithFile', function() {
|
||||||
|
it('should simultaneously remove the doc and add the file', async function() {
|
||||||
|
this.ProjectMock.expects('findOneAndUpdate')
|
||||||
|
.withArgs(
|
||||||
|
{ _id: this.project._id },
|
||||||
|
{
|
||||||
|
$pull: { 'rootFolder.0.docs': { _id: this.doc._id } },
|
||||||
|
$push: { 'rootFolder.0.fileRefs': this.file },
|
||||||
|
$inc: { version: 1 }
|
||||||
|
},
|
||||||
|
{ new: true }
|
||||||
|
)
|
||||||
|
.chain('exec')
|
||||||
|
.resolves(this.project)
|
||||||
|
await this.subject.promises.replaceDocWithFile(
|
||||||
|
this.project._id,
|
||||||
|
this.doc._id,
|
||||||
|
this.file
|
||||||
|
)
|
||||||
|
this.ProjectMock.verify()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue