Merge branch 'master' into as-show-v1-warnings

This commit is contained in:
Alasdair Smith 2017-12-05 11:13:25 +00:00
commit ab6830976e
32 changed files with 774 additions and 251 deletions

View file

@ -204,11 +204,11 @@ module.exports = DocumentUpdaterHandler =
logger.error {project_id, doc_id, thread_id}, "doc updater returned a non-success status code: #{res.statusCode}"
callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
updateProjectStructure : (project_id, userId, oldDocs, newDocs, oldFiles, newFiles, callback = (error) ->)->
updateProjectStructure : (project_id, userId, changes, callback = (error) ->)->
return callback() if !settings.apis.project_history?.enabled
docUpdates = DocumentUpdaterHandler._getRenameUpdates('doc', oldDocs, newDocs)
fileUpdates = DocumentUpdaterHandler._getRenameUpdates('file', oldFiles, newFiles)
docUpdates = DocumentUpdaterHandler._getRenameUpdates('doc', changes.oldDocs, changes.newDocs)
fileUpdates = DocumentUpdaterHandler._getRenameUpdates('file', changes.oldFiles, changes.newFiles)
timer = new metrics.Timer("set-document")
url = "#{settings.apis.documentupdater.url}/project/#{project_id}"
@ -231,14 +231,25 @@ module.exports = DocumentUpdaterHandler =
callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
_getRenameUpdates: (entityType, oldEntities, newEntities) ->
oldEntities ||= []
newEntities ||= []
updates = []
for oldEntity in oldEntities
id = oldEntity[entityType]._id
newEntity = _.find newEntities, (newEntity) ->
newEntity[entityType]._id.toString() == id.toString()
oldEntitiesHash = _.indexBy oldEntities, (entity) -> entity[entityType]._id.toString()
newEntitiesHash = _.indexBy newEntities, (entity) -> entity[entityType]._id.toString()
if newEntity.path != oldEntity.path
for id, newEntity of newEntitiesHash
oldEntity = oldEntitiesHash[id]
if !oldEntity?
# entity added
updates.push
id: id
pathname: newEntity.path
docLines: newEntity.docLines
url: newEntity.url
else if newEntity.path != oldEntity.path
# entity renamed
updates.push
id: id
pathname: oldEntity.path

View file

@ -19,48 +19,48 @@ module.exports = EditorController =
DocumentUpdaterHandler.flushDocToMongo project_id, doc_id, callback
addDoc: (project_id, folder_id, docName, docLines, source, callback = (error, doc)->)->
addDoc: (project_id, folder_id, docName, docLines, source, user_id, callback = (error, doc)->)->
LockManager.getLock project_id, (err)->
if err?
logger.err err:err, project_id:project_id, source:source, "could not get lock to addDoc"
return callback(err)
EditorController.addDocWithoutLock project_id, folder_id, docName, docLines, source, (error, doc)->
EditorController.addDocWithoutLock project_id, folder_id, docName, docLines, source, user_id, (error, doc)->
LockManager.releaseLock project_id, ->
callback(error, doc)
addDocWithoutLock: (project_id, folder_id, docName, docLines, source, callback = (error, doc)->)->
addDocWithoutLock: (project_id, folder_id, docName, docLines, source, user_id, callback = (error, doc)->)->
docName = docName.trim()
logger.log {project_id, folder_id, docName, source}, "sending new doc to project"
Metrics.inc "editor.add-doc"
ProjectEntityHandler.addDoc project_id, folder_id, docName, docLines, (err, doc, folder_id)=>
ProjectEntityHandler.addDoc project_id, folder_id, docName, docLines, user_id, (err, doc, folder_id)=>
if err?
logger.err err:err, project_id:project_id, docName:docName, "error adding doc without lock"
return callback(err)
EditorRealTimeController.emitToRoom(project_id, 'reciveNewDoc', folder_id, doc, source)
callback(err, doc)
addFile: (project_id, folder_id, fileName, path, source, callback = (error, file)->)->
addFile: (project_id, folder_id, fileName, path, source, user_id, callback = (error, file)->)->
LockManager.getLock project_id, (err)->
if err?
logger.err err:err, project_id:project_id, source:source, "could not get lock to addFile"
return callback(err)
EditorController.addFileWithoutLock project_id, folder_id, fileName, path, source, (error, file)->
EditorController.addFileWithoutLock project_id, folder_id, fileName, path, source, user_id, (error, file)->
LockManager.releaseLock project_id, ->
callback(error, file)
addFileWithoutLock: (project_id, folder_id, fileName, path, source, callback = (error, file)->)->
addFileWithoutLock: (project_id, folder_id, fileName, path, source, user_id, callback = (error, file)->)->
fileName = fileName.trim()
logger.log {project_id, folder_id, fileName, path}, "sending new file to project"
Metrics.inc "editor.add-file"
ProjectEntityHandler.addFile project_id, folder_id, fileName, path, (err, fileRef, folder_id)=>
ProjectEntityHandler.addFile project_id, folder_id, fileName, path, user_id, (err, fileRef, folder_id)=>
if err?
logger.err err:err, project_id:project_id, folder_id:folder_id, fileName:fileName, "error adding file without lock"
return callback(err)
EditorRealTimeController.emitToRoom(project_id, 'reciveNewFile', folder_id, fileRef, source)
callback(err, fileRef)
replaceFile: (project_id, file_id, fsPath, source, callback = (error) ->)->
ProjectEntityHandler.replaceFile project_id, file_id, fsPath, callback
replaceFile: (project_id, file_id, fsPath, source, user_id, callback = (error) ->)->
ProjectEntityHandler.replaceFile project_id, file_id, fsPath, user_id, callback
addFolder : (project_id, folder_id, folderName, source, callback = (error, folder)->)->
LockManager.getLock project_id, (err)->

View file

@ -81,10 +81,11 @@ module.exports = EditorHttpController =
project_id = req.params.Project_id
name = req.body.name
parent_folder_id = req.body.parent_folder_id
user_id = AuthenticationController.getLoggedInUserId(req)
logger.log project_id:project_id, name:name, parent_folder_id:parent_folder_id, "getting request to add doc to project"
if !EditorHttpController._nameIsAcceptableLength(name)
return res.sendStatus 400
EditorController.addDoc project_id, parent_folder_id, name, [], "editor", (error, doc) ->
EditorController.addDoc project_id, parent_folder_id, name, [], "editor", user_id, (error, doc) ->
if error == "project_has_to_many_files"
res.status(400).json(req.i18n.translate("project_has_to_many_files"))
else if error?
@ -113,9 +114,9 @@ module.exports = EditorHttpController =
entity_id = req.params.entity_id
entity_type = req.params.entity_type
name = req.body.name
user_id = AuthenticationController.getLoggedInUserId(req)
if !EditorHttpController._nameIsAcceptableLength(name)
return res.sendStatus 400
user_id = AuthenticationController.getLoggedInUserId(req)
EditorController.renameEntity project_id, entity_id, entity_type, name, user_id, (error) ->
return next(error) if error?
res.sendStatus 204

View file

@ -21,9 +21,9 @@ module.exports = FileStoreHandler =
return callback(new Error("can not upload symlink"))
_cb = callback
callback = (err) ->
callback = (err, url) ->
callback = -> # avoid double callbacks
_cb(err)
_cb(err, url)
logger.log project_id:project_id, file_id:file_id, fsPath:fsPath, "uploading file from disk"
readStream = fs.createReadStream(fsPath)
@ -31,9 +31,10 @@ module.exports = FileStoreHandler =
logger.err err:err, project_id:project_id, file_id:file_id, fsPath:fsPath, "something went wrong on the read stream of uploadFileFromDisk"
callback err
readStream.on "open", () ->
url = FileStoreHandler._buildUrl(project_id, file_id)
opts =
method: "post"
uri: FileStoreHandler._buildUrl(project_id, file_id)
uri: url
timeout:fiveMinsInMs
writeStream = request(opts)
writeStream.on "error", (err)->
@ -45,7 +46,7 @@ module.exports = FileStoreHandler =
logger.err {err, statusCode: response.statusCode}, "error uploading to filestore"
callback(err)
else
callback(null)
callback(null, url)
readStream.pipe writeStream
getFileStream: (project_id, file_id, query, callback)->
@ -91,7 +92,7 @@ module.exports = FileStoreHandler =
request opts, (err)->
if err?
logger.err err:err, oldProject_id:oldProject_id, oldFile_id:oldFile_id, newProject_id:newProject_id, newFile_id:newFile_id, "something went wrong telling filestore api to copy file"
callback(err)
callback(err, opts.uri)
_buildUrl: (project_id, file_id)->
return "#{settings.apis.filestore.url}/project/#{project_id}/file/#{file_id}"

View file

@ -52,7 +52,7 @@ module.exports = ProjectCreationHandler =
return callback(error) if error?
self._buildTemplate "mainbasic.tex", owner_id, projectName, (error, docLines)->
return callback(error) if error?
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, (error, doc)->
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, owner_id, (error, doc)->
if error?
logger.err err:error, "error adding doc when creating basic project"
return callback(error)
@ -67,17 +67,17 @@ module.exports = ProjectCreationHandler =
(callback) ->
self._buildTemplate "main.tex", owner_id, projectName, (error, docLines)->
return callback(error) if error?
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, (error, doc)->
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, owner_id, (error, doc)->
return callback(error) if error?
ProjectEntityHandler.setRootDoc project._id, doc._id, callback
(callback) ->
self._buildTemplate "references.bib", owner_id, projectName, (error, docLines)->
return callback(error) if error?
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "references.bib", docLines, (error, doc)->
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "references.bib", docLines, owner_id, (error, doc)->
callback(error)
(callback) ->
universePath = Path.resolve(__dirname + "/../../../templates/project_files/universe.jpg")
ProjectEntityHandler.addFile project._id, project.rootFolder[0]._id, "universe.jpg", universePath, callback
ProjectEntityHandler.addFile project._id, project.rootFolder[0]._id, "universe.jpg", universePath, owner_id, callback
], (error) ->
callback(error, project)

View file

@ -12,7 +12,7 @@ logger = require("logger-sharelatex")
module.exports = ProjectDuplicator =
_copyDocs: (newProject, originalRootDoc, originalFolder, desFolder, docContents, callback)->
_copyDocs: (owner_id, newProject, originalRootDoc, originalFolder, desFolder, docContents, callback)->
setRootDoc = _.once (doc_id)->
projectEntityHandler.setRootDoc newProject._id, doc_id
docs = originalFolder.docs or []
@ -21,7 +21,7 @@ module.exports = ProjectDuplicator =
if !doc?._id?
return callback()
content = docContents[doc._id.toString()]
projectEntityHandler.addDocWithProject newProject, desFolder._id, doc.name, content.lines, (err, newDoc)->
projectEntityHandler.addDocWithProject newProject, desFolder._id, doc.name, content.lines, owner_id, (err, newDoc)->
if err?
logger.err err:err, "error copying doc"
return callback(err)
@ -31,15 +31,15 @@ module.exports = ProjectDuplicator =
async.series jobs, callback
_copyFiles: (newProject, originalProject_id, originalFolder, desFolder, callback)->
_copyFiles: (owner_id, newProject, originalProject_id, originalFolder, desFolder, callback)->
fileRefs = originalFolder.fileRefs or []
jobs = fileRefs.map (file)->
return (cb)->
projectEntityHandler.copyFileFromExistingProjectWithProject newProject, desFolder._id, originalProject_id, file, cb
projectEntityHandler.copyFileFromExistingProjectWithProject newProject, desFolder._id, originalProject_id, file, owner_id, cb
async.parallelLimit jobs, 5, callback
_copyFolderRecursivly: (newProject_id, originalProject_id, originalRootDoc, originalFolder, desFolder, docContents, callback)->
_copyFolderRecursivly: (owner_id, newProject_id, originalProject_id, originalRootDoc, originalFolder, desFolder, docContents, callback)->
ProjectGetter.getProject newProject_id, {rootFolder:true, name:true}, (err, newProject)->
if err?
logger.err project_id:newProject_id, "could not get project"
@ -53,12 +53,12 @@ module.exports = ProjectDuplicator =
return cb()
projectEntityHandler.addFolderWithProject newProject, desFolder?._id, childFolder.name, (err, newFolder)->
return cb(err) if err?
ProjectDuplicator._copyFolderRecursivly newProject_id, originalProject_id, originalRootDoc, childFolder, newFolder, docContents, cb
ProjectDuplicator._copyFolderRecursivly owner_id, newProject_id, originalProject_id, originalRootDoc, childFolder, newFolder, docContents, cb
jobs.push (cb)->
ProjectDuplicator._copyFiles newProject, originalProject_id, originalFolder, desFolder, cb
ProjectDuplicator._copyFiles owner_id, newProject, originalProject_id, originalFolder, desFolder, cb
jobs.push (cb)->
ProjectDuplicator._copyDocs newProject, originalRootDoc, originalFolder, desFolder, docContents, cb
ProjectDuplicator._copyDocs owner_id, newProject, originalRootDoc, originalFolder, desFolder, docContents, cb
async.series jobs, callback
@ -90,7 +90,7 @@ module.exports = ProjectDuplicator =
projectOptionsHandler.setCompiler newProject._id, originalProject.compiler, ->
ProjectDuplicator._copyFolderRecursivly newProject._id, originalProject_id, originalRootDoc, originalProject.rootFolder[0], newProject.rootFolder[0], docContents, ->
ProjectDuplicator._copyFolderRecursivly owner._id, newProject._id, originalProject_id, originalRootDoc, originalProject.rootFolder[0], newProject.rootFolder[0], docContents, ->
if err?
logger.err err:err, originalProject_id:originalProject_id, newProjectName:newProjectName, "error cloning project"
callback(err, newProject)

View file

@ -16,7 +16,7 @@ projectUpdateHandler = require('./ProjectUpdateHandler')
DocstoreManager = require "../Docstore/DocstoreManager"
ProjectGetter = require "./ProjectGetter"
CooldownManager = require '../Cooldown/CooldownManager'
DocumentUpdaterHandler = require('../../Features/DocumentUpdater/DocumentUpdaterHandler')
module.exports = ProjectEntityHandler =
getAllFolders: (project_id, callback) ->
@ -106,8 +106,7 @@ module.exports = ProjectEntityHandler =
flushProjectToThirdPartyDataStore: (project_id, callback) ->
self = @
logger.log project_id:project_id, "flushing project to tpds"
documentUpdaterHandler = require('../../Features/DocumentUpdater/DocumentUpdaterHandler')
documentUpdaterHandler.flushProjectToMongo project_id, (error) ->
DocumentUpdaterHandler.flushProjectToMongo project_id, (error) ->
return callback(error) if error?
ProjectGetter.getProject project_id, {name:true}, (error, project) ->
return callback(error) if error?
@ -150,14 +149,14 @@ module.exports = ProjectEntityHandler =
else
DocstoreManager.getDoc project_id, doc_id, options, callback
addDoc: (project_id, folder_id, docName, docLines, callback = (error, doc, folder_id) ->)=>
addDoc: (project_id, folder_id, docName, docLines, userId, callback = (error, doc, folder_id) ->)=>
ProjectGetter.getProjectWithOnlyFolders project_id, (err, project) ->
if err?
logger.err project_id:project_id, err:err, "error getting project for add doc"
return callback(err)
ProjectEntityHandler.addDocWithProject project, folder_id, docName, docLines, callback
ProjectEntityHandler.addDocWithProject project, folder_id, docName, docLines, userId, callback
addDocWithProject: (project, folder_id, docName, docLines, callback = (error, doc, folder_id) ->)=>
addDocWithProject: (project, folder_id, docName, docLines, userId, callback = (error, doc, folder_id) ->)=>
project_id = project._id
logger.log project_id: project_id, folder_id: folder_id, doc_name: docName, "adding doc to project with project"
confirmFolder project, folder_id, (folder_id)=>
@ -177,7 +176,14 @@ module.exports = ProjectEntityHandler =
rev: 0
}, (err) ->
return callback(err) if err?
callback(null, doc, folder_id)
newDocs = [
doc: doc
path: result?.path?.fileSystem
docLines: docLines.join('\n')
]
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newDocs}, (error) ->
return callback(error) if error?
callback null, doc, folder_id
restoreDoc: (project_id, doc_id, name, callback = (error, doc, folder_id) ->) ->
# getDoc will return the deleted doc's lines, but we don't actually remove
@ -186,20 +192,20 @@ module.exports = ProjectEntityHandler =
return callback(error) if error?
ProjectEntityHandler.addDoc project_id, null, name, lines, callback
addFile: (project_id, folder_id, fileName, path, callback = (error, fileRef, folder_id) ->)->
addFile: (project_id, folder_id, fileName, path, userId, callback = (error, fileRef, folder_id) ->)->
ProjectGetter.getProjectWithOnlyFolders project_id, (err, project) ->
if err?
logger.err project_id:project_id, err:err, "error getting project for add file"
return callback(err)
ProjectEntityHandler.addFileWithProject project, folder_id, fileName, path, callback
ProjectEntityHandler.addFileWithProject project, folder_id, fileName, path, userId, callback
addFileWithProject: (project, folder_id, fileName, path, callback = (error, fileRef, folder_id) ->)->
addFileWithProject: (project, folder_id, fileName, path, userId, callback = (error, fileRef, folder_id) ->)->
project_id = project._id
logger.log project_id: project._id, folder_id: folder_id, file_name: fileName, path:path, "adding file"
return callback(err) if err?
confirmFolder project, folder_id, (folder_id)->
fileRef = new File name : fileName
FileStoreHandler.uploadFileFromDisk project._id, fileRef._id, path, (err)->
FileStoreHandler.uploadFileFromDisk project._id, fileRef._id, path, (err, fileStoreUrl)->
if err?
logger.err err:err, project_id: project._id, folder_id: folder_id, file_name: fileName, fileRef:fileRef, "error uploading image to s3"
return callback(err)
@ -209,27 +215,31 @@ module.exports = ProjectEntityHandler =
return callback(err)
tpdsUpdateSender.addFile {project_id:project._id, file_id:fileRef._id, path:result?.path?.fileSystem, project_name:project.name, rev:fileRef.rev}, (err) ->
return callback(err) if err?
callback(null, fileRef, folder_id)
newFiles = [
file: fileRef
path: result?.path?.fileSystem
url: fileStoreUrl
]
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newFiles}, (error) ->
return callback(error) if error?
callback null, fileRef, folder_id
replaceFile: (project_id, file_id, fsPath, callback)->
ProjectGetter.getProject project_id, {name:true}, (err, project) ->
replaceFile: (project_id, file_id, fsPath, userId, callback)->
self = ProjectEntityHandler
FileStoreHandler.uploadFileFromDisk project_id, file_id, fsPath, (err, fileStoreUrl)->
return callback(err) if err?
findOpts =
project_id:project._id
element_id:file_id
type:"file"
FileStoreHandler.uploadFileFromDisk project._id, file_id, fsPath, (err)->
ProjectGetter.getProject project_id, {rootFolder: true, name:true}, (err, project) ->
return callback(err) if err?
# Note there is a potential race condition here (and elsewhere)
# If the file tree changes between findElement and the Project.update
# then the path to the file element will be out of date. In practice
# this is not a problem so long as we do not do anything longer running
# between them (like waiting for the file to upload.)
projectLocator.findElement findOpts, (err, fileRef, path)=>
projectLocator.findElement {project:project, element_id: file_id, type: 'file'}, (err, fileRef, path)=>
return callback(err) if err?
tpdsUpdateSender.addFile {project_id:project._id, file_id:fileRef._id, path:path.fileSystem, rev:fileRef.rev+1, project_name:project.name}, (error) ->
tpdsUpdateSender.addFile {project_id:project._id, file_id:fileRef._id, path:path.fileSystem, rev:fileRef.rev+1, project_name:project.name}, (err) ->
return callback(err) if err?
conditons = _id:project._id
conditions = _id:project._id
inc = {}
inc["#{path.mongo}.rev"] = 1
set = {}
@ -237,39 +247,43 @@ module.exports = ProjectEntityHandler =
update =
"$inc": inc
"$set": set
Project.update conditons, update, {}, (err, second)->
callback()
Project.findOneAndUpdate conditions, update, { "new": true}, (err) ->
return callback(err) if err?
newFiles = [
file: fileRef
path: path.fileSystem
url: fileStoreUrl
]
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newFiles}, callback
copyFileFromExistingProject: (project_id, folder_id, originalProject_id, origonalFileRef, callback = (error, fileRef, folder_id) ->)->
logger.log project_id:project_id, folder_id:folder_id, originalProject_id:originalProject_id, origonalFileRef:origonalFileRef, "copying file in s3"
ProjectGetter.getProject project_id, {name:true}, (err, project) ->
if err?
logger.err project_id:project_id, err:err, "error getting project for copy file from existing project"
return callback(err)
ProjectEntityHandler.copyFileFromExistingProjectWithProject project, folder_id, originalProject_id, origonalFileRef, callback
copyFileFromExistingProjectWithProject: (project, folder_id, originalProject_id, origonalFileRef, callback = (error, fileRef, folder_id) ->)->
copyFileFromExistingProjectWithProject: (project, folder_id, originalProject_id, origonalFileRef, userId, callback = (error, fileRef, folder_id) ->)->
project_id = project._id
logger.log project_id:project_id, folder_id:folder_id, originalProject_id:originalProject_id, origonalFileRef:origonalFileRef, "copying file in s3 with project"
logger.log { project_id, folder_id, originalProject_id, origonalFileRef }, "copying file in s3 with project"
return callback(err) if err?
confirmFolder project, folder_id, (folder_id)=>
if !origonalFileRef?
logger.err project_id:project._id, folder_id:folder_id, originalProject_id:originalProject_id, origonalFileRef:origonalFileRef, "file trying to copy is null"
logger.err { project_id, folder_id, originalProject_id, origonalFileRef }, "file trying to copy is null"
return callback()
fileRef = new File name : origonalFileRef.name
FileStoreHandler.copyFile originalProject_id, origonalFileRef._id, project._id, fileRef._id, (err)->
FileStoreHandler.copyFile originalProject_id, origonalFileRef._id, project._id, fileRef._id, (err, fileStoreUrl)->
if err?
logger.err err:err, project_id:project._id, folder_id:folder_id, originalProject_id:originalProject_id, origonalFileRef:origonalFileRef, "error coping file in s3"
logger.err { err, project_id, folder_id, originalProject_id, origonalFileRef }, "error coping file in s3"
return callback(err)
ProjectEntityHandler._putElement project, folder_id, fileRef, "file", (err, result)=>
if err?
logger.err err:err, project_id:project._id, folder_id:folder_id, "error putting element as part of copy"
logger.err { err, project_id, folder_id }, "error putting element as part of copy"
return callback(err)
tpdsUpdateSender.addFile {project_id:project._id, file_id:fileRef._id, path:result?.path?.fileSystem, rev:fileRef.rev, project_name:project.name}, (err) ->
tpdsUpdateSender.addFile { project_id, file_id:fileRef._id, path:result?.path?.fileSystem, rev:fileRef.rev, project_name:project.name}, (err) ->
if err?
logger.err err:err, project_id:project._id, folder_id:folder_id, originalProject_id:originalProject_id, origonalFileRef:origonalFileRef, "error sending file to tpds worker"
callback(null, fileRef, folder_id)
logger.err { err, project_id, folder_id, originalProject_id, origonalFileRef }, "error sending file to tpds worker"
newFiles = [
file: fileRef
path: result?.path?.fileSystem
url: fileStoreUrl
]
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newFiles}, (error) ->
return callback(error) if error?
callback null, fileRef, folder_id
mkdirp: (project_id, path, callback = (err, newlyCreatedFolders, lastFolderInPath)->)->
self = @
@ -381,11 +395,9 @@ module.exports = ProjectEntityHandler =
endPath: result.path.fileSystem,
rev: entity.rev
tpdsUpdateSender.moveEntity opts
self.getAllEntitiesFromProject newProject, (error, newDocs, newFiles
) =>
self.getAllEntitiesFromProject newProject, (error, newDocs, newFiles) =>
return callback(error) if error?
documentUpdaterHandler = require('../../Features/DocumentUpdater/DocumentUpdaterHandler')
documentUpdaterHandler.updateProjectStructure project_id, userId, oldDocs, newDocs, oldFiles, newFiles, callback
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {oldDocs, newDocs, oldFiles, newFiles}, callback
_checkValidMove: (project, entityType, entityPath, destFolderId, callback = (error) ->) ->
return callback() if !entityType.match(/folder/)
@ -442,8 +454,7 @@ module.exports = ProjectEntityHandler =
return callback(error) if error?
ProjectEntityHandler.getAllEntitiesFromProject newProject, (error, newDocs, newFiles) =>
return callback(error) if error?
documentUpdaterHandler = require('../../Features/DocumentUpdater/DocumentUpdaterHandler')
documentUpdaterHandler.updateProjectStructure project_id, userId, oldDocs, newDocs, oldFiles, newFiles, callback
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {oldDocs, newDocs, oldFiles, newFiles}, callback
_cleanUpEntity: (project, entity, entityType, callback = (error) ->) ->
if(entityType.indexOf("file") != -1)
@ -466,7 +477,7 @@ module.exports = ProjectEntityHandler =
unsetRootDocIfRequired (error) ->
return callback(error) if error?
require('../../Features/DocumentUpdater/DocumentUpdaterHandler').deleteDoc project_id, doc_id, (error) ->
DocumentUpdaterHandler.deleteDoc project_id, doc_id, (error) ->
return callback(error) if error?
ProjectEntityHandler._insertDeletedDocReference project._id, doc, (error) ->
return callback(error) if error?

View file

@ -28,7 +28,7 @@ module.exports =
FileTypeManager.isBinary path, fsPath, (err, isFile)->
return callback(err) if err?
if isFile
self.p.processFile project_id, elementId, fsPath, path, source, callback
self.p.processFile project_id, elementId, fsPath, path, source, user_id, callback
else
self.p.processDoc project_id, elementId, user_id, fsPath, path, source, callback
@ -57,9 +57,9 @@ module.exports =
if err?
logger.err err:err, project_id:project_id, doc_id:doc_id, path:path, "error processing file"
return callback(err)
editorController.addDoc project_id, folder._id, fileName, docLines, source, callback
editorController.addDoc project_id, folder._id, fileName, docLines, source, user_id, callback
processFile: (project_id, file_id, fsPath, path, source, callback)->
processFile: (project_id, file_id, fsPath, path, source, user_id, callback)->
finish = (err)->
logger.log project_id:project_id, file_id:file_id, path:path, "completed processing file update from tpds"
callback(err)
@ -69,9 +69,9 @@ module.exports =
logger.err err:err, project_id:project_id, file_id:file_id, path:path, "error processing file"
return callback(err)
else if file_id?
editorController.replaceFile project_id, file_id, fsPath, source, finish
editorController.replaceFile project_id, file_id, fsPath, source, user_id, finish
else
editorController.addFile project_id, folder?._id, fileName, fsPath, source, finish
editorController.addFile project_id, folder?._id, fileName, fsPath, source, user_id, finish
writeStreamToDisk: (project_id, file_id, stream, callback = (err, fsPath)->)->
if !file_id?

View file

@ -28,9 +28,9 @@ module.exports = FileSystemImportManager =
if existingDoc?
EditorController.setDoc project_id, existingDoc._id, user_id, lines, "upload", callback
else
EditorController.addDocWithoutLock project_id, folder_id, name, lines, "upload", callback
EditorController.addDocWithoutLock project_id, folder_id, name, lines, "upload", user_id, callback
else
EditorController.addDocWithoutLock project_id, folder_id, name, lines, "upload", callback
EditorController.addDocWithoutLock project_id, folder_id, name, lines, "upload", user_id, callback
addFile: (user_id, project_id, folder_id, name, path, replace, callback = (error, file)-> )->
FileSystemImportManager._isSafeOnFileSystem path, (err, isSafe)->
@ -39,7 +39,7 @@ module.exports = FileSystemImportManager =
return callback("path is symlink")
if !replace
EditorController.addFileWithoutLock project_id, folder_id, name, path, "upload", callback
EditorController.addFileWithoutLock project_id, folder_id, name, path, "upload", user_id, callback
else
ProjectLocator.findElement project_id: project_id, element_id: folder_id, type: "folder", (error, folder) ->
return callback(error) if error?
@ -50,9 +50,9 @@ module.exports = FileSystemImportManager =
existingFile = fileRef
break
if existingFile?
EditorController.replaceFile project_id, existingFile._id, path, "upload", callback
EditorController.replaceFile project_id, existingFile._id, path, "upload", user_id, callback
else
EditorController.addFileWithoutLock project_id, folder_id, name, path, "upload", callback
EditorController.addFileWithoutLock project_id, folder_id, name, path, "upload", user_id, callback
addFolder: (user_id, project_id, folder_id, name, path, replace, callback = (error)-> ) ->
FileSystemImportManager._isSafeOnFileSystem path, (err, isSafe)->

View file

@ -111,7 +111,7 @@ module.exports = settings =
trackchanges:
url : "http://localhost:3015"
project_history:
enabled: false
enabled: process.env.PROJECT_HISTORY_ENABLED == 'true' or false
url : "http://localhost:3054"
docstore:
url : "http://#{process.env['DOCSTORE_HOST'] or 'localhost'}:3016"

View file

@ -24,6 +24,7 @@ services:
REDIS_HOST: redis
MONGO_URL: "mongodb://mongo/sharelatex"
SHARELATEX_ALLOW_PUBLIC_ACCESS: 'true'
PROJECT_HISTORY_ENABLED: 'true'
depends_on:
- redis
- mongo

View file

@ -25,6 +25,7 @@ services:
- ./config:/app/config
- ./test/unit/coffee:/app/test/unit/coffee:ro
- ./test/acceptance/coffee:/app/test/acceptance/coffee:ro
- ./test/acceptance/files:/app/test/acceptance/files:ro
- ./test/smoke/coffee:/app/test/smoke/coffee:ro
MODULE_VOLUMES
working_dir: /app
working_dir: /app

View file

@ -0,0 +1,307 @@
async = require "async"
expect = require("chai").expect
mkdirp = require "mkdirp"
ObjectId = require("mongojs").ObjectId
Path = require "path"
fs = require "fs"
Settings = require "settings-sharelatex"
_ = require "underscore"
ProjectGetter = require "../../../app/js/Features/Project/ProjectGetter.js"
MockDocUpdaterApi = require './helpers/MockDocUpdaterApi'
MockFileStoreApi = require './helpers/MockFileStoreApi'
MockProjectHistoryApi = require './helpers/MockProjectHistoryApi'
request = require "./helpers/request"
User = require "./helpers/User"
describe "ProjectStructureChanges", ->
before (done) ->
@owner = new User()
@owner.login done
describe "creating a project from the example template", ->
before (done) ->
MockDocUpdaterApi.clearProjectStructureUpdates()
@owner.createProject "example-project", {template: "example"}, (error, project_id) =>
throw error if error?
@example_project_id = project_id
done()
it "should version creating a doc", ->
updates = MockDocUpdaterApi.getProjectStructureUpdates(@example_project_id).docUpdates
expect(updates.length).to.equal(2)
_.each updates, (update) =>
expect(update.userId).to.equal(@owner._id)
expect(update.docLines).to.be.a('string')
expect(_.where(updates, pathname: "/main.tex").length).to.equal 1
expect(_.where(updates, pathname: "/references.bib").length).to.equal 1
it "should version creating a file", ->
updates = MockDocUpdaterApi.getProjectStructureUpdates(@example_project_id).fileUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/universe.jpg")
expect(update.url).to.be.a('string');
describe "duplicating a project", ->
before (done) ->
MockDocUpdaterApi.clearProjectStructureUpdates()
@owner.request.post {
uri: "/Project/#{@example_project_id}/clone",
json:
projectName: 'new.tex'
}, (error, res, body) =>
throw error if error?
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to add doc #{res.statusCode}")
@dup_project_id = body.project_id
done()
it "should version the dosc created", ->
updates = MockDocUpdaterApi.getProjectStructureUpdates(@dup_project_id).docUpdates
expect(updates.length).to.equal(2)
_.each updates, (update) =>
expect(update.userId).to.equal(@owner._id)
expect(update.docLines).to.be.a('string')
expect(_.where(updates, pathname: "/main.tex").length).to.equal(1)
expect(_.where(updates, pathname: "/references.bib").length).to.equal(1)
it "should version the files created", ->
updates = MockDocUpdaterApi.getProjectStructureUpdates(@dup_project_id).fileUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/universe.jpg")
expect(update.url).to.be.a('string');
describe "adding a doc", ->
before (done) ->
MockDocUpdaterApi.clearProjectStructureUpdates()
ProjectGetter.getProject @example_project_id, (error, projects) =>
throw error if error?
@owner.request.post {
uri: "project/#{@example_project_id}/doc",
json:
name: 'new.tex'
parent_folder_id: projects[0].rootFolder[0]._id
}, (error, res, body) =>
throw error if error?
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to add doc #{res.statusCode}")
done()
it "should version the doc added", ->
updates = MockDocUpdaterApi.getProjectStructureUpdates(@example_project_id).docUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/new.tex")
expect(update.docLines).to.be.a('string');
describe "uploading a project", ->
before (done) ->
MockDocUpdaterApi.clearProjectStructureUpdates()
zip_file = fs.createReadStream(Path.resolve(__dirname + '/../files/test_project.zip'))
req = @owner.request.post {
uri: "project/new/upload",
formData:
qqfile: zip_file
}, (error, res, body) =>
throw error if error?
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to upload project #{res.statusCode}")
@uploaded_project_id = JSON.parse(body).project_id
done()
it "should version the dosc created", ->
updates = MockDocUpdaterApi.getProjectStructureUpdates(@uploaded_project_id).docUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/main.tex")
expect(update.docLines).to.equal("Test")
it "should version the files created", ->
updates = MockDocUpdaterApi.getProjectStructureUpdates(@uploaded_project_id).fileUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/1pixel.png")
expect(update.url).to.be.a('string');
describe "uploading a file", ->
before (done) ->
ProjectGetter.getProject @example_project_id, (error, projects) =>
throw error if error?
@root_folder_id = projects[0].rootFolder[0]._id.toString()
done()
beforeEach () ->
MockDocUpdaterApi.clearProjectStructureUpdates()
it "should version a newly uploaded file", (done) ->
image_file = fs.createReadStream(Path.resolve(__dirname + '/../files/1pixel.png'))
req = @owner.request.post {
uri: "project/#{@example_project_id}/upload",
qs:
folder_id: @root_folder_id
formData:
qqfile:
value: image_file
options:
filename: '1pixel.png',
contentType: 'image/png'
}, (error, res, body) =>
throw error if error?
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to upload file #{res.statusCode}")
updates = MockDocUpdaterApi.getProjectStructureUpdates(@example_project_id).fileUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/1pixel.png")
expect(update.url).to.be.a('string');
@original_file_url = update.url
done()
it "should version a replacement file", (done) ->
image_file = fs.createReadStream(Path.resolve(__dirname + '/../files/2pixel.png'))
req = @owner.request.post {
uri: "project/#{@example_project_id}/upload",
qs:
folder_id: @root_folder_id
formData:
qqfile:
value: image_file
options:
filename: '1pixel.png',
contentType: 'image/png'
}, (error, res, body) =>
throw error if error?
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to upload file #{res.statusCode}")
updates = MockDocUpdaterApi.getProjectStructureUpdates(@example_project_id).fileUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/1pixel.png")
expect(update.url).to.be.a('string');
done()
describe "tpds", ->
before (done) ->
@tpds_project_name = "tpds-project-#{new ObjectId().toString()}"
@owner.createProject @tpds_project_name, (error, project_id) =>
throw error if error?
@tpds_project_id = project_id
mkdirp Settings.path.dumpFolder, done
beforeEach () ->
MockDocUpdaterApi.clearProjectStructureUpdates()
it "should version adding a doc", (done) ->
tex_file = fs.createReadStream(Path.resolve(__dirname + '/../files/test.tex'))
req = @owner.request.post {
uri: "/user/#{@owner._id}/update/#{@tpds_project_name}/test.tex",
auth:
user: _.keys(Settings.httpAuthUsers)[0]
pass: _.values(Settings.httpAuthUsers)[0]
sendImmediately: true
}
tex_file.on "error", (err) ->
throw err
req.on "error", (err) ->
throw err
req.on "response", (res) =>
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to upload file #{res.statusCode}")
updates = MockDocUpdaterApi.getProjectStructureUpdates(@tpds_project_id).docUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/test.tex")
expect(update.docLines).to.equal("Test")
done()
tex_file.pipe(req)
it "should version adding a new file", (done) ->
image_file = fs.createReadStream(Path.resolve(__dirname + '/../files/1pixel.png'))
req = @owner.request.post {
uri: "/user/#{@owner._id}/update/#{@tpds_project_name}/1pixel.png",
auth:
user: _.keys(Settings.httpAuthUsers)[0]
pass: _.values(Settings.httpAuthUsers)[0]
sendImmediately: true
}
image_file.on "error", (err) ->
throw err
req.on "error", (err) ->
throw err
req.on "response", (res) =>
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to upload file #{res.statusCode}")
updates = MockDocUpdaterApi.getProjectStructureUpdates(@tpds_project_id).fileUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/1pixel.png")
expect(update.url).to.be.a('string');
done()
image_file.pipe(req)
it "should version replacing a file", (done) ->
image_file = fs.createReadStream(Path.resolve(__dirname + '/../files/2pixel.png'))
req = @owner.request.post {
uri: "/user/#{@owner._id}/update/#{@tpds_project_name}/1pixel.png",
auth:
user: _.keys(Settings.httpAuthUsers)[0]
pass: _.values(Settings.httpAuthUsers)[0]
sendImmediately: true
}
image_file.on "error", (err) ->
throw err
req.on "error", (err) ->
throw err
req.on "response", (res) =>
if res.statusCode < 200 || res.statusCode >= 300
throw new Error("failed to upload file #{res.statusCode}")
updates = MockDocUpdaterApi.getProjectStructureUpdates(@tpds_project_id).fileUpdates
expect(updates.length).to.equal(1)
update = updates[0]
expect(update.userId).to.equal(@owner._id)
expect(update.pathname).to.equal("/1pixel.png")
expect(update.url).to.be.a('string');
done()
image_file.pipe(req)

View file

@ -1,11 +1,38 @@
express = require("express")
app = express()
bodyParser = require "body-parser"
jsonParser = bodyParser.json()
module.exports = MockDocUpdaterApi =
updates: {}
clearProjectStructureUpdates: () ->
@updates = {}
getProjectStructureUpdates: (project_id) ->
@updates[project_id] || { docUpdates: [], fileUpdates: [] }
addProjectStructureUpdates: (project_id, userId, docUpdates, fileUpdates) ->
@updates[project_id] ||= { docUpdates: [], fileUpdates: [] }
for update in docUpdates
update.userId = userId
@updates[project_id].docUpdates.push(update)
for update in fileUpdates
update.userId = userId
@updates[project_id].fileUpdates.push(update)
run: () ->
app.post "/project/:project_id/flush", (req, res, next) =>
res.sendStatus 200
app.post "/project/:project_id", jsonParser, (req, res, next) =>
project_id = req.params.project_id
{userId, docUpdates, fileUpdates} = req.body
@addProjectStructureUpdates(project_id, userId, docUpdates, fileUpdates)
res.sendStatus 200
app.listen 3003, (error) ->
throw error if error?
.on "error", (error) ->

View file

@ -13,6 +13,7 @@ module.exports = MockDocStoreApi =
@docs[project_id][doc_id] = {lines, version, ranges}
@docs[project_id][doc_id].rev ?= 0
@docs[project_id][doc_id].rev += 1
@docs[project_id][doc_id]._id = doc_id
res.json {
modified: true
rev: @docs[project_id][doc_id].rev

View file

@ -0,0 +1,20 @@
express = require("express")
app = express()
module.exports = MockFileStoreApi =
files: {}
run: () ->
app.post "/project/:project_id/file/:file_id", (req, res, next) =>
req.on 'data', ->
req.on 'end', ->
res.send 200
app.listen 3009, (error) ->
throw error if error?
.on "error", (error) ->
console.error "error starting MockFileStoreApi:", error.message
process.exit(1)
MockFileStoreApi.run()

View file

@ -0,0 +1,18 @@
express = require("express")
app = express()
module.exports = MockProjectHistoryApi =
docs: {}
run: () ->
app.post "/project", (req, res, next) =>
res.json project: id: 1
app.listen 3054, (error) ->
throw error if error?
.on "error", (error) ->
console.error "error starting MockProjectHistoryApi:", error.message
process.exit(1)
MockProjectHistoryApi.run()

View file

@ -99,11 +99,14 @@ class User
getProject: (project_id, callback = (error, project)->) ->
db.projects.findOne {_id: ObjectId(project_id.toString())}, callback
createProject: (name, callback = (error, project_id) ->) ->
createProject: (name, options, callback = (error, oroject_id) ->) ->
if typeof options == "function"
callback = options
options = {}
@request.post {
url: "/project/new",
json:
projectName: name
json: Object.assign({projectName: name}, options)
}, (error, response, body) ->
return callback(error) if error?
if !body?.project_id?

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -0,0 +1 @@
Test

Binary file not shown.

View file

@ -3,7 +3,7 @@
# If you're running on OS X, you probably need to rebuild
# some dependencies in the docker container, before it will start.
#
# npm rebuild --update-binary
#npm rebuild --update-binary
echo ">> Starting server..."

View file

@ -390,26 +390,13 @@ describe 'DocumentUpdaterHandler', ->
describe "updateProjectStructure ", ->
beforeEach ->
@user_id = 1234
@docIdA = new ObjectId()
@docIdB = new ObjectId()
@oldDocs = [
{ path: '/old_a', doc: _id: @docIdA }
{ path: '/old_b', doc: _id: @docIdB }
]
# create new instances of the same ObjectIds so that == doens't pass
@newDocs = [
{ path: '/old_a', doc: _id: new ObjectId(@docIdA.toString()) }
{ path: '/new_b', doc: _id: new ObjectId(@docIdB.toString()) }
]
@oldFiles = []
@newFiles = []
describe "with project history disabled", ->
beforeEach ->
@settings.apis.project_history.enabled = false
@request.post = sinon.stub()
@handler.updateProjectStructure @project_id, @user_id, @oldDocs, @newDocs, @oldFiles, @newFiles, @callback
@handler.updateProjectStructure @project_id, @user_id, {}, @callback
it 'does not make a web request', ->
@request.post.called.should.equal false
@ -420,20 +407,85 @@ describe 'DocumentUpdaterHandler', ->
describe "with project history enabled", ->
beforeEach ->
@settings.apis.project_history.enabled = true
@url = "#{@settings.apis.documentupdater.url}/project/#{@project_id}"
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 204}, "")
@handler.updateProjectStructure @project_id, @user_id, @oldDocs, @newDocs, @oldFiles, @newFiles, @callback
it 'should send the structure update to the document updater', ->
docUpdates = [
id: @docIdB,
pathname: "/old_b"
newPathname: "/new_b"
]
describe "when an entity has changed name", ->
it 'should send the structure update to the document updater', (done) ->
@docIdA = new ObjectId()
@docIdB = new ObjectId()
@changes = {
oldDocs: [
{ path: '/old_a', doc: _id: @docIdA }
{ path: '/old_b', doc: _id: @docIdB }
]
# create new instances of the same ObjectIds so that == doesn't pass
newDocs: [
{ path: '/old_a', doc: _id: new ObjectId(@docIdA.toString()) }
{ path: '/new_b', doc: _id: new ObjectId(@docIdB.toString()) }
]
}
url = "#{@settings.apis.documentupdater.url}/project/#{@project_id}"
@request.post
.calledWith(url: url, json: {docUpdates, fileUpdates: [], userId: @user_id})
.should.equal true
docUpdates = [
id: @docIdB.toString(),
pathname: "/old_b"
newPathname: "/new_b"
]
@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
@request.post
.calledWith(url: @url, json: {docUpdates, fileUpdates: [], userId: @user_id})
.should.equal true
done()
describe "when a doc has been added", ->
it 'should send the structure update to the document updater', (done) ->
@docId = new ObjectId()
@changes = newDocs: [
{ path: '/foo', docLines: 'a\nb', doc: _id: @docId }
]
docUpdates = [
id: @docId.toString(),
pathname: "/foo"
docLines: 'a\nb'
url: undefined
]
@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
@request.post
.calledWith(url: @url, json: {docUpdates, fileUpdates: [], userId: @user_id})
.should.equal true
done()
describe "when a file has been added", ->
it 'should send the structure update to the document updater', (done) ->
@fileId = new ObjectId()
@changes = newFiles: [
{ path: '/bar', url: 'filestore.example.com/file', file: _id: @fileId }
]
fileUpdates = [
id: @fileId.toString(),
pathname: "/bar"
url: 'filestore.example.com/file'
docLines: undefined
]
@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
@request.post
.calledWith(url: @url, json: {docUpdates: [], fileUpdates, userId: @user_id})
.should.equal true
done()
describe "when a doc has been deleted", ->
it 'should do nothing', (done) ->
@docId = new ObjectId()
@changes = oldDocs: [
{ path: '/foo', docLines: 'a\nb', doc: _id: @docId }
]
@handler.updateProjectStructure @project_id, @user_id, @changes, () =>
@request.post.called.should.equal false
done()
it "should call the callback with no error", ->
@callback.calledWith(null).should.equal true

View file

@ -131,24 +131,24 @@ describe "EditorController", ->
@docLines = ["1234","dskl"]
it 'should add the doc using the project entity handler', (done)->
mock = sinon.mock(@ProjectEntityHandler).expects("addDoc").withArgs(@project_id, @folder_id, @docName, @docLines).callsArg(4)
mock = sinon.mock(@ProjectEntityHandler).expects("addDoc").withArgs(@project_id, @folder_id, @docName, @docLines).callsArg(5)
@EditorController.addDocWithoutLock @project_id, @folder_id, @docName, @docLines, @source, ->
@EditorController.addDocWithoutLock @project_id, @folder_id, @docName, @docLines, @source, @user_id, ->
mock.verify()
done()
it 'should send the update out to the users in the project', (done)->
@ProjectEntityHandler.addDoc = sinon.stub().callsArgWith(4, null, @doc, @folder_id)
@ProjectEntityHandler.addDoc = sinon.stub().callsArgWith(5, null, @doc, @folder_id)
@EditorController.addDocWithoutLock @project_id, @folder_id, @docName, @docLines, @source, =>
@EditorController.addDocWithoutLock @project_id, @folder_id, @docName, @docLines, @source, @user_id, =>
@EditorRealTimeController.emitToRoom
.calledWith(@project_id, "reciveNewDoc", @folder_id, @doc, @source)
.should.equal true
done()
it 'should return the doc to the callback', (done) ->
@ProjectEntityHandler.addDoc = sinon.stub().callsArgWith(4, null, @doc, @folder_id)
@EditorController.addDocWithoutLock @project_id, @folder_id, @docName, @docLines, @source, (error, doc) =>
@ProjectEntityHandler.addDoc = sinon.stub().callsArgWith(5, null, @doc, @folder_id)
@EditorController.addDocWithoutLock @project_id, @folder_id, @docName, @docLines, @source, @user_id, (error, doc) =>
doc.should.equal @doc
done()
@ -157,32 +157,29 @@ describe "EditorController", ->
beforeEach ->
@LockManager.getLock.callsArgWith(1)
@LockManager.releaseLock.callsArgWith(1)
@EditorController.addDocWithoutLock = sinon.stub().callsArgWith(5)
@EditorController.addDocWithoutLock = sinon.stub().callsArgWith(6)
it "should call addDocWithoutLock", (done)->
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, =>
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @docName, @docLines, @source).should.equal true
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, @user_id, =>
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @docName, @docLines, @source, @user_id).should.equal true
done()
it "should take the lock", (done)->
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, =>
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, @user_id, =>
@LockManager.getLock.calledWith(@project_id).should.equal true
done()
it "should release the lock", (done)->
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, =>
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, @user_id, =>
@LockManager.releaseLock.calledWith(@project_id).should.equal true
done()
it "should error if it can't cat the lock", (done)->
@LockManager.getLock = sinon.stub().callsArgWith(1, "timed out")
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, (err)=>
@EditorController.addDoc @project_id, @folder_id, @docName, @docLines, @source, @user_id, (err)=>
expect(err).to.exist
err.should.equal "timed out"
done()
done()
describe 'addFileWithoutLock:', ->
beforeEach ->
@ -196,23 +193,23 @@ describe "EditorController", ->
@stream = new ArrayBuffer()
it 'should add the folder using the project entity handler', (done)->
@ProjectEntityHandler.addFile = sinon.stub().callsArgWith(4)
@EditorController.addFileWithoutLock @project_id, @folder_id, @fileName, @stream, @source, =>
@ProjectEntityHandler.addFile.calledWith(@project_id, @folder_id).should.equal true
@ProjectEntityHandler.addFile = sinon.stub().callsArgWith(5)
@EditorController.addFileWithoutLock @project_id, @folder_id, @fileName, @stream, @source, @user_id, =>
@ProjectEntityHandler.addFile.calledWith(@project_id, @folder_id, @fileName, @stream, @user_id).should.equal true
done()
it 'should send the update of a new folder out to the users in the project', (done)->
@ProjectEntityHandler.addFile = sinon.stub().callsArgWith(4, null, @file, @folder_id)
@ProjectEntityHandler.addFile = sinon.stub().callsArgWith(5, null, @file, @folder_id)
@EditorController.addFileWithoutLock @project_id, @folder_id, @fileName, @stream, @source, =>
@EditorController.addFileWithoutLock @project_id, @folder_id, @fileName, @stream, @source, @user_id, =>
@EditorRealTimeController.emitToRoom
.calledWith(@project_id, "reciveNewFile", @folder_id, @file, @source)
.should.equal true
done()
it "should return the file in the callback", (done) ->
@ProjectEntityHandler.addFile = sinon.stub().callsArgWith(4, null, @file, @folder_id)
@EditorController.addFileWithoutLock @project_id, @folder_id, @fileName, @stream, @source, (error, file) =>
@ProjectEntityHandler.addFile = sinon.stub().callsArgWith(5, null, @file, @folder_id)
@EditorController.addFileWithoutLock @project_id, @folder_id, @fileName, @stream, @source, @user_id, (error, file) =>
file.should.equal @file
done()
@ -222,28 +219,28 @@ describe "EditorController", ->
beforeEach ->
@LockManager.getLock.callsArgWith(1)
@LockManager.releaseLock.callsArgWith(1)
@EditorController.addFileWithoutLock = sinon.stub().callsArgWith(5)
@EditorController.addFileWithoutLock = sinon.stub().callsArgWith(6)
it "should call addFileWithoutLock", (done)->
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, (error, file) =>
@EditorController.addFileWithoutLock.calledWith(@project_id, @folder_id, @fileName, @stream, @source).should.equal true
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, @user_id, (error, file) =>
@EditorController.addFileWithoutLock.calledWith(@project_id, @folder_id, @fileName, @stream, @source, @user_id).should.equal true
done()
it "should take the lock", (done)->
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, (error, file) =>
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, @user_id, (error, file) =>
@LockManager.getLock.calledWith(@project_id).should.equal true
done()
it "should release the lock", (done)->
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, (error, file) =>
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, @user_id, (error, file) =>
@LockManager.releaseLock.calledWith(@project_id).should.equal true
done()
it "should error if it can't cat the lock", (done)->
@LockManager.getLock = sinon.stub().callsArgWith(1, "timed out")
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, (err, file) =>
expect(err).to.exist
err.should.equal "timed out"
@EditorController.addFile @project_id, @folder_id, @fileName, @stream, @source, @user_id, (error, file) =>
expect(error).to.exist
error.should.equal "timed out"
done()
@ -256,9 +253,9 @@ describe "EditorController", ->
@fsPath = "/folder/file.png"
it 'should send the replace file message to the editor controller', (done)->
@ProjectEntityHandler.replaceFile = sinon.stub().callsArgWith(3)
@EditorController.replaceFile @project_id, @file_id, @fsPath, @source, =>
@ProjectEntityHandler.replaceFile.calledWith(@project_id, @file_id, @fsPath).should.equal true
@ProjectEntityHandler.replaceFile = sinon.stub().callsArgWith(4)
@EditorController.replaceFile @project_id, @file_id, @fsPath, @source, @user_id, =>
@ProjectEntityHandler.replaceFile.calledWith(@project_id, @file_id, @fsPath, @user_id).should.equal true
done()
describe 'addFolderWithoutLock :', ->

View file

@ -201,7 +201,7 @@ describe "EditorHttpController", ->
@req.body =
name: @name = "doc-name"
parent_folder_id: @parent_folder_id
@EditorController.addDoc = sinon.stub().callsArgWith(5, null, @doc)
@EditorController.addDoc = sinon.stub().callsArgWith(6, null, @doc)
describe "successfully", ->
beforeEach ->
@ -209,7 +209,7 @@ describe "EditorHttpController", ->
it "should call EditorController.addDoc", ->
@EditorController.addDoc
.calledWith(@project_id, @parent_folder_id, @name, [], "editor")
.calledWith(@project_id, @parent_folder_id, @name, [], "editor", @userId)
.should.equal true
it "should send the doc back as JSON", ->

View file

@ -16,7 +16,7 @@ describe "FileStoreHandler", ->
})
@writeStream =
my:"writeStream"
on: (type, cb)->
on: (type, cb)->
if type == "response"
cb({statusCode: 200})
@readStream = {my:"readStream", on: sinon.stub()}
@ -38,7 +38,7 @@ describe "FileStoreHandler", ->
@isSafeOnFileSystem = true
it "should create read stream", (done)->
@fs.createReadStream.returns
@fs.createReadStream.returns
pipe:->
on: (type, cb)->
if type == "open"
@ -49,8 +49,8 @@ describe "FileStoreHandler", ->
it "should pipe the read stream to request", (done)->
@request.returns(@writeStream)
@fs.createReadStream.returns
on: (type, cb)->
@fs.createReadStream.returns
on: (type, cb)->
if type == "open"
cb()
pipe:(o)=>
@ -59,9 +59,9 @@ describe "FileStoreHandler", ->
@handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
it "should pass the correct options to request", (done)->
@fs.createReadStream.returns
@fs.createReadStream.returns
pipe:->
on: (type, cb)->
on: (type, cb)->
if type == "open"
cb()
@handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
@ -70,23 +70,24 @@ describe "FileStoreHandler", ->
done()
it "builds the correct url", (done)->
@fs.createReadStream.returns
@fs.createReadStream.returns
pipe:->
on: (type, cb)->
on: (type, cb)->
if type == "open"
cb()
@handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
@handler._buildUrl.calledWith(@project_id, @file_id).should.equal true
done()
it 'should callback with null', (done) ->
it 'should callback with the url', (done) ->
@fs.createReadStream.returns
pipe:->
on: (type, cb)->
if type == "open"
cb()
@handler.uploadFileFromDisk @project_id, @file_id, @fsPath, (err) =>
@handler.uploadFileFromDisk @project_id, @file_id, @fsPath, (err, url) =>
expect(err).to.not.exist
expect(url).to.equal(@handler._buildUrl())
done()
describe "symlink", ->
@ -218,6 +219,11 @@ describe "FileStoreHandler", ->
@handler._buildUrl.calledWith(@newProject_id, @newFile_id).should.equal true
done()
it "returns the url", (done)->
@request.callsArgWith(1, null)
@handler.copyFile @project_id, @file_id, @newProject_id, @newFile_id, (err, url) =>
url.should.equal "http://filestore.stubbedBuilder.com"
done()
it "should return the err", (done)->
error = "errrror"

View file

@ -33,8 +33,8 @@ describe 'ProjectCreationHandler', ->
constructor:(options)->
{@name} = options
@ProjectEntityHandler =
addDoc: sinon.stub().callsArgWith(4, null, {_id: docId})
addFile: sinon.stub().callsArg(4)
addDoc: sinon.stub().callsArgWith(5, null, {_id: docId})
addFile: sinon.stub().callsArg(5)
setRootDoc: sinon.stub().callsArg(2)
@ProjectDetailsHandler =
validateProjectName: sinon.stub().yields()
@ -149,7 +149,7 @@ describe 'ProjectCreationHandler', ->
.should.equal true
it 'should insert main.tex', ->
@ProjectEntityHandler.addDoc.calledWith(project_id, rootFolderId, "main.tex", ["mainbasic.tex", "lines"])
@ProjectEntityHandler.addDoc.calledWith(project_id, rootFolderId, "main.tex", ["mainbasic.tex", "lines"], ownerId)
.should.equal true
it 'should set the main doc id', ->
@ -180,19 +180,20 @@ describe 'ProjectCreationHandler', ->
it 'should insert main.tex', ->
@ProjectEntityHandler.addDoc
.calledWith(project_id, rootFolderId, "main.tex", ["main.tex", "lines"])
.calledWith(project_id, rootFolderId, "main.tex", ["main.tex", "lines"], ownerId)
.should.equal true
it 'should insert references.bib', ->
@ProjectEntityHandler.addDoc
.calledWith(project_id, rootFolderId, "references.bib", ["references.bib", "lines"])
.calledWith(project_id, rootFolderId, "references.bib", ["references.bib", "lines"], ownerId)
.should.equal true
it 'should insert universe.jpg', ->
@ProjectEntityHandler.addFile
.calledWith(
project_id, rootFolderId, "universe.jpg",
Path.resolve(__dirname + "/../../../../app/templates/project_files/universe.jpg")
Path.resolve(__dirname + "/../../../../app/templates/project_files/universe.jpg"),
ownerId
)
.should.equal true

View file

@ -64,8 +64,8 @@ describe 'ProjectDuplicator', ->
@projectOptionsHandler =
setCompiler : sinon.stub()
@entityHandler =
addDocWithProject: sinon.stub().callsArgWith(4, null, {name:"somDoc"})
copyFileFromExistingProjectWithProject: sinon.stub().callsArgWith(4)
addDocWithProject: sinon.stub().callsArgWith(5, null, {name:"somDoc"})
copyFileFromExistingProjectWithProject: sinon.stub().callsArgWith(5)
setRootDoc: sinon.stub()
addFolderWithProject: sinon.stub().callsArgWith(3, null, @newFolder)
@ -112,13 +112,13 @@ describe 'ProjectDuplicator', ->
done()
it 'should use the same compiler', (done)->
@entityHandler.addDocWithProject.callsArgWith(4, null, @rootFolder.docs[0])
@entityHandler.addDocWithProject.callsArgWith(5, null, @rootFolder.docs[0], @owner._id)
@duplicator.duplicate @owner, @old_project_id, "", (err, newProject)=>
@projectOptionsHandler.setCompiler.calledWith(@stubbedNewProject._id, @project.compiler).should.equal true
done()
it 'should use the same root doc', (done)->
@entityHandler.addDocWithProject.callsArgWith(4, null, @rootFolder.docs[0])
@entityHandler.addDocWithProject.callsArgWith(5, null, @rootFolder.docs[0], @owner._id)
@duplicator.duplicate @owner, @old_project_id, "", (err, newProject)=>
@entityHandler.setRootDoc.calledWith(@stubbedNewProject._id, @rootFolder.docs[0]._id).should.equal true
done()
@ -139,14 +139,26 @@ describe 'ProjectDuplicator', ->
it 'should copy all the docs', (done)->
@duplicator.duplicate @owner, @old_project_id, "", (err, newProject)=>
@DocstoreManager.getAllDocs.calledWith(@old_project_id).should.equal true
@entityHandler.addDocWithProject.calledWith(@stubbedNewProject, @stubbedNewProject.rootFolder[0]._id, @doc0.name, @doc0_lines).should.equal true
@entityHandler.addDocWithProject.calledWith(@stubbedNewProject, @newFolder._id, @doc1.name, @doc1_lines).should.equal true
@entityHandler.addDocWithProject.calledWith(@stubbedNewProject, @newFolder._id, @doc2.name, @doc2_lines).should.equal true
@entityHandler.addDocWithProject
.calledWith(@stubbedNewProject, @stubbedNewProject.rootFolder[0]._id, @doc0.name, @doc0_lines, @owner._id)
.should.equal true
@entityHandler.addDocWithProject
.calledWith(@stubbedNewProject, @newFolder._id, @doc1.name, @doc1_lines, @owner._id)
.should.equal true
@entityHandler.addDocWithProject
.calledWith(@stubbedNewProject, @newFolder._id, @doc2.name, @doc2_lines, @owner._id)
.should.equal true
done()
it 'should copy all the files', (done)->
@duplicator.duplicate @owner, @old_project_id, "", (err, newProject)=>
@entityHandler.copyFileFromExistingProjectWithProject.calledWith(@stubbedNewProject, @stubbedNewProject.rootFolder[0]._id, @project._id, @rootFolder.fileRefs[0]).should.equal true
@entityHandler.copyFileFromExistingProjectWithProject.calledWith(@stubbedNewProject, @newFolder._id, @project._id, @level1folder.fileRefs[0]).should.equal true
@entityHandler.copyFileFromExistingProjectWithProject.calledWith(@stubbedNewProject, @newFolder._id, @project._id, @level2folder.fileRefs[0]).should.equal true
@entityHandler.copyFileFromExistingProjectWithProject
.calledWith(@stubbedNewProject, @stubbedNewProject.rootFolder[0]._id, @project._id, @rootFolder.fileRefs[0], @owner._id)
.should.equal true
@entityHandler.copyFileFromExistingProjectWithProject
.calledWith(@stubbedNewProject, @newFolder._id, @project._id, @level1folder.fileRefs[0], @owner._id)
.should.equal true
@entityHandler.copyFileFromExistingProjectWithProject
.calledWith(@stubbedNewProject, @newFolder._id, @project._id, @level2folder.fileRefs[0], @owner._id)
.should.equal true
done()

View file

@ -17,9 +17,10 @@ describe 'ProjectEntityHandler', ->
userId = 1234
beforeEach ->
@fileUrl = 'filestore.example.com/file'
@FileStoreHandler =
uploadFileFromDisk:(project_id, fileRef, localImagePath, callback)->callback()
copyFile: sinon.stub().callsArgWith(4, null)
uploadFileFromDisk: sinon.stub().callsArgWith(3, null, @fileUrl)
copyFile: sinon.stub().callsArgWith(4, null, @fileUrl)
@tpdsUpdateSender =
addDoc:sinon.stub().callsArg(1)
addFile:sinon.stub().callsArg(1)
@ -67,6 +68,9 @@ describe 'ProjectEntityHandler', ->
findElement : sinon.stub()
@settings =
maxEntitiesPerProject:200
@documentUpdaterHandler =
updateProjectStructure: sinon.stub().yields()
deleteDoc: sinon.stub().callsArg(2)
@ProjectEntityHandler = SandboxedModule.require modulePath, requires:
'../../models/Project': Project:@ProjectModel
'../../models/Doc': Doc:@DocModel
@ -75,7 +79,7 @@ describe 'ProjectEntityHandler', ->
'../FileStore/FileStoreHandler':@FileStoreHandler
'../ThirdPartyDataStore/TpdsUpdateSender':@tpdsUpdateSender
'./ProjectLocator': @projectLocator
'../../Features/DocumentUpdater/DocumentUpdaterHandler':@documentUpdaterHandler = {}
'../../Features/DocumentUpdater/DocumentUpdaterHandler':@documentUpdaterHandler
'../Docstore/DocstoreManager': @DocstoreManager = {}
'logger-sharelatex': @logger = {log:sinon.stub(), error: sinon.stub(), err:->}
'./ProjectUpdateHandler': @projectUpdater
@ -184,7 +188,6 @@ describe 'ProjectEntityHandler', ->
describe "_cleanUpEntity", ->
beforeEach ->
@entity_id = "4eecaffcbffa66588e000009"
@documentUpdaterHandler.deleteDoc = sinon.stub().callsArg(2)
@FileStoreHandler.deleteFile = sinon.stub().callsArg(2)
@ProjectEntityHandler.unsetRootDoc = sinon.stub().callsArg(1)
@ -240,7 +243,6 @@ describe 'ProjectEntityHandler', ->
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, path: @pathAfterMove)
@ProjectGetter.getProject.callsArgWith(2, null, @project)
@tpdsUpdateSender.moveEntity = sinon.stub()
@documentUpdaterHandler.updateProjectStructure = sinon.stub().callsArg(6)
@ProjectEntityHandler.getAllEntitiesFromProject = sinon.stub()
@ProjectEntityHandler.getAllEntitiesFromProject
.onFirstCall()
@ -272,7 +274,7 @@ describe 'ProjectEntityHandler', ->
it "should should send the update to the doc updater", ->
@documentUpdaterHandler.updateProjectStructure
.calledWith(project_id, userId, @oldDocs, @newDocs, @oldFiles, @newFiles)
.calledWith(project_id, userId, {@oldDocs, @newDocs, @oldFiles, @newFiles})
.should.equal true
it 'should remove the element from its current position', ->
@ -324,7 +326,7 @@ describe 'ProjectEntityHandler', ->
it "should should send the update to the doc updater", ->
@documentUpdaterHandler.updateProjectStructure
.calledWith(project_id, userId, @oldDocs, @newDocs, @oldFiles, @newFiles)
.calledWith(project_id, userId, {@oldDocs, @newDocs, @oldFiles, @newFiles})
.should.equal true
it 'should remove the element from its current position', ->
@ -455,7 +457,7 @@ describe 'ProjectEntityHandler', ->
@tpdsUpdateSender.addDoc = sinon.stub().callsArg(1)
@DocstoreManager.updateDoc = sinon.stub().yields(null, true, 0)
@ProjectEntityHandler.addDoc project_id, folder_id, @name, @lines, @callback
@ProjectEntityHandler.addDoc project_id, folder_id, @name, @lines, userId, @callback
# Created doc
@doc = @ProjectEntityHandler._putElement.args[0][2]
@ -484,6 +486,16 @@ describe 'ProjectEntityHandler', ->
.calledWith(project_id, @doc._id.toString(), @lines)
.should.equal true
it "should should send the change in project structure to the doc updater", () ->
newDocs = [
doc: @doc
path: @path
docLines: @lines.join('\n')
]
@documentUpdaterHandler.updateProjectStructure
.calledWith(project_id, userId, {newDocs})
.should.equal true
describe "restoreDoc", ->
beforeEach ->
@name = "doc-name"
@ -512,7 +524,10 @@ describe 'ProjectEntityHandler', ->
describe 'addFile', ->
fileName = "something.jpg"
beforeEach ->
@fileSystemPath = "somehintg"
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, {path:{fileSystem: @fileSystemPath}})
@filePath = "somewhere"
it 'should upload it via the FileStoreHandler', (done)->
@FileStoreHandler.uploadFileFromDisk = (passedProject_id, file_id, filePath, callback)=>
file_id.should.equal "file_id"
@ -520,7 +535,7 @@ describe 'ProjectEntityHandler', ->
filePath.should.equal @filePath
done()
@ProjectEntityHandler.addFile project_id, folder_id, fileName, @filePath, (err, fileRef, parentFolder)->
@ProjectEntityHandler.addFile project_id, folder_id, fileName, @filePath, userId, (err, fileRef, parentFolder)->
it 'should put file into folder by calling put element', (done)->
@ProjectEntityHandler._putElement = (passedProject, passedFolder_id, passedFileRef, passedType, callback)->
@ -530,11 +545,10 @@ describe 'ProjectEntityHandler', ->
passedType.should.equal 'file'
done()
@ProjectEntityHandler.addFile project_id, folder_id, fileName, {}, (err, fileRef, parentFolder)->
@ProjectEntityHandler.addFile project_id, folder_id, fileName, {}, userId, (err, fileRef, parentFolder)->
it 'should return doc and parent folder', (done)->
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, {path:{fileSystem:"somehintg"}})
@ProjectEntityHandler.addFile project_id, folder_id, fileName, {}, (err, fileRef, parentFolder)->
@ProjectEntityHandler.addFile project_id, folder_id, fileName, {}, userId, (err, fileRef, parentFolder)->
parentFolder.should.equal folder_id
fileRef.name.should.equal fileName
done()
@ -554,33 +568,45 @@ describe 'ProjectEntityHandler', ->
options.rev.should.equal 0
done()
@ProjectEntityHandler.addFile project_id, folder_id, fileName, {}, (err, fileRef, parentFolder)->
@ProjectEntityHandler.addFile project_id, folder_id, fileName, {}, userId, (err, fileRef, parentFolder)->
describe 'replacing a file', ->
it "should should send the change in project structure to the doc updater", (done) ->
@documentUpdaterHandler.updateProjectStructure = (passed_project_id, passed_user_id, changes) =>
passed_project_id.should.equal project_id
passed_user_id.should.equal userId
{ newFiles } = changes
newFiles.length.should.equal 1
newFile = newFiles[0]
newFile.file.name.should.equal fileName
newFile.path.should.equal @fileSystemPath
newFile.url.should.equal @fileUrl
done()
@ProjectEntityHandler.addFile project_id, folder_id, fileName, {}, userId, () ->
describe 'replaceFile', ->
beforeEach ->
@projectLocator
@file_id = "file_id_here"
@fsPath = "fs_path_here.png"
@fileRef = {rev:3, _id:@file_id}
@filePaths = {fileSystem:"/folder1/file.png", mongo:"folder.1.files.somewhere"}
@fileRef = {rev:3, _id: @file_id, name: @fileName = "fileName"}
@filePaths = {fileSystem: @fileSystemPath="/folder1/file.png", mongo:"folder.1.files.somewhere"}
@projectLocator.findElement = sinon.stub().callsArgWith(1, null, @fileRef, @filePaths)
@ProjectModel.update = (_, __, ___, cb)-> cb()
@ProjectModel.findOneAndUpdate = sinon.stub().callsArgWith(3)
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project)
it 'should find the file', (done)->
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, =>
@projectLocator.findElement.calledWith({element_id:@file_id, type:"file", project_id:project_id}).should.equal true
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, userId, =>
@projectLocator.findElement
.calledWith({element_id:@file_id, type:"file", project: @project})
.should.equal true
done()
it 'should tell the file store handler to upload the file from disk', (done)->
@FileStoreHandler.uploadFileFromDisk = sinon.stub().callsArgWith(3)
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, =>
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, userId, =>
@FileStoreHandler.uploadFileFromDisk.calledWith(project_id, @file_id, @fsPath).should.equal true
done()
it 'should send the file to the tpds with an incremented rev', (done)->
@tpdsUpdateSender.addFile = (options)=>
options.project_id.should.equal project_id
@ -590,26 +616,39 @@ describe 'ProjectEntityHandler', ->
options.rev.should.equal @fileRef.rev + 1
done()
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, =>
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, userId, =>
it 'should inc the rev id', (done)->
@ProjectModel.update = (conditions, update, options, callback)=>
@ProjectModel.findOneAndUpdate = (conditions, update, options, callback)=>
conditions._id.should.equal project_id
update.$inc["#{@filePaths.mongo}.rev"].should.equal 1
done()
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, =>
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, userId, =>
it 'should update the created at date', (done)->
d = new Date()
@ProjectModel.update = (conditions, update, options, callback)=>
@ProjectModel.findOneAndUpdate = (conditions, update, options, callback)=>
conditions._id.should.equal project_id
differenceInMs = update.$set["#{@filePaths.mongo}.created"].getTime() - d.getTime()
differenceInMs.should.be.below(20)
done()
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, =>
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, userId, =>
it "should should send the old and new project structure to the doc updater", (done) ->
@documentUpdaterHandler.updateProjectStructure = (passed_project_id, passed_user_id, changes) =>
passed_project_id.should.equal project_id
passed_user_id.should.equal userId
{ newFiles } = changes
newFiles.length.should.equal 1
newFile = newFiles[0]
newFile.file.name.should.equal @fileName
newFile.path.should.equal @fileSystemPath
newFile.url.should.equal @fileUrl
done()
@ProjectEntityHandler.replaceFile project_id, @file_id, @fsPath, userId, =>
describe 'addFolder', ->
folderName = "folder1234"
@ -943,19 +982,19 @@ describe 'ProjectEntityHandler', ->
@ProjectModel.update.calledWith({_id : @project_id}, {$unset : {rootDoc_id: true}})
.should.equal true
describe 'copyFileFromExistingProject', ->
describe 'copyFileFromExistingProjectWithProject', ->
fileName = "something.jpg"
filePath = "dumpFolder/somewhere/image.jpeg"
oldProject_id = "123kljadas"
oldFileRef = {name:fileName, _id:"oldFileRef"}
beforeEach ->
@ProjectGetter.getProject = (project_id, fields, callback)=> callback(null, {name:@project.name, _id:@project._id})
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, {path:{fileSystem:"somehintg"}})
beforeEach ->
@fileSystemPath = "somehintg"
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, {path:{fileSystem: @fileSystemPath}})
it 'should copy the file in FileStoreHandler', (done)->
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, {path:{fileSystem:"somehintg"}})
@ProjectEntityHandler.copyFileFromExistingProject project_id, folder_id, oldProject_id, oldFileRef, (err, fileRef, parentFolder)=>
@ProjectEntityHandler.copyFileFromExistingProjectWithProject @project, folder_id, oldProject_id, oldFileRef, userId, (err, fileRef, parentFolder)=>
@FileStoreHandler.copyFile.calledWith(oldProject_id, oldFileRef._id, project_id, fileRef._id).should.equal true
done()
@ -967,10 +1006,10 @@ describe 'ProjectEntityHandler', ->
passedType.should.equal 'file'
done()
@ProjectEntityHandler.copyFileFromExistingProject project_id, folder_id, oldProject_id, oldFileRef, (err, fileRef, parentFolder)->
@ProjectEntityHandler.copyFileFromExistingProjectWithProject @project, folder_id, oldProject_id, oldFileRef, userId, (err, fileRef, parentFolder)->
it 'should return doc and parent folder', (done)->
@ProjectEntityHandler.copyFileFromExistingProject project_id, folder_id, oldProject_id, oldFileRef, (err, fileRef, parentFolder)->
@ProjectEntityHandler.copyFileFromExistingProjectWithProject @project, folder_id, oldProject_id, oldFileRef, userId, (err, fileRef, parentFolder)->
parentFolder.should.equal folder_id
fileRef.name.should.equal fileName
done()
@ -990,8 +1029,21 @@ describe 'ProjectEntityHandler', ->
options.rev.should.equal 0
done()
@ProjectEntityHandler.copyFileFromExistingProject project_id, folder_id, oldProject_id, oldFileRef, (err, fileRef, parentFolder)->
@ProjectEntityHandler.copyFileFromExistingProjectWithProject @project, folder_id, oldProject_id, oldFileRef, userId, (err, fileRef, parentFolder)->
it "should should send the change in project structure to the doc updater", (done) ->
@documentUpdaterHandler.updateProjectStructure = (passed_project_id, passed_user_id, changes) =>
passed_project_id.should.equal project_id
passed_user_id.should.equal userId
{ newFiles } = changes
newFiles.length.should.equal 1
newFile = newFiles[0]
newFile.file.name.should.equal fileName
newFile.path.should.equal @fileSystemPath
newFile.url.should.equal @fileUrl
done()
@ProjectEntityHandler.copyFileFromExistingProjectWithProject @project, folder_id, oldProject_id, oldFileRef, userId, (err, fileRef, parentFolder)->
describe "renameEntity", ->
beforeEach ->
@ -1012,12 +1064,12 @@ describe 'ProjectEntityHandler', ->
@projectLocator.findElement = sinon.stub().callsArgWith(1, null, @entity = { _id: @entity_id, name:"old.tex", rev:4 }, @path)
@tpdsUpdateSender.moveEntity = sinon.stub()
@ProjectModel.findOneAndUpdate = sinon.stub().callsArgWith(3, null, @project)
@documentUpdaterHandler.updateProjectStructure = sinon.stub().callsArg(6)
@documentUpdaterHandler.updateProjectStructure = sinon.stub().yields()
it "should should send the old and new project structure to the doc updater", (done) ->
@ProjectEntityHandler.renameEntity project_id, @entity_id, @entityType, @newName, userId, =>
@documentUpdaterHandler.updateProjectStructure
.calledWith(project_id, userId, @oldDocs, @newDocs, @oldFiles, @newFiles)
.calledWith(project_id, userId, {@oldDocs, @newDocs, @oldFiles, @newFiles})
.should.equal true
done()

View file

@ -63,11 +63,11 @@ describe 'UpdateMerger :', ->
file_id = "1231"
@projectLocator.findElementByPath = (_, __, cb)->cb(null, {_id:file_id})
@FileTypeManager.isBinary.callsArgWith(2, null, true)
@updateMerger.p.processFile = sinon.stub().callsArgWith(5)
@updateMerger.p.processFile = sinon.stub().callsArgWith(6)
filePath = "/folder/file1.png"
@updateMerger.mergeUpdate @user_id, @project_id, filePath, @update, @source, =>
@updateMerger.p.processFile.calledWith(@project_id, file_id, @fsPath, filePath, @source).should.equal true
@updateMerger.p.processFile.calledWith(@project_id, file_id, @fsPath, filePath, @source, @user_id).should.equal true
@FileTypeManager.isBinary.calledWith(filePath, @fsPath).should.equal true
@fs.unlink.calledWith(@fsPath).should.equal true
done()
@ -97,7 +97,7 @@ describe 'UpdateMerger :', ->
path = "folder1/folder2/#{docName}"
@editorController.mkdirp = sinon.stub().withArgs(@project_id).callsArgWith(2, null, [folder], folder)
@editorController.addDoc = ->
mock = sinon.mock(@editorController).expects("addDoc").withArgs(@project_id, folder._id, docName, @splitDocLines, @source).callsArg(5)
mock = sinon.mock(@editorController).expects("addDoc").withArgs(@project_id, folder._id, docName, @splitDocLines, @source, @user_id).callsArg(6)
@update.write(@docLines)
@update.end()
@ -114,22 +114,22 @@ describe 'UpdateMerger :', ->
@folder = _id: @folder_id
@fileName = "file.png"
@fsPath = "fs/path.tex"
@editorController.addFile = sinon.stub().callsArg(5)
@editorController.replaceFile = sinon.stub().callsArg(4)
@editorController.addFile = sinon.stub().callsArg(6)
@editorController.replaceFile = sinon.stub().callsArg(5)
@editorController.deleteEntity = sinon.stub()
@editorController.mkdirp = sinon.stub().withArgs(@project_id).callsArgWith(2, null, [@folder], @folder)
@updateMerger.p.writeStreamToDisk = sinon.stub().withArgs(@project_id, @file_id, @update).callsArgWith(3, null, @fsPath)
it 'should replace file if the file already exists', (done)->
@updateMerger.p.processFile @project_id, @file_id, @fsPath, @path, @source, =>
@updateMerger.p.processFile @project_id, @file_id, @fsPath, @path, @source, @user_id, =>
@editorController.addFile.called.should.equal false
@editorController.replaceFile.calledWith(@project_id, @file_id, @fsPath, @source).should.equal true
@editorController.replaceFile.calledWith(@project_id, @file_id, @fsPath, @source, @user_id).should.equal true
done()
it 'should call add file if the file does not exist', (done)->
@updateMerger.p.processFile @project_id, undefined, @fsPath, @path, @source, =>
@updateMerger.p.processFile @project_id, undefined, @fsPath, @path, @source, @user_id, =>
@editorController.mkdirp.calledWith(@project_id, "folder/").should.equal true
@editorController.addFile.calledWith(@project_id, @folder_id, @fileName, @fsPath, @source).should.equal true
@editorController.addFile.calledWith(@project_id, @folder_id, @fileName, @fsPath, @source, @user_id).should.equal true
@editorController.replaceFile.called.should.equal false
done()

View file

@ -44,14 +44,14 @@ describe "FileSystemImportManager", ->
describe "with replace set to false", ->
beforeEach ->
@EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
@EditorController.addDocWithoutLock = sinon.stub().callsArg(6)
@FileSystemImportManager.addDoc @user_id, @project_id, @folder_id, @name, @path_on_disk, false, @callback
it "should read the file from disk", ->
@fs.readFile.calledWith(@path_on_disk, "utf8").should.equal true
it "should insert the doc", ->
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload")
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload", @user_id)
.should.equal true
describe "with windows line ending", ->
@ -59,11 +59,11 @@ describe "FileSystemImportManager", ->
@docContent = "one\r\ntwo\r\nthree"
@docLines = ["one", "two", "three"]
@fs.readFile = sinon.stub().callsArgWith(2, null, @docContent)
@EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
@EditorController.addDocWithoutLock = sinon.stub().callsArg(6)
@FileSystemImportManager.addDoc @user_id, @project_id, @folder_id, @name, @path_on_disk, false, @callback
it "should strip the \\r characters before adding", ->
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload")
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload", @user_id)
.should.equal true
describe "with replace set to true", ->
@ -76,7 +76,7 @@ describe "FileSystemImportManager", ->
}]
}
@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @folder)
@EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
@EditorController.addDocWithoutLock = sinon.stub().callsArg(6)
@FileSystemImportManager.addDoc @user_id, @project_id, @folder_id, @name, @path_on_disk, true, @callback
it "should look up the folder", ->
@ -85,7 +85,7 @@ describe "FileSystemImportManager", ->
.should.equal true
it "should insert the doc", ->
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload")
@EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload", @user_id)
.should.equal true
describe "when the doc does exist", ->
@ -114,12 +114,12 @@ describe "FileSystemImportManager", ->
describe "addFile with replace set to false", ->
beforeEach ->
@EditorController.addFileWithoutLock = sinon.stub().callsArg(5)
@EditorController.addFileWithoutLock = sinon.stub().callsArg(6)
@FileSystemImportManager._isSafeOnFileSystem = sinon.stub().callsArgWith(1, null, true)
@FileSystemImportManager.addFile @user_id, @project_id, @folder_id, @name, @path_on_disk, false, @callback
it "should add the file", ->
@EditorController.addFileWithoutLock.calledWith(@project_id, @folder_id, @name, @path_on_disk, "upload")
@EditorController.addFileWithoutLock.calledWith(@project_id, @folder_id, @name, @path_on_disk, "upload", @user_id)
.should.equal true
describe "addFile with symlink", ->
@ -144,7 +144,7 @@ describe "FileSystemImportManager", ->
}
@FileSystemImportManager._isSafeOnFileSystem = sinon.stub().callsArgWith(1, null, true)
@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @folder)
@EditorController.addFileWithoutLock = sinon.stub().callsArg(5)
@EditorController.addFileWithoutLock = sinon.stub().callsArg(6)
@FileSystemImportManager.addFile @user_id, @project_id, @folder_id, @name, @path_on_disk, true, @callback
it "should look up the folder", ->
@ -153,7 +153,7 @@ describe "FileSystemImportManager", ->
.should.equal true
it "should add the file", ->
@EditorController.addFileWithoutLock.calledWith(@project_id, @folder_id, @name, @path_on_disk, "upload")
@EditorController.addFileWithoutLock.calledWith(@project_id, @folder_id, @name, @path_on_disk, "upload", @user_id)
.should.equal true
describe "when the file does exist", ->
@ -169,7 +169,7 @@ describe "FileSystemImportManager", ->
}
@FileSystemImportManager._isSafeOnFileSystem = sinon.stub().callsArgWith(1, null, true)
@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @folder)
@EditorController.replaceFile = sinon.stub().callsArg(4)
@EditorController.replaceFile = sinon.stub().callsArg(5)
@FileSystemImportManager.addFile @user_id, @project_id, @folder_id, @name, @path_on_disk, true, @callback
it "should look up the folder", ->
@ -178,7 +178,7 @@ describe "FileSystemImportManager", ->
.should.equal true
it "should replace the file", ->
@EditorController.replaceFile.calledWith(@project_id, @file_id, @path_on_disk, "upload")
@EditorController.replaceFile.calledWith(@project_id, @file_id, @path_on_disk, "upload", @user_id)
.should.equal true
describe "addFolder", ->