Merge pull request #286 from sharelatex/bg-prevent-duplicate-filenames

prevent duplicate filenames
This commit is contained in:
Brian Gough
2018-01-31 11:50:45 +00:00
committed by GitHub
10 changed files with 690 additions and 51 deletions

View File

@@ -105,7 +105,7 @@ module.exports = EditorHttpController =
else if error?.message == 'invalid element name'
res.status(400).json(req.i18n.translate('invalid_file_name'))
else if error?
res.status(500).json(req.i18n.translate('generic_something_went_wrong'))
next(error)
else
res.json doc

View File

@@ -170,7 +170,8 @@ module.exports = ProjectEntityHandler =
if project_or_id._id? # project
return cb(null, project_or_id)
else # id
return ProjectGetter.getProjectWithOnlyFolders project_or_id, cb
# need to retrieve full project structure to check for duplicates
return ProjectGetter.getProject project_or_id, {rootFolder:true, name:true}, cb
getProject (error, project) ->
if err?
logger.err project_id:project_id, err:err, "error getting project for add doc"
@@ -207,7 +208,7 @@ module.exports = ProjectEntityHandler =
ProjectEntityHandler.addDoc project_id, null, name, lines, callback
addFileWithoutUpdatingHistory: (project_id, folder_id, fileName, path, userId, callback = (error, fileRef, folder_id, path, fileStoreUrl) ->)->
ProjectGetter.getProjectWithOnlyFolders project_id, (err, project) ->
ProjectGetter.getProject project_id, {rootFolder:true, name:true}, (err, project) ->
if err?
logger.err project_id:project_id, err:err, "error getting project for add file"
return callback(err)
@@ -229,6 +230,7 @@ module.exports = ProjectEntityHandler =
addFile: (project_id, folder_id, fileName, fsPath, userId, callback = (error, fileRef, folder_id) ->)->
ProjectEntityHandler.addFileWithoutUpdatingHistory project_id, folder_id, fileName, fsPath, userId, (error, fileRef, folder_id, path, fileStoreUrl) ->
return callback(error) if error?
newFiles = [
file: fileRef
path: path
@@ -340,7 +342,7 @@ module.exports = ProjectEntityHandler =
callback(null, folders, lastFolder)
addFolder: (project_id, parentFolder_id, folderName, callback) ->
ProjectGetter.getProjectWithOnlyFolders project_id, (err, project)=>
ProjectGetter.getProject project_id, {rootFolder:true, name:true}, (err, project)=>
if err?
logger.err project_id:project_id, err:err, "error getting project for add folder"
return callback(err)
@@ -394,7 +396,7 @@ module.exports = ProjectEntityHandler =
return callback(err) if err?
projectLocator.findElement {project, element_id: entity_id, type: entityType}, (err, entity, entityPath)->
return callback(err) if err?
self._checkValidMove project, entityType, entityPath, destFolderId, (error) ->
self._checkValidMove project, entityType, entity, entityPath, destFolderId, (error) ->
return callback(error) if error?
self.getAllEntitiesFromProject project, (error, oldDocs, oldFiles) =>
return callback(error) if error?
@@ -413,19 +415,20 @@ module.exports = ProjectEntityHandler =
return callback(error) if error?
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {oldDocs, newDocs, oldFiles, newFiles}, callback
_checkValidMove: (project, entityType, entityPath, destFolderId, callback = (error) ->) ->
return callback() if !entityType.match(/folder/)
_checkValidMove: (project, entityType, entity, entityPath, destFolderId, callback = (error) ->) ->
projectLocator.findElement { project, element_id: destFolderId, type:"folder"}, (err, destEntity, destFolderPath) ->
return callback(err) if err?
logger.log destFolderPath: destFolderPath.fileSystem, folderPath: entityPath.fileSystem, "checking folder is not moving into child folder"
isNestedFolder = destFolderPath.fileSystem.slice(0, entityPath.fileSystem.length) == entityPath.fileSystem
if isNestedFolder
callback(new Error("destination folder is a child folder of me"))
else
# check if there is already a doc/file/folder with the same name
# in the destination folder
ProjectEntityHandler.checkValidElementName destEntity, entity.name, (err)->
return callback(err) if err?
if entityType.match(/folder/)
logger.log destFolderPath: destFolderPath.fileSystem, folderPath: entityPath.fileSystem, "checking folder is not moving into child folder"
isNestedFolder = destFolderPath.fileSystem.slice(0, entityPath.fileSystem.length) == entityPath.fileSystem
if isNestedFolder
return callback(new Errors.InvalidNameError("destination folder is a child folder of me"))
callback()
deleteEntity: (project_id, entity_id, entityType, userId, callback = (error) ->)->
self = @
logger.log entity_id:entity_id, entityType:entityType, project_id:project_id, "deleting project entity"
@@ -456,19 +459,22 @@ module.exports = ProjectEntityHandler =
return callback(error) if error?
ProjectEntityHandler.getAllEntitiesFromProject project, (error, oldDocs, oldFiles) =>
return callback(error) if error?
projectLocator.findElement {project:project, element_id:entity_id, type:entityType}, (error, entity, entPath)=>
projectLocator.findElement {project:project, element_id:entity_id, type:entityType}, (error, entity, entPath, parentFolder)=>
return callback(error) if error?
endPath = path.join(path.dirname(entPath.fileSystem), newName)
conditions = {_id:project_id}
update = "$set":{}
namePath = entPath.mongo+".name"
update["$set"][namePath] = newName
tpdsUpdateSender.moveEntity({project_id:project_id, startPath:entPath.fileSystem, endPath:endPath, project_name:project.name, rev:entity.rev})
Project.findOneAndUpdate conditions, update, { "new": true}, (error, newProject) ->
# check if the new name already exists in the current folder
ProjectEntityHandler.checkValidElementName parentFolder, newName, (error) =>
return callback(error) if error?
ProjectEntityHandler.getAllEntitiesFromProject newProject, (error, newDocs, newFiles) =>
endPath = path.join(path.dirname(entPath.fileSystem), newName)
conditions = {_id:project_id}
update = "$set":{}
namePath = entPath.mongo+".name"
update["$set"][namePath] = newName
tpdsUpdateSender.moveEntity({project_id:project_id, startPath:entPath.fileSystem, endPath:endPath, project_name:project.name, rev:entity.rev})
Project.findOneAndUpdate conditions, update, { "new": true}, (error, newProject) ->
return callback(error) if error?
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {oldDocs, newDocs, oldFiles, newFiles}, callback
ProjectEntityHandler.getAllEntitiesFromProject newProject, (error, newDocs, newFiles) =>
return callback(error) if error?
DocumentUpdaterHandler.updateProjectStructure project_id, userId, {oldDocs, newDocs, oldFiles, newFiles}, callback
_cleanUpEntity: (project, entity, entityType, path, userId, callback = (error) ->) ->
if(entityType.indexOf("file") != -1)
@@ -606,19 +612,32 @@ module.exports = ProjectEntityHandler =
newPath =
fileSystem: "#{path.fileSystem}/#{element.name}"
mongo: path.mongo
id = element._id+''
element._id = require('mongoose').Types.ObjectId(id)
conditions = _id:project._id
mongopath = "#{path.mongo}.#{type}"
update = "$push":{}
update["$push"][mongopath] = element
logger.log project_id: project._id, element_id: element._id, fileType: type, folder_id: folder_id, mongopath:mongopath, "adding element to project"
Project.findOneAndUpdate conditions, update, {"new": true}, (err, project)->
if err?
logger.err err: err, project_id: project._id, 'error saving in putElement project'
return callback(err)
callback(err, {path:newPath}, project)
ProjectEntityHandler.checkValidElementName folder, element.name, (err) =>
return callback(err) if err?
id = element._id+''
element._id = require('mongoose').Types.ObjectId(id)
conditions = _id:project._id
mongopath = "#{path.mongo}.#{type}"
update = "$push":{}
update["$push"][mongopath] = element
logger.log project_id: project._id, element_id: element._id, fileType: type, folder_id: folder_id, mongopath:mongopath, "adding element to project"
Project.findOneAndUpdate conditions, update, {"new": true}, (err, project)->
if err?
logger.err err: err, project_id: project._id, 'error saving in putElement project'
return callback(err)
callback(err, {path:newPath}, project)
checkValidElementName: (folder, name, callback = (err) ->) ->
# check if the name is already taken by a doc, file or
# folder. If so, return an error "file already exists".
err = new Errors.InvalidNameError("file already exists")
for doc in folder?.docs or []
return callback(err) if doc.name is name
for file in folder?.fileRefs or []
return callback(err) if file.name is name
for folder in folder?.folders or []
return callback(err) if folder.name is name
callback()
confirmFolder = (project, folder_id, callback)->
logger.log folder_id:folder_id, project_id:project._id, "confirming folder in project"

View File

@@ -110,7 +110,7 @@ script(type='text/ng-template', id='entityListItemTemplate')
i.fa.fa-fw(ng-if="entity.type != 'folder'", ng-class="'fa-' + iconTypeFromName(entity.name)")
span(
ng-hide="entity.renaming"
) {{ entity.name }}
) {{ entity.renamingToName || entity.name }}
span.rename-input
input(
ng-if="permissions.write",
@@ -198,7 +198,7 @@ script(type='text/ng-template', id='entityListItemTemplate')
span(
ng-hide="entity.renaming"
) {{ entity.name }}
) {{ entity.renamingToName || entity.name }}
span.rename-input
input(
ng-if="permissions.write",

View File

@@ -321,7 +321,20 @@ define [
return null
existsInThisFolder: (folder, name) ->
for entity in folder?.children or []
return true if entity.name is name
return false
nameExistsError: (message = "already exists") ->
nameExists = @ide.$q.defer()
nameExists.reject({data: message})
return nameExists.promise
createDoc: (name, parent_folder = @getCurrentFolder()) ->
# check if a doc/file/folder already exists with this name
if @existsInThisFolder parent_folder, name
return @nameExistsError()
# We'll wait for the socket.io notification to actually
# add the doc for us.
@ide.$http.post "/project/#{@ide.project_id}/doc", {
@@ -331,6 +344,9 @@ define [
}
createFolder: (name, parent_folder = @getCurrentFolder()) ->
# check if a doc/file/folder already exists with this name
if @existsInThisFolder parent_folder, name
return @nameExistsError()
# We'll wait for the socket.io notification to actually
# add the folder for us.
return @ide.$http.post "/project/#{@ide.project_id}/folder", {
@@ -341,12 +357,20 @@ define [
renameEntity: (entity, name, callback = (error) ->) ->
return if entity.name == name
if name.length < 150
entity.name = name
return @ide.$http.post "/project/#{@ide.project_id}/#{entity.type}/#{entity.id}/rename", {
name: entity.name,
return if name.length >= 150
# check if a doc/file/folder already exists with this name
parent_folder = @getCurrentFolder()
if @existsInThisFolder parent_folder, name
return @nameExistsError()
entity.renamingToName = name
@ide.$http.post("/project/#{@ide.project_id}/#{entity.type}/#{entity.id}/rename", {
name: name,
_csrf: window.csrfToken
}
})
.then () ->
entity.name = name
.finally () ->
entity.renamingToName = null
deleteEntity: (entity, callback = (error) ->) ->
# We'll wait for the socket.io notification to
@@ -362,11 +386,15 @@ define [
# Abort move if the folder being moved (entity) has the parent_folder as child
# since that would break the tree structure.
return if @_isChildFolder(entity, parent_folder)
@_moveEntityInScope(entity, parent_folder)
return @ide.queuedHttp.post "/project/#{@ide.project_id}/#{entity.type}/#{entity.id}/move", {
# check if a doc/file/folder already exists with this name
if @existsInThisFolder parent_folder, entity.name
return @nameExistsError()
# Wait for the http response before doing the move
@ide.queuedHttp.post("/project/#{@ide.project_id}/#{entity.type}/#{entity.id}/move", {
folder_id: parent_folder.id
_csrf: window.csrfToken
}
}).then () =>
@_moveEntityInScope(entity, parent_folder)
_isChildFolder: (parent_folder, child_folder) ->
parent_path = @getEntityPath(parent_folder) or "" # null if root folder

View File

@@ -69,6 +69,7 @@ define [
.catch (response)->
{ data } = response
$scope.error = data
$scope.state.inflight = false
$scope.cancel = () ->
$modalInstance.dismiss('cancel')

View File

@@ -28,6 +28,9 @@ define [
invalidModalShowing = false
$scope.finishRenaming = () ->
# avoid double events when blur and on-enter fire together
return if !$scope.entity.renaming
name = $scope.inputs.name
if !name.match(new RegExp(ide.validFileRegex))

View File

@@ -3,10 +3,11 @@ define [
], (App) ->
# We create and provide this as service so that we can access the global ide
# from within other parts of the angular app.
App.factory "ide", ["$http", "queuedHttp", "$modal", ($http, queuedHttp, $modal) ->
App.factory "ide", ["$http", "queuedHttp", "$modal", "$q", ($http, queuedHttp, $modal, $q) ->
ide = {}
ide.$http = $http
ide.queuedHttp = queuedHttp
ide.$q = $q
@recentEvents = []
ide.pushEvent = (type, meta = {}) =>

View File

@@ -0,0 +1,448 @@
async = require "async"
expect = require("chai").expect
sinon = require "sinon"
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"
MockDocStoreApi = require './helpers/MockDocstoreApi'
MockFileStoreApi = require './helpers/MockFileStoreApi'
request = require "./helpers/request"
User = require "./helpers/User"
describe "ProjectDuplicateNames", ->
before (done) ->
@owner = new User()
@owner.login done
@project = {}
@callback = sinon.stub()
describe "creating a project from the example template", ->
before (done) ->
@owner.createProject "example-project", {template: "example"}, (error, project_id) =>
throw error if error?
@example_project_id = project_id
@owner.getProject project_id, (error, project) =>
@project = project
@mainTexDoc = _.find(project.rootFolder[0].docs, (doc) -> doc.name is 'main.tex')
@refBibDoc = _.find(project.rootFolder[0].docs, (doc) -> doc.name is 'references.bib')
@imageFile = _.find(project.rootFolder[0].fileRefs, (file) -> file.name is 'universe.jpg')
@rootFolderId = project.rootFolder[0]._id.toString()
# create a folder called 'testfolder'
@owner.request.post {
uri: "/project/#{@example_project_id}/folder"
json:
name: "testfolder"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@testFolderId = body._id
done()
it "should create a project", ->
expect(@project.rootFolder[0].docs.length).to.equal(2)
expect(@project.rootFolder[0].fileRefs.length).to.equal(1)
it "should create two docs in the docstore", ->
docs = MockDocStoreApi.docs[@example_project_id]
expect(Object.keys(docs).length).to.equal(2)
it "should create one file in the filestore", ->
files = MockFileStoreApi.files[@example_project_id]
expect(Object.keys(files).length).to.equal(1)
describe "for an existing doc", ->
describe "trying to add a doc with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc"
json:
name: "main.tex"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to add a folder with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder"
json:
name: "main.tex"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to upload a file with the same name", ->
before (done) ->
@owner.request.post
uri: "/project/#{@example_project_id}/upload"
json: true
qs:
folder_id: @rootFolderId
qqfilename: "main.tex"
formData:
qqfile:
value: fs.createReadStream Path.resolve(__dirname + '/../files/1pixel.png')
options:
filename: 'main.tex',
contentType: 'image/png'
, (err, res, body) =>
@body = body
done()
it "should respond with failure status", ->
expect(@body.success).to.equal false
describe "trying to add a folder with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder"
json:
name: "main.tex"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to upload a file with the same name", ->
before (done) ->
@owner.request.post
uri: "/project/#{@example_project_id}/upload"
json: true
qs:
folder_id: @rootFolderId
qqfilename: "main.tex"
formData:
qqfile:
value: fs.createReadStream Path.resolve(__dirname + '/../files/1pixel.png')
options:
filename: 'main.tex',
contentType: 'image/png'
, (err, res, body) =>
@body = body
done()
it "should respond with failure status", ->
expect(@body.success).to.equal false
describe "for an existing file", ->
describe "trying to add a doc with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc"
json:
name: "universe.jpg"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to add a folder with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder"
json:
name: "universe.jpg"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to upload a file with the same name", ->
before (done) ->
@owner.request.post
uri: "/project/#{@example_project_id}/upload"
json: true
qs:
folder_id: @rootFolderId
qqfilename: "universe.jpg"
formData:
qqfile:
value: fs.createReadStream Path.resolve(__dirname + '/../files/1pixel.png')
options:
filename: 'universe.jpg',
contentType: 'image/jpeg'
, (err, res, body) =>
@body = body
done()
it "should succeed (overwriting the file)", ->
expect(@body.success).to.equal true
describe "for an existing folder", ->
describe "trying to add a doc with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc"
json:
name: "testfolder"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to add a folder with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder"
json:
name: "testfolder"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to upload a file with the same name", ->
before (done) ->
@owner.request.post
uri: "/project/#{@example_project_id}/upload"
json: true
qs:
folder_id: @rootFolderId
qqfilename: "universe.jpg"
formData:
qqfile:
value: fs.createReadStream Path.resolve(__dirname + '/../files/1pixel.png')
options:
filename: 'testfolder',
contentType: 'image/jpeg'
, (err, res, body) =>
@body = body
done()
it "should respond with failure status", ->
expect(@body.success).to.equal false
describe "for an existing doc", ->
describe "trying to rename a doc to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc/#{@refBibDoc._id}/rename"
json:
name: "main.tex"
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to rename a folder to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder/#{@testFolderId}/rename"
json:
name: "main.tex"
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to rename a file to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/file/#{@imageFile._id}/rename"
json:
name: "main.tex"
}, (err, res, body) =>
@res = res
done()
it "should respond with failure status", ->
expect(@res.statusCode).to.equal 400
describe "for an existing file", ->
describe "trying to rename a doc to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc/#{@refBibDoc._id}/rename"
json:
name: "universe.jpg"
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to rename a folder to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder/#{@testFolderId}/rename"
json:
name: "universe.jpg"
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to rename a file to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/file/#{@imageFile._id}/rename"
json:
name: "universe.jpg"
}, (err, res, body) =>
@res = res
done()
it "should respond with failure status", ->
expect(@res.statusCode).to.equal 400
describe "for an existing folder", ->
describe "trying to rename a doc to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc/#{@refBibDoc._id}/rename"
json:
name: "testfolder"
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to rename a folder to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder/#{@testFolderId}/rename"
json:
name: "testfolder"
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to rename a file to the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/file/#{@imageFile._id}/rename"
json:
name: "testfolder"
}, (err, res, body) =>
@res = res
done()
it "should respond with failure status", ->
expect(@res.statusCode).to.equal 400
describe "for an existing folder with a file with the same name", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc"
json:
name: "main.tex"
parent_folder_id: @testFolderId
}, (err, res, body) =>
@owner.request.post {
uri: "/project/#{@example_project_id}/doc"
json:
name: "universe.jpg"
parent_folder_id: @testFolderId
}, (err, res, body) =>
@owner.request.post {
uri: "/project/#{@example_project_id}/folder"
json:
name: "otherFolder"
parent_folder_id: @testFolderId
}, (err, res, body) =>
@subFolderId = body._id
@owner.request.post {
uri: "/project/#{@example_project_id}/folder"
json:
name: "otherFolder"
parent_folder_id: @rootFolderId
}, (err, res, body) =>
@otherFolderId = body._id
done()
describe "trying to move a doc into the folder", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/doc/#{@mainTexDoc._id}/move"
json:
folder_id: @testFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to move a file into the folder", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/file/#{@imageFile._id}/move"
json:
folder_id: @testFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to move a folder into the folder", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder/#{@otherFolderId}/move"
json:
folder_id: @testFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400
describe "trying to move a folder into a subfolder of itself", ->
before (done) ->
@owner.request.post {
uri: "/project/#{@example_project_id}/folder/#{@testFolderId}/move"
json:
folder_id: @subFolderId
}, (err, res, body) =>
@res = res
done()
it "should respond with 400 error status", ->
expect(@res.statusCode).to.equal 400

View File

@@ -8,8 +8,11 @@ module.exports = MockFileStoreApi =
app.post "/project/:project_id/file/:file_id", (req, res, next) =>
req.on 'data', ->
req.on 'end', ->
res.send 200
req.on 'end', =>
{project_id, file_id} = req.params
@files[project_id] ?= {}
@files[project_id][file_id] = { content : "test-file-content" }
res.sendStatus 200
app.listen 3009, (error) ->
throw error if error?

View File

@@ -62,7 +62,7 @@ describe 'ProjectEntityHandler', ->
@ProjectGetter =
getProjectWithOnlyFolders : (project_id, callback)=> callback(null, @project)
getProjectWithoutDocLines : (project_id, callback)=> callback(null, @project)
getProject:sinon.stub()
getProject: sinon.stub().callsArgWith(2, null, @project)
@projectUpdater = markAsUpdated:sinon.stub()
@projectLocator =
findElement : sinon.stub()
@@ -287,6 +287,8 @@ describe 'ProjectEntityHandler', ->
@projectLocator.findElement = sinon.stub()
@projectLocator.findElement.withArgs({project: @project, element_id: @docId, type: 'docs'})
.callsArgWith(1, null, @doc, @path)
@projectLocator.findElement.withArgs({project: @project, element_id: folder_id, type:"folder"},)
.callsArgWith(1, null, @destFolder, @destFolderPath)
@ProjectEntityHandler.moveEntity project_id, @docId, folder_id, "docs", userId, done
it 'should find the doc to move', ->
@@ -315,6 +317,46 @@ describe 'ProjectEntityHandler', ->
})
.should.equal true
describe "moving a doc when another with the same name already exists", ->
beforeEach () ->
@docId = "4eecaffcbffa66588e000009"
@doc = { name: "another-doc.tex", lines:["1234","312343d"], rev: "1234"}
@path = {
mongo:"folders[0]"
fileSystem:"/old_folder/somewhere.txt"
}
@destFolder = { name: "folder", docs: [ {name:"another-doc.tex"} ] }
@destFolderPath = {
mongo: "folders[0]"
fileSystem: "/dest_folder"
}
@projectLocator.findElement = sinon.stub()
@projectLocator.findElement.withArgs({project: @project, element_id: @docId, type: 'docs'})
.callsArgWith(1, null, @doc, @path)
@projectLocator.findElement.withArgs({project: @project, element_id: folder_id, type:"folder"},)
.callsArgWith(1, null, @destFolder, @destFolderPath)
@callback = sinon.stub()
@ProjectEntityHandler.moveEntity project_id, @docId, folder_id, "docs", userId, @callback
it 'should return an error', ->
@callback.calledWith(new Errors.InvalidNameError("file already exists")).should.equal true
it "should should not send the update to the doc updater", ->
@documentUpdaterHandler.updateProjectStructure
.called.should.equal false
it 'should not remove the element from its current position', ->
@ProjectEntityHandler._removeElementFromMongoArray
.called.should.equal false
it "should not put the element back in the new folder", ->
@ProjectEntityHandler._putElement.called.should.equal false
it 'should not tell the third party data store', ->
@tpdsUpdateSender.moveEntity
.called.should.equal false
describe "moving a folder", ->
beforeEach ->
@folder_id = "folder-to-move"
@@ -379,10 +421,37 @@ describe 'ProjectEntityHandler', ->
})
.should.equal true
describe "when the destination folder contains a file with the same name", ->
beforeEach ->
@path.fileSystem = "/one/src_dir"
@pathToMoveTo.fileSystem = "/two/dest_dir"
@folder_to_move_to = { name: "folder to move to", fileRefs: [ {name: "folder"}] }
@projectLocator.findElement.withArgs({project: @project, element_id: @move_to_folder_id, type: 'folder'})
.callsArgWith(1, null, @folder_to_move_to, @pathToMoveTo)
@callback = sinon.stub()
@ProjectEntityHandler.moveEntity project_id, @folder_id, @move_to_folder_id, "folder", userId, @callback
it 'should find the folder we are moving to element', ->
@projectLocator.findElement
.calledWith({
element_id: @move_to_folder_id,
type: "folder",
project: @project
})
.should.equal true
it "should return an error", ->
@callback
.calledWith(new Errors.InvalidNameError("file already exists"))
.should.equal true
describe "when the destination folder is inside the moving folder", ->
beforeEach ->
@path.fileSystem = "/one/two"
@pathToMoveTo.fileSystem = "/one/two/three"
@projectLocator.findElement.withArgs({project: @project, element_id: @move_to_folder_id, type: 'folder'})
.callsArgWith(1, null, @folder_to_move_to, @pathToMoveTo)
@callback = sinon.stub()
@ProjectEntityHandler.moveEntity project_id, @folder_id, @move_to_folder_id, "folder", userId, @callback
@@ -472,6 +541,7 @@ describe 'ProjectEntityHandler', ->
@lines = ['1234','abc']
@path = "/path/to/doc"
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project)
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, {path:{fileSystem:@path}})
@callback = sinon.stub()
@tpdsUpdateSender.addDoc = sinon.stub().callsArg(1)
@@ -522,6 +592,7 @@ describe 'ProjectEntityHandler', ->
@lines = ['1234','abc']
@path = "/path/to/doc"
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project)
@ProjectEntityHandler._putElement = sinon.stub().callsArgWith(4, null, {path:{fileSystem:@path}})
@callback = sinon.stub()
@tpdsUpdateSender.addDoc = sinon.stub().callsArg(1)
@@ -1123,6 +1194,20 @@ describe 'ProjectEntityHandler', ->
@newName = "new.tex"
@path = mongo: "mongo.path", fileSystem: "/oldnamepath/oldname"
@project_id = project_id
@project =
_id: ObjectId(project_id)
rootFolder: [_id:ObjectId()]
@folder =
_id: ObjectId()
name: "someFolder"
docs: [ {name: "another-doc.tex"} ]
fileRefs: [ {name: "another-file.tex"} ]
folders: [ {name: "another-folder"} ]
@doc =
_id: ObjectId()
name: "new.tex"
@ProjectGetter.getProject.callsArgWith(2, null, @project)
@ProjectEntityHandler.getAllEntitiesFromProject = sinon.stub()
@ProjectEntityHandler.getAllEntitiesFromProject
@@ -1132,7 +1217,7 @@ describe 'ProjectEntityHandler', ->
.onSecondCall()
.callsArgWith(1, null, @newDocs = ['new-doc'], @newFiles = ['new-file'])
@projectLocator.findElement = sinon.stub().callsArgWith(1, null, @entity = { _id: @entity_id, name:"oldname", rev:4 }, @path)
@projectLocator.findElement = sinon.stub().callsArgWith(1, null, @entity = { _id: @entity_id, name:"oldname", rev:4 }, @path, @folder)
@tpdsUpdateSender.moveEntity = sinon.stub()
@ProjectModel.findOneAndUpdate = sinon.stub().callsArgWith(3, null, @project)
@documentUpdaterHandler.updateProjectStructure = sinon.stub().yields()
@@ -1154,6 +1239,27 @@ describe 'ProjectEntityHandler', ->
@tpdsUpdateSender.moveEntity.calledWith({project_id:project_id, startPath:@path.fileSystem, endPath:"/oldnamepath/new.tex", project_name:@project.name, rev:4}).should.equal true
done()
describe "when a document already exists with the same name", ->
beforeEach ->
@project =
_id: ObjectId(project_id)
rootFolder: [_id:ObjectId()]
@folder =
_id: ObjectId()
name: "someFolder"
docs: [ {name: "another-doc.tex"} ]
fileRefs: [ {name: "another-file.tex"} ]
folders: [ {name: "another-folder"} ]
@doc =
_id: ObjectId()
name: "new.tex"
@newName = "another-doc.tex"
it "should return an error", (done)->
@ProjectEntityHandler.renameEntity project_id, @entity_id, @entityType, @newName, userId, (err)=>
err.should.deep.equal new Errors.InvalidNameError("file already exists")
done()
describe "_insertDeletedDocReference", ->
beforeEach ->
@doc =
@@ -1248,6 +1354,9 @@ describe 'ProjectEntityHandler', ->
@folder =
_id: ObjectId()
name: "someFolder"
docs: [ {name: "another-doc.tex"} ]
fileRefs: [ {name: "another-file.tex"} ]
folders: [ {name: "another-folder"} ]
@doc =
_id: ObjectId()
name: "new.tex"
@@ -1290,6 +1399,33 @@ describe 'ProjectEntityHandler', ->
@ProjectModel.findOneAndUpdate.called.should.equal false
done()
it "should error if a document already exists with the same name", (done)->
doc =
_id: ObjectId()
name: "another-doc.tex"
@ProjectEntityHandler._putElement @project, @folder, doc, "doc", (err)=>
@ProjectModel.findOneAndUpdate.called.should.equal false
err.should.deep.equal new Errors.InvalidNameError("file already exists")
done()
it "should error if a file already exists with the same name", (done)->
doc =
_id: ObjectId()
name: "another-file.tex"
@ProjectEntityHandler._putElement @project, @folder, doc, "doc", (err)=>
@ProjectModel.findOneAndUpdate.called.should.equal false
err.should.deep.equal new Errors.InvalidNameError("file already exists")
done()
it "should error if a folder already exists with the same name", (done)->
doc =
_id: ObjectId()
name: "another-folder"
@ProjectEntityHandler._putElement @project, @folder, doc, "doc", (err)=>
@ProjectModel.findOneAndUpdate.called.should.equal false
err.should.deep.equal new Errors.InvalidNameError("file already exists")
done()
describe "_countElements", ->
beforeEach ->