mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-28 02:51:25 +00:00
Merge branch 'master-redesign' of https://github.com/sharelatex/web-sharelatex into master-redesign
updated upstream into a topic branch.
This commit is contained in:
commit
7255231abc
11 changed files with 177 additions and 54 deletions
|
@ -14,6 +14,7 @@ SubscriptionHandler = require('../Subscription/SubscriptionHandler')
|
|||
projectEntityHandler = require('../Project/ProjectEntityHandler')
|
||||
TpdsPollingBackgroundTasks = require("../ThirdPartyDataStore/TpdsPollingBackgroundTasks")
|
||||
EditorRealTimeController = require("../Editor/EditorRealTimeController")
|
||||
SystemMessageManager = require("../SystemMessages/SystemMessageManager")
|
||||
|
||||
oneMinInMs = 60 * 1000
|
||||
|
||||
|
@ -29,66 +30,20 @@ setTimeout updateOpenConnetionsMetrics, oneMinInMs
|
|||
|
||||
module.exports = AdminController =
|
||||
|
||||
index : (req, res)=>
|
||||
index : (req, res, next)=>
|
||||
http = require('http')
|
||||
openSockets = {}
|
||||
for url, agents of require('http').globalAgent.sockets
|
||||
openSockets["http://#{url}"] = (agent._httpMessage.path for agent in agents)
|
||||
for url, agents of require('https').globalAgent.sockets
|
||||
openSockets["https://#{url}"] = (agent._httpMessage.path for agent in agents)
|
||||
memory = process.memoryUsage()
|
||||
io = require("../../infrastructure/Server").io
|
||||
allUsers = io.sockets.clients()
|
||||
users = []
|
||||
allUsers.forEach (user)->
|
||||
u = {}
|
||||
user.get "email", (err, email)->
|
||||
u.email = email
|
||||
user.get "first_name", (err, first_name)->
|
||||
u.first_name = first_name
|
||||
user.get "last_name", (err, last_name)->
|
||||
u.last_name = last_name
|
||||
user.get "project_id", (err, project_id)->
|
||||
u.project_id = project_id
|
||||
user.get "user_id", (err, user_id)->
|
||||
u.user_id = user_id
|
||||
user.get "signup_date", (err, signup_date)->
|
||||
u.signup_date = signup_date
|
||||
user.get "login_count", (err, login_count)->
|
||||
u.login_count = login_count
|
||||
user.get "connected_time", (err, connected_time)->
|
||||
now = new Date()
|
||||
connected_mins = (((now - new Date(connected_time))/1000)/60).toFixed(2)
|
||||
u.connected_mins = connected_mins
|
||||
users.push u
|
||||
|
||||
d = new Date()
|
||||
today = d.getDate()+":"+(d.getMonth()+1)+":"+d.getFullYear()+":"
|
||||
yesterday = (d.getDate()-1)+":"+(d.getMonth()+1)+":"+d.getFullYear()+":"
|
||||
|
||||
multi = rclient.multi()
|
||||
multi.get today+"docsets"
|
||||
multi.get yesterday+"docsets"
|
||||
multi.exec (err, replys)->
|
||||
redisstats =
|
||||
today:
|
||||
docsets: replys[0]
|
||||
compiles: replys[1]
|
||||
yesterday:
|
||||
docsets: replys[2]
|
||||
compiles: replys[3]
|
||||
DocumentUpdaterHandler.getNumberOfDocsInMemory (err, numberOfInMemoryDocs)=>
|
||||
User.count (err, totalUsers)->
|
||||
Project.count (err, totalProjects)->
|
||||
res.render 'admin',
|
||||
title: 'System Admin'
|
||||
currentConnectedUsers:allUsers.length
|
||||
users: users
|
||||
numberOfAceDocs : numberOfInMemoryDocs
|
||||
totalUsers: totalUsers
|
||||
totalProjects: totalProjects
|
||||
openSockets: openSockets
|
||||
redisstats: redisstats
|
||||
SystemMessageManager.getMessagesFromDB (error, systemMessages) ->
|
||||
return next(error) if error?
|
||||
res.render 'admin',
|
||||
title: 'System Admin'
|
||||
openSockets: openSockets
|
||||
systemMessages: systemMessages
|
||||
|
||||
dissconectAllUsers: (req, res)=>
|
||||
logger.warn "disconecting everyone"
|
||||
|
@ -122,3 +77,13 @@ module.exports = AdminController =
|
|||
pollUsersWithDropbox: (req, res)->
|
||||
TpdsPollingBackgroundTasks.pollUsersWithDropbox ->
|
||||
res.send 200
|
||||
|
||||
createMessage: (req, res, next) ->
|
||||
SystemMessageManager.createMessage req.body.content, (error) ->
|
||||
return next(error) if error?
|
||||
res.send 200
|
||||
|
||||
clearMessages: (req, res, next) ->
|
||||
SystemMessageManager.clearMessages (error) ->
|
||||
return next(error) if error?
|
||||
res.send 200
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
SystemMessage = require("../../models/SystemMessage").SystemMessage
|
||||
|
||||
module.exports = SystemMessageManager =
|
||||
getMessages: (callback = (error, messages) ->) ->
|
||||
if @_cachedMessages?
|
||||
return callback null, @_cachedMessages
|
||||
else
|
||||
@getMessagesFromDB (error, messages) =>
|
||||
return callback(error) if error?
|
||||
@_cachedMessages = messages
|
||||
return callback null, messages
|
||||
|
||||
getMessagesFromDB: (callback = (error, messages) ->) ->
|
||||
SystemMessage.find {}, callback
|
||||
|
||||
clearMessages: (callback = (error) ->) ->
|
||||
SystemMessage.remove {}, callback
|
||||
|
||||
createMessage: (content, callback = (error) ->) ->
|
||||
message = new SystemMessage { content: content }
|
||||
message.save callback
|
||||
|
||||
clearCache: () ->
|
||||
delete @_cachedMessages
|
||||
|
||||
CACHE_TIMEOUT = 5 * 60 * 1000 # 5 minutes
|
||||
setInterval () ->
|
||||
SystemMessageManager.clearCache()
|
||||
, CACHE_TIMEOUT
|
|
@ -4,6 +4,7 @@ crypto = require 'crypto'
|
|||
Settings = require('settings-sharelatex')
|
||||
SubscriptionFormatters = require('../Features/Subscription/SubscriptionFormatters')
|
||||
querystring = require('querystring')
|
||||
SystemMessageManager = require("../Features/SystemMessages/SystemMessageManager")
|
||||
|
||||
fingerprints = {}
|
||||
Path = require 'path'
|
||||
|
@ -125,4 +126,9 @@ module.exports = (app)->
|
|||
app.use (req, res, next) ->
|
||||
res.locals.nav = Settings.nav
|
||||
next()
|
||||
|
||||
app.use (req, res, next) ->
|
||||
SystemMessageManager.getMessages (error, messages = []) ->
|
||||
res.locals.systemMessages = messages
|
||||
next()
|
||||
|
||||
|
|
12
services/web/app/coffee/models/SystemMessage.coffee
Normal file
12
services/web/app/coffee/models/SystemMessage.coffee
Normal file
|
@ -0,0 +1,12 @@
|
|||
mongoose = require 'mongoose'
|
||||
Settings = require 'settings-sharelatex'
|
||||
|
||||
Schema = mongoose.Schema
|
||||
ObjectId = Schema.ObjectId
|
||||
|
||||
SystemMessageSchema = new Schema
|
||||
content : type: String, default:''
|
||||
|
||||
conn = mongoose.createConnection(Settings.mongo.url, server: poolSize: Settings.mongo.poolSize || 10)
|
||||
|
||||
exports.SystemMessage = conn.model('SystemMessage', SystemMessageSchema)
|
|
@ -170,6 +170,8 @@ module.exports = class Router
|
|||
app.post '/admin/syncUserToSubscription', SecurityManager.requestIsAdmin, AdminController.syncUserToSubscription
|
||||
app.post '/admin/flushProjectToTpds', SecurityManager.requestIsAdmin, AdminController.flushProjectToTpds
|
||||
app.post '/admin/pollUsersWithDropbox', SecurityManager.requestIsAdmin, AdminController.pollUsersWithDropbox
|
||||
app.post '/admin/messages', SecurityManager.requestIsAdmin, AdminController.createMessage
|
||||
app.post '/admin/messages/clear', SecurityManager.requestIsAdmin, AdminController.clearMessages
|
||||
|
||||
app.get '/perfTest', (req,res)->
|
||||
res.send("hello")
|
||||
|
|
|
@ -59,6 +59,21 @@ block content
|
|||
.row-spaced
|
||||
form(enctype='multipart/form-data', method='post',action='/admin/pollUsersWithDropbox')
|
||||
input(name="_csrf", type="hidden", value=csrfToken)
|
||||
button.btn.btn-primary(type="submit") Poll users with dropbox
|
||||
button.btn.btn-primary(type="submit") Poll users with dropbox
|
||||
|
||||
tab(heading="System Messages")
|
||||
each message in systemMessages
|
||||
.alert.alert-info.row-spaced !{message.content}
|
||||
hr
|
||||
form(enctype='multipart/form-data', method='post', action='/admin/messages')
|
||||
input(name="_csrf", type="hidden", value=csrfToken)
|
||||
.form-group
|
||||
label(for="content")
|
||||
input.form-control(name="content", type="text", placeholder="Message...", required)
|
||||
button.btn.btn-primary(type="submit") Post Message
|
||||
hr
|
||||
form(enctype='multipart/form-data', method='post', action='/admin/messages/clear')
|
||||
input(name="_csrf", type="hidden", value=csrfToken)
|
||||
button.btn.btn-danger(type="submit") Clear all messages
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ html(itemscope, itemtype='http://schema.org/Product')
|
|||
siteUrl: '#{settings.siteUrl}',
|
||||
jsPath: '#{jsPath}'
|
||||
};
|
||||
window.systemMessages = !{JSON.stringify(systemMessages).replace(/\//g, '\\/')};
|
||||
|
||||
- if (typeof(settings.algolia) != "undefined")
|
||||
script.
|
||||
|
@ -58,6 +59,19 @@ html(itemscope, itemtype='http://schema.org/Product')
|
|||
}
|
||||
|
||||
body
|
||||
- if(typeof(suppressSystemMessages) == "undefined")
|
||||
.system-messages(
|
||||
ng-cloak
|
||||
ng-controller="SystemMessagesController"
|
||||
)
|
||||
.system-message(
|
||||
ng-repeat="message in messages"
|
||||
ng-controller="SystemMessageController"
|
||||
ng-hide="hidden"
|
||||
)
|
||||
a(href, ng-click="hide()").pull-right ×
|
||||
.system-message-content(ng-bind-html="htmlContent")
|
||||
|
||||
- if(typeof(suppressNavbar) == "undefined")
|
||||
include layout/navbar
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ define [
|
|||
"main/scribtex-popup"
|
||||
"main/event-tracking"
|
||||
"main/bonus"
|
||||
"main/system-messages"
|
||||
"directives/asyncForm"
|
||||
"directives/stopPropagation"
|
||||
"directives/focus"
|
||||
|
|
13
services/web/public/coffee/main/system-messages.coffee
Normal file
13
services/web/public/coffee/main/system-messages.coffee
Normal file
|
@ -0,0 +1,13 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.controller "SystemMessagesController", ($scope) ->
|
||||
$scope.messages = window.systemMessages;
|
||||
|
||||
App.controller "SystemMessageController", ($scope, $sce) ->
|
||||
$scope.hidden = $.localStorage("systemMessage.hide.#{$scope.message._id}")
|
||||
$scope.htmlContent = $sce.trustAsHtml $scope.message.content
|
||||
|
||||
$scope.hide = () ->
|
||||
$scope.hidden = true
|
||||
$.localStorage("systemMessage.hide.#{$scope.message._id}", true)
|
|
@ -2,6 +2,13 @@
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
padding: (@line-height-computed / 4) (@line-height-computed / 2);
|
||||
background-color: @state-warning-bg;
|
||||
color: #333;
|
||||
border-bottom: 1px solid @toolbar-border-color;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
SandboxedModule = require('sandboxed-module')
|
||||
assert = require('assert')
|
||||
require('chai').should()
|
||||
sinon = require('sinon')
|
||||
modulePath = require('path').join __dirname, '../../../../app/js/Features/SystemMessages/SystemMessageManager.js'
|
||||
|
||||
|
||||
describe 'SystemMessageManager', ->
|
||||
beforeEach ->
|
||||
@SystemMessage = {}
|
||||
@SystemMessageManager = SandboxedModule.require modulePath, requires:
|
||||
"../../models/SystemMessage": SystemMessage: @SystemMessage
|
||||
@callback = sinon.stub()
|
||||
|
||||
describe "getMessage", ->
|
||||
beforeEach ->
|
||||
@messages = ["messages-stub"]
|
||||
@SystemMessage.find = sinon.stub().callsArgWith(1, null, @messages)
|
||||
|
||||
describe "when the messages are not cached", ->
|
||||
beforeEach ->
|
||||
@SystemMessageManager.getMessages @callback
|
||||
|
||||
it "should look the messages up in the database", ->
|
||||
@SystemMessage.find
|
||||
.calledWith({})
|
||||
.should.equal true
|
||||
|
||||
it "should return the messages", ->
|
||||
@callback.calledWith(null, @messages).should.equal true
|
||||
|
||||
it "should cache the messages", ->
|
||||
@SystemMessageManager._cachedMessages.should.equal @messages
|
||||
|
||||
describe "when the messages are cached", ->
|
||||
beforeEach ->
|
||||
@SystemMessageManager._cachedMessages = @messages
|
||||
@SystemMessageManager.getMessages @callback
|
||||
|
||||
it "should not look the messages up in the database", ->
|
||||
@SystemMessage.find.called.should.equal false
|
||||
|
||||
it "should return the messages", ->
|
||||
@callback.calledWith(null, @messages).should.equal true
|
||||
|
||||
describe "clearMessages", ->
|
||||
beforeEach ->
|
||||
@SystemMessage.remove = sinon.stub().callsArg(1)
|
||||
@SystemMessageManager.clearMessages @callback
|
||||
|
||||
it "should remove the messages from the database", ->
|
||||
@SystemMessage.remove
|
||||
.calledWith({})
|
||||
.should.equal true
|
||||
|
||||
it "should return the callback", ->
|
||||
@callback.called.should.equal true
|
||||
|
||||
|
Loading…
Reference in a new issue