Merge branch 'deploy-20181029a'

GitOrigin-RevId: c51d4da706319564bd31514370fe13413655b6cf
This commit is contained in:
Douglas Lovell 2018-10-29 11:48:23 -03:00 committed by sharelatex
parent 207b0d84c7
commit b1bda995a6
10 changed files with 210 additions and 129 deletions

View file

@ -28,8 +28,8 @@ module.exports = CompileManager =
CompileManager._checkIfAutoCompileLimitHasBeenHit options.isAutoCompile, "everyone", (err, canCompile)->
if !canCompile
return callback null, "autocompile-backoff", []
CompileManager._ensureRootDocumentIsSet project_id, (error) ->
ProjectRootDocManager.ensureRootDocumentIsSet project_id, (error) ->
return callback(error) if error?
CompileManager.getProjectCompileLimits project_id, (error, limits) ->
return callback(error) if error?
@ -103,17 +103,6 @@ module.exports = CompileManager =
Metrics.inc "auto-compile-#{compileGroup}-limited"
callback err, canCompile
_ensureRootDocumentIsSet: (project_id, callback = (error) ->) ->
ProjectGetter.getProject project_id, rootDoc_id: 1, (error, project) ->
return callback(error) if error?
if !project?
return callback new Error("project not found")
if project.rootDoc_id?
callback()
else
ProjectRootDocManager.setRootDocAutomatically project_id, callback
wordCount: (project_id, user_id, file, callback = (error) ->) ->
CompileManager.getProjectCompileLimits project_id, (error, limits) ->
return callback(error) if error?

View file

@ -4,7 +4,7 @@ logger = require("logger-sharelatex")
module.exports =
exportProject: (req, res) ->
exportProject: (req, res, next) ->
{project_id, brand_variation_id} = req.params
user_id = AuthenticationController.getLoggedInUserId(req)
export_params = {
@ -21,10 +21,10 @@ module.exports =
export_params.description = req.body.description.trim() if req.body.description
export_params.author = req.body.author.trim() if req.body.author
export_params.license = req.body.license.trim() if req.body.license
export_params.show_source = req.body.show_source if req.body.show_source
export_params.show_source = req.body.showSource if req.body.showSource?
ExportsHandler.exportProject export_params, (err, export_data) ->
return err if err?
return next(err) if err?
logger.log
user_id:user_id
project_id: project_id
@ -36,7 +36,13 @@ module.exports =
exportStatus: (req, res) ->
{export_id} = req.params
ExportsHandler.fetchExport export_id, (err, export_json) ->
return err if err?
if err?
json = {
status_summary: 'failed',
status_detail: err.toString,
}
res.send export_json: json
return err
parsed_export = JSON.parse(export_json)
json = {
status_summary: parsed_export.status_summary,
@ -46,11 +52,11 @@ module.exports =
}
res.send export_json: json
exportDownload: (req, res) ->
exportDownload: (req, res, next) ->
{type, export_id} = req.params
AuthenticationController.getLoggedInUserId(req)
ExportsHandler.fetchDownload export_id, type, (err, export_file_url) ->
return err if err?
return next(err) if err?
res.redirect export_file_url

View file

@ -1,5 +1,6 @@
ProjectGetter = require('../Project/ProjectGetter')
ProjectLocator = require('../Project/ProjectLocator')
ProjectRootDocManager = require('../Project/ProjectRootDocManager')
UserGetter = require('../User/UserGetter')
logger = require('logger-sharelatex')
settings = require 'settings-sharelatex'
@ -20,13 +21,16 @@ module.exports = ExportsHandler = self =
callback null, export_data
_buildExport: (export_params, callback=(err, export_data) ->) ->
{project_id, user_id, brand_variation_id, title, description, author, license, show_source} = export_params
{project_id, user_id, brand_variation_id, title, description, author,
license, show_source} = export_params
jobs =
project: (cb) ->
ProjectGetter.getProject project_id, cb
# TODO: when we update async, signature will change from (cb, results) to (results, cb)
rootDoc: [ 'project', (cb, results) ->
ProjectLocator.findRootDoc {project: results.project, project_id: project_id}, cb
ProjectRootDocManager.ensureRootDocumentIsSet project_id, (error) ->
return callback(error) if error?
ProjectLocator.findRootDoc {project: results.project, project_id: project_id}, cb
]
user: (cb) ->
UserGetter.getUser user_id, {first_name: 1, last_name: 1, email: 1, overleaf: 1}, cb
@ -62,7 +66,7 @@ module.exports = ExportsHandler = self =
description: description
author: author
license: license
show_source: show_source
showSource: show_source
user:
id: user_id
firstName: user.first_name

View file

@ -1,5 +1,6 @@
ProjectEntityHandler = require "./ProjectEntityHandler"
ProjectEntityUpdateHandler = require "./ProjectEntityUpdateHandler"
ProjectGetter = require "./ProjectGetter"
Path = require "path"
async = require("async")
_ = require("underscore")
@ -45,13 +46,24 @@ module.exports = ProjectRootDocManager =
# docpaths have a leading / so allow matching "folder/filename" and "/folder/filename"
if path == rootDocName
root_doc_id = doc_id
# try a basename match if there was no match
# try a basename match if there was no match
if !root_doc_id
for doc_id, path of docPaths
if Path.basename(path) == Path.basename(rootDocName)
if Path.basename(path) == Path.basename(rootDocName)
root_doc_id = doc_id
# set the root doc id if we found a match
if root_doc_id?
ProjectEntityUpdateHandler.setRootDoc project_id, root_doc_id, callback
else
callback()
callback()
ensureRootDocumentIsSet: (project_id, callback = (error) ->) ->
ProjectGetter.getProject project_id, rootDoc_id: 1, (error, project) ->
return callback(error) if error?
if !project?
return callback new Error("project not found")
if project.rootDoc_id?
callback()
else
ProjectRootDocManager.setRootDocAutomatically project_id, callback

View file

@ -1,12 +1,17 @@
.modal-body-publish {
@label-column-width: 10em;
@control-left-margin: 1.0em;
.form-control-box {
margin-bottom: 1.5ex;
margin-left: 1.0em;
margin-left: @control-left-margin;
label {
display: inline-block;
width: 10em;
width: @label-column-width;
vertical-align: baseline;
}
label.checkbox-label {
width: auto;
}
.form-control {
display: inline-block;
width: 60%;
@ -26,6 +31,12 @@
option {
margin-left: -4px;
}
a.help {
margin-left: 0.6em;
}
}
.no-label {
margin-left: @label-column-width + @control-left-margin;
}
#search-input-container {
overflow: hidden;

View file

@ -36,7 +36,7 @@ describe 'Exports', ->
description: 'description'
author: 'author'
license: 'other'
show_source: true
showSource: true
}, (error, response, body) =>
throw error if error?
expect(response.statusCode).to.equal 200
@ -53,7 +53,7 @@ describe 'Exports', ->
expect(project.metadata.description).to.equal 'description'
expect(project.metadata.author).to.equal 'author'
expect(project.metadata.license).to.equal 'other'
expect(project.metadata.show_source).to.equal true
expect(project.metadata.showSource).to.equal true
# version should match what was retrieved from project-history
expect(project.historyVersion).to.equal @version
# user details should match

View file

@ -10,7 +10,7 @@ describe "CompileManager", ->
beforeEach ->
@rateLimitGetStub = sinon.stub()
rateLimitGetStub = @rateLimitGetStub
@ratelimiter =
@ratelimiter =
addCount: sinon.stub()
@CompileManager = SandboxedModule.require modulePath, requires:
"settings-sharelatex": @settings =
@ -34,11 +34,11 @@ describe "CompileManager", ->
timeout: 42
}
describe "compile", ->
beforeEach ->
@CompileManager._checkIfRecentlyCompiled = sinon.stub().callsArgWith(2, null, false)
@CompileManager._ensureRootDocumentIsSet = sinon.stub().callsArgWith(1, null)
@ProjectRootDocManager.ensureRootDocumentIsSet = sinon.stub().callsArgWith(1, null)
@CompileManager.getProjectCompileLimits = sinon.stub().callsArgWith(1, null, @limits)
@ClsiManager.sendRequest = sinon.stub().callsArgWith(3, null, @status = "mock-status", @outputFiles = "mock output files", @output = "mock output")
@ -53,7 +53,7 @@ describe "CompileManager", ->
.should.equal true
it "should ensure that the root document is set", ->
@CompileManager._ensureRootDocumentIsSet
@ProjectRootDocManager.ensureRootDocumentIsSet
.calledWith(@project_id)
.should.equal true
@ -81,7 +81,7 @@ describe "CompileManager", ->
@logger.log
.calledWith(project_id: @project_id, user_id: @user_id, "compiling project")
.should.equal true
describe "when the project has been recently compiled", ->
it "should return", (done)->
@CompileManager._checkIfAutoCompileLimitHasBeenHit = (isAutoCompile, compileGroup, cb)-> cb(null, true)
@ -96,7 +96,7 @@ describe "CompileManager", ->
@CompileManager.compile @project_id, @user_id, {}, (err, status)->
status.should.equal "autocompile-backoff"
done()
describe "getProjectCompileLimits", ->
beforeEach ->
@features = {
@ -106,17 +106,17 @@ describe "CompileManager", ->
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project = { owner_ref: @owner_id = "owner-id-123" })
@UserGetter.getUser = sinon.stub().callsArgWith(2, null, @user = { features: @features })
@CompileManager.getProjectCompileLimits @project_id, @callback
it "should look up the owner of the project", ->
@ProjectGetter.getProject
.calledWith(@project_id, { owner_ref: 1 })
.should.equal true
it "should look up the owner's features", ->
@UserGetter.getUser
.calledWith(@project.owner_ref, { features: 1 })
.should.equal true
it "should return the limits", ->
@callback
.calledWith(null, {
@ -124,23 +124,23 @@ describe "CompileManager", ->
compileGroup: @group
})
.should.equal true
describe "deleteAuxFiles", ->
beforeEach ->
@CompileManager.getProjectCompileLimits = sinon.stub().callsArgWith 1, null, @limits = { compileGroup: "mock-compile-group" }
@ClsiManager.deleteAuxFiles = sinon.stub().callsArg(3)
@CompileManager.deleteAuxFiles @project_id, @user_id, @callback
it "should look up the compile group to use", ->
@CompileManager.getProjectCompileLimits
.calledWith(@project_id)
.should.equal true
it "should delete the aux files", ->
@ClsiManager.deleteAuxFiles
.calledWith(@project_id, @user_id, @limits)
.should.equal true
it "should call the callback", ->
@callback.called.should.equal true
@ -170,55 +170,7 @@ describe "CompileManager", ->
it "should call the callback with false", ->
@callback.calledWith(null, false).should.equal true
describe "_ensureRootDocumentIsSet", ->
beforeEach ->
@project = {}
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project)
@ProjectRootDocManager.setRootDocAutomatically = sinon.stub().callsArgWith(1, null)
describe "when the root doc is set", ->
beforeEach ->
@project.rootDoc_id = "root-doc-id"
@CompileManager._ensureRootDocumentIsSet(@project_id, @callback)
it "should find the project with only the rootDoc_id fiel", ->
@ProjectGetter.getProject
.calledWith(@project_id, rootDoc_id: 1)
.should.equal true
it "should not try to update the project rootDoc_id", ->
@ProjectRootDocManager.setRootDocAutomatically
.called.should.equal false
it "should call the callback", ->
@callback.called.should.equal true
describe "when the root doc is not set", ->
beforeEach ->
@CompileManager._ensureRootDocumentIsSet(@project_id, @callback)
it "should find the project with only the rootDoc_id fiel", ->
@ProjectGetter.getProject
.calledWith(@project_id, rootDoc_id: 1)
.should.equal true
it "should update the project rootDoc_id", ->
@ProjectRootDocManager.setRootDocAutomatically
.calledWith(@project_id)
.should.equal true
it "should call the callback", ->
@callback.called.should.equal true
describe "when the project does not exist", ->
beforeEach ->
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, null)
@CompileManager._ensureRootDocumentIsSet(@project_id, @callback)
it "should call the callback with an error", ->
@callback.calledWith(new Error("project not found")).should.equal true
describe "_checkIfAutoCompileLimitHasBeenHit", ->
it "should be able to compile if it is not an autocompile", (done)->
@ -255,16 +207,16 @@ describe "CompileManager", ->
@CompileManager.getProjectCompileLimits = sinon.stub().callsArgWith 1, null, @limits = { compileGroup: "mock-compile-group" }
@ClsiManager.wordCount = sinon.stub().callsArg(4)
@CompileManager.wordCount @project_id, @user_id, false, @callback
it "should look up the compile group to use", ->
@CompileManager.getProjectCompileLimits
.calledWith(@project_id)
.should.equal true
it "should call wordCount for project", ->
@ClsiManager.wordCount
.calledWith(@project_id, @user_id, false, @limits)
.should.equal true
it "should call the callback", ->
@callback.called.should.equal true

View file

@ -62,7 +62,7 @@ describe 'ExportsController', ->
@req.body.description = description
@req.body.author = author
@req.body.license = license
@req.body.show_source = true
@req.body.showSource = true
it 'should ask the handler to perform the export', (done) ->
@handler.exportProject = sinon.stub().yields(null, {iAmAnExport: true, v1_id: 897})

View file

@ -8,20 +8,17 @@ SandboxedModule = require('sandboxed-module')
describe 'ExportsHandler', ->
beforeEach ->
@ProjectGetter = {}
@ProjectLocator = {}
@UserGetter = {}
@settings = {}
@stubRequest = {}
@request = defaults: => return @stubRequest
@ExportsHandler = SandboxedModule.require modulePath, requires:
'logger-sharelatex':
log: ->
err: ->
'../Project/ProjectGetter': @ProjectGetter
'../Project/ProjectLocator': @ProjectLocator
'../User/UserGetter': @UserGetter
'settings-sharelatex': @settings
'../Project/ProjectGetter': @ProjectGetter = {}
'../Project/ProjectLocator': @ProjectLocator = {}
'../Project/ProjectRootDocManager': @ProjectRootDocManager = {}
'../User/UserGetter': @UserGetter = {}
'settings-sharelatex': @settings = {}
'request': @request
@project_id = "project-id-123"
@project_history_id = 987
@ -45,34 +42,49 @@ describe 'ExportsHandler', ->
@callback = sinon.stub()
describe 'exportProject', ->
beforeEach (done) ->
beforeEach ->
@export_data = {iAmAnExport: true}
@response_body = {iAmAResponseBody: true}
@ExportsHandler._buildExport = sinon.stub().yields(null, @export_data)
@ExportsHandler._requestExport = sinon.stub().yields(null, @response_body)
@ExportsHandler.exportProject @export_params, (error, export_data) =>
@callback(error, export_data)
done()
it "should build the export", ->
@ExportsHandler._buildExport
.calledWith(@export_params)
.should.equal true
describe "when all goes well", ->
beforeEach (done) ->
@ExportsHandler.exportProject @export_params, (error, export_data) =>
@callback(error, export_data)
done()
it "should request the export", ->
@ExportsHandler._requestExport
.calledWith(@export_data)
.should.equal true
it "should build the export", ->
@ExportsHandler._buildExport
.calledWith(@export_params)
.should.equal true
it "should return the export", ->
@callback
.calledWith(null, @export_data)
.should.equal true
it "should request the export", ->
@ExportsHandler._requestExport
.calledWith(@export_data)
.should.equal true
it "should return the export", ->
@callback
.calledWith(null, @export_data)
.should.equal true
describe "when request can't be built", ->
beforeEach (done) ->
@ExportsHandler._buildExport = sinon.stub().yields(new Error("cannot export project without root doc"))
@ExportsHandler.exportProject @export_params, (error, export_data) =>
@callback(error, export_data)
done()
it "should return an error", ->
(@callback.args[0][0] instanceof Error)
.should.equal true
describe '_buildExport', ->
beforeEach (done) ->
@project =
id: @project_id
rootDoc_id: 'doc1_id'
compiler: 'pdflatex'
imageName: 'mock-image-name'
overleaf:
@ -90,6 +102,7 @@ describe 'ExportsHandler', ->
@historyVersion = 777
@ProjectGetter.getProject = sinon.stub().yields(null, @project)
@ProjectLocator.findRootDoc = sinon.stub().yields(null, [null, {fileSystem: 'main.tex'}])
@ProjectRootDocManager.ensureRootDocumentIsSet = sinon.stub().callsArgWith(1, null)
@UserGetter.getUser = sinon.stub().yields(null, @user)
@ExportsHandler._requestVersion = sinon.stub().yields(null, @historyVersion)
done()
@ -119,7 +132,7 @@ describe 'ExportsHandler', ->
description: @description
author: @author
license: @license
show_source: @show_source
showSource: @show_source
user:
id: @user_id
firstName: @user.first_name
@ -159,7 +172,7 @@ describe 'ExportsHandler', ->
description: @description
author: @author
license: @license
show_source: @show_source
showSource: @show_source
user:
id: @user_id
firstName: @custom_first_name
@ -186,15 +199,58 @@ describe 'ExportsHandler', ->
.should.equal true
describe "when project has no root doc", ->
beforeEach (done) ->
@ProjectLocator.findRootDoc = sinon.stub().yields(null, [null, null])
@ExportsHandler._buildExport @export_params, (error, export_data) =>
@callback(error, export_data)
done()
describe "when a root doc can be set automatically", ->
beforeEach (done) ->
@project.rootDoc_id = null
@ProjectLocator.findRootDoc = sinon.stub().yields(null, [null, {fileSystem: 'other.tex'}])
@ExportsHandler._buildExport @export_params, (error, export_data) =>
@callback(error, export_data)
done()
it "should return an error", ->
(@callback.args[0][0] instanceof Error)
.should.equal true
it "should set a root doc", ->
@ProjectRootDocManager.ensureRootDocumentIsSet.called
.should.equal true
it "should return export data", ->
expected_export_data =
project:
id: @project_id
rootDocPath: 'other.tex'
historyId: @project_history_id
historyVersion: @historyVersion
v1ProjectId: @project_history_id
metadata:
compiler: 'pdflatex'
imageName: 'mock-image-name'
title: @title
description: @description
author: @author
license: @license
showSource: @show_source
user:
id: @user_id
firstName: @user.first_name
lastName: @user.last_name
email: @user.email
orcidId: null
v1UserId: 876
destination:
brandVariationId: @brand_variation_id
options:
callbackUrl: null
@callback.calledWith(null, expected_export_data)
.should.equal true
describe "when no root doc can be identified", ->
beforeEach (done) ->
@ProjectLocator.findRootDoc = sinon.stub().yields(null, [null, null])
@ExportsHandler._buildExport @export_params, (error, export_data) =>
@callback(error, export_data)
done()
it "should return an error", ->
(@callback.args[0][0] instanceof Error)
.should.equal true
describe "when user is not found", ->
beforeEach (done) ->

View file

@ -12,7 +12,8 @@ describe 'ProjectRootDocManager', ->
@ProjectRootDocManager = SandboxedModule.require modulePath, requires:
"./ProjectEntityHandler" : @ProjectEntityHandler = {}
"./ProjectEntityUpdateHandler" : @ProjectEntityUpdateHandler = {}
"./ProjectGetter" : @ProjectGetter = {}
describe "setRootDocAutomatically", ->
describe "when there is a suitable root doc", ->
beforeEach (done)->
@ -165,3 +166,53 @@ describe 'ProjectRootDocManager', ->
it "should not set the root doc", ->
@ProjectEntityUpdateHandler.setRootDoc.called.should.equal false
describe "ensureRootDocumentIsSet", ->
beforeEach ->
@project = {}
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, @project)
@ProjectRootDocManager.setRootDocAutomatically = sinon.stub().callsArgWith(1, null)
describe "when the root doc is set", ->
beforeEach ->
@project.rootDoc_id = "root-doc-id"
@ProjectRootDocManager.ensureRootDocumentIsSet(@project_id, @callback)
it "should find the project with only the rootDoc_id fiel", ->
@ProjectGetter.getProject
.calledWith(@project_id, rootDoc_id: 1)
.should.equal true
it "should not try to update the project rootDoc_id", ->
@ProjectRootDocManager.setRootDocAutomatically
.called.should.equal false
it "should call the callback", ->
@callback.called.should.equal true
describe "when the root doc is not set", ->
beforeEach ->
@ProjectRootDocManager.ensureRootDocumentIsSet(@project_id, @callback)
it "should find the project with only the rootDoc_id fiel", ->
@ProjectGetter.getProject
.calledWith(@project_id, rootDoc_id: 1)
.should.equal true
it "should update the project rootDoc_id", ->
@ProjectRootDocManager.setRootDocAutomatically
.calledWith(@project_id)
.should.equal true
it "should call the callback", ->
@callback.called.should.equal true
describe "when the project does not exist", ->
beforeEach ->
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, null)
@ProjectRootDocManager.ensureRootDocumentIsSet(@project_id, @callback)
it "should call the callback with an error", ->
@callback.calledWith(new Error("project not found")).should.equal true