mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge branch 'master' into support-cached-pdfs
This commit is contained in:
commit
0315954b47
31 changed files with 240 additions and 166 deletions
|
@ -6,7 +6,6 @@ Metrics = require('../../infrastructure/Metrics')
|
|||
logger = require("logger-sharelatex")
|
||||
querystring = require('querystring')
|
||||
Url = require("url")
|
||||
uid = require "uid"
|
||||
|
||||
module.exports = AuthenticationController =
|
||||
login: (req, res, next = (error) ->) ->
|
||||
|
|
|
@ -24,5 +24,5 @@ module.exports =
|
|||
if err?
|
||||
logger.err err:err, query:query, "problem getting messages from chat api"
|
||||
return res.send 500
|
||||
logger.log messages:messages, "sending messages to client"
|
||||
logger.log length:messages?.length, "sending messages to client"
|
||||
res.send messages
|
||||
|
|
|
@ -71,9 +71,9 @@ module.exports = CompileManager =
|
|||
return callback(null, true)
|
||||
opts =
|
||||
endpointName:"auto_compile"
|
||||
timeInterval:15
|
||||
timeInterval:20
|
||||
subjectName:"everyone"
|
||||
throttle: 15
|
||||
throttle: 25
|
||||
rateLimiter.addCount opts, (err, canCompile)->
|
||||
if err?
|
||||
canCompile = false
|
||||
|
|
|
@ -48,12 +48,13 @@ module.exports = ProjectEntityHandler =
|
|||
for folderPath, folder of folders
|
||||
for doc in folder.docs
|
||||
content = docContents[doc._id.toString()]
|
||||
docs[path.join(folderPath, doc.name)] = {
|
||||
_id: doc._id
|
||||
name: doc.name
|
||||
lines: content.lines
|
||||
rev: content.rev
|
||||
}
|
||||
if content?
|
||||
docs[path.join(folderPath, doc.name)] = {
|
||||
_id: doc._id
|
||||
name: doc.name
|
||||
lines: content.lines
|
||||
rev: content.rev
|
||||
}
|
||||
logger.log count:_.keys(docs).length, project_id:project_id, "returning docs for project"
|
||||
callback null, docs
|
||||
|
||||
|
|
|
@ -92,6 +92,11 @@ module.exports =
|
|||
|
||||
|
||||
Project.getProject project_or_id, "", (err, project)->
|
||||
if err?
|
||||
logger.err err:err, project_or_id:project_or_id, "error getting project for finding element"
|
||||
return callback(err)
|
||||
if !project?
|
||||
return callback("project could not be found for finding a element #{project_or_id}")
|
||||
if needlePath == '' || needlePath == '/'
|
||||
return callback(null, project.rootFolder[0])
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ module.exports =
|
|||
self = @
|
||||
clientTokenId = ""
|
||||
RecurlyWrapper.createSubscription user, subscriptionDetails, recurly_token_id, (error, recurlySubscription)->
|
||||
console.log recurlySubscription
|
||||
return callback(error) if error?
|
||||
SubscriptionUpdater.syncSubscription recurlySubscription, user._id, (error) ->
|
||||
return callback(error) if error?
|
||||
|
|
|
@ -53,7 +53,9 @@ module.exports =
|
|||
async.series [
|
||||
(cb)-> User.update {_id: user._id}, {"$set":{holdingAccount:false}}, cb
|
||||
(cb)-> AuthenticationManager.setUserPassword user._id, userDetails.password, cb
|
||||
(cb)-> NewsLetterManager.subscribe user, cb
|
||||
(cb)->
|
||||
NewsLetterManager.subscribe user, ->
|
||||
cb() #this can be slow, just fire it off
|
||||
(cb)->
|
||||
emailOpts =
|
||||
first_name:user.first_name
|
||||
|
|
|
@ -3,37 +3,47 @@ settings = require("settings-sharelatex")
|
|||
logger = require("logger-sharelatex")
|
||||
ErrorController = require "../Errors/ErrorController"
|
||||
_ = require("underscore")
|
||||
AuthenticationController = require("../Authentication/AuthenticationController")
|
||||
|
||||
other_lngs = ["es"]
|
||||
|
||||
module.exports = WikiController =
|
||||
getPage: (req, res, next) ->
|
||||
|
||||
page = req.url.replace(/^\/learn/, "").replace(/^\//, "")
|
||||
if page == ""
|
||||
page = "Main_Page"
|
||||
|
||||
logger.log page: page, "getting page from wiki"
|
||||
if _.include(other_lngs, req.lng)
|
||||
lngPage = "#{page}_#{req.lng}"
|
||||
|
||||
_checkIfLoginIsNeeded: (req, res, next)->
|
||||
if settings.apis.wiki.requireLogin
|
||||
AuthenticationController.requireLogin()(req, res, next)
|
||||
else
|
||||
lngPage = page
|
||||
next()
|
||||
|
||||
WikiController._getPageContent "Contents", (error, contents) ->
|
||||
return next(error) if error?
|
||||
WikiController._getPageContent lngPage, (error, pageData) ->
|
||||
getPage: (req, res, next) ->
|
||||
WikiController._checkIfLoginIsNeeded req, res, ->
|
||||
|
||||
page = req.url.replace(/^\/learn/, "").replace(/^\//, "")
|
||||
if page == ""
|
||||
page = "Main_Page"
|
||||
|
||||
logger.log page: page, "getting page from wiki"
|
||||
if _.include(other_lngs, req.lng)
|
||||
lngPage = "#{page}_#{req.lng}"
|
||||
else
|
||||
lngPage = page
|
||||
|
||||
WikiController._getPageContent "Contents", (error, contents) ->
|
||||
return next(error) if error?
|
||||
if pageData.content?.length > 280
|
||||
if _.include(other_lngs, req.lng)
|
||||
pageData.title = pageData.title.slice(0, pageData.title.length - (req.lng.length+1) )
|
||||
WikiController._renderPage(pageData, contents, res)
|
||||
else
|
||||
WikiController._getPageContent page, (error, pageData) ->
|
||||
return next(error) if error?
|
||||
WikiController._getPageContent lngPage, (error, pageData) ->
|
||||
return next(error) if error?
|
||||
if pageData.content?.length > 280
|
||||
if _.include(other_lngs, req.lng)
|
||||
pageData.title = pageData.title.slice(0, pageData.title.length - (req.lng.length+1) )
|
||||
WikiController._renderPage(pageData, contents, res)
|
||||
else
|
||||
WikiController._getPageContent page, (error, pageData) ->
|
||||
return next(error) if error?
|
||||
WikiController._renderPage(pageData, contents, res)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_getPageContent: (page, callback = (error, data = { content: "", title: "" }) ->) ->
|
||||
request {
|
||||
|
|
|
@ -112,6 +112,11 @@ module.exports = (app)->
|
|||
res.locals.formatPrice = SubscriptionFormatters.formatPrice
|
||||
next()
|
||||
|
||||
app.use (req, res, next)->
|
||||
res.locals.externalAuthenticationSystemUsed = ->
|
||||
Settings.ldap?
|
||||
next()
|
||||
|
||||
app.use (req, res, next)->
|
||||
if req.session.user?
|
||||
res.locals.user =
|
||||
|
|
|
@ -27,11 +27,11 @@ html(itemscope, itemtype='http://schema.org/Product')
|
|||
meta(itemprop="name", content="ShareLaTeX, the Online LaTeX Editor")
|
||||
|
||||
-if (typeof(meta) == "undefined")
|
||||
meta(itemprop="description", content="An online LaTeX editor that's easy to use. No installation, real-time collaboration, version control, hundreds of LaTeX templates, and more.")
|
||||
meta(itemprop="description", name="description", content="An online LaTeX editor that's easy to use. No installation, real-time collaboration, version control, hundreds of LaTeX templates, and more.")
|
||||
-else
|
||||
meta(itemprop="description", content=meta)
|
||||
meta(itemprop="description", name="description" , content=meta)
|
||||
|
||||
meta(itemprop="image", content="https://www.sharelatex.com/favicon.ico")
|
||||
meta(itemprop="image", name="image", content="https://www.sharelatex.com/favicon.ico")
|
||||
|
||||
- if (typeof(gaToken) != "undefined")
|
||||
script(type='text/javascript').
|
||||
|
@ -98,7 +98,10 @@ html(itemscope, itemtype='http://schema.org/Product')
|
|||
// Other plugins
|
||||
/127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
|
||||
/webappstoolbarba\.texthelp\.com\//i,
|
||||
/metrics\.itunes\.apple\.com\.edgesuite\.net\//i
|
||||
/metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
|
||||
/a\.disquscdn\.com/i,
|
||||
/platform\.twitter\.com/i,
|
||||
/pstatic\.datafastguru\.info/i
|
||||
],
|
||||
shouldSendCallback: function(data) {
|
||||
// only send a fraction of errors
|
||||
|
|
|
@ -41,12 +41,12 @@ aside#left-menu.full-size(
|
|||
)
|
||||
i.fa.fa-fw.fa-copy
|
||||
| #{translate("copy_project")}
|
||||
!{moduleIncludes("editorLeftMenu:actions", locals)}
|
||||
!= moduleIncludes("editorLeftMenu:actions", locals)
|
||||
|
||||
if (moduleIncludesAvailable("editorLeftMenu:sync"))
|
||||
div(ng-show="!anonymous")
|
||||
h4() #{translate("sync")}
|
||||
!{moduleIncludes("editorLeftMenu:sync", locals)}
|
||||
!= moduleIncludes("editorLeftMenu:sync", locals)
|
||||
|
||||
h4(ng-show="!anonymous") #{translate("settings")}
|
||||
form.settings(ng-controller="SettingsController", ng-show="!anonymous")
|
||||
|
|
|
@ -8,9 +8,14 @@ div#trackChanges(ng-show="ui.view == 'track-changes'")
|
|||
ng-class="buttonClass"
|
||||
ng-click="startFreeTrial('track-changes')"
|
||||
) #{translate("start_free_trial")}
|
||||
|
|
||||
a.small(href, ng-click="toggleTrackChanges()") #{translate("cancel")}
|
||||
p.small(ng-show="startedFreeTrial") #{translate("refresh_page_after_starting_free_trial")}
|
||||
|
||||
.message(ng-show="project.owner._id != user.id")
|
||||
p #{translate("ask_proj_owner_to_upgrade_for_history")}
|
||||
p
|
||||
a.small(href, ng-click="toggleTrackChanges()") #{translate("cancel")}
|
||||
|
||||
aside.change-list(
|
||||
ng-controller="TrackChangesListController"
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
href,
|
||||
ng-click="openUploadProjectModal()"
|
||||
) #{translate("upload_project")}
|
||||
!{moduleIncludes("newProjectMenu", locals)}
|
||||
!= moduleIncludes("newProjectMenu", locals)
|
||||
if (templates)
|
||||
li.divider
|
||||
li.dropdown-header #{translate("templates")}
|
||||
|
|
|
@ -143,8 +143,9 @@ block content
|
|||
function callback(response) {
|
||||
// document.getElementById('msg').innerHTML = "Post ID: " + response['post_id'];
|
||||
}
|
||||
|
||||
FB.ui(obj, callback);
|
||||
if (typeof FB !== "undefined" && FB !== null) {
|
||||
FB.ui(obj, callback);
|
||||
}
|
||||
}
|
||||
|
||||
script(type="text/javascript").
|
||||
|
|
|
@ -19,19 +19,20 @@ block content
|
|||
h3 #{translate("update_account_info")}
|
||||
form(async-form="settings", name="settingsForm", method="POST", action="/user/settings", novalidate)
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
.form-group
|
||||
label(for='email') #{translate("email")}
|
||||
input.form-control(
|
||||
type='email',
|
||||
name='email',
|
||||
placeholder="email@example.com"
|
||||
required,
|
||||
ng-model="email",
|
||||
ng-init="email = #{JSON.stringify(user.email)}",
|
||||
ng-model-options="{ updateOn: 'blur' }"
|
||||
)
|
||||
span.small.text-primary(ng-show="settingsForm.email.$invalid && settingsForm.email.$dirty")
|
||||
| #{translate("must_be_email_address")}
|
||||
if !externalAuthenticationSystemUsed()
|
||||
.form-group
|
||||
label(for='email') #{translate("email")}
|
||||
input.form-control(
|
||||
type='email',
|
||||
name='email',
|
||||
placeholder="email@example.com"
|
||||
required,
|
||||
ng-model="email",
|
||||
ng-init="email = #{JSON.stringify(user.email)}",
|
||||
ng-model-options="{ updateOn: 'blur' }"
|
||||
)
|
||||
span.small.text-primary(ng-show="settingsForm.email.$invalid && settingsForm.email.$dirty")
|
||||
| #{translate("must_be_email_address")}
|
||||
.form-group
|
||||
label(for='firstName').control-label #{translate("first_name")}
|
||||
input.form-control(
|
||||
|
@ -51,75 +52,77 @@ block content
|
|||
type='submit',
|
||||
ng-disabled="settingsForm.$invalid"
|
||||
) #{translate("update")}
|
||||
|
||||
.col-md-5.col-md-offset-1
|
||||
h3 #{translate("change_password")}
|
||||
form(async-form="changepassword", name="changePasswordForm", action="/user/password/update", method="POST", novalidate)
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
.form-group
|
||||
label(for='currentPassword') #{translate("current_password")}
|
||||
input.form-control(
|
||||
type='password',
|
||||
name='currentPassword',
|
||||
placeholder='*********',
|
||||
ng-model="currentPassword",
|
||||
required
|
||||
)
|
||||
span.small.text-primary(ng-show="changePasswordForm.currentPassword.$invalid && changePasswordForm.currentPassword.$dirty")
|
||||
| #{translate("required")}
|
||||
.form-group
|
||||
label(for='newPassword1') #{translate("new_password")}
|
||||
input.form-control(
|
||||
id='newPassword1',
|
||||
type='password',
|
||||
name='newPassword1',
|
||||
placeholder='*********',
|
||||
ng-model="newPassword1",
|
||||
required
|
||||
)
|
||||
span.small.text-primary(ng-show="changePasswordForm.newPassword1.$invalid && changePasswordForm.newPassword1.$dirty")
|
||||
| #{translate("required")}
|
||||
.form-group
|
||||
label(for='newPassword2') #{translate("confirm_new_password")}
|
||||
input.form-control(
|
||||
type='password',
|
||||
name='newPassword2',
|
||||
placeholder='*********',
|
||||
ng-model="newPassword2",
|
||||
equals="newPassword1"
|
||||
)
|
||||
span.small.text-primary(ng-show="changePasswordForm.newPassword2.$invalid && changePasswordForm.newPassword2.$dirty")
|
||||
| #{translate("doesnt_match")}
|
||||
.actions
|
||||
button.btn.btn-primary(
|
||||
type='submit',
|
||||
ng-disabled="changePasswordForm.$invalid"
|
||||
) #{translate("change")}
|
||||
if !externalAuthenticationSystemUsed()
|
||||
.col-md-5.col-md-offset-1
|
||||
h3 #{translate("change_password")}
|
||||
form(async-form="changepassword", name="changePasswordForm", action="/user/password/update", method="POST", novalidate)
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
.form-group
|
||||
label(for='currentPassword') #{translate("current_password")}
|
||||
input.form-control(
|
||||
type='password',
|
||||
name='currentPassword',
|
||||
placeholder='*********',
|
||||
ng-model="currentPassword",
|
||||
required
|
||||
)
|
||||
span.small.text-primary(ng-show="changePasswordForm.currentPassword.$invalid && changePasswordForm.currentPassword.$dirty")
|
||||
| #{translate("required")}
|
||||
.form-group
|
||||
label(for='newPassword1') #{translate("new_password")}
|
||||
input.form-control(
|
||||
id='newPassword1',
|
||||
type='password',
|
||||
name='newPassword1',
|
||||
placeholder='*********',
|
||||
ng-model="newPassword1",
|
||||
required
|
||||
)
|
||||
span.small.text-primary(ng-show="changePasswordForm.newPassword1.$invalid && changePasswordForm.newPassword1.$dirty")
|
||||
| #{translate("required")}
|
||||
.form-group
|
||||
label(for='newPassword2') #{translate("confirm_new_password")}
|
||||
input.form-control(
|
||||
type='password',
|
||||
name='newPassword2',
|
||||
placeholder='*********',
|
||||
ng-model="newPassword2",
|
||||
equals="newPassword1"
|
||||
)
|
||||
span.small.text-primary(ng-show="changePasswordForm.newPassword2.$invalid && changePasswordForm.newPassword2.$dirty")
|
||||
| #{translate("doesnt_match")}
|
||||
.actions
|
||||
button.btn.btn-primary(
|
||||
type='submit',
|
||||
ng-disabled="changePasswordForm.$invalid"
|
||||
) #{translate("change")}
|
||||
|
||||
| !{moduleIncludes("userSettings", locals)}
|
||||
|
||||
hr
|
||||
|
||||
p.small
|
||||
| #{translate("newsletter_info_and_unsubscribe")}
|
||||
a(
|
||||
href,
|
||||
ng-click="unsubscribe()",
|
||||
ng-show="subscribed && !unsubscribing"
|
||||
) #{translate("unsubscribe")}
|
||||
span(
|
||||
ng-show="unsubscribing"
|
||||
)
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("unsubscribing")}
|
||||
span.text-success(
|
||||
ng-show="!subscribed"
|
||||
)
|
||||
i.fa.fa-check
|
||||
| #{translate("unsubscribed")}
|
||||
if !externalAuthenticationSystemUsed()
|
||||
|
||||
p #{translate("need_to_leave")}
|
||||
a(href, ng-click="deleteAccount()") #{translate("delete_your_account")}
|
||||
p.small
|
||||
| #{translate("newsletter_info_and_unsubscribe")}
|
||||
a(
|
||||
href,
|
||||
ng-click="unsubscribe()",
|
||||
ng-show="subscribed && !unsubscribing"
|
||||
) #{translate("unsubscribe")}
|
||||
span(
|
||||
ng-show="unsubscribing"
|
||||
)
|
||||
i.fa.fa-spin.fa-refresh
|
||||
| #{translate("unsubscribing")}
|
||||
span.text-success(
|
||||
ng-show="!subscribed"
|
||||
)
|
||||
i.fa.fa-check
|
||||
| #{translate("unsubscribed")}
|
||||
|
||||
p #{translate("need_to_leave")}
|
||||
a(href, ng-click="deleteAccount()") #{translate("delete_your_account")}
|
||||
|
||||
|
||||
script(type='text/ng-template', id='deleteAccountModalTemplate')
|
||||
|
|
|
@ -331,3 +331,19 @@ module.exports =
|
|||
proxyUrls: {}
|
||||
|
||||
reloadModuleViewsOnEachRequest: true
|
||||
|
||||
# ShareLaTeX Server Pro options (https://www.sharelatex.com/university/onsite.html)
|
||||
# ----------
|
||||
|
||||
|
||||
|
||||
# ldap:
|
||||
# host: 'ldap://ldap.forumsys.com'
|
||||
# dnObj: 'uid'
|
||||
# dnSuffix: 'dc=example,dc=com'
|
||||
# failMessage: 'LDAP User Fail'
|
||||
# fieldName: 'LDAP User'
|
||||
# placeholder: 'LDAP User ID'
|
||||
# emailAtt: 'mail'
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "web-sharelatex",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "The HTTP front end for ShareLaTeX",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -19,6 +19,7 @@
|
|||
"express": "3.3.4",
|
||||
"fairy": "0.0.2",
|
||||
"jade": "~1.3.1",
|
||||
"ldapjs": "^0.7.1",
|
||||
"logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#v1.0.0",
|
||||
"lynx": "0.1.1",
|
||||
"metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.0.0",
|
||||
|
@ -39,7 +40,6 @@
|
|||
"settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#v1.0.0",
|
||||
"socket.io": "0.9.16",
|
||||
"translations-sharelatex": "git+https://github.com/sharelatex/translations-sharelatex.git#master",
|
||||
"uid": "0.0.2",
|
||||
"underscore": "1.6.0",
|
||||
"underscore.string": "^3.0.2",
|
||||
"v8-profiler": "^5.2.3",
|
||||
|
|
|
@ -83,7 +83,7 @@ define [
|
|||
$scope.$on "project:joined", () ->
|
||||
return if inited
|
||||
inited = true
|
||||
if $scope.project.deletedByExternalDataSource
|
||||
if $scope?.project?.deletedByExternalDataSource
|
||||
ide.showGenericMessageModal("Project Renamed or Deleted", """
|
||||
This project has either been renamed or deleted by an external data source such as Dropbox.
|
||||
We don't want to delete your data on ShareLaTeX, so this project still contains your history and collaborators.
|
||||
|
|
|
@ -15,7 +15,7 @@ define [
|
|||
|
||||
$scope.$on "chat:newMessage", (e, message) ->
|
||||
if message?
|
||||
if message.user.id != ide.$scope.user.id
|
||||
if message?.user?.id != ide.$scope.user.id
|
||||
if !$scope.ui.chatOpen
|
||||
$scope.unreadMessages += 1
|
||||
flashTitle()
|
||||
|
|
|
@ -30,7 +30,7 @@ define [
|
|||
$scope.loadMoreMessages = ->
|
||||
chatMessages.loadMoreMessages()
|
||||
|
||||
$scope.linkify = (message)->
|
||||
$scope.linkify = (message = "")->
|
||||
return autolinker.link(message)
|
||||
|
||||
|
|
@ -15,12 +15,12 @@ define [
|
|||
processEscapes: true
|
||||
skipStartupTypeset: true
|
||||
|
||||
MathJax.Hub.Config(mathjaxConfig);
|
||||
MathJax?.Hub?.Config(mathjaxConfig);
|
||||
|
||||
App.directive "mathjax", () ->
|
||||
return {
|
||||
link: (scope, element, attrs) ->
|
||||
setTimeout () ->
|
||||
MathJax.Hub.Queue(["Typeset", MathJax.Hub, element.get(0)])
|
||||
MathJax?.Hub?.Queue(["Typeset", MathJax?.Hub, element.get(0)])
|
||||
, 0
|
||||
}
|
|
@ -18,7 +18,7 @@ define [
|
|||
|
||||
justSent = false
|
||||
ide.socket.on "new-chat-message", (message) =>
|
||||
if message.user.id == ide.$scope.user.id and justSent
|
||||
if message?.user?.id == ide.$scope.user.id and justSent
|
||||
# Nothing to do
|
||||
else
|
||||
ide.$scope.$apply () ->
|
||||
|
@ -51,9 +51,9 @@ define [
|
|||
if messages.length < MESSAGE_LIMIT
|
||||
chat.state.atEnd = true
|
||||
if !messages.reverse?
|
||||
Raven?.captureException(new Error("messages has no reverse property #{JSON.stringify(messages)}"))
|
||||
Raven?.captureException(new Error("messages has no reverse property #{typeof(messages)}"))
|
||||
if typeof messages.reverse isnt 'function'
|
||||
Raven?.captureException(new Error("messages.reverse not a function #{typeof(messages.reverse)} #{JSON.stringify(messages)}"))
|
||||
Raven?.captureException(new Error("messages.reverse not a function #{typeof(messages.reverse)} #{typeof(messages)}"))
|
||||
chat.state.errored = true
|
||||
else
|
||||
messages.reverse()
|
||||
|
@ -65,7 +65,7 @@ define [
|
|||
prependMessage = (message) ->
|
||||
firstMessage = chat.state.messages[0]
|
||||
shouldGroup = firstMessage? and
|
||||
firstMessage.user.id == message.user.id and
|
||||
firstMessage.user.id == message?.user?.id and
|
||||
firstMessage.timestamp - message.timestamp < TIMESTAMP_GROUP_SIZE
|
||||
if shouldGroup
|
||||
firstMessage.timestamp = message.timestamp
|
||||
|
@ -86,7 +86,7 @@ define [
|
|||
|
||||
lastMessage = chat.state.messages[chat.state.messages.length - 1]
|
||||
shouldGroup = lastMessage? and
|
||||
lastMessage.user.id == message.user.id and
|
||||
lastMessage.user.id == message?.user?.id and
|
||||
message.timestamp - lastMessage.timestamp < TIMESTAMP_GROUP_SIZE
|
||||
if shouldGroup
|
||||
lastMessage.timestamp = message.timestamp
|
||||
|
|
|
@ -162,13 +162,8 @@ define [
|
|||
return if !path?
|
||||
return path.split("/").slice(0, -1).join("/")
|
||||
|
||||
# forEachFolder: (callback) ->
|
||||
# @forEachEntity (entity) ->
|
||||
# if entity.type == "folder"
|
||||
# callback(entity)
|
||||
|
||||
loadRootFolder: () ->
|
||||
@$scope.rootFolder = @_parseFolder(@$scope.project.rootFolder[0])
|
||||
@$scope.rootFolder = @_parseFolder(@$scope?.project?.rootFolder[0])
|
||||
|
||||
_parseFolder: (rawFolder) ->
|
||||
folder = {
|
||||
|
@ -306,6 +301,7 @@ define [
|
|||
return (child_path.slice(0, parent_path.length) == parent_path)
|
||||
|
||||
_deleteEntityFromScope: (entity, options = { moveToDeleted: true }) ->
|
||||
return if !entity?
|
||||
parent_folder = null
|
||||
@forEachEntity (possible_entity, folder) ->
|
||||
if possible_entity == entity
|
||||
|
|
|
@ -17,7 +17,7 @@ define [
|
|||
# We need this here as well as in FileTreeController
|
||||
# since the file-entity diretive creates a new scope
|
||||
# that doesn't inherit from previous scopes.
|
||||
return '0' if entity.type == "folder"
|
||||
return '0' if entity?.type == "folder"
|
||||
return '1'
|
||||
|
||||
$scope.openNewDocModal = () ->
|
||||
|
|
|
@ -60,6 +60,9 @@ define [
|
|||
|
||||
IGNORE_FILES = ["output.fls", "output.fdb_latexmk"]
|
||||
$scope.pdf.outputFiles = []
|
||||
|
||||
if !response.outputFiles?
|
||||
return
|
||||
for file in response.outputFiles
|
||||
if IGNORE_FILES.indexOf(file.path) == -1
|
||||
# Turn 'output.blg' into 'blg file'.
|
||||
|
@ -80,16 +83,17 @@ define [
|
|||
|
||||
$scope.pdf.logEntryAnnotations = {}
|
||||
for entry in logEntries.all
|
||||
entry.file = normalizeFilePath(entry.file)
|
||||
if entry.file?
|
||||
entry.file = normalizeFilePath(entry.file)
|
||||
|
||||
entity = ide.fileTreeManager.findEntityByPath(entry.file)
|
||||
if entity?
|
||||
$scope.pdf.logEntryAnnotations[entity.id] ||= []
|
||||
$scope.pdf.logEntryAnnotations[entity.id].push {
|
||||
row: entry.line - 1
|
||||
type: if entry.level == "error" then "error" else "warning"
|
||||
text: entry.message
|
||||
}
|
||||
entity = ide.fileTreeManager.findEntityByPath(entry.file)
|
||||
if entity?
|
||||
$scope.pdf.logEntryAnnotations[entity.id] ||= []
|
||||
$scope.pdf.logEntryAnnotations[entity.id].push {
|
||||
row: entry.line - 1
|
||||
type: if entry.level == "error" then "error" else "warning"
|
||||
text: entry.message
|
||||
}
|
||||
|
||||
.error () ->
|
||||
$scope.pdf.logEntries = []
|
||||
|
|
|
@ -24,6 +24,6 @@ define [
|
|||
|
||||
clearHighlights: () ->
|
||||
for h in @highlightElements
|
||||
h.remove()
|
||||
h?.remove()
|
||||
@highlightElements = []
|
||||
]
|
||||
|
|
|
@ -45,7 +45,10 @@ define [
|
|||
pricing.plan(planCode, { quantity: 1 }).currency(MultiCurrencyPricing.currencyCode).done (price)->
|
||||
totalPriceExTax = parseFloat(price.next.total)
|
||||
$scope.$evalAsync () ->
|
||||
$scope.prices[planCode] = $scope.currencySymbol + (totalPriceExTax + (totalPriceExTax * taxRate))
|
||||
taxAmmount = totalPriceExTax * taxRate
|
||||
if isNaN(taxAmmount)
|
||||
taxAmmount = 0
|
||||
$scope.prices[planCode] = $scope.currencySymbol + (totalPriceExTax + taxAmmount)
|
||||
|
||||
price = ""
|
||||
|
||||
|
|
|
@ -84,7 +84,6 @@
|
|||
}
|
||||
.qq-upload-spinner {
|
||||
display: inline-block;
|
||||
background: url("loading.gif");
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
vertical-align: text-bottom;
|
||||
|
|
|
@ -241,9 +241,9 @@ describe "CompileManager", ->
|
|||
@ratelimiter.addCount.callsArgWith(1, null, true)
|
||||
@CompileManager._checkIfAutoCompileLimitHasBeenHit true, (err, canCompile)=>
|
||||
args = @ratelimiter.addCount.args[0][0]
|
||||
args.throttle.should.equal 15
|
||||
args.throttle.should.equal 25
|
||||
args.subjectName.should.equal "everyone"
|
||||
args.timeInterval.should.equal 15
|
||||
args.timeInterval.should.equal 20
|
||||
args.endpointName.should.equal "auto_compile"
|
||||
canCompile.should.equal true
|
||||
done()
|
||||
|
|
|
@ -6,7 +6,7 @@ modulePath = "../../../../app/js/Features/Project/ProjectLocator"
|
|||
SandboxedModule = require('sandboxed-module')
|
||||
sinon = require('sinon')
|
||||
Errors = require "../../../../app/js/errors"
|
||||
|
||||
expect = require("chai").expect
|
||||
Project = class Project
|
||||
|
||||
project = _id : "1234566", rootFolder:[]
|
||||
|
@ -221,6 +221,7 @@ describe 'project model', ->
|
|||
assert.equal element, undefined
|
||||
done()
|
||||
|
||||
|
||||
describe "where duplicate folder exists", ->
|
||||
|
||||
beforeEach ->
|
||||
|
@ -266,7 +267,23 @@ describe 'project model', ->
|
|||
element.name.should.equal "other.tex"
|
||||
done()
|
||||
|
||||
|
||||
|
||||
describe "with a null project", ->
|
||||
beforeEach ->
|
||||
@project =
|
||||
rootFolder:[
|
||||
folders: []
|
||||
fileRefs: []
|
||||
docs: [{name:"main.tex"}, null, {name:"other.tex"}]
|
||||
]
|
||||
Project.getProject = sinon.stub()
|
||||
Project.getProject.callsArgWith(2, null)
|
||||
|
||||
it "should not crash with a null", (done)->
|
||||
callback = sinon.stub()
|
||||
@locator.findElementByPath project._id, "/other.tex", (err, element)->
|
||||
expect(err).to.exist
|
||||
done()
|
||||
|
||||
|
||||
describe 'finding a project by user_id and project name', ()->
|
||||
|
|
|
@ -10,6 +10,18 @@ cookeFilePath = "/tmp/smoke-test-cookie-#{port}.txt"
|
|||
buildUrl = (path) -> " -b #{cookeFilePath} --resolve 'smoke#{Settings.cookieDomain}:#{port}:127.0.0.1' http://smoke#{Settings.cookieDomain}:#{port}/#{path}?setLng=en"
|
||||
logger = require "logger-sharelatex"
|
||||
|
||||
# Change cookie to be non secure so curl will send it
|
||||
convertCookieFile = (callback) ->
|
||||
fs = require("fs")
|
||||
fs.readFile cookeFilePath, "utf8", (err, data) ->
|
||||
return callback(err) if err
|
||||
firstTrue = data.indexOf("TRUE")
|
||||
secondTrue = data.indexOf("TRUE", firstTrue+4)
|
||||
result = data.slice(0, secondTrue)+"FALSE"+data.slice(secondTrue+4)
|
||||
fs.writeFile cookeFilePath, result, "utf8", (err) ->
|
||||
return callback(err) if err
|
||||
callback()
|
||||
|
||||
describe "Opening", ->
|
||||
|
||||
before (done) ->
|
||||
|
@ -26,20 +38,14 @@ describe "Opening", ->
|
|||
return done("smoke test: does not have csrf token")
|
||||
csrf = csrfMatches[1]
|
||||
|
||||
# Change cookie to be non secure so curl will send it
|
||||
fs = require("fs")
|
||||
fs.readFile cookeFilePath, "utf8", (err, data) ->
|
||||
return done(err) if err
|
||||
firstTrue = data.indexOf("TRUE")
|
||||
secondTrue = data.indexOf("TRUE", firstTrue+4)
|
||||
result = data.slice(0, secondTrue)+"FALSE"+data.slice(secondTrue+4)
|
||||
fs.writeFile cookeFilePath, result, "utf8", (err) ->
|
||||
return done(err) if err
|
||||
|
||||
command = """
|
||||
curl -H "Content-Type: application/json" -H "X-Forwarded-Proto: https" -d '{"_csrf":"#{csrf}", "email":"#{Settings.smokeTest.user}", "password":"#{Settings.smokeTest.password}"}' #{buildUrl('register')}
|
||||
"""
|
||||
child.exec command, done
|
||||
convertCookieFile (err) ->
|
||||
return done(err) if err?
|
||||
command = """
|
||||
curl -c #{cookeFilePath} -H "Content-Type: application/json" -H "X-Forwarded-Proto: https" -d '{"_csrf":"#{csrf}", "email":"#{Settings.smokeTest.user}", "password":"#{Settings.smokeTest.password}"}' #{buildUrl('register')}
|
||||
"""
|
||||
child.exec command, (err) ->
|
||||
return done(err) if err?
|
||||
convertCookieFile done
|
||||
|
||||
after (done)->
|
||||
command = """
|
||||
|
|
Loading…
Reference in a new issue