Merge branch 'master' into ja-review-panel

This commit is contained in:
Paulo Reis 2016-11-23 10:41:20 +00:00
commit ba5118d02a
212 changed files with 56549 additions and 710 deletions

View file

@ -1,43 +1,48 @@
Settings = require "settings-sharelatex" settings = require "settings-sharelatex"
logger = require "logger-sharelatex" logger = require "logger-sharelatex"
_ = require "underscore" _ = require "underscore"
request = require "request"
if !Settings.analytics?.postgres?
module.exports =
recordEvent: (user_id, event, segmentation, callback = () ->) ->
logger.log {user_id, event, segmentation}, "no event tracking configured, logging event"
callback()
else
Sequelize = require "sequelize"
options = _.extend {logging:false}, Settings.analytics.postgres
sequelize = new Sequelize( makeRequest = (opts, callback)->
Settings.analytics.postgres.database, if settings.apis?.analytics?.url?
Settings.analytics.postgres.username, urlPath = opts.url
Settings.analytics.postgres.password, opts.url = "#{settings.apis.analytics.url}#{urlPath}"
options request opts, callback
) else
callback()
Event = sequelize.define("Event", {
user_id: Sequelize.STRING,
event: Sequelize.STRING,
segmentation: Sequelize.JSONB
})
module.exports =
recordEvent: (user_id, event, segmentation = {}, callback = (error) ->) ->
if user_id? and typeof(user_id) != "string" module.exports =
user_id = user_id.toString()
if user_id == Settings.smokeTest?.userId
# Don't record smoke tests analytics recordEvent: (user_id, event, segmentation = {}, callback = (error) ->) ->
return callback() if user_id == settings.smokeTest?.userId
Event return callback()
.create({ user_id, event, segmentation }) opts =
.then( body:
(result) -> callback(), event:event
(error) -> segmentation:segmentation
logger.err {err: error, user_id, event, segmentation}, "error recording analytics event" json:true
callback(error) method:"POST"
) timeout:1000
url: "/user/#{user_id}/event"
sync: () -> sequelize.sync() makeRequest opts, callback
getLastOccurance: (user_id, event, callback = (error) ->) ->
opts =
body:
event:event
json:true
method:"POST"
timeout:1000
url: "/user/#{user_id}/event/last_occurnace"
makeRequest opts, (err, response, body)->
if err?
console.log response, opts
logger.err {user_id, err}, "error getting last occurance of event"
return callback err
else
return callback null, body

View file

@ -0,0 +1,24 @@
AnnouncementsHandler = require("./AnnouncementsHandler")
AuthenticationController = require("../Authentication/AuthenticationController")
logger = require("logger-sharelatex")
module.exports =
getUndreadAnnouncements: (req, res, next)->
if !settings?.apis?.analytics?.url? or !settings.apis.blog.url?
return res.json []
user_id = AuthenticationController.getLoggedInUserId(req)
logger.log {user_id}, "getting unread announcements"
AnnouncementsHandler.getUnreadAnnouncements user_id, (err, announcements)->
if err?
logger.err {err, user_id}, "unable to get unread announcements"
next(err)
else
res.json announcements

View file

@ -0,0 +1,33 @@
AnalyticsManager = require("../Analytics/AnalyticsManager")
BlogHandler = require("../Blog/BlogHandler")
async = require("async")
_ = require("lodash")
logger = require("logger-sharelatex")
settings = require("settings-sharelatex")
module.exports =
getUnreadAnnouncements : (user_id, callback = (err, announcements)->)->
async.parallel {
lastEvent: (cb)->
AnalyticsManager.getLastOccurance user_id, "announcement-alert-dismissed", cb
announcements: (cb)->
BlogHandler.getLatestAnnouncements cb
}, (err, results)->
if err?
logger.err err:err, user_id:user_id, "error getting unread announcements"
return callback(err)
announcements = _.sortBy(results.announcements, "date").reverse()
lastSeenBlogId = results?.lastEvent?.segmentation?.blogPostId
announcementIndex = _.findIndex announcements, (announcement)->
announcement.id == lastSeenBlogId
if announcementIndex != -1
announcements = announcements.slice(0, announcementIndex)
logger.log announcementsLength:announcements?.length, user_id:user_id, "returning announcements"
callback null, announcements

View file

@ -32,21 +32,27 @@ module.exports = AuthenticationController =
afterLoginSessionSetup: (req, user, callback=(err)->) -> afterLoginSessionSetup: (req, user, callback=(err)->) ->
req.login user, (err) -> req.login user, (err) ->
if err?
logger.err {user_id: user._id, err}, "error from req.login"
return callback(err)
# Regenerate the session to get a new sessionID (cookie value) to # Regenerate the session to get a new sessionID (cookie value) to
# protect against session fixation attacks # protect against session fixation attacks
oldSession = req.session oldSession = req.session
req.session.destroy() req.session.destroy (err) ->
req.sessionStore.generate(req)
for key, value of oldSession
req.session[key] = value
# copy to the old `session.user` location, for backward-comptability
req.session.user = req.session.passport.user
req.session.save (err) ->
if err? if err?
logger.err {user_id: user._id}, "error saving regenerated session after login" logger.err {user_id: user._id, err}, "error when trying to destroy old session"
return callback(err) return callback(err)
UserSessionsManager.trackSession(user, req.sessionID, () ->) req.sessionStore.generate(req)
callback(null) for key, value of oldSession
req.session[key] = value
# copy to the old `session.user` location, for backward-comptability
req.session.user = req.session.passport.user
req.session.save (err) ->
if err?
logger.err {user_id: user._id}, "error saving regenerated session after login"
return callback(err)
UserSessionsManager.trackSession(user, req.sessionID, () ->)
callback(null)
passportLogin: (req, res, next) -> passportLogin: (req, res, next) ->
# This function is middleware which wraps the passport.authenticate middleware, # This function is middleware which wraps the passport.authenticate middleware,

View file

@ -0,0 +1,24 @@
request = require "request"
settings = require "settings-sharelatex"
_ = require("underscore")
logger = require "logger-sharelatex"
module.exports = BlogHandler =
getLatestAnnouncements: (callback)->
blogUrl = "#{settings.apis.blog.url}/blog/latestannouncements.json"
opts =
url:blogUrl
json:true
timeout:500
request.get opts, (err, res, announcements)->
if err?
return callback err
if res.statusCode != 200
return callback("blog announcement returned non 200")
logger.log announcementsLength: announcements?.length, "announcements returned"
announcements = _.map announcements, (announcement)->
announcement.url = "/blog#{announcement.url}"
announcement.date = new Date(announcement.date)
return announcement
callback(err, announcements)

View file

@ -25,7 +25,7 @@ else if Settings?.email?.parameters?.sendgridApiKey?
logger.log "using sendgrid for email" logger.log "using sendgrid for email"
nm_client = nodemailer.createTransport(sgTransport({auth:{api_key:Settings?.email?.parameters?.sendgridApiKey}})) nm_client = nodemailer.createTransport(sgTransport({auth:{api_key:Settings?.email?.parameters?.sendgridApiKey}}))
else if Settings?.email?.parameters? else if Settings?.email?.parameters?
smtp = _.pick(Settings?.email?.parameters, "host", "port", "secure", "auth") smtp = _.pick(Settings?.email?.parameters, "host", "port", "secure", "auth", "ignoreTLS")
logger.log "using smtp for email" logger.log "using smtp for email"

View file

@ -64,7 +64,7 @@ Reporter = (res) ->
res.contentType("application/json") res.contentType("application/json")
if failures.length > 0 if failures.length > 0
logger.err failures:failures, "health check failed" logger.err failures:failures, "health check failed"
res.send 500, JSON.stringify(results, null, 2) res.status(500).send(JSON.stringify(results, null, 2))
else else
res.send 200, JSON.stringify(results, null, 2) res.status(200).send(JSON.stringify(results, null, 2))

View file

@ -153,6 +153,8 @@ module.exports = ProjectController =
return next(err) return next(err)
logger.log results:results, user_id:user_id, "rendering project list" logger.log results:results, user_id:user_id, "rendering project list"
tags = results.tags[0] tags = results.tags[0]
notifications = require("underscore").map results.notifications, (notification)-> notifications = require("underscore").map results.notifications, (notification)->
notification.html = req.i18n.translate(notification.templateKey, notification.messageOpts) notification.html = req.i18n.translate(notification.templateKey, notification.messageOpts)
return notification return notification

View file

@ -1,26 +0,0 @@
Settings = require("settings-sharelatex")
redis = require("redis-sharelatex")
rclient = redis.createClient(Settings.redis.web)
crypto = require("crypto")
async = require("async")
module.exports =
_getEmailKey : (email)->
hash = crypto.createHash("md5").update(email).digest("hex")
return "e_sess:#{hash}"
tracksession:(sessionId, email, callback = ->)->
session_lookup_key = @_getEmailKey(email)
rclient.set session_lookup_key, sessionId, callback
invalidateSession:(email, callback = ->)->
session_lookup_key = @_getEmailKey(email)
rclient.get session_lookup_key, (err, sessionId)->
async.series [
(cb)-> rclient.del sessionId, cb
(cb)-> rclient.del session_lookup_key, cb
], callback

View file

@ -44,6 +44,7 @@ module.exports = UserController =
updateUserSettings : (req, res)-> updateUserSettings : (req, res)->
user_id = AuthenticationController.getLoggedInUserId(req) user_id = AuthenticationController.getLoggedInUserId(req)
usingExternalAuth = settings.ldap? or settings.saml?
logger.log user_id: user_id, "updating account settings" logger.log user_id: user_id, "updating account settings"
User.findById user_id, (err, user)-> User.findById user_id, (err, user)->
if err? or !user? if err? or !user?
@ -74,12 +75,15 @@ module.exports = UserController =
user.ace.syntaxValidation = req.body.syntaxValidation user.ace.syntaxValidation = req.body.syntaxValidation
user.save (err)-> user.save (err)->
newEmail = req.body.email?.trim().toLowerCase() newEmail = req.body.email?.trim().toLowerCase()
if !newEmail? or newEmail == user.email if !newEmail? or newEmail == user.email or usingExternalAuth
# end here, don't update email
AuthenticationController.setInSessionUser(req, {first_name: user.first_name, last_name: user.last_name}) AuthenticationController.setInSessionUser(req, {first_name: user.first_name, last_name: user.last_name})
return res.sendStatus 200 return res.sendStatus 200
else if newEmail.indexOf("@") == -1 else if newEmail.indexOf("@") == -1
# email invalid
return res.sendStatus(400) return res.sendStatus(400)
else else
# update the user email
UserUpdater.changeEmailAddress user_id, newEmail, (err)-> UserUpdater.changeEmailAddress user_id, newEmail, (err)->
if err? if err?
logger.err err:err, user_id:user_id, newEmail:newEmail, "problem updaing users email address" logger.err err:err, user_id:user_id, newEmail:newEmail, "problem updaing users email address"

View file

@ -3,14 +3,11 @@ redis = require('redis-sharelatex')
logger = require("logger-sharelatex") logger = require("logger-sharelatex")
Async = require('async') Async = require('async')
_ = require('underscore') _ = require('underscore')
UserSessionsRedis = require('./UserSessionsRedis')
rclient = redis.createClient(Settings.redis.web) rclient = UserSessionsRedis.client()
module.exports = UserSessionsManager = module.exports = UserSessionsManager =
_sessionSetKey: (user) ->
return "UserSessions:#{user._id}"
# mimic the key used by the express sessions # mimic the key used by the express sessions
_sessionKey: (sessionId) -> _sessionKey: (sessionId) ->
return "sess:#{sessionId}" return "sess:#{sessionId}"
@ -23,7 +20,7 @@ module.exports = UserSessionsManager =
logger.log {user_id: user._id}, "no sessionId to track, returning" logger.log {user_id: user._id}, "no sessionId to track, returning"
return callback(null) return callback(null)
logger.log {user_id: user._id, sessionId}, "onLogin handler" logger.log {user_id: user._id, sessionId}, "onLogin handler"
sessionSetKey = UserSessionsManager._sessionSetKey(user) sessionSetKey = UserSessionsRedis.sessionSetKey(user)
value = UserSessionsManager._sessionKey sessionId value = UserSessionsManager._sessionKey sessionId
rclient.multi() rclient.multi()
.sadd(sessionSetKey, value) .sadd(sessionSetKey, value)
@ -43,7 +40,7 @@ module.exports = UserSessionsManager =
logger.log {user_id: user._id}, "no sessionId to untrack, returning" logger.log {user_id: user._id}, "no sessionId to untrack, returning"
return callback(null) return callback(null)
logger.log {user_id: user._id, sessionId}, "onLogout handler" logger.log {user_id: user._id, sessionId}, "onLogout handler"
sessionSetKey = UserSessionsManager._sessionSetKey(user) sessionSetKey = UserSessionsRedis.sessionSetKey(user)
value = UserSessionsManager._sessionKey sessionId value = UserSessionsManager._sessionKey sessionId
rclient.multi() rclient.multi()
.srem(sessionSetKey, value) .srem(sessionSetKey, value)
@ -57,7 +54,7 @@ module.exports = UserSessionsManager =
getAllUserSessions: (user, exclude, callback=(err, sessionKeys)->) -> getAllUserSessions: (user, exclude, callback=(err, sessionKeys)->) ->
exclude = _.map(exclude, UserSessionsManager._sessionKey) exclude = _.map(exclude, UserSessionsManager._sessionKey)
sessionSetKey = UserSessionsManager._sessionSetKey(user) sessionSetKey = UserSessionsRedis.sessionSetKey(user)
rclient.smembers sessionSetKey, (err, sessionKeys) -> rclient.smembers sessionSetKey, (err, sessionKeys) ->
if err? if err?
logger.err user_id: user._id, "error getting all session keys for user from redis" logger.err user_id: user._id, "error getting all session keys for user from redis"
@ -66,7 +63,8 @@ module.exports = UserSessionsManager =
if sessionKeys.length == 0 if sessionKeys.length == 0
logger.log {user_id: user._id}, "no other sessions found, returning" logger.log {user_id: user._id}, "no other sessions found, returning"
return callback(null, []) return callback(null, [])
rclient.mget sessionKeys, (err, sessions) ->
Async.mapSeries sessionKeys, ((k, cb) -> rclient.get(k, cb)), (err, sessions) ->
if err? if err?
logger.err {user_id: user._id}, "error getting all sessions for user from redis" logger.err {user_id: user._id}, "error getting all sessions for user from redis"
return callback(err) return callback(err)
@ -92,7 +90,7 @@ module.exports = UserSessionsManager =
logger.log {}, "no user to revoke sessions for, returning" logger.log {}, "no user to revoke sessions for, returning"
return callback(null) return callback(null)
logger.log {user_id: user._id}, "revoking all existing sessions for user" logger.log {user_id: user._id}, "revoking all existing sessions for user"
sessionSetKey = UserSessionsManager._sessionSetKey(user) sessionSetKey = UserSessionsRedis.sessionSetKey(user)
rclient.smembers sessionSetKey, (err, sessionKeys) -> rclient.smembers sessionSetKey, (err, sessionKeys) ->
if err? if err?
logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set" logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set"
@ -102,12 +100,18 @@ module.exports = UserSessionsManager =
logger.log {user_id: user._id}, "no sessions in UserSessions set to delete, returning" logger.log {user_id: user._id}, "no sessions in UserSessions set to delete, returning"
return callback(null) return callback(null)
logger.log {user_id: user._id, count: keysToDelete.length}, "deleting sessions for user" logger.log {user_id: user._id, count: keysToDelete.length}, "deleting sessions for user"
rclient.multi()
.del(keysToDelete) deletions = keysToDelete.map (k) ->
.srem(sessionSetKey, keysToDelete) (cb) ->
.exec (err, result) -> rclient.del k, cb
Async.series deletions, (err, _result) ->
if err?
logger.err {err, user_id: user._id, sessionSetKey}, "errror revoking all sessions for user"
return callback(err)
rclient.srem sessionSetKey, keysToDelete, (err) ->
if err? if err?
logger.err {err, user_id: user._id, sessionSetKey}, "error revoking all sessions for user" logger.err {err, user_id: user._id, sessionSetKey}, "error removing session set for user"
return callback(err) return callback(err)
callback(null) callback(null)
@ -115,7 +119,7 @@ module.exports = UserSessionsManager =
if !user if !user
logger.log {}, "no user to touch sessions for, returning" logger.log {}, "no user to touch sessions for, returning"
return callback(null) return callback(null)
sessionSetKey = UserSessionsManager._sessionSetKey(user) sessionSetKey = UserSessionsRedis.sessionSetKey(user)
rclient.expire sessionSetKey, "#{Settings.cookieSessionLength}", (err, response) -> rclient.expire sessionSetKey, "#{Settings.cookieSessionLength}", (err, response) ->
if err? if err?
logger.err {err, user_id: user._id}, "error while updating ttl on UserSessions set" logger.err {err, user_id: user._id}, "error while updating ttl on UserSessions set"
@ -127,7 +131,7 @@ module.exports = UserSessionsManager =
logger.log {}, "no user, returning" logger.log {}, "no user, returning"
return callback(null) return callback(null)
logger.log {user_id: user._id}, "checking sessions for user" logger.log {user_id: user._id}, "checking sessions for user"
sessionSetKey = UserSessionsManager._sessionSetKey(user) sessionSetKey = UserSessionsRedis.sessionSetKey(user)
rclient.smembers sessionSetKey, (err, sessionKeys) -> rclient.smembers sessionSetKey, (err, sessionKeys) ->
if err? if err?
logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set" logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set"

View file

@ -0,0 +1,21 @@
Settings = require 'settings-sharelatex'
redis = require 'redis-sharelatex'
ioredis = require 'ioredis'
logger = require 'logger-sharelatex'
redisSessionsSettings = Settings.redis.websessions or Settings.redis.web
module.exports = Redis =
client: () ->
if redisSessionsSettings?.cluster?
logger.log {}, "using redis cluster for web sessions"
rclient = new ioredis.Cluster(redisSessionsSettings.cluster)
else
rclient = redis.createClient(redisSessionsSettings)
return rclient
sessionSetKey: (user) ->
if redisSessionsSettings?.cluster?
return "UserSessions:{#{user._id}}"
else
return "UserSessions:#{user._id}"

View file

@ -210,7 +210,7 @@ module.exports = (app, webRouter, apiRouter)->
webRouter.use (req, res, next)-> webRouter.use (req, res, next)->
res.locals.externalAuthenticationSystemUsed = -> res.locals.externalAuthenticationSystemUsed = ->
Settings.ldap? Settings.ldap? or Settings.saml?
next() next()
webRouter.use (req, res, next)-> webRouter.use (req, res, next)->

View file

@ -18,6 +18,10 @@ module.exports = Modules =
applyRouter: (webRouter, apiRouter) -> applyRouter: (webRouter, apiRouter) ->
for module in @modules for module in @modules
module.router?.apply(webRouter, apiRouter) module.router?.apply(webRouter, apiRouter)
applyNonCsrfRouter: (webRouter, apiRouter) ->
for module in @modules
module.nonCsrfRouter?.apply(webRouter, apiRouter)
viewIncludes: {} viewIncludes: {}
loadViewIncludes: (app) -> loadViewIncludes: (app) ->
@ -58,4 +62,4 @@ module.exports = Modules =
return callback(error) if error? return callback(error) if error?
return callback null, results return callback null, results
Modules.loadModules() Modules.loadModules()

View file

@ -1,5 +1,5 @@
version = { version = {
"pdfjs": "1.6.210p1" "pdfjs": "1.6.210p2"
"moment": "2.9.0" "moment": "2.9.0"
"ace": "1.2.5" "ace": "1.2.5"
} }

View file

@ -8,7 +8,9 @@ expressLocals = require('./ExpressLocals')
Router = require('../router') Router = require('../router')
metrics.inc("startup") metrics.inc("startup")
redis = require("redis-sharelatex") redis = require("redis-sharelatex")
rclient = redis.createClient(Settings.redis.web) UserSessionsRedis = require('../Features/User/UserSessionsRedis')
sessionsRedisClient = UserSessionsRedis.client()
session = require("express-session") session = require("express-session")
RedisStore = require('connect-redis')(session) RedisStore = require('connect-redis')(session)
@ -19,7 +21,8 @@ csrf = require('csurf')
csrfProtection = csrf() csrfProtection = csrf()
cookieParser = require('cookie-parser') cookieParser = require('cookie-parser')
sessionStore = new RedisStore(client:rclient) # Init the session store
sessionStore = new RedisStore(client:sessionsRedisClient)
passport = require('passport') passport = require('passport')
LocalStrategy = require('passport-local').Strategy LocalStrategy = require('passport-local').Strategy
@ -87,9 +90,6 @@ webRouter.use session
secure: Settings.secureCookie secure: Settings.secureCookie
store: sessionStore store: sessionStore
key: Settings.cookieName key: Settings.cookieName
webRouter.use csrfProtection
webRouter.use translations.expressMiddlewear
webRouter.use translations.setLangBasedOnDomainMiddlewear
# passport # passport
webRouter.use passport.initialize() webRouter.use passport.initialize()
@ -110,6 +110,12 @@ Modules.hooks.fire 'passportSetup', passport, (err) ->
if err? if err?
logger.err {err}, "error setting up passport in modules" logger.err {err}, "error setting up passport in modules"
Modules.applyNonCsrfRouter(webRouter, apiRouter)
webRouter.use csrfProtection
webRouter.use translations.expressMiddlewear
webRouter.use translations.setLangBasedOnDomainMiddlewear
# Measure expiry from last request, not last login # Measure expiry from last request, not last login
webRouter.use (req, res, next) -> webRouter.use (req, res, next) ->
req.session.touch() req.session.touch()

View file

@ -39,6 +39,7 @@ ReferencesController = require('./Features/References/ReferencesController')
AuthorizationMiddlewear = require('./Features/Authorization/AuthorizationMiddlewear') AuthorizationMiddlewear = require('./Features/Authorization/AuthorizationMiddlewear')
BetaProgramController = require('./Features/BetaProgram/BetaProgramController') BetaProgramController = require('./Features/BetaProgram/BetaProgramController')
AnalyticsRouter = require('./Features/Analytics/AnalyticsRouter') AnalyticsRouter = require('./Features/Analytics/AnalyticsRouter')
AnnouncementsController = require("./Features/Announcements/AnnouncementsController")
logger = require("logger-sharelatex") logger = require("logger-sharelatex")
_ = require("underscore") _ = require("underscore")
@ -187,6 +188,9 @@ module.exports = class Router
webRouter.get '/notifications', AuthenticationController.requireLogin(), NotificationsController.getAllUnreadNotifications webRouter.get '/notifications', AuthenticationController.requireLogin(), NotificationsController.getAllUnreadNotifications
webRouter.delete '/notifications/:notification_id', AuthenticationController.requireLogin(), NotificationsController.markNotificationAsRead webRouter.delete '/notifications/:notification_id', AuthenticationController.requireLogin(), NotificationsController.markNotificationAsRead
webRouter.get '/announcements', AuthenticationController.requireLogin(), AnnouncementsController.getUndreadAnnouncements
# Deprecated in favour of /internal/project/:project_id but still used by versioning # Deprecated in favour of /internal/project/:project_id but still used by versioning
apiRouter.get '/project/:project_id/details', AuthenticationController.httpAuth, ProjectApiController.getProjectDetails apiRouter.get '/project/:project_id/details', AuthenticationController.httpAuth, ProjectApiController.getProjectDetails

View file

@ -3,7 +3,8 @@ html(itemscope, itemtype='http://schema.org/Product')
head head
title Something went wrong title Something went wrong
link(rel="icon", href="/favicon.ico") link(rel="icon", href="/favicon.ico")
link(rel='stylesheet', href=buildCssPath('/style.css')) if buildCssPath
link(rel='stylesheet', href=buildCssPath('/style.css'))
link(href="//netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css",rel="stylesheet") link(href="//netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css",rel="stylesheet")
body body
.content .content
@ -12,7 +13,9 @@ html(itemscope, itemtype='http://schema.org/Product')
.col-md-8.col-md-offset-2.text-center .col-md-8.col-md-offset-2.text-center
.page-header .page-header
h2 Oh dear, something went wrong. h2 Oh dear, something went wrong.
p: img(src=buildImgPath("lion-sad-128.png"), alt="Sad Lion") if buildImgPath
p
img(src=buildImgPath("lion-sad-128.png"), alt="Sad Lion")
p p
| Something went wrong with your request, sorry. Our staff are probably looking into this, but if it continues, please contact us at #{settings.adminEmail} | Something went wrong with your request, sorry. Our staff are probably looking into this, but if it continues, please contact us at #{settings.adminEmail}
p p

View file

@ -1,388 +1,125 @@
div(ng-if="!shouldABTestHeaderLabels") header.toolbar.toolbar-header.toolbar-with-labels(
header.toolbar.toolbar-header( ng-cloak,
ng-cloak, ng-hide="state.loading"
ng-hide="state.loading" )
) .toolbar-left
a.btn.btn-full-height( a.btn.btn-full-height(
href, href,
ng-click="ui.leftMenuShown = true" ng-click="ui.leftMenuShown = true;",
tooltip='#{translate("menu")}',
tooltip-placement="bottom",
tooltip-append-to-body="true",
) )
i.fa.fa-fw.fa-bars i.fa.fa-fw.fa-bars
p.toolbar-label #{translate("menu")}
a( a(
href="/project" href="/project"
tooltip="#{translate('back_to_projects')}",
tooltip-placement="bottom",
tooltip-append-to-body="true"
) )
i.fa.fa-fw.fa-level-up i.fa.fa-fw.fa-level-up
span(ng-controller="PdfViewToggleController")
a(
href,
ng-show="ui.pdfLayout == 'flat' && fileTreeClosed",
tooltip="PDF",
tooltip-placement="bottom",
tooltip-append-to-body="true",
ng-click="togglePdfView()",
ng-class="{ 'active': ui.view == 'pdf' }"
)
i.fa.fa-file-pdf-o
.toolbar-center.project-name(ng-controller="ProjectNameController") span(ng-controller="PdfViewToggleController")
span.name( a(
ng-dblclick="!permissions.admin || startRenaming()", href,
ng-show="!state.renaming" ng-show="ui.pdfLayout == 'flat' && fileTreeClosed",
) {{ project.name }} tooltip="PDF",
tooltip-placement="bottom",
input.form-control( tooltip-append-to-body="true",
type="text" ng-click="togglePdfView()",
ng-model="inputs.name", ng-class="{ 'active': ui.view == 'pdf' }"
ng-show="state.renaming",
on-enter="finishRenaming()",
ng-blur="finishRenaming()",
select-name-when="state.renaming"
)
a.rename(
ng-if="permissions.admin",
href='#',
tooltip-placement="bottom",
tooltip="#{translate('rename')}",
tooltip-append-to-body="true",
ng-click="startRenaming()",
ng-show="!state.renaming"
)
i.fa.fa-pencil
.toolbar-right
span.online-users(
ng-show="onlineUsersArray.length > 0"
ng-controller="OnlineUsersController"
)
span(ng-if="onlineUsersArray.length < 4")
span.online-user(
ng-repeat="user in onlineUsersArray",
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }",
popover="{{ user.name }}"
popover-placement="bottom"
popover-append-to-body="true"
popover-trigger="mouseenter"
ng-click="gotoUser(user)"
) {{ user.name.slice(0,1) }}
span.dropdown(dropdown, ng-if="onlineUsersArray.length >= 4")
span.online-user.online-user-multi(
dropdown-toggle,
tooltip="#{translate('connected_users')}",
tooltip-placement="left"
)
strong {{ onlineUsersArray.length }}
i.fa.fa-fw.fa-user
ul.dropdown-menu.pull-right
li.dropdown-header #{translate('connected_users')}
li(ng-repeat="user in onlineUsersArray")
a(href, ng-click="gotoUser(user)")
span.online-user(
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }"
) {{ user.name.slice(0,1) }}
| {{ user.name }}
a.btn.btn-full-height(
href,
ng-if="trackChangesFeatureFlag",
ng-class="{ active: ui.reviewPanelOpen }"
tooltip="#{translate('review')}",
tooltip-placement="bottom",
ng-click="toggleReviewPanel()"
)
| Review
a.btn.btn-full-height(
href,
ng-if="permissions.admin",
tooltip="#{translate('share')}",
tooltip-placement="bottom",
ng-click="openShareProjectModal()",
ng-controller="ShareController",
)
i.fa.fa-fw.fa-group
a.btn.btn-full-height(
href,
ng-click="toggleHistory()",
ng-class="{ active: (ui.view == 'history') }"
tooltip="#{translate('recent_changes')}",
tooltip-placement="bottom",
)
i.fa.fa-fw.fa-history
a.btn.btn-full-height(
href,
tooltip="#{translate('chat')}",
tooltip-placement="bottom",
ng-class="{ active: ui.chatOpen }",
ng-click="toggleChat()",
ng-controller="ChatButtonController",
ng-show="!anonymous",
)
i.fa.fa-fw.fa-comment(
ng-class="{ 'bounce': unreadMessages > 0 }"
)
span.label.label-info(
ng-show="unreadMessages > 0"
) {{ unreadMessages }}
div(ng-if="shouldABTestHeaderLabels")
div(sixpack-switch="editor-header")
header.toolbar.toolbar-header(
ng-cloak,
ng-hide="state.loading"
sixpack-default
) )
a.btn.btn-full-height( i.fa.fa-file-pdf-o
href,
ng-click="ui.leftMenuShown = true; trackABTestConversion('menu');"
tooltip='#{translate("menu")}',
tooltip-placement="bottom",
tooltip-append-to-body="true",
sixpack-convert="editor-header"
)
i.fa.fa-fw.fa-bars
a(
href="/project"
tooltip="#{translate('back_to_projects')}",
tooltip-placement="bottom",
tooltip-append-to-body="true"
)
i.fa.fa-fw.fa-level-up
span(ng-controller="PdfViewToggleController")
a(
href,
ng-show="ui.pdfLayout == 'flat' && fileTreeClosed",
tooltip="PDF",
tooltip-placement="bottom",
tooltip-append-to-body="true",
ng-click="togglePdfView()",
ng-class="{ 'active': ui.view == 'pdf' }"
)
i.fa.fa-file-pdf-o
.toolbar-center.project-name(ng-controller="ProjectNameController") .toolbar-center.project-name(ng-controller="ProjectNameController")
span.name( span.name(
ng-dblclick="!permissions.admin || startRenaming()", ng-dblclick="!permissions.admin || startRenaming()",
ng-show="!state.renaming" ng-show="!state.renaming"
) {{ project.name }} ) {{ project.name }}
input.form-control( input.form-control(
type="text" type="text"
ng-model="inputs.name", ng-model="inputs.name",
ng-show="state.renaming", ng-show="state.renaming",
on-enter="finishRenaming()", on-enter="finishRenaming()",
ng-blur="finishRenaming()", ng-blur="finishRenaming()",
select-name-when="state.renaming" select-name-when="state.renaming"
)
a.rename(
ng-if="permissions.admin",
href='#',
tooltip-placement="bottom",
tooltip="#{translate('rename')}",
tooltip-append-to-body="true",
ng-click="startRenaming()",
ng-show="!state.renaming"
)
i.fa.fa-pencil
.toolbar-right
span.online-users(
ng-show="onlineUsersArray.length > 0"
ng-controller="OnlineUsersController"
)
span(ng-if="onlineUsersArray.length < 4")
span.online-user(
ng-repeat="user in onlineUsersArray",
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }",
popover="{{ user.name }}"
popover-placement="bottom"
popover-append-to-body="true"
popover-trigger="mouseenter"
ng-click="gotoUser(user)"
) {{ user.name.slice(0,1) }}
span.dropdown(dropdown, ng-if="onlineUsersArray.length >= 4")
span.online-user.online-user-multi(
dropdown-toggle,
tooltip="#{translate('connected_users')}",
tooltip-placement="left"
)
strong {{ onlineUsersArray.length }}
i.fa.fa-fw.fa-user
ul.dropdown-menu.pull-right
li.dropdown-header #{translate('connected_users')}
li(ng-repeat="user in onlineUsersArray")
a(href, ng-click="gotoUser(user)")
span.online-user(
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }"
) {{ user.name.slice(0,1) }}
| {{ user.name }}
a.btn.btn-full-height(
href,
ng-if="permissions.admin",
tooltip="#{translate('share')}",
tooltip-placement="bottom",
ng-click="openShareProjectModal(); trackABTestConversion('share');",
ng-controller="ShareController",
sixpack-convert="editor-header"
)
i.fa.fa-fw.fa-group
a.btn.btn-full-height(
href,
ng-click="toggleHistory(); trackABTestConversion('history');",
ng-class="{ active: (ui.view == 'history') }"
tooltip="#{translate('recent_changes')}",
tooltip-placement="bottom",
sixpack-convert="editor-header"
)
i.fa.fa-fw.fa-history
a.btn.btn-full-height(
href,
tooltip="#{translate('chat')}",
tooltip-placement="bottom",
ng-class="{ active: ui.chatOpen }",
ng-click="toggleChat(); trackABTestConversion('chat');",
ng-controller="ChatButtonController",
ng-show="!anonymous",
sixpack-convert="editor-header"
)
i.fa.fa-fw.fa-comment(
ng-class="{ 'bounce': unreadMessages > 0 }"
)
span.label.label-info(
ng-show="unreadMessages > 0"
) {{ unreadMessages }}
header.toolbar.toolbar-header.toolbar-with-labels(
ng-cloak,
ng-hide="state.loading"
sixpack-when="labels"
) )
.toolbar-left
a.btn.btn-full-height(
href,
ng-click="ui.leftMenuShown = true; trackABTestConversion('menu');",
sixpack-convert="editor-header"
)
i.fa.fa-fw.fa-bars
p.toolbar-label #{translate("menu")}
a(
href="/project"
)
i.fa.fa-fw.fa-level-up
span(ng-controller="PdfViewToggleController") a.rename(
a( ng-if="permissions.admin",
href, href='#',
ng-show="ui.pdfLayout == 'flat' && fileTreeClosed", tooltip-placement="bottom",
tooltip="PDF", tooltip="#{translate('rename')}",
tooltip-placement="bottom", tooltip-append-to-body="true",
tooltip-append-to-body="true", ng-click="startRenaming()",
ng-click="togglePdfView()", ng-show="!state.renaming"
ng-class="{ 'active': ui.view == 'pdf' }" )
) i.fa.fa-pencil
i.fa.fa-file-pdf-o
.toolbar-center.project-name(ng-controller="ProjectNameController")
span.name(
ng-dblclick="!permissions.admin || startRenaming()",
ng-show="!state.renaming"
) {{ project.name }}
input.form-control(
type="text"
ng-model="inputs.name",
ng-show="state.renaming",
on-enter="finishRenaming()",
ng-blur="finishRenaming()",
select-name-when="state.renaming"
)
a.rename(
ng-if="permissions.admin",
href='#',
tooltip-placement="bottom",
tooltip="#{translate('rename')}",
tooltip-append-to-body="true",
ng-click="startRenaming()",
ng-show="!state.renaming"
)
i.fa.fa-pencil
.toolbar-right
span.online-users(
ng-show="onlineUsersArray.length > 0"
ng-controller="OnlineUsersController"
)
span(ng-if="onlineUsersArray.length < 4")
span.online-user(
ng-repeat="user in onlineUsersArray",
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }",
popover="{{ user.name }}"
popover-placement="bottom"
popover-append-to-body="true"
popover-trigger="mouseenter"
ng-click="gotoUser(user)"
) {{ user.name.slice(0,1) }}
span.dropdown(dropdown, ng-if="onlineUsersArray.length >= 4")
span.online-user.online-user-multi(
dropdown-toggle,
tooltip="#{translate('connected_users')}",
tooltip-placement="left"
)
strong {{ onlineUsersArray.length }}
i.fa.fa-fw.fa-user
ul.dropdown-menu.pull-right
li.dropdown-header #{translate('connected_users')}
li(ng-repeat="user in onlineUsersArray")
a(href, ng-click="gotoUser(user)")
span.online-user(
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }"
) {{ user.name.slice(0,1) }}
| {{ user.name }}
.toolbar-right
span.online-users(
ng-show="onlineUsersArray.length > 0"
ng-controller="OnlineUsersController"
)
span(ng-if="onlineUsersArray.length < 4")
span.online-user(
ng-repeat="user in onlineUsersArray",
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }",
popover="{{ user.name }}"
popover-placement="bottom"
popover-append-to-body="true"
popover-trigger="mouseenter"
ng-click="gotoUser(user)"
) {{ user.name.slice(0,1) }}
a.btn.btn-full-height( span.dropdown(dropdown, ng-if="onlineUsersArray.length >= 4")
href, span.online-user.online-user-multi(
ng-if="permissions.admin", dropdown-toggle,
ng-click="openShareProjectModal(); trackABTestConversion('share');", tooltip="#{translate('connected_users')}",
ng-controller="ShareController", tooltip-placement="left"
sixpack-convert="editor-header"
) )
i.fa.fa-fw.fa-group strong {{ onlineUsersArray.length }}
p.toolbar-label #{translate("share")} i.fa.fa-fw.fa-user
a.btn.btn-full-height( ul.dropdown-menu.pull-right
href, li.dropdown-header #{translate('connected_users')}
ng-click="toggleHistory(); trackABTestConversion('history');", li(ng-repeat="user in onlineUsersArray")
ng-class="{ active: (ui.view == 'history') }", a(href, ng-click="gotoUser(user)")
sixpack-convert="editor-header" span.online-user(
) ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 70%, 50%)' }"
i.fa.fa-fw.fa-history ) {{ user.name.slice(0,1) }}
p.toolbar-label #{translate("history")} | {{ user.name }}
a.btn.btn-full-height(
href, a.btn.btn-full-height(
ng-class="{ active: ui.chatOpen }", href,
ng-click="toggleChat(); trackABTestConversion('chat');", ng-if="trackChangesFeatureFlag",
ng-controller="ChatButtonController", ng-class="{ active: ui.reviewPanelOpen }"
ng-show="!anonymous", tooltip="#{translate('review')}",
sixpack-convert="editor-header" tooltip-placement="bottom",
) ng-click="toggleReviewPanel()"
i.fa.fa-fw.fa-comment( )
ng-class="{ 'bounce': unreadMessages > 0 }" | Review
) a.btn.btn-full-height(
span.label.label-info( href,
ng-show="unreadMessages > 0" ng-if="permissions.admin",
) {{ unreadMessages }} ng-click="openShareProjectModal();",
p.toolbar-label #{translate("chat")} ng-controller="ShareController",
)
i.fa.fa-fw.fa-group
p.toolbar-label #{translate("share")}
a.btn.btn-full-height(
href,
ng-click="toggleHistory();",
ng-class="{ active: (ui.view == 'history') }",
)
i.fa.fa-fw.fa-history
p.toolbar-label #{translate("history")}
a.btn.btn-full-height(
href,
ng-class="{ active: ui.chatOpen }",
ng-click="toggleChat();",
ng-controller="ChatButtonController",
ng-show="!anonymous",
)
i.fa.fa-fw.fa-comment(
ng-class="{ 'bounce': unreadMessages > 0 }"
)
span.label.label-info(
ng-show="unreadMessages > 0"
) {{ unreadMessages }}
p.toolbar-label #{translate("chat")}

View file

@ -21,7 +21,11 @@ block content
.content.content-alt(ng-controller="ProjectPageController") .content.content-alt(ng-controller="ProjectPageController")
.container .container
//- div(ng-controller="AnnouncementsController", ng-cloak)
//- .alert.alert-success(ng-show="dataRecived")
//- a(href, ng-click="openLink()") {{title}} and {{totalAnnouncements}} others
.row(ng-cloak) .row(ng-cloak)
span(ng-if="projects.length > 0") span(ng-if="projects.length > 0")
aside.col-md-2.col-xs-3 aside.col-md-2.col-xs-3

View file

@ -33,6 +33,12 @@ block content
) )
span.small.text-primary(ng-show="settingsForm.email.$invalid && settingsForm.email.$dirty") span.small.text-primary(ng-show="settingsForm.email.$invalid && settingsForm.email.$dirty")
| #{translate("must_be_email_address")} | #{translate("must_be_email_address")}
else
// show the email, non-editable
.form-group
label.control-label #{translate("email")}
div.form-control(readonly="true") #{user.email}
.form-group .form-group
label(for='firstName').control-label #{translate("first_name")} label(for='firstName').control-label #{translate("first_name")}
input.form-control( input.form-control(

View file

@ -38,6 +38,16 @@ module.exports = settings =
port: "6379" port: "6379"
password: "" password: ""
# websessions:
# cluster: [
# {host: 'localhost', port: 7000}
# {host: 'localhost', port: 7001}
# {host: 'localhost', port: 7002}
# {host: 'localhost', port: 7003}
# {host: 'localhost', port: 7004}
# {host: 'localhost', port: 7005}
# ]
api: api:
host: "localhost" host: "localhost"
port: "6379" port: "6379"
@ -107,8 +117,8 @@ module.exports = settings =
# references: # references:
# url: "http://localhost:3040" # url: "http://localhost:3040"
notifications: notifications:
url: "http://localhost:3042" url: "http://localhost:3042"
templates: templates:
user_id: process.env.TEMPLATES_USER_ID or "5395eb7aad1f29a88756c7f2" user_id: process.env.TEMPLATES_USER_ID or "5395eb7aad1f29a88756c7f2"
showSocialButtons: false showSocialButtons: false
@ -131,13 +141,13 @@ module.exports = settings =
# this is only used if cookies are used for clsi backend # this is only used if cookies are used for clsi backend
#clsiCookieKey: "clsiserver" #clsiCookieKey: "clsiserver"
# Same, but with http auth credentials. # Same, but with http auth credentials.
httpAuthSiteUrl: 'http://#{httpAuthUser}:#{httpAuthPass}@localhost:3000' httpAuthSiteUrl: 'http://#{httpAuthUser}:#{httpAuthPass}@localhost:3000'
maxEntitiesPerProject: 2000 maxEntitiesPerProject: 2000
# Security # Security
# -------- # --------
security: security:
@ -166,12 +176,12 @@ module.exports = settings =
price: 0 price: 0
features: defaultFeatures features: defaultFeatures
}] }]
enableSubscriptions:false enableSubscriptions:false
# i18n # i18n
# ------ # ------
# #
i18n: i18n:
subdomainLang: subdomainLang:
www: {lngCode:"en", url: siteUrl} www: {lngCode:"en", url: siteUrl}
@ -180,7 +190,7 @@ module.exports = settings =
# Spelling languages # Spelling languages
# ------------------ # ------------------
# #
# You must have the corresponding aspell package installed to # You must have the corresponding aspell package installed to
# be able to use a language. # be able to use a language.
languages: [ languages: [
{name: "English", code: "en"}, {name: "English", code: "en"},
@ -228,7 +238,7 @@ module.exports = settings =
# analytics: # analytics:
# ga: # ga:
# token: "" # token: ""
# #
# ShareLaTeX's help desk is provided by tenderapp.com # ShareLaTeX's help desk is provided by tenderapp.com
# tenderUrl: "" # tenderUrl: ""
# #
@ -262,10 +272,10 @@ module.exports = settings =
# then set this to true to allow it to correctly detect the forwarded IP # then set this to true to allow it to correctly detect the forwarded IP
# address and http/https protocol information. # address and http/https protocol information.
behindProxy: false behindProxy: false
# Cookie max age (in milliseconds). Set to false for a browser session. # Cookie max age (in milliseconds). Set to false for a browser session.
cookieSessionLength: 5 * 24 * 60 * 60 * 1000 # 5 days cookieSessionLength: 5 * 24 * 60 * 60 * 1000 # 5 days
# Should we allow access to any page without logging in? This includes # Should we allow access to any page without logging in? This includes
# public projects, /learn, /templates, about pages, etc. # public projects, /learn, /templates, about pages, etc.
allowPublicAccess: if process.env["SHARELATEX_ALLOW_PUBLIC_ACCESS"] == 'true' then true else false allowPublicAccess: if process.env["SHARELATEX_ALLOW_PUBLIC_ACCESS"] == 'true' then true else false
@ -273,10 +283,10 @@ module.exports = settings =
# Use a single compile directory for all users in a project # Use a single compile directory for all users in a project
# (otherwise each user has their own directory) # (otherwise each user has their own directory)
# disablePerUserCompiles: true # disablePerUserCompiles: true
# Maximum size of text documents in the real-time editing system. # Maximum size of text documents in the real-time editing system.
max_doc_length: 2 * 1024 * 1024 # 2mb max_doc_length: 2 * 1024 * 1024 # 2mb
# Internal configs # Internal configs
# ---------------- # ----------------
path: path:
@ -285,11 +295,11 @@ module.exports = settings =
# them to disk here). # them to disk here).
dumpFolder: Path.resolve __dirname + "/../data/dumpFolder" dumpFolder: Path.resolve __dirname + "/../data/dumpFolder"
uploadFolder: Path.resolve __dirname + "/../data/uploads" uploadFolder: Path.resolve __dirname + "/../data/uploads"
# Automatic Snapshots # Automatic Snapshots
# ------------------- # -------------------
automaticSnapshots: automaticSnapshots:
# How long should we wait after the user last edited to # How long should we wait after the user last edited to
# take a snapshot? # take a snapshot?
waitTimeAfterLastEdit: 5 * minutes waitTimeAfterLastEdit: 5 * minutes
# Even if edits are still taking place, this is maximum # Even if edits are still taking place, this is maximum
@ -305,13 +315,13 @@ module.exports = settings =
# user: "" # user: ""
# password: "" # password: ""
# projectId: "" # projectId: ""
appName: "ShareLaTeX (Community Edition)" appName: "ShareLaTeX (Community Edition)"
adminEmail: "placeholder@example.com" adminEmail: "placeholder@example.com"
nav: nav:
title: "ShareLaTeX Community Edition" title: "ShareLaTeX Community Edition"
left_footer: [{ left_footer: [{
text: "Powered by <a href='https://www.sharelatex.com'>ShareLaTeX</a> © 2016" text: "Powered by <a href='https://www.sharelatex.com'>ShareLaTeX</a> © 2016"
}] }]
@ -377,11 +387,11 @@ module.exports = settings =
"/templates/index": "/templates/" "/templates/index": "/templates/"
proxyUrls: {} proxyUrls: {}
reloadModuleViewsOnEachRequest: true reloadModuleViewsOnEachRequest: true
domainLicences: [ domainLicences: [
] ]
sixpack: sixpack:
@ -390,12 +400,12 @@ module.exports = settings =
# ---------- # ----------
# LDAP # LDAP
# ---------- # ----------
# Settings below use a working LDAP test server kindly provided by forumsys.com # Settings below use a working LDAP test server kindly provided by forumsys.com
# When testing with forumsys.com use username = einstein and password = password # When testing with forumsys.com use username = einstein and password = password
# ldap : # ldap :
# host: 'ldap://ldap.forumsys.com' # host: 'ldap://ldap.forumsys.com'
# dn: 'uid=:userKey,dc=example,dc=com' # dn: 'uid=:userKey,dc=example,dc=com'
@ -406,13 +416,13 @@ module.exports = settings =
# placeholder: 'email@example.com' # placeholder: 'email@example.com'
# emailAtt: 'mail' # emailAtt: 'mail'
# anonymous: false # anonymous: false
# adminDN: 'cn=read-only-admin,dc=example,dc=com' # adminDN: 'cn=read-only-admin,dc=example,dc=com'
# adminPW: 'password' # adminPW: 'password'
# starttls: true # starttls: true
# tlsOptions: # tlsOptions:
# rejectUnauthorized: false # rejectUnauthorized: false
# ca: ['/etc/ldap/ca_certs.pem'] # ca: ['/etc/ldap/ca_certs.pem']
#templateLinks: [{ #templateLinks: [{
# name : "CV projects", # name : "CV projects",
# url : "/templates/cv" # url : "/templates/cv"
@ -420,5 +430,3 @@ module.exports = settings =
# name : "all projects", # name : "all projects",
# url: "/templates/all" # url: "/templates/all"
#}] #}]

View file

@ -274,12 +274,12 @@
"dependencies": { "dependencies": {
"bytes": { "bytes": {
"version": "2.4.0", "version": "2.4.0",
"from": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", "from": "bytes@2.4.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz" "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz"
}, },
"content-type": { "content-type": {
"version": "1.0.2", "version": "1.0.2",
"from": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", "from": "content-type@~1.0.1",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz" "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz"
}, },
"debug": { "debug": {
@ -328,7 +328,7 @@
}, },
"on-finished": { "on-finished": {
"version": "2.3.0", "version": "2.3.0",
"from": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "from": "on-finished@~2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"dependencies": { "dependencies": {
"ee-first": { "ee-first": {
@ -345,7 +345,7 @@
}, },
"raw-body": { "raw-body": {
"version": "2.1.7", "version": "2.1.7",
"from": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", "from": "raw-body@~2.1.5",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz",
"dependencies": { "dependencies": {
"unpipe": { "unpipe": {
@ -357,7 +357,7 @@
}, },
"type-is": { "type-is": {
"version": "1.6.13", "version": "1.6.13",
"from": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz", "from": "type-is@~1.6.10",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz",
"dependencies": { "dependencies": {
"media-typer": { "media-typer": {
@ -387,26 +387,42 @@
"resolved": "https://registry.npmjs.org/bufferedstream/-/bufferedstream-1.6.0.tgz" "resolved": "https://registry.npmjs.org/bufferedstream/-/bufferedstream-1.6.0.tgz"
}, },
"connect-redis": { "connect-redis": {
"version": "2.3.0", "version": "3.1.0",
"from": "https://registry.npmjs.org/connect-redis/-/connect-redis-2.3.0.tgz", "from": "connect-redis@3.1.0",
"resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-2.3.0.tgz", "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-3.1.0.tgz",
"dependencies": { "dependencies": {
"debug": { "debug": {
"version": "1.0.4", "version": "2.3.0",
"from": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz", "from": "https://registry.npmjs.org/debug/-/debug-2.3.0.tgz",
"resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.0.tgz",
"dependencies": { "dependencies": {
"ms": { "ms": {
"version": "0.6.2", "version": "0.7.2",
"from": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz", "from": "ms@0.7.2"
"resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
} }
} }
}, },
"redis": { "redis": {
"version": "0.12.1", "version": "2.6.3",
"from": "https://registry.npmjs.org/redis/-/redis-0.12.1.tgz", "from": "https://registry.npmjs.org/redis/-/redis-2.6.3.tgz",
"resolved": "https://registry.npmjs.org/redis/-/redis-0.12.1.tgz" "resolved": "https://registry.npmjs.org/redis/-/redis-2.6.3.tgz",
"dependencies": {
"double-ended-queue": {
"version": "2.1.0-0",
"from": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
"resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz"
},
"redis-commands": {
"version": "1.3.0",
"from": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.0.tgz",
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.0.tgz"
},
"redis-parser": {
"version": "2.1.1",
"from": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.1.1.tgz",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.1.1.tgz"
}
}
} }
} }
}, },
@ -470,7 +486,7 @@
}, },
"json-stringify-safe": { "json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",
"from": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "from": "json-stringify-safe@~5.0.0",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
} }
} }
@ -504,7 +520,7 @@
"dependencies": { "dependencies": {
"cookie": { "cookie": {
"version": "0.3.1", "version": "0.3.1",
"from": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "from": "cookie@0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz" "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz"
}, },
"cookie-signature": { "cookie-signature": {
@ -616,7 +632,7 @@
}, },
"content-type": { "content-type": {
"version": "1.0.2", "version": "1.0.2",
"from": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", "from": "content-type@~1.0.1",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz" "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz"
}, },
"cookie": { "cookie": {
@ -631,7 +647,7 @@
}, },
"debug": { "debug": {
"version": "2.2.0", "version": "2.2.0",
"from": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "from": "debug@~2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"dependencies": { "dependencies": {
"ms": { "ms": {
@ -685,7 +701,7 @@
}, },
"on-finished": { "on-finished": {
"version": "2.3.0", "version": "2.3.0",
"from": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "from": "on-finished@~2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"dependencies": { "dependencies": {
"ee-first": { "ee-first": {
@ -829,7 +845,7 @@
}, },
"type-is": { "type-is": {
"version": "1.6.13", "version": "1.6.13",
"from": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz", "from": "type-is@~1.6.10",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz",
"dependencies": { "dependencies": {
"media-typer": { "media-typer": {
@ -864,68 +880,66 @@
} }
}, },
"express-session": { "express-session": {
"version": "1.11.3", "version": "1.14.2",
"from": "https://registry.npmjs.org/express-session/-/express-session-1.11.3.tgz", "from": "express-session@1.14.2",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.11.3.tgz", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.14.2.tgz",
"dependencies": { "dependencies": {
"cookie": { "cookie": {
"version": "0.1.3", "version": "0.3.1",
"from": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", "from": "cookie@0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz" "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz"
}, },
"cookie-signature": { "cookie-signature": {
"version": "1.0.6", "version": "1.0.6",
"from": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "from": "cookie-signature@1.0.6"
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
}, },
"crc": { "crc": {
"version": "3.3.0", "version": "3.4.1",
"from": "https://registry.npmjs.org/crc/-/crc-3.3.0.tgz", "from": "crc@3.4.1",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.3.0.tgz" "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.1.tgz"
}, },
"debug": { "debug": {
"version": "2.2.0", "version": "2.2.0",
"from": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "from": "debug@2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"dependencies": { "dependencies": {
"ms": { "ms": {
"version": "0.7.1", "version": "0.7.1",
"from": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "from": "ms@0.7.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
} }
} }
}, },
"depd": { "depd": {
"version": "1.0.1", "version": "1.1.0",
"from": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", "from": "depd@1.1.0"
"resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz"
}, },
"on-headers": { "on-headers": {
"version": "1.0.1", "version": "1.0.1",
"from": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", "from": "on-headers@1.0.1"
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz"
}, },
"parseurl": { "parseurl": {
"version": "1.3.1", "version": "1.3.1",
"from": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", "from": "parseurl@1.3.1"
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz"
}, },
"uid-safe": { "uid-safe": {
"version": "2.0.0", "version": "2.1.3",
"from": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz", "from": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.3.tgz",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.3.tgz",
"dependencies": { "dependencies": {
"base64-url": { "base64-url": {
"version": "1.2.1", "version": "1.3.3",
"from": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz", "from": "base64-url@1.3.3"
"resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz" },
"random-bytes": {
"version": "1.0.0",
"from": "random-bytes@1.0.0"
} }
} }
}, },
"utils-merge": { "utils-merge": {
"version": "1.0.0", "version": "1.0.0",
"from": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", "from": "utils-merge@1.0.0"
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz"
} }
} }
}, },
@ -1166,6 +1180,53 @@
} }
} }
}, },
"ioredis": {
"version": "2.4.0",
"from": "https://registry.npmjs.org/ioredis/-/ioredis-2.4.0.tgz",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-2.4.0.tgz",
"dependencies": {
"bluebird": {
"version": "3.4.6",
"from": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz"
},
"cluster-key-slot": {
"version": "1.0.8",
"from": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.0.8.tgz",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.0.8.tgz"
},
"debug": {
"version": "2.3.0",
"from": "https://registry.npmjs.org/debug/-/debug-2.3.0.tgz",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.0.tgz",
"dependencies": {
"ms": {
"version": "0.7.2",
"from": "ms@0.7.2"
}
}
},
"double-ended-queue": {
"version": "2.1.0-0",
"from": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
"resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz"
},
"flexbuffer": {
"version": "0.0.6",
"from": "flexbuffer@0.0.6"
},
"redis-commands": {
"version": "1.3.0",
"from": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.0.tgz",
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.0.tgz"
},
"redis-parser": {
"version": "1.3.0",
"from": "https://registry.npmjs.org/redis-parser/-/redis-parser-1.3.0.tgz",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-1.3.0.tgz"
}
}
},
"jade": { "jade": {
"version": "1.3.1", "version": "1.3.1",
"from": "https://registry.npmjs.org/jade/-/jade-1.3.1.tgz", "from": "https://registry.npmjs.org/jade/-/jade-1.3.1.tgz",
@ -1602,7 +1663,7 @@
}, },
"logger-sharelatex": { "logger-sharelatex": {
"version": "1.3.1", "version": "1.3.1",
"from": "git+https://github.com/sharelatex/logger-sharelatex.git#bf413ec621a000cf0e08c939de38d5e24541a08c", "from": "logger-sharelatex@git+https://github.com/sharelatex/logger-sharelatex.git#bf413ec621a000cf0e08c939de38d5e24541a08c",
"resolved": "git+https://github.com/sharelatex/logger-sharelatex.git#bf413ec621a000cf0e08c939de38d5e24541a08c", "resolved": "git+https://github.com/sharelatex/logger-sharelatex.git#bf413ec621a000cf0e08c939de38d5e24541a08c",
"dependencies": { "dependencies": {
"bunyan": { "bunyan": {
@ -1783,7 +1844,7 @@
"dependencies": { "dependencies": {
"debug": { "debug": {
"version": "2.2.0", "version": "2.2.0",
"from": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "from": "debug@2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"dependencies": { "dependencies": {
"ms": { "ms": {
@ -1812,7 +1873,7 @@
}, },
"metrics-sharelatex": { "metrics-sharelatex": {
"version": "1.3.0", "version": "1.3.0",
"from": "git+https://github.com/sharelatex/metrics-sharelatex.git#080c4aeb696edcd5d6d86f202f2c528f0661d7a6", "from": "metrics-sharelatex@git+https://github.com/sharelatex/metrics-sharelatex.git#080c4aeb696edcd5d6d86f202f2c528f0661d7a6",
"resolved": "git+https://github.com/sharelatex/metrics-sharelatex.git#080c4aeb696edcd5d6d86f202f2c528f0661d7a6", "resolved": "git+https://github.com/sharelatex/metrics-sharelatex.git#080c4aeb696edcd5d6d86f202f2c528f0661d7a6",
"dependencies": { "dependencies": {
"coffee-script": { "coffee-script": {
@ -2535,32 +2596,32 @@
}, },
"passport-ldapauth": { "passport-ldapauth": {
"version": "0.6.0", "version": "0.6.0",
"from": "passport-ldapauth@*", "from": "https://registry.npmjs.org/passport-ldapauth/-/passport-ldapauth-0.6.0.tgz",
"resolved": "https://registry.npmjs.org/passport-ldapauth/-/passport-ldapauth-0.6.0.tgz", "resolved": "https://registry.npmjs.org/passport-ldapauth/-/passport-ldapauth-0.6.0.tgz",
"dependencies": { "dependencies": {
"passport-strategy": { "passport-strategy": {
"version": "1.0.0", "version": "1.0.0",
"from": "passport-strategy@>=1.0.0 <2.0.0", "from": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz" "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz"
}, },
"ldapauth-fork": { "ldapauth-fork": {
"version": "2.5.3", "version": "2.5.3",
"from": "ldapauth-fork@>=2.5.0 <2.6.0", "from": "https://registry.npmjs.org/ldapauth-fork/-/ldapauth-fork-2.5.3.tgz",
"resolved": "https://registry.npmjs.org/ldapauth-fork/-/ldapauth-fork-2.5.3.tgz", "resolved": "https://registry.npmjs.org/ldapauth-fork/-/ldapauth-fork-2.5.3.tgz",
"dependencies": { "dependencies": {
"bcryptjs": { "bcryptjs": {
"version": "2.3.0", "version": "2.3.0",
"from": "bcryptjs@2.3.0", "from": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.3.0.tgz",
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.3.0.tgz" "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.3.0.tgz"
}, },
"lru-cache": { "lru-cache": {
"version": "3.2.0", "version": "3.2.0",
"from": "lru-cache@3.2.0", "from": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz",
"dependencies": { "dependencies": {
"pseudomap": { "pseudomap": {
"version": "1.0.2", "version": "1.0.2",
"from": "pseudomap@>=1.0.1 <2.0.0", "from": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz"
} }
} }
@ -2581,6 +2642,89 @@
} }
} }
}, },
"passport-saml": {
"version": "0.15.0",
"from": "passport-saml@",
"resolved": "https://registry.npmjs.org/passport-saml/-/passport-saml-0.15.0.tgz",
"dependencies": {
"passport-strategy": {
"version": "1.0.0",
"from": "passport-strategy@*"
},
"q": {
"version": "1.1.2",
"from": "q@1.1.x"
},
"xml2js": {
"version": "0.4.17",
"from": "xml2js@0.4.x",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz",
"dependencies": {
"sax": {
"version": "1.2.1",
"from": "sax@>=0.6.0"
},
"xmlbuilder": {
"version": "4.2.1",
"from": "xmlbuilder@^4.1.0",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz"
}
}
},
"xml-crypto": {
"version": "0.8.4",
"from": "xml-crypto@0.8.x",
"dependencies": {
"xmldom": {
"version": "0.1.19",
"from": "xmldom@=0.1.19"
},
"xpath.js": {
"version": "1.0.6",
"from": "xpath.js@>=0.0.3"
}
}
},
"xmldom": {
"version": "0.1.22",
"from": "xmldom@0.1.x"
},
"xmlbuilder": {
"version": "2.5.2",
"from": "xmlbuilder@2.5.x",
"dependencies": {
"lodash": {
"version": "3.2.0",
"from": "lodash@~3.2.0"
}
}
},
"xml-encryption": {
"version": "0.7.4",
"from": "xml-encryption@~0.7",
"dependencies": {
"ejs": {
"version": "0.8.8",
"from": "ejs@~0.8.3"
},
"async": {
"version": "0.2.10",
"from": "async@~0.2.7"
},
"xpath": {
"version": "0.0.5",
"from": "xpath@0.0.5",
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.5.tgz"
},
"node-forge": {
"version": "0.2.24",
"from": "node-forge@0.2.24",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.2.24.tgz"
}
}
}
}
},
"pg": { "pg": {
"version": "6.0.3", "version": "6.0.3",
"from": "https://registry.npmjs.org/pg/-/pg-6.0.3.tgz", "from": "https://registry.npmjs.org/pg/-/pg-6.0.3.tgz",
@ -3430,7 +3574,7 @@
}, },
"json-stringify-safe": { "json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",
"from": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "from": "json-stringify-safe@~5.0.0",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
}, },
"mime-types": { "mime-types": {
@ -3462,7 +3606,7 @@
}, },
"stringstream": { "stringstream": {
"version": "0.0.5", "version": "0.0.5",
"from": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "from": "stringstream@~0.0.4",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
}, },
"tough-cookie": { "tough-cookie": {
@ -3472,7 +3616,7 @@
}, },
"tunnel-agent": { "tunnel-agent": {
"version": "0.4.3", "version": "0.4.3",
"from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "from": "tunnel-agent@~0.4.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz"
} }
} }
@ -3558,7 +3702,7 @@
}, },
"depd": { "depd": {
"version": "1.1.0", "version": "1.1.0",
"from": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", "from": "depd@~1.1.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz" "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz"
}, },
"dottie": { "dottie": {
@ -3656,7 +3800,7 @@
}, },
"settings-sharelatex": { "settings-sharelatex": {
"version": "1.0.0", "version": "1.0.0",
"from": "git+https://github.com/sharelatex/settings-sharelatex.git#cbc5e41c1dbe6789721a14b3fdae05bf22546559", "from": "settings-sharelatex@git+https://github.com/sharelatex/settings-sharelatex.git#cbc5e41c1dbe6789721a14b3fdae05bf22546559",
"resolved": "git+https://github.com/sharelatex/settings-sharelatex.git#cbc5e41c1dbe6789721a14b3fdae05bf22546559", "resolved": "git+https://github.com/sharelatex/settings-sharelatex.git#cbc5e41c1dbe6789721a14b3fdae05bf22546559",
"dependencies": { "dependencies": {
"coffee-script": { "coffee-script": {

View file

@ -17,17 +17,18 @@
"bcrypt": "0.8.3", "bcrypt": "0.8.3",
"body-parser": "^1.13.1", "body-parser": "^1.13.1",
"bufferedstream": "1.6.0", "bufferedstream": "1.6.0",
"connect-redis": "2.3.0", "connect-redis": "^3.1.0",
"contentful": "^3.3.14", "contentful": "^3.3.14",
"cookie": "^0.2.3", "cookie": "^0.2.3",
"cookie-parser": "1.3.5", "cookie-parser": "1.3.5",
"csurf": "^1.8.3", "csurf": "^1.8.3",
"dateformat": "1.0.4-1.2.3", "dateformat": "1.0.4-1.2.3",
"express": "4.13.0", "express": "4.13.0",
"express-session": "1.11.3", "express-session": "^1.14.2",
"grunt": "^0.4.5", "grunt": "^0.4.5",
"heapdump": "^0.3.7", "heapdump": "^0.3.7",
"http-proxy": "^1.8.1", "http-proxy": "^1.8.1",
"ioredis": "^2.4.0",
"jade": "~1.3.1", "jade": "~1.3.1",
"ldapjs": "^1.0.0", "ldapjs": "^1.0.0",
"lodash": "^4.13.1", "lodash": "^4.13.1",
@ -49,8 +50,6 @@
"passport": "^0.3.2", "passport": "^0.3.2",
"passport-ldapauth": "^0.6.0", "passport-ldapauth": "^0.6.0",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"pg": "^6.0.3",
"pg-hstore": "^2.3.2",
"redback": "0.4.0", "redback": "0.4.0",
"redis": "0.10.1", "redis": "0.10.1",
"redis-sharelatex": "0.0.9", "redis-sharelatex": "0.0.9",
@ -64,7 +63,8 @@
"temp": "^0.8.3", "temp": "^0.8.3",
"underscore": "1.6.0", "underscore": "1.6.0",
"v8-profiler": "^5.2.3", "v8-profiler": "^5.2.3",
"xml2js": "0.2.0" "xml2js": "0.2.0",
"passport-saml": "^0.15.0"
}, },
"devDependencies": { "devDependencies": {
"bunyan": "0.22.1", "bunyan": "0.22.1",

View file

@ -91,23 +91,6 @@ define [
if value? if value?
localStorage "ui.reviewPanelOpen.#{window.project_id}", value localStorage "ui.reviewPanelOpen.#{window.project_id}", value
# Only run the header AB test for newly registered users.
_abTestStartDate = new Date(Date.UTC(2016, 8, 28))
_userSignUpDate = new Date(window.user.signUpDate)
$scope.shouldABTestHeaderLabels = _userSignUpDate > _abTestStartDate
$scope.headerLabelsABVariant = ""
if ($scope.shouldABTestHeaderLabels)
sixpack.participate "editor-header", [ "default", "labels"], (chosenVariation) ->
$scope.headerLabelsABVariant = chosenVariation
$scope.trackABTestConversion = (headerItem) ->
event_tracking.sendMB "header-ab-conversion", {
headerItem: headerItem,
variant: $scope.headerLabelsABVariant
}
# Tracking code. # Tracking code.
$scope.$watch "ui.view", (newView, oldView) -> $scope.$watch "ui.view", (newView, oldView) ->
if newView? and newView != "editor" and newView != "pdf" if newView? and newView != "editor" and newView != "pdf"

View file

@ -310,7 +310,7 @@ define [
_onError: (error, meta = {}) -> _onError: (error, meta = {}) ->
meta.doc_id = @doc_id meta.doc_id = @doc_id
console.error "ShareJS error", error, meta sl_console.log "ShareJS error", error, meta
ga?('send', 'event', 'error', "shareJsError", "#{error.message} - #{@ide.socket.socket.transport.name}" ) ga?('send', 'event', 'error', "shareJsError", "#{error.message} - #{@ide.socket.socket.transport.name}" )
@doc?.clearInflightAndPendingOps() @doc?.clearInflightAndPendingOps()
@trigger "error", error, meta @trigger "error", error, meta

View file

@ -207,16 +207,19 @@ define [
return doc.split("\n") return doc.split("\n")
_aceDeltaSetsToSimpleDeltaSets: (aceDeltaSets, docLines) -> _aceDeltaSetsToSimpleDeltaSets: (aceDeltaSets, docLines) ->
simpleDeltaSets = []
for deltaSet in aceDeltaSets for deltaSet in aceDeltaSets
simpleDeltas = [] if deltaSet.group == "doc" # ignore fold changes
for delta in deltaSet.deltas simpleDeltas = []
simpleDeltas.push @_aceDeltaToSimpleDelta(delta, docLines) for delta in deltaSet.deltas
docLines = @_applyAceDeltasToDocLines([delta], docLines) simpleDeltas.push @_aceDeltaToSimpleDelta(delta, docLines)
{ docLines = @_applyAceDeltasToDocLines([delta], docLines)
deltas: simpleDeltas simpleDeltaSets.push {
group: deltaSet.group deltas: simpleDeltas
} group: deltaSet.group
}
return simpleDeltaSets
_simpleDeltaSetsToAceDeltaSets: (simpleDeltaSets, docLines) -> _simpleDeltaSetsToAceDeltaSets: (simpleDeltaSets, docLines) ->
for deltaSet in simpleDeltaSets for deltaSet in simpleDeltaSets
aceDeltas = [] aceDeltas = []

View file

@ -14,6 +14,7 @@ define [
"main/subscription-dashboard" "main/subscription-dashboard"
"main/new-subscription" "main/new-subscription"
"main/annual-upgrade" "main/annual-upgrade"
"main/announcements"
"main/register-users" "main/register-users"
"main/subscription/group-subscription-invite-controller" "main/subscription/group-subscription-invite-controller"
"main/contact-us" "main/contact-us"

View file

@ -0,0 +1,20 @@
define [
"base"
], (App) ->
App.controller "AnnouncementsController", ($scope, $http, event_tracking, $window) ->
$scope.dataRecived = false
announcement = null
$http.get("/announcements").success (announcements) ->
if announcements?[0]?
announcement = announcements[0]
$scope.title = announcement.title
$scope.totalAnnouncements = announcements.length
$scope.dataRecived = true
dismissannouncement = ->
event_tracking.sendMB "announcement-alert-dismissed", {blogPostId:announcement.id}
$scope.openLink = ->
dismissannouncement()
$window.location.href = announcement.url

View file

@ -53,16 +53,6 @@ define [
@sendMB key, segmentation @sendMB key, segmentation
} }
# App.directive "countlyTrack", () ->
# return {
# restrict: "A"
# scope: false,
# link: (scope, el, attrs) ->
# eventKey = attrs.countlyTrack
# if (eventKey?)
# el.on "click", () ->
# console.log eventKey
# }
#header #header
$('.navbar a').on "click", (e)-> $('.navbar a').on "click", (e)->

View file

@ -99,7 +99,7 @@ define [
visible = true visible = true
# Only show if it matches any search text # Only show if it matches any search text
if $scope.searchText.value? and $scope.searchText.value != "" if $scope.searchText.value? and $scope.searchText.value != ""
if !project.name.toLowerCase().match($scope.searchText.value.toLowerCase()) if project.name.toLowerCase().indexOf($scope.searchText.value.toLowerCase()) == -1
visible = false visible = false
# Only show if it matches the selected tag # Only show if it matches the selected tag
if $scope.filter == "tag" and selectedTag? and project.id not in selectedTag.project_ids if $scope.filter == "tag" and selectedTag? and project.id not in selectedTag.project_ids

View file

@ -1813,7 +1813,7 @@ var CheckEnvironments = function (Environments, ErrorReporter) {
var verbatimRanges = []; var verbatimRanges = [];
for (var i = 0, len = Environments.length; i < len; i++) { for (var i = 0, len = Environments.length; i < len; i++) {
var name = Environments[i].name ; var name = Environments[i].name ;
if (name && name.match(/^(verbatim|boxedverbatim|lstlisting)$/)) { if (name && name.match(/^(verbatim|boxedverbatim|lstlisting|minted)$/)) {
Environments[i].verbatim = true; Environments[i].verbatim = true;
} }
} }

View file

@ -0,0 +1 @@
* binary

View file

@ -0,0 +1,3 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSEáCNS2-H

View file

@ -0,0 +1,3 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSEá ETen-B5-H` ^

Some files were not shown because too many files have changed in this diff Show more