From 5cb85c03321c1f7d694387f7eecabc3c9f6a217d Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 3 May 2018 14:29:03 +0100 Subject: [PATCH] WIP: Add ProjectFileAgent --- .../LinkedFiles/LinkedFilesController.coffee | 5 +- .../LinkedFiles/ProjectFileAgent.coffee | 70 +++++++++++++++++++ .../coffee/infrastructure/FileWriter.coffee | 14 +++- .../ide/file-tree/FileTreeManager.coffee | 12 ++++ 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 services/web/app/coffee/Features/LinkedFiles/ProjectFileAgent.coffee diff --git a/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee b/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee index aaf4172cf4..bb5a93efb9 100644 --- a/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee +++ b/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee @@ -5,7 +5,8 @@ logger = require 'logger-sharelatex' module.exports = LinkedFilesController = { Agents: { - url: require('./UrlAgent') + url: require('./UrlAgent'), + project_file: require('./ProjectFileAgent') } createLinkedFile: (req, res, next) -> @@ -29,4 +30,4 @@ module.exports = LinkedFilesController = { EditorController.upsertFile project_id, parent_folder_id, name, fsPath, linkedFileData, "upload", user_id, (error) -> return next(error) if error? res.send(204) # created -} \ No newline at end of file +} diff --git a/services/web/app/coffee/Features/LinkedFiles/ProjectFileAgent.coffee b/services/web/app/coffee/Features/LinkedFiles/ProjectFileAgent.coffee new file mode 100644 index 0000000000..116434ef3f --- /dev/null +++ b/services/web/app/coffee/Features/LinkedFiles/ProjectFileAgent.coffee @@ -0,0 +1,70 @@ +FileWriter = require('../../infrastructure/FileWriter') +AuthorizationManager = require('../Authorization/AuthorizationManager') +ProjectLocator = require('../Project/ProjectLocator') +DocstoreManager = require('../Docstore/DocstoreManager') +FileStoreHandler = require('../FileStore/FileStoreHandler') +FileWriter = require('../../infrastructure/FileWriter') +_ = require "underscore" +Settings = require 'settings-sharelatex' + + +AccessDeniedError = (message) -> + error = new Error(message) + error.name = 'AccessDenied' + error.__proto__ = AccessDeniedError.prototype + return error +AccessDeniedError.prototype.__proto__ = Error.prototype + +BadEntityTypeError = (message) -> + error = new Error(message) + error.name = 'BadEntityType' + error.__proto__ = BadEntityTypeError.prototype + return error +BadEntityTypeError.prototype.__proto__ = Error.prototype + + +module.exports = ProjectFileAgent = + + sanitizeData: (data) -> + # TODO: + # - Nothing? + return data + + writeIncomingFileToDisk: + (project_id, data, current_user_id, callback = (error, fsPath) ->) -> + callback = _.once(callback) + {source_project_id, source_entity_path} = data + AuthorizationManager.canUserReadProject current_user_id, source_project_id, + null, (err, canRead) -> + return callback(err) if err? + return callback(new AccessDeniedError()) if !canRead + ProjectLocator.findElementByPath { + project_id: source_project_id, + path: source_entity_path + }, (err, entity, type) -> + return callback(err) if err? # also applies when file not found + ProjectFileAgent._writeEntityToDisk source_project_id, entity._id, type, callback + + _writeEntityToDisk: (project_id, entity_id, type, callback=(err, location)->) -> + callback = _.once(callback) + if type == 'doc' + DocstoreManager.getDoc project_id, entity_id, (err, lines) -> + return callback(err) if err? + FileWriter.writeLinesToDisk entity_id, lines, callback + else if type == 'file' + FileStoreHandler.getFileStream project_id, entity_id, (err, fileStream) -> + return callback(err) if err? + FileWriter.writeStreamToDisk entity_id, fileStream, callback + else + callback(new BadEntityTypeError()) + + handleError: (error, req, res, next) -> + if error instanceof AccessDeniedError + res.status(403).send("You do not have access to this project") + else if error instanceof FileNotFoundError + res.status(404).send("The file does not exist") + else if error instanceof BadEntityTypeError + res.status(404).send("The file is the wrong type") # TODO: better error message + else + next(error) + next() diff --git a/services/web/app/coffee/infrastructure/FileWriter.coffee b/services/web/app/coffee/infrastructure/FileWriter.coffee index dedeed9bad..21353e7a36 100644 --- a/services/web/app/coffee/infrastructure/FileWriter.coffee +++ b/services/web/app/coffee/infrastructure/FileWriter.coffee @@ -6,6 +6,18 @@ Settings = require 'settings-sharelatex' request = require 'request' module.exports = FileWriter = + + writeLinesToDisk: (identifier, lines, callback = (error, fsPath)->) -> + callback = _.once(callback) + fsPath = "#{Settings.path.dumpFolder}/#{identifier}_#{uuid.v4()}" + fs.mkdir Settings.path.dumpFolder, (error) -> + if error? and error.code != 'EEXIST' + # Ignore error about already existing + return callback(error) + fs.writeFile fsPath, lines.join('\n'), (error) -> + return callback(error) if error? + callback(null, fsPath) + writeStreamToDisk: (identifier, stream, callback = (error, fsPath) ->) -> callback = _.once(callback) fsPath = "#{Settings.path.dumpFolder}/#{identifier}_#{uuid.v4()}" @@ -39,4 +51,4 @@ module.exports = FileWriter = else err = new Error("bad response from url: #{response.statusCode}") logger.err {err, identifier, url}, err.message - callback(err) \ No newline at end of file + callback(err) diff --git a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee index d7a428ec80..f342843a54 100644 --- a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee +++ b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee @@ -25,6 +25,18 @@ define [ $(document).on "click", => @clearMultiSelectedEntities() @$scope.$digest() + window.doLinkedFileImportFromProject = (project, path, name) => + parent_folder = @getCurrentFolder() + @ide.$http.post "/project/#{@ide.project_id}/linked_file", { + name: name, + parent_folder_id: parent_folder?.id + provider: 'project_file', + data: { + source_project_id: project, + source_entity_path: path + }, + _csrf: window.csrfToken + } _bindToSocketEvents: () -> @ide.socket.on "reciveNewDoc", (parent_folder_id, doc) =>