diff --git a/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee b/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee index 34f77fde20..9f5c380fb8 100644 --- a/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee +++ b/services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee @@ -6,7 +6,6 @@ logger = require 'logger-sharelatex' _ = require 'underscore' LinkedFilesHandler = require './LinkedFilesHandler' { - UrlFetchFailedError, InvalidUrlError, OutputFileFetchFailedError, @@ -16,16 +15,23 @@ LinkedFilesHandler = require './LinkedFilesHandler' ProjectNotFoundError, V1ProjectNotFoundError, SourceFileNotFoundError, + NotOriginalImporterError, + FeatureNotAvailableError, + RemoteServiceError } = require './LinkedFilesErrors' +Modules = require '../../infrastructure/Modules' module.exports = LinkedFilesController = { - Agents: { - url: require('./UrlAgent'), - project_file: require('./ProjectFileAgent'), - project_output_file: require('./ProjectOutputFileAgent') - } + Agents: _.extend( + { + url: require('./UrlAgent'), + project_file: require('./ProjectFileAgent'), + project_output_file: require('./ProjectOutputFileAgent'), + }, + Modules.linkedFileAgentsIncludes() + ) _getAgent: (provider) -> if !LinkedFilesController.Agents.hasOwnProperty(provider) @@ -117,6 +123,22 @@ module.exports = LinkedFilesController = { "Your URL is not valid. Please check it and try again." ) + else if error instanceof NotOriginalImporterError + res.status(400).send( + "You are not the user who originally imported this file" + ) + + else if error instanceof FeatureNotAvailableError + res.status(400).send( + "This feature is not enabled on your account" + ) + + else if error instanceof RemoteServiceError + res.status(502).send( + "The remote service produced an error" + ) + + else next(error) } diff --git a/services/web/app/coffee/Features/LinkedFiles/LinkedFilesErrors.coffee b/services/web/app/coffee/Features/LinkedFiles/LinkedFilesErrors.coffee index 8cf671702e..e7ea63e563 100644 --- a/services/web/app/coffee/Features/LinkedFiles/LinkedFilesErrors.coffee +++ b/services/web/app/coffee/Features/LinkedFiles/LinkedFilesErrors.coffee @@ -70,6 +70,30 @@ SourceFileNotFoundError = (message) -> SourceFileNotFoundError.prototype.__proto__ = Error.prototype +NotOriginalImporterError = (message) -> + error = new Error(message) + error.name = 'NotOriginalImporter' + error.__proto__ = NotOriginalImporterError.prototype + return error +NotOriginalImporterError.prototype.__proto__ = Error.prototype + + +FeatureNotAvailableError = (message) -> + error = new Error(message) + error.name = 'FeatureNotAvailable' + error.__proto__ = FeatureNotAvailableError.prototype + return error +FeatureNotAvailableError.prototype.__proto__ = Error.prototype + + +RemoteServiceError = (message) -> + error = new Error(message) + error.name = 'RemoteService' + error.__proto__ = RemoteServiceError.prototype + return error +RemoteServiceError.prototype.__proto__ = Error.prototype + + module.exports = { UrlFetchFailedError, @@ -81,4 +105,7 @@ module.exports = { ProjectNotFoundError, V1ProjectNotFoundError, SourceFileNotFoundError, + NotOriginalImporterError, + FeatureNotAvailableError, + RemoteServiceError } diff --git a/services/web/app/coffee/infrastructure/Modules.coffee b/services/web/app/coffee/infrastructure/Modules.coffee index e1b2e11520..a7944e54dc 100644 --- a/services/web/app/coffee/infrastructure/Modules.coffee +++ b/services/web/app/coffee/infrastructure/Modules.coffee @@ -23,7 +23,7 @@ module.exports = Modules = for module in @modules module.nonCsrfRouter?.apply(webRouter, privateApiRouter, publicApiRouter) module.router?.applyNonCsrfRouter?(webRouter, privateApiRouter, publicApiRouter) - + viewIncludes: {} loadViewIncludes: (app) -> @viewIncludes = {} @@ -32,7 +32,7 @@ module.exports = Modules = @viewIncludes[view] ||= [] filePath = Path.join(MODULE_BASE_PATH, module.name, "app/views", partial + ".pug") @viewIncludes[view].push pug.compileFile(filePath, doctype: "html") - + moduleIncludes: (view, locals) -> compiledPartials = Modules.viewIncludes[view] or [] html = "" @@ -43,7 +43,7 @@ module.exports = Modules = moduleIncludesAvailable: (view) -> return (Modules.viewIncludes[view] or []).length > 0 - + moduleAssetFiles: (pathPrefix) -> assetFiles = [] for module in @modules @@ -51,18 +51,25 @@ module.exports = Modules = assetFiles.push "#{pathPrefix}#{assetFile}" return assetFiles + linkedFileAgentsIncludes: () -> + agents = {} + for module in @modules + for name, agentFunction of module.linkedFileAgents + agents[name] = agentFunction() + return agents + attachHooks: () -> for module in @modules if module.hooks? for hook, method of module.hooks Modules.hooks.attach hook, method - + hooks: _hooks: {} attach: (name, method) -> @_hooks[name] ?= [] @_hooks[name].push method - + fire: (name, args..., callback) -> methods = @_hooks[name] or [] call_methods = methods.map (method) -> @@ -70,5 +77,5 @@ module.exports = Modules = async.series call_methods, (error, results) -> return callback(error) if error? return callback null, results - + Modules.loadModules() diff --git a/services/web/app/views/project/editor/binary-file.pug b/services/web/app/views/project/editor/binary-file.pug index e7cd1e32ed..c729db09bc 100644 --- a/services/web/app/views/project/editor/binary-file.pug +++ b/services/web/app/views/project/editor/binary-file.pug @@ -78,6 +78,8 @@ div.binary-file.full-size( | | at {{ openFile.created | formatDate:'h:mm a' }} {{ openFile.created | relativeDate }} + != moduleIncludes("binaryFile:linkedFileInfo", locals) + // Bottom Controls span(ng-if="openFile.linkedFileData.provider") button.btn.btn-success( @@ -95,7 +97,10 @@ div.binary-file.full-size( i.fa.fa-fw.fa-download | | #{translate("download")} - div(ng-if="refreshError") + + // Refresh Error + div(ng-if="refreshError").row br .alert.alert-danger.col-md-6.col-md-offset-3 | Error: {{ refreshError}} + != moduleIncludes("binaryFile:linkedFileRefreshError", locals) diff --git a/services/web/app/views/project/editor/new-file-modal.pug b/services/web/app/views/project/editor/new-file-modal.pug index 1a0e77f665..66bc124844 100644 --- a/services/web/app/views/project/editor/new-file-modal.pug +++ b/services/web/app/views/project/editor/new-file-modal.pug @@ -26,6 +26,8 @@ script(type='text/ng-template', id='newFileModalTemplate') i.fa.fa-fw.fa-globe | | From External URL + != moduleIncludes("newFileModal:selector", locals) + td(class="modal-new-file--body modal-new-file--body-{{type}}") div(ng-if="type == 'doc'", ng-controller="NewDocModalController") form(novalidate, name="newDocForm") @@ -175,6 +177,9 @@ script(type='text/ng-template', id='newFileModalTemplate') div(ng-switch="error") span(ng-switch-when="already exists") #{translate("file_already_exists")} span(ng-switch-default) {{error}} + + != moduleIncludes("newFileModal:panel", locals) + .modal-footer button.btn.btn-default( ng-disabled="state.inflight" diff --git a/services/web/docker-compose.yml b/services/web/docker-compose.yml index f2966da141..afba1ccc60 100644 --- a/services/web/docker-compose.yml +++ b/services/web/docker-compose.yml @@ -17,7 +17,7 @@ services: PROJECT_HISTORY_ENABLED: 'true' ENABLED_LINKED_FILE_TYPES: 'url' LINKED_URL_PROXY: 'http://localhost:6543' - ENABLED_LINKED_FILE_TYPES: 'url,project_file,project_output_file' + ENABLED_LINKED_FILE_TYPES: 'url,project_file,project_output_file,mendeley' SHARELATEX_CONFIG: /app/test/acceptance/config/settings.test.coffee depends_on: - redis diff --git a/services/web/public/stylesheets/app/editor.less b/services/web/public/stylesheets/app/editor.less index af3063cf22..42c6c15daf 100644 --- a/services/web/public/stylesheets/app/editor.less +++ b/services/web/public/stylesheets/app/editor.less @@ -606,19 +606,16 @@ CodeMirror } .referencesImportModal { - .referencesImportPreview { - margin-top: 15px; - .referencesImportPreviewScroller { - font-family: monospace; - font-size: 0.8em; - max-height: 360px; - overflow: scroll; - white-space: pre; - padding: 8px 12px; - margin-bottom: 15px; - border: 1px solid @gray-lighter; - background-color: @gray-lightest; - } + .referencesImportPreviewScroller { + font-family: monospace; + font-size: 0.8em; + max-height: 360px; + overflow: scroll; + white-space: pre; + padding: 8px 12px; + margin-bottom: 15px; + border: 1px solid @gray-lighter; + background-color: @gray-lightest; } } diff --git a/services/web/test/acceptance/coffee/LinkedFilesTests.coffee b/services/web/test/acceptance/coffee/LinkedFilesTests.coffee index 0c369097cd..9bae2a1fc0 100644 --- a/services/web/test/acceptance/coffee/LinkedFilesTests.coffee +++ b/services/web/test/acceptance/coffee/LinkedFilesTests.coffee @@ -107,6 +107,7 @@ describe "LinkedFiles", -> source_project_id: @project_two_id, source_entity_path: "/#{@source_doc_name}", }, (error, response, body) => + expect(response.statusCode).to.equal 200 new_file_id = body.new_file_id @existing_file_id = new_file_id expect(new_file_id).to.exist @@ -127,6 +128,7 @@ describe "LinkedFiles", -> url: "/project/#{@project_one_id}/linked_file/#{@existing_file_id}/refresh", json: true }, (error, response, body) => + expect(response.statusCode).to.equal 200 new_file_id = body.new_file_id expect(new_file_id).to.exist expect(new_file_id).to.not.equal @existing_file_id diff --git a/services/web/test/acceptance/coffee/helpers/User.coffee b/services/web/test/acceptance/coffee/helpers/User.coffee index 7d89b5c83c..54b660c6b5 100644 --- a/services/web/test/acceptance/coffee/helpers/User.coffee +++ b/services/web/test/acceptance/coffee/helpers/User.coffee @@ -32,6 +32,9 @@ class User get: (callback = (error, user)->) -> db.users.findOne { _id: ObjectId(@_id) }, callback + mongoUpdate: (updateOp, callback=(error)->) -> + db.users.update {_id: ObjectId(@_id)}, updateOp, callback + register: (callback = (error, user) ->) -> return callback(new Error('User already registered')) if @_id? @getCsrfToken (error) =>