mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Backend for project output file agent
This commit is contained in:
parent
e916d96792
commit
d4beba24b6
2 changed files with 121 additions and 1 deletions
|
@ -0,0 +1,102 @@
|
||||||
|
FileWriter = require('../../infrastructure/FileWriter')
|
||||||
|
AuthorizationManager = require('../Authorization/AuthorizationManager')
|
||||||
|
ProjectGetter = require('../Project/ProjectGetter')
|
||||||
|
FileWriter = require('../../infrastructure/FileWriter')
|
||||||
|
Settings = require 'settings-sharelatex'
|
||||||
|
CompileManager = require '../Compile/CompileManager'
|
||||||
|
CompileController = require '../Compile/CompileController'
|
||||||
|
ClsiCookieManager = require '../Compile/ClsiCookieManager'
|
||||||
|
_ = require "underscore"
|
||||||
|
request = require "request"
|
||||||
|
|
||||||
|
|
||||||
|
BadDataError = (message) ->
|
||||||
|
error = new Error(message)
|
||||||
|
error.name = 'BadData'
|
||||||
|
error.__proto__ = BadDataError.prototype
|
||||||
|
return error
|
||||||
|
BadDataError.prototype.__proto__ = Error.prototype
|
||||||
|
|
||||||
|
|
||||||
|
ProjectNotFoundError = (message) ->
|
||||||
|
error = new Error(message)
|
||||||
|
error.name = 'ProjectNotFound'
|
||||||
|
error.__proto__ = ProjectNotFoundError.prototype
|
||||||
|
return error
|
||||||
|
ProjectNotFoundError.prototype.__proto__ = Error.prototype
|
||||||
|
|
||||||
|
|
||||||
|
OutputFileFetchFailedError = (message) ->
|
||||||
|
error = new Error(message)
|
||||||
|
error.name = 'OutputFileFetchFailedError'
|
||||||
|
error.__proto__ = OutputFileFetchFailedError.prototype
|
||||||
|
return error
|
||||||
|
OutputFileFetchFailedError.prototype.__proto__ = Error.prototype
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = ProjectOutputFileAgent = {
|
||||||
|
|
||||||
|
sanitizeData: (data) ->
|
||||||
|
return {
|
||||||
|
source_project_id: data.source_project_id,
|
||||||
|
source_output_file_path: data.source_output_file_path
|
||||||
|
}
|
||||||
|
|
||||||
|
canCreate: (data) -> true
|
||||||
|
|
||||||
|
decorateLinkedFileData: (data, callback = (err, newData) ->) ->
|
||||||
|
callback = _.once(callback)
|
||||||
|
ProjectGetter.getProject data.source_project_id, {name: 1}, (err, project) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
if !project?
|
||||||
|
return callback(new ProjectNotFoundError())
|
||||||
|
callback(err, _.extend(data, {source_project_display_name: project.name}))
|
||||||
|
|
||||||
|
checkAuth: (project_id, data, current_user_id, callback = (error, allowed)->) ->
|
||||||
|
callback = _.once(callback)
|
||||||
|
{ source_project_id } = data
|
||||||
|
AuthorizationManager.canUserReadProject current_user_id, source_project_id, null, (err, canRead) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
callback(null, canRead)
|
||||||
|
|
||||||
|
_validate: (data) ->
|
||||||
|
data.source_project_id? && data.source_output_file_path?
|
||||||
|
|
||||||
|
writeIncomingFileToDisk: (project_id, data, current_user_id, callback = (error, fsPath) ->) ->
|
||||||
|
callback = _.once(callback)
|
||||||
|
# TODO:
|
||||||
|
# - Compile project
|
||||||
|
# - Get output file content
|
||||||
|
# - Write to disk
|
||||||
|
# - callback with fs-path
|
||||||
|
if !ProjectOutputFileAgent._validate(data)
|
||||||
|
return callback(new BadDataError())
|
||||||
|
{ source_project_id, source_output_file_path } = data
|
||||||
|
CompileManager.compile source_project_id, null, {}, (err) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
url = "#{Settings.apis.clsi.url}/project/#{source_project_id}/output/#{source_output_file_path}"
|
||||||
|
ClsiCookieManager.getCookieJar source_project_id, (err, jar)->
|
||||||
|
return callback(err) if err?
|
||||||
|
oneMinute = 60 * 1000
|
||||||
|
# the base request
|
||||||
|
options = { url: url, method: "GET", timeout: oneMinute, jar : jar }
|
||||||
|
readStream = request(options)
|
||||||
|
readStream.on "error", callback
|
||||||
|
readStream.on "response", (response) ->
|
||||||
|
if 200 <= response.statusCode < 300
|
||||||
|
FileWriter.writeStreamToDisk project_id, readStream, callback
|
||||||
|
else
|
||||||
|
error = new OutputFileFetchFailedError("Output file fetch failed: #{url}")
|
||||||
|
error.statusCode = response.statusCode
|
||||||
|
callback(error)
|
||||||
|
|
||||||
|
handleError: (error, req, res, next) ->
|
||||||
|
if error instanceof BadDataError
|
||||||
|
res.status(400).send("The submitted data is not valid")
|
||||||
|
else if error instanceof SourceFileNotFoundError
|
||||||
|
res.status(404).send("Source file not found")
|
||||||
|
else if error instanceof ProjectNotFoundError
|
||||||
|
res.status(404).send("Project not found")
|
||||||
|
else
|
||||||
|
next(error)
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ div.binary-file.full-size(
|
||||||
) #{translate("no_preview_available")}
|
) #{translate("no_preview_available")}
|
||||||
|
|
||||||
div.binary-file-footer
|
div.binary-file-footer
|
||||||
|
// Linked Files: URL
|
||||||
div(ng-if="openFile.linkedFileData.provider == 'url'")
|
div(ng-if="openFile.linkedFileData.provider == 'url'")
|
||||||
p
|
p
|
||||||
i.fa.fa-fw.fa-external-link-square.fa-rotate-180.linked-file-icon
|
i.fa.fa-fw.fa-external-link-square.fa-rotate-180.linked-file-icon
|
||||||
|
@ -47,6 +48,7 @@ div.binary-file.full-size(
|
||||||
|
|
|
|
||||||
| at {{ openFile.created | formatDate:'h:mm a' }} {{ openFile.created | relativeDate }}
|
| at {{ openFile.created | formatDate:'h:mm a' }} {{ openFile.created | relativeDate }}
|
||||||
|
|
||||||
|
// Linked Files: Project File
|
||||||
div(ng-if="openFile.linkedFileData.provider == 'project_file'")
|
div(ng-if="openFile.linkedFileData.provider == 'project_file'")
|
||||||
p
|
p
|
||||||
i.fa.fa-fw.fa-external-link-square.fa-rotate-180.linked-file-icon
|
i.fa.fa-fw.fa-external-link-square.fa-rotate-180.linked-file-icon
|
||||||
|
@ -61,7 +63,23 @@ div.binary-file.full-size(
|
||||||
|
|
|
|
||||||
| at {{ openFile.created | formatDate:'h:mm a' }} {{ openFile.created | relativeDate }}
|
| at {{ openFile.created | formatDate:'h:mm a' }} {{ openFile.created | relativeDate }}
|
||||||
|
|
||||||
span(ng-if="openFile.linkedFileData.provider == 'url' || openFile.linkedFileData.provider == 'project_file'")
|
// Linked Files: Project Output File
|
||||||
|
div(ng-if="openFile.linkedFileData.provider == 'project_output_file'")
|
||||||
|
p
|
||||||
|
i.fa.fa-fw.fa-external-link-square.fa-rotate-180.linked-file-icon
|
||||||
|
| Imported from the output of
|
||||||
|
|
|
||||||
|
a(ng-if='!openFile.linkedFileData.v1_source_doc_id'
|
||||||
|
ng-href='/project/{{openFile.linkedFileData.source_project_id}}' target="_blank")
|
||||||
|
| {{ openFile.linkedFileData.source_project_display_name }}
|
||||||
|
span(ng-if='openFile.linkedFileData.v1_source_doc_id')
|
||||||
|
| {{ openFile.linkedFileData.source_project_display_name }}
|
||||||
|
| : {{ openFile.linkedFileData.source_output_file_path }},
|
||||||
|
|
|
||||||
|
| at {{ openFile.created | formatDate:'h:mm a' }} {{ openFile.created | relativeDate }}
|
||||||
|
|
||||||
|
// Bottom Controls
|
||||||
|
span(ng-if="openFile.linkedFileData.provider")
|
||||||
button.btn.btn-success(
|
button.btn.btn-success(
|
||||||
href, ng-click="refreshFile(openFile)",
|
href, ng-click="refreshFile(openFile)",
|
||||||
ng-disabled="refreshing"
|
ng-disabled="refreshing"
|
||||||
|
|
Loading…
Reference in a new issue