diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee
index e7fdc4f3e3..4f5d3cb3d0 100644
--- a/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee
+++ b/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee
@@ -12,7 +12,7 @@ module.exports =
addUserToGroup: (req, res)->
adminUserId = req.session.user._id
- newEmail = req.body.email
+ newEmail = req.body?.email?.toLowerCase()?.trim()
logger.log adminUserId:adminUserId, newEmail:newEmail, "adding user to group subscription"
SubscriptionGroupHandler.addUserToGroup adminUserId, newEmail, (err, user)->
if err?
diff --git a/services/web/app/coffee/Features/Uploads/ArchiveManager.coffee b/services/web/app/coffee/Features/Uploads/ArchiveManager.coffee
index e666b83f24..325df9369f 100644
--- a/services/web/app/coffee/Features/Uploads/ArchiveManager.coffee
+++ b/services/web/app/coffee/Features/Uploads/ArchiveManager.coffee
@@ -1,6 +1,8 @@
child = require "child_process"
logger = require "logger-sharelatex"
metrics = require "../../infrastructure/Metrics"
+fs = require "fs"
+Path = require "path"
module.exports = ArchiveManager =
extractZipArchive: (source, destination, _callback = (err) ->) ->
@@ -34,4 +36,18 @@ module.exports = ArchiveManager =
error = new Error(error)
logger.error err:error, source: source, destination: destination, "error unzipping file"
callback(error)
+
+ findTopLevelDirectory: (directory, callback = (error, topLevelDir) ->) ->
+ fs.readdir directory, (error, files) ->
+ return callback(error) if error?
+ if files.length == 1
+ childPath = Path.join(directory, files[0])
+ fs.stat childPath, (error, stat) ->
+ return callback(error) if error?
+ if stat.isDirectory()
+ return callback(null, childPath)
+ else
+ return callback(null, directory)
+ else
+ return callback(null, directory)
diff --git a/services/web/app/coffee/Features/Uploads/FileSystemImportManager.coffee b/services/web/app/coffee/Features/Uploads/FileSystemImportManager.coffee
index 4f0c4dcc0b..c7e4fbe03a 100644
--- a/services/web/app/coffee/Features/Uploads/FileSystemImportManager.coffee
+++ b/services/web/app/coffee/Features/Uploads/FileSystemImportManager.coffee
@@ -6,14 +6,28 @@ EditorController = require "../Editor/EditorController"
ProjectLocator = require "../Project/ProjectLocator"
module.exports = FileSystemImportManager =
- addDoc: (project_id, folder_id, name, path, replace, callback = (error, doc)-> )->
+ addDoc: (user_id, project_id, folder_id, name, path, replace, callback = (error, doc)-> )->
fs.readFile path, "utf8", (error, content = "") ->
return callback(error) if error?
content = content.replace(/\r/g, "")
lines = content.split("\n")
- EditorController.addDocWithoutLock project_id, folder_id, name, lines, "upload", callback
+ if replace
+ ProjectLocator.findElement project_id: project_id, element_id: folder_id, type: "folder", (error, folder) ->
+ return callback(error) if error?
+ return callback(new Error("Couldn't find folder")) if !folder?
+ existingDoc = null
+ for doc in folder.docs
+ if doc.name == name
+ existingDoc = doc
+ break
+ if existingDoc?
+ EditorController.setDoc project_id, existingDoc._id, user_id, lines, "upload", callback
+ else
+ EditorController.addDocWithoutLock project_id, folder_id, name, lines, "upload", callback
+ else
+ EditorController.addDocWithoutLock project_id, folder_id, name, lines, "upload", callback
- addFile: (project_id, folder_id, name, path, replace, callback = (error, file)-> )->
+ addFile: (user_id, project_id, folder_id, name, path, replace, callback = (error, file)-> )->
if replace
ProjectLocator.findElement project_id: project_id, element_id: folder_id, type: "folder", (error, folder) ->
return callback(error) if error?
@@ -30,14 +44,14 @@ module.exports = FileSystemImportManager =
else
EditorController.addFileWithoutLock project_id, folder_id, name, path, "upload", callback
- addFolder: (project_id, folder_id, name, path, replace, callback = (error)-> ) ->
+ addFolder: (user_id, project_id, folder_id, name, path, replace, callback = (error)-> ) ->
EditorController.addFolderWithoutLock project_id, folder_id, name, "upload", (error, new_folder) =>
return callback(error) if error?
- @addFolderContents project_id, new_folder._id, path, replace, (error) ->
+ @addFolderContents user_id, project_id, new_folder._id, path, replace, (error) ->
return callback(error) if error?
callback null, new_folder
- addFolderContents: (project_id, parent_folder_id, folderPath, replace, callback = (error)-> ) ->
+ addFolderContents: (user_id, project_id, parent_folder_id, folderPath, replace, callback = (error)-> ) ->
fs.readdir folderPath, (error, entries = []) =>
return callback(error) if error?
jobs = _.map entries, (entry) =>
@@ -45,21 +59,21 @@ module.exports = FileSystemImportManager =
FileTypeManager.shouldIgnore entry, (error, ignore) =>
return callback(error) if error?
if !ignore
- @addEntity project_id, parent_folder_id, entry, "#{folderPath}/#{entry}", replace, callback
+ @addEntity user_id, project_id, parent_folder_id, entry, "#{folderPath}/#{entry}", replace, callback
else
callback()
async.parallelLimit jobs, 5, callback
- addEntity: (project_id, folder_id, name, path, replace, callback = (error, entity)-> ) ->
+ addEntity: (user_id, project_id, folder_id, name, path, replace, callback = (error, entity)-> ) ->
FileTypeManager.isDirectory path, (error, isDirectory) =>
return callback(error) if error?
if isDirectory
- @addFolder project_id, folder_id, name, path, replace, callback
+ @addFolder user_id, project_id, folder_id, name, path, replace, callback
else
FileTypeManager.isBinary name, path, (error, isBinary) =>
return callback(error) if error?
if isBinary
- @addFile project_id, folder_id, name, path, replace, callback
+ @addFile user_id, project_id, folder_id, name, path, replace, callback
else
- @addDoc project_id, folder_id, name, path, replace, callback
+ @addDoc user_id, project_id, folder_id, name, path, replace, callback
diff --git a/services/web/app/coffee/Features/Uploads/ProjectUploadController.coffee b/services/web/app/coffee/Features/Uploads/ProjectUploadController.coffee
index 83a8db5c2d..d2b720e8dc 100644
--- a/services/web/app/coffee/Features/Uploads/ProjectUploadController.coffee
+++ b/services/web/app/coffee/Features/Uploads/ProjectUploadController.coffee
@@ -34,7 +34,8 @@ module.exports = ProjectUploadController =
if !name? or name.length == 0 or name.length > 150
logger.err project_id:project_id, name:name, "bad name when trying to upload file"
return res.send success: false
- FileSystemImportManager.addEntity project_id, folder_id, name, path, true, (error, entity) ->
+ user_id = req.session.user._id
+ FileSystemImportManager.addEntity user_id, project_id, folder_id, name, path, true, (error, entity) ->
fs.unlink path, ->
timer.done()
if error?
diff --git a/services/web/app/coffee/Features/Uploads/ProjectUploadManager.coffee b/services/web/app/coffee/Features/Uploads/ProjectUploadManager.coffee
index b5d108d21d..127c6bc94f 100644
--- a/services/web/app/coffee/Features/Uploads/ProjectUploadManager.coffee
+++ b/services/web/app/coffee/Features/Uploads/ProjectUploadManager.coffee
@@ -9,19 +9,21 @@ module.exports = ProjectUploadHandler =
createProjectFromZipArchive: (owner_id, name, zipPath, callback = (error, project) ->) ->
ProjectCreationHandler.createBlankProject owner_id, name, (error, project) =>
return callback(error) if error?
- @insertZipArchiveIntoFolder project._id, project.rootFolder[0]._id, zipPath, (error) ->
+ @insertZipArchiveIntoFolder owner_id, project._id, project.rootFolder[0]._id, zipPath, (error) ->
return callback(error) if error?
ProjectRootDocManager.setRootDocAutomatically project._id, (error) ->
return callback(error) if error?
callback(error, project)
- insertZipArchiveIntoFolder: (project_id, folder_id, path, callback = (error) ->) ->
+ insertZipArchiveIntoFolder: (owner_id, project_id, folder_id, path, callback = (error) ->) ->
destination = @_getDestinationDirectory path
ArchiveManager.extractZipArchive path, destination, (error) ->
return callback(error) if error?
- FileSystemImportManager.addFolderContents project_id, folder_id, destination, false, (error) ->
+ ArchiveManager.findTopLevelDirectory destination, (error, topLevelDestination) ->
return callback(error) if error?
- rimraf(destination, callback)
+ FileSystemImportManager.addFolderContents owner_id, project_id, folder_id, topLevelDestination, false, (error) ->
+ return callback(error) if error?
+ rimraf(destination, callback)
_getDestinationDirectory: (source) ->
return path.join(path.dirname(source), "#{path.basename(source, ".zip")}-#{Date.now()}")
diff --git a/services/web/app/views/project/editor/file-tree.jade b/services/web/app/views/project/editor/file-tree.jade
index 69b2e2aed3..1bdc248039 100644
--- a/services/web/app/views/project/editor/file-tree.jade
+++ b/services/web/app/views/project/editor/file-tree.jade
@@ -360,6 +360,17 @@ script(type="text/ng-template", id="uploadFileModalTemplate")
.alert.alert-warning.small.modal-alert(ng-if="tooManyFiles") #{translate("maximum_files_uploaded_together", {max:"{{max_files}}"})}
.alert.alert-warning.small.modal-alert(ng-if="rateLimitHit") #{translate("too_many_files_uploaded_throttled_short_period")}
.alert.alert-warning.small.modal-alert(ng-if="notLoggedIn") #{translate("session_expired_redirecting_to_login", {seconds:"{{secondsToRedirect}}"})}
+ .alert.alert-warning.small.modal-alert(ng-if="conflicts.length > 0")
+ p.text-center
+ | The following files already exist in this project:
+ ul.text-center.list-unstyled.row-spaced-small
+ li(ng-repeat="conflict in conflicts"): strong {{ conflict }}
+ p.text-center.row-spaced-small
+ | Do you want to overwrite them?
+ p.text-center
+ a(href, ng-click="doUpload()").btn.btn-primary Overwrite
+ |
+ a(href, ng-click="cancel()").btn.btn-default Cancel
.modal-body(
fine-upload
@@ -370,10 +381,14 @@ script(type="text/ng-template", id="uploadFileModalTemplate")
drag-area-text="{{drag_files}}"
hint-text="{{hint_press_and_hold_control_key}}"
multiple="true"
+ auto-upload="false"
on-complete-callback="onComplete"
on-upload-callback="onUpload"
on-validate-batch="onValidateBatch"
on-error-callback="onError"
+ on-submit-callback="onSubmit"
+ on-cancel-callback="onCancel"
+ control="control"
params="{'folder_id': parent_folder_id}"
)
span #{translate("upload_files")}
diff --git a/services/web/public/coffee/directives/fineUpload.coffee b/services/web/public/coffee/directives/fineUpload.coffee
index 9856da5076..92cdf720f4 100644
--- a/services/web/public/coffee/directives/fineUpload.coffee
+++ b/services/web/public/coffee/directives/fineUpload.coffee
@@ -16,7 +16,11 @@ define [
onUploadCallback: "="
onValidateBatch: "="
onErrorCallback: "="
+ onSubmitCallback: "="
+ onCancelCallback: "="
+ autoUpload: "="
params: "="
+ control: "="
}
link: (scope, element, attrs) ->
multiple = scope.multiple or false
@@ -37,12 +41,19 @@ define [
onUpload = scope.onUploadCallback or () ->
onError = scope.onErrorCallback or () ->
onValidateBatch = scope.onValidateBatch or () ->
+ onSubmit = scope.onSubmitCallback or () ->
+ onCancel = scope.onCancelCallback or () ->
+ if !scope.autoUpload?
+ autoUpload = true
+ else
+ autoUpload = scope.autoUpload
params = scope.params or {}
params._csrf = window.csrfToken
q = new qq.FineUploader
element: element[0]
multiple: multiple
+ autoUpload: autoUpload
disabledCancelForFormUploads: true
validation: validation
maxConnections: maxConnections
@@ -56,6 +67,8 @@ define [
onUpload: onUpload
onValidateBatch: onValidateBatch
onError: onError
+ onSubmit: onSubmit
+ onCancel: onCancel
text: text
template: """
@@ -70,5 +83,7 @@ define [
"""
+ window.q = q
+ scope.control?.q = q
return q
}
\ No newline at end of file
diff --git a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee
index c93ed4f4c0..8c49d54c23 100644
--- a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee
+++ b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee
@@ -135,6 +135,12 @@ define [
multiSelectSelectedEntity: () ->
@findSelectedEntity()?.multiSelected = true
+ existsInFolder: (folder_id, name) ->
+ folder = @findEntityById(folder_id)
+ return false if !folder?
+ entity = @_findEntityByPathInFolder(folder, name)
+ return entity?
+
findSelectedEntity: () ->
selected = null
@forEachEntity (entity) ->
diff --git a/services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee b/services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee
index f3bdc3c9e6..17ac9da8dd 100644
--- a/services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee
+++ b/services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee
@@ -106,7 +106,8 @@ define [
$scope.rateLimitHit = false
$scope.secondsToRedirect = 10
$scope.notLoggedIn = false
-
+ $scope.conflicts = []
+ $scope.control = {}
needToLogBackIn = ->
$scope.notLoggedIn = true
@@ -121,11 +122,6 @@ define [
decreseTimeout()
-
- uploadCount = 0
- $scope.onUpload = () ->
- uploadCount++
-
$scope.max_files = 40
$scope.onComplete = (error, name, response) ->
$timeout (() ->
@@ -150,6 +146,34 @@ define [
else if reason.indexOf("403") != -1
needToLogBackIn()
+ _uploadTimer = null
+ uploadIfNoConflicts = () ->
+ if $scope.conflicts.length == 0
+ $scope.doUpload()
+
+ uploadCount = 0
+ $scope.onSubmit = (id, name) ->
+ uploadCount++
+ if ide.fileTreeManager.existsInFolder($scope.parent_folder_id, name)
+ $scope.conflicts.push name
+ $scope.$apply()
+ if !_uploadTimer?
+ _uploadTimer = setTimeout () ->
+ _uploadTimer = null
+ uploadIfNoConflicts()
+ , 0
+ return true
+
+ $scope.onCancel = (id, name) ->
+ uploadCount--
+ index = $scope.conflicts.indexOf(name)
+ if index > -1
+ $scope.conflicts.splice(index, 1)
+ $scope.$apply()
+ uploadIfNoConflicts()
+
+ $scope.doUpload = () ->
+ $scope.control?.q?.uploadStoredFiles()
$scope.cancel = () ->
$modalInstance.dismiss('cancel')
diff --git a/services/web/public/stylesheets/app/editor/toolbar.less b/services/web/public/stylesheets/app/editor/toolbar.less
index bc1976764f..f83135972f 100644
--- a/services/web/public/stylesheets/app/editor/toolbar.less
+++ b/services/web/public/stylesheets/app/editor/toolbar.less
@@ -95,15 +95,16 @@
&.toolbar-small {
height: 32px;
> a, .toolbar-right > a {
- padding: 4px 2px 2px;
+ padding: 2px 4px 1px 4px;
margin: 0;
+ margin-top: 2px;
}
> a {
- margin-left: 6px;
+ margin-left: 2px;
}
.toolbar-right > a {
margin-left: 0;
- margin-right: 6px;
+ margin-right: 2px;
}
}
diff --git a/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee b/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee
index dbaf751c70..455c441239 100644
--- a/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee
+++ b/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee
@@ -54,11 +54,11 @@ describe "SubscriptionGroupController", ->
describe "addUserToGroup", ->
it "should use the admin id for the logged in user and take the email address from the body", (done)->
- newEmail = "31231"
+ newEmail = " boB@gmaiL.com "
@req.body = email: newEmail
res =
json : (data)=>
- @GroupHandler.addUserToGroup.calledWith(@adminUserId, newEmail).should.equal true
+ @GroupHandler.addUserToGroup.calledWith(@adminUserId, "bob@gmail.com").should.equal true
data.user.should.deep.equal @user
done()
@Controller.addUserToGroup @req, res
diff --git a/services/web/test/UnitTests/coffee/Uploads/ArchiveManagerTests.coffee b/services/web/test/UnitTests/coffee/Uploads/ArchiveManagerTests.coffee
index d1f72a780e..079ab6d099 100644
--- a/services/web/test/UnitTests/coffee/Uploads/ArchiveManagerTests.coffee
+++ b/services/web/test/UnitTests/coffee/Uploads/ArchiveManagerTests.coffee
@@ -22,6 +22,7 @@ describe "ArchiveManager", ->
"child_process": @child
"logger-sharelatex": @logger
"../../infrastructure/Metrics": @metrics
+ "fs": @fs = {}
describe "extractZipArchive", ->
beforeEach ->
@@ -69,4 +70,57 @@ describe "ArchiveManager", ->
it "should log out the error", ->
@logger.error.called.should.equal true
+
+ describe "findTopLevelDirectory", ->
+ beforeEach ->
+ @fs.readdir = sinon.stub()
+ @fs.stat = sinon.stub()
+ @directory = "test/directory"
+
+ describe "with multiple files", ->
+ beforeEach ->
+ @fs.readdir.callsArgWith(1, null, ["multiple", "files"])
+ @ArchiveManager.findTopLevelDirectory(@directory, @callback)
+
+ it "should find the files in the directory", ->
+ @fs.readdir
+ .calledWith(@directory)
+ .should.equal true
+
+ it "should return the original directory", ->
+ @callback
+ .calledWith(null, @directory)
+ .should.equal true
+
+ describe "with a single file (not folder)", ->
+ beforeEach ->
+ @fs.readdir.callsArgWith(1, null, ["foo.tex"])
+ @fs.stat.callsArgWith(1, null, { isDirectory: () -> false })
+ @ArchiveManager.findTopLevelDirectory(@directory, @callback)
+
+ it "should check if the file is a directory", ->
+ @fs.stat
+ .calledWith(@directory + "/foo.tex")
+ .should.equal true
+
+ it "should return the original directory", ->
+ @callback
+ .calledWith(null, @directory)
+ .should.equal true
+
+ describe "with a single top-level folder", ->
+ beforeEach ->
+ @fs.readdir.callsArgWith(1, null, ["folder"])
+ @fs.stat.callsArgWith(1, null, { isDirectory: () -> true })
+ @ArchiveManager.findTopLevelDirectory(@directory, @callback)
+
+ it "should check if the file is a directory", ->
+ @fs.stat
+ .calledWith(@directory + "/folder")
+ .should.equal true
+
+ it "should return the child directory", ->
+ @callback
+ .calledWith(null, @directory + "/folder")
+ .should.equal true
diff --git a/services/web/test/UnitTests/coffee/Uploads/FileSystemImportManagerTests.coffee b/services/web/test/UnitTests/coffee/Uploads/FileSystemImportManagerTests.coffee
index fa385f7261..441dd8163d 100644
--- a/services/web/test/UnitTests/coffee/Uploads/FileSystemImportManagerTests.coffee
+++ b/services/web/test/UnitTests/coffee/Uploads/FileSystemImportManagerTests.coffee
@@ -11,43 +11,94 @@ describe "FileSystemImportManager", ->
@name = "test-file.tex"
@path_on_disk = "/path/to/file/#{@name}"
@replace = "replace-boolean-flag-mock"
+ @user_id = "mock-user-123"
+ @callback = sinon.stub()
@FileSystemImportManager = SandboxedModule.require modulePath, requires:
"fs" : @fs = {}
"../Editor/EditorController": @EditorController = {}
"./FileTypeManager": @FileTypeManager = {}
"../Project/ProjectLocator": @ProjectLocator = {}
-
+
describe "addDoc", ->
beforeEach ->
@docContent = "one\ntwo\nthree"
@docLines = @docContent.split("\n")
@fs.readFile = sinon.stub().callsArgWith(2, null, @docContent)
- @EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
- @FileSystemImportManager.addDoc @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
+ describe "with replace set to false", ->
+ beforeEach ->
+ @EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
+ @FileSystemImportManager.addDoc @user_id, @project_id, @folder_id, @name, @path_on_disk, false, @callback
- it "should insert the doc", ->
- @EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload")
- .should.equal true
+ it "should read the file from disk", ->
+ @fs.readFile.calledWith(@path_on_disk, "utf8").should.equal true
- describe "addDoc with windows line ending", ->
- beforeEach ->
- @docContent = "one\r\ntwo\r\nthree"
- @docLines = ["one", "two", "three"]
- @fs.readFile = sinon.stub().callsArgWith(2, null, @docContent)
- @EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
- @FileSystemImportManager.addDoc @project_id, @folder_id, @name, @path_on_disk, false, @callback
+ it "should insert the doc", ->
+ @EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload")
+ .should.equal true
- it "should strip the \\r characters before adding", ->
- @EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload")
- .should.equal true
+ describe "with windows line ending", ->
+ beforeEach ->
+ @docContent = "one\r\ntwo\r\nthree"
+ @docLines = ["one", "two", "three"]
+ @fs.readFile = sinon.stub().callsArgWith(2, null, @docContent)
+ @EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
+ @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")
+ .should.equal true
+
+ describe "with replace set to true", ->
+ describe "when the doc doesn't exist", ->
+ beforeEach ->
+ @folder = {
+ docs: [{
+ _id: "doc-id-2"
+ name: "not-the-right-file.tex"
+ }]
+ }
+ @ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @folder)
+ @EditorController.addDocWithoutLock = sinon.stub().callsArg(5)
+ @FileSystemImportManager.addDoc @user_id, @project_id, @folder_id, @name, @path_on_disk, true, @callback
+
+ it "should look up the folder", ->
+ @ProjectLocator.findElement
+ .calledWith(project_id: @project_id, element_id: @folder_id, type: "folder")
+ .should.equal true
+
+ it "should insert the doc", ->
+ @EditorController.addDocWithoutLock.calledWith(@project_id, @folder_id, @name, @docLines, "upload")
+ .should.equal true
+
+ describe "when the doc does exist", ->
+ beforeEach ->
+ @folder = {
+ docs: [{
+ _id: @doc_id = "doc-id-1"
+ name: @name
+ }, {
+ _id: "doc-id-2"
+ name: "not-the-right-file.tex"
+ }]
+ }
+ @ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @folder)
+ @EditorController.setDoc = sinon.stub().callsArg(5)
+ @FileSystemImportManager.addDoc @user_id, @project_id, @folder_id, @name, @path_on_disk, true, @callback
+
+ it "should look up the folder", ->
+ @ProjectLocator.findElement
+ .calledWith(project_id: @project_id, element_id: @folder_id, type: "folder")
+ .should.equal true
+
+ it "should set the doc with the new doc lines", ->
+ @EditorController.setDoc.calledWith(@project_id, @doc_id, @user_id, @docLines, "upload")
+ .should.equal true
describe "addFile with replace set to false", ->
beforeEach ->
@EditorController.addFileWithoutLock = sinon.stub().callsArg(5)
- @FileSystemImportManager.addFile @project_id, @folder_id, @name, @path_on_disk, false, @callback
+ @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")
@@ -64,7 +115,7 @@ describe "FileSystemImportManager", ->
}
@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @folder)
@EditorController.addFileWithoutLock = sinon.stub().callsArg(5)
- @FileSystemImportManager.addFile @project_id, @folder_id, @name, @path_on_disk, true, @callback
+ @FileSystemImportManager.addFile @user_id, @project_id, @folder_id, @name, @path_on_disk, true, @callback
it "should look up the folder", ->
@ProjectLocator.findElement
@@ -88,7 +139,7 @@ describe "FileSystemImportManager", ->
}
@ProjectLocator.findElement = sinon.stub().callsArgWith(1, null, @folder)
@EditorController.replaceFile = sinon.stub().callsArg(4)
- @FileSystemImportManager.addFile @project_id, @folder_id, @name, @path_on_disk, true, @callback
+ @FileSystemImportManager.addFile @user_id, @project_id, @folder_id, @name, @path_on_disk, true, @callback
it "should look up the folder", ->
@ProjectLocator.findElement
@@ -103,15 +154,15 @@ describe "FileSystemImportManager", ->
beforeEach ->
@new_folder_id = "new-folder-id"
@EditorController.addFolderWithoutLock = sinon.stub().callsArgWith(4, null, _id: @new_folder_id)
- @FileSystemImportManager.addFolderContents = sinon.stub().callsArg(4)
- @FileSystemImportManager.addFolder @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
+ @FileSystemImportManager.addFolderContents = sinon.stub().callsArg(5)
+ @FileSystemImportManager.addFolder @user_id, @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
it "should add a folder to the project", ->
@EditorController.addFolderWithoutLock.calledWith(@project_id, @folder_id, @name, "upload")
.should.equal true
it "should add the folders contents", ->
- @FileSystemImportManager.addFolderContents.calledWith(@project_id, @new_folder_id, @path_on_disk, @replace)
+ @FileSystemImportManager.addFolderContents.calledWith(@user_id, @project_id, @new_folder_id, @path_on_disk, @replace)
.should.equal true
describe "addFolderContents", ->
@@ -119,19 +170,19 @@ describe "FileSystemImportManager", ->
@folderEntries = ["path1", "path2", "path3"]
@ignoredEntries = [".DS_Store"]
@fs.readdir = sinon.stub().callsArgWith(1, null, @folderEntries.concat @ignoredEntries)
- @FileSystemImportManager.addEntity = sinon.stub().callsArg(5)
+ @FileSystemImportManager.addEntity = sinon.stub().callsArg(6)
@FileTypeManager.shouldIgnore = (path, callback) =>
callback null, @ignoredEntries.indexOf(require("path").basename(path)) != -1
- @FileSystemImportManager.addFolderContents @project_id, @folder_id, @path_on_disk, @replace, @callback
+ @FileSystemImportManager.addFolderContents @user_id, @project_id, @folder_id, @path_on_disk, @replace, @callback
it "should call addEntity for each file in the folder which is not ignored", ->
for name in @folderEntries
- @FileSystemImportManager.addEntity.calledWith(@project_id, @folder_id, name, "#{@path_on_disk}/#{name}", @replace)
+ @FileSystemImportManager.addEntity.calledWith(@user_id, @project_id, @folder_id, name, "#{@path_on_disk}/#{name}", @replace)
.should.equal true
it "should not call addEntity for the ignored files", ->
for name in @ignoredEntries
- @FileSystemImportManager.addEntity.calledWith(@project_id, @folder_id, name, "#{@path_on_disk}/#{name}", @replace)
+ @FileSystemImportManager.addEntity.calledWith(@user_id, @project_id, @folder_id, name, "#{@path_on_disk}/#{name}", @replace)
.should.equal false
it "should look in the correct directory", ->
@@ -141,33 +192,33 @@ describe "FileSystemImportManager", ->
describe "with directory", ->
beforeEach ->
@FileTypeManager.isDirectory = sinon.stub().callsArgWith(1, null, true)
- @FileSystemImportManager.addFolder = sinon.stub().callsArg(5)
- @FileSystemImportManager.addEntity @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
+ @FileSystemImportManager.addFolder = sinon.stub().callsArg(6)
+ @FileSystemImportManager.addEntity @user_id, @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
it "should call addFolder", ->
- @FileSystemImportManager.addFolder.calledWith(@project_id, @folder_id, @name, @path_on_disk, @replace, @callback)
+ @FileSystemImportManager.addFolder.calledWith(@user_id, @project_id, @folder_id, @name, @path_on_disk, @replace)
.should.equal true
describe "with binary file", ->
beforeEach ->
@FileTypeManager.isDirectory = sinon.stub().callsArgWith(1, null, false)
@FileTypeManager.isBinary = sinon.stub().callsArgWith(2, null, true)
- @FileSystemImportManager.addFile = sinon.stub().callsArg(5)
- @FileSystemImportManager.addEntity @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
+ @FileSystemImportManager.addFile = sinon.stub().callsArg(6)
+ @FileSystemImportManager.addEntity @user_id, @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
it "should call addFile", ->
- @FileSystemImportManager.addFile.calledWith(@project_id, @folder_id, @name, @path_on_disk, @replace, @callback)
+ @FileSystemImportManager.addFile.calledWith(@user_id, @project_id, @folder_id, @name, @path_on_disk, @replace, @callback)
.should.equal true
describe "with text file", ->
beforeEach ->
@FileTypeManager.isDirectory = sinon.stub().callsArgWith(1, null, false)
@FileTypeManager.isBinary = sinon.stub().callsArgWith(2, null, false)
- @FileSystemImportManager.addDoc = sinon.stub().callsArg(5)
- @FileSystemImportManager.addEntity @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
+ @FileSystemImportManager.addDoc = sinon.stub().callsArg(6)
+ @FileSystemImportManager.addEntity @user_id, @project_id, @folder_id, @name, @path_on_disk, @replace, @callback
it "should call addFile", ->
- @FileSystemImportManager.addDoc.calledWith(@project_id, @folder_id, @name, @path_on_disk, @replace, @callback)
+ @FileSystemImportManager.addDoc.calledWith(@user_id, @project_id, @folder_id, @name, @path_on_disk, @replace, @callback)
.should.equal true
diff --git a/services/web/test/UnitTests/coffee/Uploads/ProjectUploadControllerTests.coffee b/services/web/test/UnitTests/coffee/Uploads/ProjectUploadControllerTests.coffee
index dd4240d1b8..176ae96d24 100644
--- a/services/web/test/UnitTests/coffee/Uploads/ProjectUploadControllerTests.coffee
+++ b/services/web/test/UnitTests/coffee/Uploads/ProjectUploadControllerTests.coffee
@@ -103,6 +103,9 @@ describe "ProjectUploadController", ->
qqfile:
path: @path
originalname: @name
+ @req.session =
+ user:
+ _id: @user_id
@req.params =
Project_id: @project_id
@req.query =
@@ -115,27 +118,12 @@ describe "ProjectUploadController", ->
beforeEach ->
@entity =
_id : "1234"
- @FileSystemImportManager.addEntity = sinon.stub().callsArgWith(5, null, @entity)
+ @FileSystemImportManager.addEntity = sinon.stub().callsArgWith(6, null, @entity)
@ProjectUploadController.uploadFile @req, @res
- it "should insert the file into the correct project", ->
+ it "should insert the file", ->
@FileSystemImportManager.addEntity
- .calledWith(@project_id)
- .should.equal true
-
- it "should insert the file into the provided folder", ->
- @FileSystemImportManager.addEntity
- .calledWith(sinon.match.any, @folder_id)
- .should.equal true
-
- it "should insert the file with the correct name", ->
- @FileSystemImportManager.addEntity
- .calledWith(sinon.match.any, sinon.match.any, @name)
- .should.equal true
-
- it "should insert the file from the uploaded path", ->
- @FileSystemImportManager.addEntity
- .calledWith(sinon.match.any, sinon.match.any, sinon.match.any, @path)
+ .calledWith(@user_id, @project_id, @folder_id, @name, @path)
.should.equal true
it "should return a successful response to the FileUploader client", ->
@@ -143,7 +131,6 @@ describe "ProjectUploadController", ->
success: true
entity_id: @entity._id
-
it "should output a log line", ->
@logger.log
.calledWith(sinon.match.any, "uploaded file")
@@ -158,7 +145,7 @@ describe "ProjectUploadController", ->
describe "when FileSystemImportManager.addEntity returns an error", ->
beforeEach ->
@FileSystemImportManager.addEntity = sinon.stub()
- .callsArgWith(5, new Error("Sorry something went wrong"))
+ .callsArgWith(6, new Error("Sorry something went wrong"))
@ProjectUploadController.uploadFile @req, @res
it "should return an unsuccessful response to the FileUploader client", ->
diff --git a/services/web/test/UnitTests/coffee/Uploads/ProjectUploadManagerTests.coffee b/services/web/test/UnitTests/coffee/Uploads/ProjectUploadManagerTests.coffee
index 53b7cb2064..d4571f0474 100644
--- a/services/web/test/UnitTests/coffee/Uploads/ProjectUploadManagerTests.coffee
+++ b/services/web/test/UnitTests/coffee/Uploads/ProjectUploadManagerTests.coffee
@@ -8,6 +8,7 @@ describe "ProjectUploadManager", ->
beforeEach ->
@project_id = "project-id-123"
@folder_id = "folder-id-123"
+ @owner_id = "onwer-id-123"
@callback = sinon.stub()
@ProjectUploadManager = SandboxedModule.require modulePath, requires:
"./FileSystemImportManager" : @FileSystemImportManager = {}
@@ -26,7 +27,7 @@ describe "ProjectUploadManager", ->
_id: @project_id
rootFolder: [ _id: @root_folder_id ]
@ProjectCreationHandler.createBlankProject = sinon.stub().callsArgWith(2, null, @project)
- @ProjectUploadManager.insertZipArchiveIntoFolder = sinon.stub().callsArg(3)
+ @ProjectUploadManager.insertZipArchiveIntoFolder = sinon.stub().callsArg(4)
@ProjectRootDocManager.setRootDocAutomatically = sinon.stub().callsArg(1)
@ProjectUploadManager.createProjectFromZipArchive @owner_id, @name, @source, @callback
@@ -45,7 +46,7 @@ describe "ProjectUploadManager", ->
it "should insert the zip file contents into the root folder", ->
@ProjectUploadManager
.insertZipArchiveIntoFolder
- .calledWith(@project_id, @root_folder_id, @source)
+ .calledWith(@owner_id, @project_id, @root_folder_id, @source)
.should.equal true
it "should automatically set the root doc", ->
@@ -63,9 +64,10 @@ describe "ProjectUploadManager", ->
@destination = "/path/to/zile/file-extracted"
@ProjectUploadManager._getDestinationDirectory = sinon.stub().returns @destination
@ArchiveManager.extractZipArchive = sinon.stub().callsArg(2)
- @FileSystemImportManager.addFolderContents = sinon.stub().callsArg(4)
+ @ArchiveManager.findTopLevelDirectory = sinon.stub().callsArgWith(1, null, @topLevelDestination = "/path/to/zip/file-extracted/nested")
+ @FileSystemImportManager.addFolderContents = sinon.stub().callsArg(5)
- @ProjectUploadManager.insertZipArchiveIntoFolder @project_id, @folder_id, @source, @callback
+ @ProjectUploadManager.insertZipArchiveIntoFolder @owner_id, @project_id, @folder_id, @source, @callback
it "should set up the directory to extract the archive to", ->
@ProjectUploadManager._getDestinationDirectory.calledWith(@source).should.equal true
@@ -73,8 +75,11 @@ describe "ProjectUploadManager", ->
it "should extract the archive", ->
@ArchiveManager.extractZipArchive.calledWith(@source, @destination).should.equal true
+ it "should find the top level directory", ->
+ @ArchiveManager.findTopLevelDirectory.calledWith(@destination).should.equal true
+
it "should insert the extracted archive into the folder", ->
- @FileSystemImportManager.addFolderContents.calledWith(@project_id, @folder_id, @destination, false)
+ @FileSystemImportManager.addFolderContents.calledWith(@owner_id, @project_id, @folder_id, @topLevelDestination, false)
.should.equal true
it "should return the callback", ->