mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge branch 'master' of github.com:sharelatex/web-sharelatex
This commit is contained in:
commit
7fceb2b3af
13 changed files with 132 additions and 42 deletions
|
@ -58,7 +58,7 @@ module.exports = ClsiManager =
|
||||||
return outputFiles
|
return outputFiles
|
||||||
|
|
||||||
VALID_COMPILERS: ["pdflatex", "latex", "xelatex", "lualatex"]
|
VALID_COMPILERS: ["pdflatex", "latex", "xelatex", "lualatex"]
|
||||||
_buildRequest: (project_id, settingsOverride={}, callback = (error, request) ->) ->
|
_buildRequest: (project_id, options={}, callback = (error, request) ->) ->
|
||||||
Project.findById project_id, {compiler: 1, rootDoc_id: 1, imageName: 1}, (error, project) ->
|
Project.findById project_id, {compiler: 1, rootDoc_id: 1, imageName: 1}, (error, project) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
return callback(new Errors.NotFoundError("project does not exist: #{project_id}")) if !project?
|
return callback(new Errors.NotFoundError("project does not exist: #{project_id}")) if !project?
|
||||||
|
@ -82,7 +82,7 @@ module.exports = ClsiManager =
|
||||||
content: doc.lines.join("\n")
|
content: doc.lines.join("\n")
|
||||||
if project.rootDoc_id? and doc._id.toString() == project.rootDoc_id.toString()
|
if project.rootDoc_id? and doc._id.toString() == project.rootDoc_id.toString()
|
||||||
rootResourcePath = path
|
rootResourcePath = path
|
||||||
if settingsOverride.rootDoc_id? and doc._id.toString() == settingsOverride.rootDoc_id.toString()
|
if options.rootDoc_id? and doc._id.toString() == options.rootDoc_id.toString()
|
||||||
rootResourcePathOverride = path
|
rootResourcePathOverride = path
|
||||||
|
|
||||||
rootResourcePath = rootResourcePathOverride if rootResourcePathOverride?
|
rootResourcePath = rootResourcePathOverride if rootResourcePathOverride?
|
||||||
|
@ -101,8 +101,9 @@ module.exports = ClsiManager =
|
||||||
compile:
|
compile:
|
||||||
options:
|
options:
|
||||||
compiler: project.compiler
|
compiler: project.compiler
|
||||||
timeout: settingsOverride.timeout
|
timeout: options.timeout
|
||||||
imageName: project.imageName
|
imageName: project.imageName
|
||||||
|
draft: !!options.draft
|
||||||
rootResourcePath: rootResourcePath
|
rootResourcePath: rootResourcePath
|
||||||
resources: resources
|
resources: resources
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ module.exports = CompileController =
|
||||||
options.rootDoc_id = req.body.settingsOverride.rootDoc_id
|
options.rootDoc_id = req.body.settingsOverride.rootDoc_id
|
||||||
if req.body?.compiler
|
if req.body?.compiler
|
||||||
options.compiler = req.body.compiler
|
options.compiler = req.body.compiler
|
||||||
|
if req.body?.draft
|
||||||
|
options.draft = req.body.draft
|
||||||
logger.log {options, project_id}, "got compile request"
|
logger.log {options, project_id}, "got compile request"
|
||||||
CompileManager.compile project_id, user_id, options, (error, status, outputFiles, output, limits) ->
|
CompileManager.compile project_id, user_id, options, (error, status, outputFiles, output, limits) ->
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
|
|
|
@ -15,7 +15,7 @@ module.exports = RateLimiterMiddlewear =
|
||||||
###
|
###
|
||||||
rateLimit: (opts) ->
|
rateLimit: (opts) ->
|
||||||
return (req, res, next) ->
|
return (req, res, next) ->
|
||||||
if req.session.user?
|
if req.session?.user?
|
||||||
user_id = req.session.user._id
|
user_id = req.session.user._id
|
||||||
else
|
else
|
||||||
user_id = req.ip
|
user_id = req.ip
|
||||||
|
|
|
@ -1,16 +1,34 @@
|
||||||
div.full-size.pdf(ng-controller="PdfController")
|
div.full-size.pdf(ng-controller="PdfController")
|
||||||
.toolbar.toolbar-tall
|
.toolbar.toolbar-tall
|
||||||
a.btn.btn-info(
|
.btn-group(dropdown)
|
||||||
href,
|
a.btn.btn-info(
|
||||||
ng-disabled="pdf.compiling",
|
href,
|
||||||
ng-click="recompile()"
|
ng-disabled="pdf.compiling",
|
||||||
)
|
ng-click="recompile()"
|
||||||
i.fa.fa-refresh(
|
|
||||||
ng-class="{'fa-spin': pdf.compiling }"
|
|
||||||
)
|
)
|
||||||
|
|
i.fa.fa-refresh(
|
||||||
span(ng-show="!pdf.compiling") #{translate("recompile")}
|
ng-class="{'fa-spin': pdf.compiling }"
|
||||||
span(ng-show="pdf.compiling") #{translate("compiling")}...
|
)
|
||||||
|
|
|
||||||
|
span(ng-show="!pdf.compiling") #{translate("recompile")}
|
||||||
|
span(ng-show="pdf.compiling") #{translate("compiling")}...
|
||||||
|
a.btn.btn-info.dropdown-toggle(
|
||||||
|
href,
|
||||||
|
ng-disabled="pdf.compiling",
|
||||||
|
dropdown-toggle
|
||||||
|
)
|
||||||
|
span.caret
|
||||||
|
ul.dropdown-menu.dropdown-menu-right
|
||||||
|
li.dropdown-header #{translate("compile_mode")}
|
||||||
|
li
|
||||||
|
a(href, ng-click="draft = false")
|
||||||
|
i.fa.fa-fw(ng-class="{'fa-check': !draft}")
|
||||||
|
| #{translate("normal")}
|
||||||
|
li
|
||||||
|
a(href, ng-click="draft = true")
|
||||||
|
i.fa.fa-fw(ng-class="{'fa-check': draft}")
|
||||||
|
| #{translate("fast")}
|
||||||
|
span.subdued [draft]
|
||||||
a.log-btn(
|
a.log-btn(
|
||||||
href
|
href
|
||||||
ng-click="toggleLogs()"
|
ng-click="toggleLogs()"
|
||||||
|
|
|
@ -106,6 +106,8 @@ module.exports =
|
||||||
url: "http://localhost:3036"
|
url: "http://localhost:3036"
|
||||||
sixpack:
|
sixpack:
|
||||||
url: ""
|
url: ""
|
||||||
|
references:
|
||||||
|
url: "http://localhost:3040"
|
||||||
|
|
||||||
templates:
|
templates:
|
||||||
user_id: process.env.TEMPLATES_USER_ID or "5395eb7aad1f29a88756c7f2"
|
user_id: process.env.TEMPLATES_USER_ID or "5395eb7aad1f29a88756c7f2"
|
||||||
|
|
|
@ -12,6 +12,11 @@ define [
|
||||||
|
|
||||||
$scope.$on "pdf:error:display", () ->
|
$scope.$on "pdf:error:display", () ->
|
||||||
$scope.pdf.error = true
|
$scope.pdf.error = true
|
||||||
|
|
||||||
|
$scope.draft = localStorage("draft:#{$scope.project_id}") or false
|
||||||
|
$scope.$watch "draft", (new_value, old_value) ->
|
||||||
|
if new_value? and old_value != new_value
|
||||||
|
localStorage("draft:#{$scope.project_id}", new_value)
|
||||||
|
|
||||||
sendCompileRequest = (options = {}) ->
|
sendCompileRequest = (options = {}) ->
|
||||||
url = "/project/#{$scope.project_id}/compile"
|
url = "/project/#{$scope.project_id}/compile"
|
||||||
|
@ -19,6 +24,7 @@ define [
|
||||||
url += "?auto_compile=true"
|
url += "?auto_compile=true"
|
||||||
return $http.post url, {
|
return $http.post url, {
|
||||||
rootDoc_id: options.rootDocOverride_id or null
|
rootDoc_id: options.rootDocOverride_id or null
|
||||||
|
draft: $scope.draft
|
||||||
_csrf: window.csrfToken
|
_csrf: window.csrfToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,8 +109,8 @@ define [
|
||||||
doc = ide.editorManager.getCurrentDocValue()
|
doc = ide.editorManager.getCurrentDocValue()
|
||||||
return null if !doc?
|
return null if !doc?
|
||||||
for line in doc.split("\n")
|
for line in doc.split("\n")
|
||||||
match = line.match /(.*)\\documentclass/
|
match = line.match /^[^%]*\\documentclass/
|
||||||
if match and !match[1].match /%/
|
if match
|
||||||
return ide.editorManager.getCurrentDocId()
|
return ide.editorManager.getCurrentDocId()
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,21 @@ define [
|
||||||
App.controller 'UniverstiesContactController', ($scope, $modal) ->
|
App.controller 'UniverstiesContactController', ($scope, $modal) ->
|
||||||
|
|
||||||
$scope.form = {}
|
$scope.form = {}
|
||||||
|
$scope.sent = false
|
||||||
|
$scope.sending = false
|
||||||
$scope.contactUs = ->
|
$scope.contactUs = ->
|
||||||
|
if !$scope.form.email?
|
||||||
|
console.log "email not set"
|
||||||
|
return
|
||||||
|
$scope.sending = true
|
||||||
params =
|
params =
|
||||||
name: $scope.form.name || $scope.form.email
|
name: $scope.form.name || $scope.form.email
|
||||||
email: $scope.form.email
|
email: $scope.form.email
|
||||||
labels: $scope.form.type
|
labels: $scope.form.source
|
||||||
message: "Please contact me with more details"
|
message: "Please contact me with more details"
|
||||||
subject: $scope.form.subject
|
subject: $scope.form.subject
|
||||||
about : "#{$scope.form.position || ''} #{$scope.form.university || ''} #{$scope.form.source || ''}"
|
about : "#{$scope.form.position || ''} #{$scope.form.university || ''}"
|
||||||
|
|
||||||
Groove.createTicket params, (err, json)->
|
Groove.createTicket params, (err, json)->
|
||||||
|
$scope.sent = true
|
||||||
|
$scope.$apply()
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-bottom: 1px solid @toolbar-border-color;
|
border-bottom: 1px solid @toolbar-border-color;
|
||||||
|
|
||||||
a {
|
> a, .toolbar-right > a {
|
||||||
position: relative;
|
position: relative;
|
||||||
.label {
|
.label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a:not(.btn) {
|
> a:not(.btn), .toolbar-right > a:not(.btn) {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: @gray-light;
|
color: @gray-light;
|
||||||
padding: 4px 10px 5px;
|
padding: 4px 10px 5px;
|
||||||
|
@ -90,27 +90,36 @@
|
||||||
|
|
||||||
&.toolbar-small {
|
&.toolbar-small {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
a {
|
> a, .toolbar-right > a {
|
||||||
padding: 4px 2px 2px;
|
padding: 4px 2px 2px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
}
|
||||||
|
> a {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
.toolbar-right {
|
.toolbar-right > a {
|
||||||
a {
|
margin-left: 0;
|
||||||
margin-left: 0;
|
margin-right: 6px;
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.toolbar-tall {
|
&.toolbar-tall {
|
||||||
height: 58px;
|
height: 58px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
a.btn {
|
> a, .toolbar-right > a {
|
||||||
|
padding: 4px 10px 5px;
|
||||||
|
}
|
||||||
|
> a.btn, .toolbar-right > a.btn {
|
||||||
margin: 0 (@line-height-computed / 2);
|
margin: 0 (@line-height-computed / 2);
|
||||||
}
|
}
|
||||||
a {
|
.btn-group {
|
||||||
padding: 4px 10px 5px;
|
margin: 0 (@line-height-computed / 2);
|
||||||
|
> a {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
> .btn-group {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +144,7 @@
|
||||||
&.toolbar-header {
|
&.toolbar-header {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
a:not(.btn) {
|
> a:not(.btn) {
|
||||||
color: @gray;
|
color: @gray;
|
||||||
&:hover {
|
&:hover {
|
||||||
color: @gray-light;
|
color: @gray-light;
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
.btn-group > .btn:last-child:not(:first-child),
|
.btn-group > .btn:last-child:not(:first-child),
|
||||||
.btn-group > .dropdown-toggle:not(:first-child) {
|
.btn-group > .dropdown-toggle:not(:first-child) {
|
||||||
.border-left-radius(0);
|
.border-left-radius(0);
|
||||||
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)
|
// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)
|
||||||
|
|
|
@ -67,6 +67,9 @@
|
||||||
line-height: @line-height-base;
|
line-height: @line-height-base;
|
||||||
color: @dropdown-link-color;
|
color: @dropdown-link-color;
|
||||||
white-space: nowrap; // prevent links from randomly breaking onto new lines
|
white-space: nowrap; // prevent links from randomly breaking onto new lines
|
||||||
|
.subdued {
|
||||||
|
color: #7a7a7a
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +80,9 @@
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: @dropdown-link-hover-color;
|
color: @dropdown-link-hover-color;
|
||||||
background-color: @dropdown-link-hover-bg;
|
background-color: @dropdown-link-hover-bg;
|
||||||
|
.subdued {
|
||||||
|
color: @dropdown-link-hover-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,6 +166,7 @@ describe "ClsiManager", ->
|
||||||
compiler: @compiler
|
compiler: @compiler
|
||||||
timeout : 100
|
timeout : 100
|
||||||
imageName: @image
|
imageName: @image
|
||||||
|
draft: false
|
||||||
rootResourcePath: "main.tex"
|
rootResourcePath: "main.tex"
|
||||||
resources: [{
|
resources: [{
|
||||||
path: "main.tex"
|
path: "main.tex"
|
||||||
|
@ -220,6 +221,12 @@ describe "ClsiManager", ->
|
||||||
|
|
||||||
it "should return an error", ->
|
it "should return an error", ->
|
||||||
expect(@error).to.exist
|
expect(@error).to.exist
|
||||||
|
|
||||||
|
describe "with the draft option", ->
|
||||||
|
it "should add the draft option into the request", (done) ->
|
||||||
|
@ClsiManager._buildRequest @project_id, {timeout:100, draft: true}, (error, request) =>
|
||||||
|
request.compile.options.draft.should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
|
||||||
describe '_postToClsi', ->
|
describe '_postToClsi', ->
|
||||||
|
|
|
@ -43,14 +43,15 @@ describe "CompileController", ->
|
||||||
@res = new MockResponse()
|
@res = new MockResponse()
|
||||||
|
|
||||||
describe "compile", ->
|
describe "compile", ->
|
||||||
|
beforeEach ->
|
||||||
|
@req.params =
|
||||||
|
Project_id: @project_id
|
||||||
|
@req.session = {}
|
||||||
|
@AuthenticationController.getLoggedInUserId = sinon.stub().callsArgWith(1, null, @user_id = "mock-user-id")
|
||||||
|
@CompileManager.compile = sinon.stub().callsArgWith(3, null, @status = "success", @outputFiles = ["mock-output-files"])
|
||||||
|
|
||||||
describe "when not an auto compile", ->
|
describe "when not an auto compile", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@req.params =
|
|
||||||
Project_id: @project_id
|
|
||||||
@req.session = {}
|
|
||||||
@AuthenticationController.getLoggedInUserId = sinon.stub().callsArgWith(1, null, @user_id = "mock-user-id")
|
|
||||||
@CompileManager.compile = sinon.stub().callsArgWith(3, null, @status = "success", @outputFiles = ["mock-output-files"], @output = "mock-output")
|
|
||||||
@CompileController.compile @req, @res, @next
|
@CompileController.compile @req, @res, @next
|
||||||
|
|
||||||
it "should look up the user id", ->
|
it "should look up the user id", ->
|
||||||
|
@ -77,18 +78,25 @@ describe "CompileController", ->
|
||||||
|
|
||||||
describe "when an auto compile", ->
|
describe "when an auto compile", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@req.params =
|
|
||||||
Project_id: @project_id
|
|
||||||
@req.query =
|
@req.query =
|
||||||
auto_compile: "true"
|
auto_compile: "true"
|
||||||
@AuthenticationController.getLoggedInUserId = sinon.stub().callsArgWith(1, null, @user_id = "mock-user-id")
|
|
||||||
@CompileManager.compile = sinon.stub().callsArgWith(3, null, @status = "success", @outputFiles = ["mock-output-files"])
|
|
||||||
@CompileController.compile @req, @res, @next
|
@CompileController.compile @req, @res, @next
|
||||||
|
|
||||||
it "should do the compile with the auto compile flag", ->
|
it "should do the compile with the auto compile flag", ->
|
||||||
@CompileManager.compile
|
@CompileManager.compile
|
||||||
.calledWith(@project_id, @user_id, { isAutoCompile: true })
|
.calledWith(@project_id, @user_id, { isAutoCompile: true })
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
|
describe "with the draft attribute", ->
|
||||||
|
beforeEach ->
|
||||||
|
@req.body =
|
||||||
|
draft: true
|
||||||
|
@CompileController.compile @req, @res, @next
|
||||||
|
|
||||||
|
it "should do the compile without the draft compile flag", ->
|
||||||
|
@CompileManager.compile
|
||||||
|
.calledWith(@project_id, @user_id, { isAutoCompile: false, draft: true })
|
||||||
|
.should.equal true
|
||||||
|
|
||||||
describe "downloadPdf", ->
|
describe "downloadPdf", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
|
|
@ -10,7 +10,6 @@ describe "RateLimiterMiddlewear", ->
|
||||||
"logger-sharelatex": @logger = {warn: sinon.stub()}
|
"logger-sharelatex": @logger = {warn: sinon.stub()}
|
||||||
@req =
|
@req =
|
||||||
params: {}
|
params: {}
|
||||||
session: {}
|
|
||||||
@res =
|
@res =
|
||||||
status: sinon.stub()
|
status: sinon.stub()
|
||||||
write: sinon.stub()
|
write: sinon.stub()
|
||||||
|
@ -30,9 +29,30 @@ describe "RateLimiterMiddlewear", ->
|
||||||
doc_id: @doc_id = "doc-id"
|
doc_id: @doc_id = "doc-id"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe "when there is no session", ->
|
||||||
|
beforeEach ->
|
||||||
|
@RateLimiter.addCount = sinon.stub().callsArgWith(1, null, true)
|
||||||
|
@req.ip = @ip = "1.2.3.4"
|
||||||
|
@rateLimiter(@req, @res, @next)
|
||||||
|
|
||||||
|
it "should call the rate limiter backend with the ip address", ->
|
||||||
|
@RateLimiter.addCount
|
||||||
|
.calledWith({
|
||||||
|
endpointName: "test-endpoint"
|
||||||
|
timeInterval: 42
|
||||||
|
throttle: 12
|
||||||
|
subjectName: "#{@project_id}:#{@doc_id}:#{@ip}"
|
||||||
|
})
|
||||||
|
.should.equal true
|
||||||
|
|
||||||
|
it "should pass on to next()", ->
|
||||||
|
|
||||||
|
|
||||||
describe "when under the rate limit with logged in user", ->
|
describe "when under the rate limit with logged in user", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@req.session.user = { _id: @user_id = "user-id" }
|
@req.session =
|
||||||
|
user :
|
||||||
|
_id: @user_id = "user-id"
|
||||||
@RateLimiter.addCount = sinon.stub().callsArgWith(1, null, true)
|
@RateLimiter.addCount = sinon.stub().callsArgWith(1, null, true)
|
||||||
@rateLimiter(@req, @res, @next)
|
@rateLimiter(@req, @res, @next)
|
||||||
|
|
||||||
|
@ -70,7 +90,9 @@ describe "RateLimiterMiddlewear", ->
|
||||||
|
|
||||||
describe "when over the rate limit", ->
|
describe "when over the rate limit", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@req.session.user = { _id: @user_id = "user-id" }
|
@req.session =
|
||||||
|
user :
|
||||||
|
_id: @user_id = "user-id"
|
||||||
@RateLimiter.addCount = sinon.stub().callsArgWith(1, null, false)
|
@RateLimiter.addCount = sinon.stub().callsArgWith(1, null, false)
|
||||||
@rateLimiter(@req, @res, @next)
|
@rateLimiter(@req, @res, @next)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue