diff --git a/services/web/app/src/Features/HealthCheck/HealthCheckController.js b/services/web/app/src/Features/HealthCheck/HealthCheckController.js index 514c8fa18d..2daa41d0f4 100644 --- a/services/web/app/src/Features/HealthCheck/HealthCheckController.js +++ b/services/web/app/src/Features/HealthCheck/HealthCheckController.js @@ -10,8 +10,14 @@ const { module.exports = { check(req, res, next) { - // detach from express for cleaner stack traces - setTimeout(() => runSmokeTestsDetached(req, res).catch(next)) + if (!settings.siteIsOpen || !settings.editorIsOpen) { + // always return successful health checks when site is closed + res.contentType('application/json') + res.sendStatus(200) + } else { + // detach from express for cleaner stack traces + setTimeout(() => runSmokeTestsDetached(req, res).catch(next)) + } }, checkActiveHandles(req, res, next) { diff --git a/services/web/app/src/Features/ServerAdmin/AdminController.js b/services/web/app/src/Features/ServerAdmin/AdminController.js index 8a04b70e29..8404a8628d 100644 --- a/services/web/app/src/Features/ServerAdmin/AdminController.js +++ b/services/web/app/src/Features/ServerAdmin/AdminController.js @@ -98,11 +98,13 @@ const AdminController = { return res.render('admin/register') }, - dissconectAllUsers: (req, res) => { + disconnectAllUsers: (req, res) => { logger.warn('disconecting everyone') + const delay = (req.query && req.query.delay) > 0 ? req.query.delay : 10 EditorRealTimeController.emitToAll( 'forceDisconnect', - 'Sorry, we are performing a quick update to the editor and need to close it down. Please refresh the page to continue.' + 'Sorry, we are performing a quick update to the editor and need to close it down. Please refresh the page to continue.', + delay ) return res.sendStatus(200) }, diff --git a/services/web/app/src/router.js b/services/web/app/src/router.js index 62f27c9337..1bbbdbb3e3 100644 --- a/services/web/app/src/router.js +++ b/services/web/app/src/router.js @@ -954,9 +954,9 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) { AdminController.closeEditor ) webRouter.post( - '/admin/dissconectAllUsers', + '/admin/disconnectAllUsers', AuthorizationMiddleware.ensureUserIsSiteAdmin, - AdminController.dissconectAllUsers + AdminController.disconnectAllUsers ) webRouter.post( '/admin/flushProjectToTpds', @@ -981,14 +981,20 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) { privateApiRouter.post( '/disconnectAllUsers', - AdminController.dissconectAllUsers + AdminController.disconnectAllUsers ) privateApiRouter.get('/perfTest', (req, res) => res.send('hello')) - publicApiRouter.get('/status', (req, res) => - res.send('web sharelatex is alive (web)') - ) + publicApiRouter.get('/status', (req, res) => { + if (!Settings.siteIsOpen) { + res.send('web site is closed (web)') + } else if (!Settings.editorIsOpen) { + res.send('web editor is closed (web)') + } else { + res.send('web sharelatex is alive (web)') + } + }) privateApiRouter.get('/status', (req, res) => res.send('web sharelatex is alive (api)') ) diff --git a/services/web/app/views/admin/index.pug b/services/web/app/views/admin/index.pug index a227e9d0f7..bec1bdbe52 100644 --- a/services/web/app/views/admin/index.pug +++ b/services/web/app/views/admin/index.pug @@ -42,7 +42,7 @@ block content p.small Will stop anyone opening the editor. Will NOT disconnect already connected users. .row-spaced - form(method='post',action='/admin/dissconectAllUsers') + form(method='post',action='/admin/disconnectAllUsers') input(name="_csrf", type="hidden", value=csrfToken) button.btn.btn-danger(type="submit") Disconnect all users p.small Will force disconnect all users with the editor open. Make sure to close the editor first to avoid them reconnecting. diff --git a/services/web/app/views/project/editor.pug b/services/web/app/views/project/editor.pug index 62fd40479c..9ad1eef194 100644 --- a/services/web/app/views/project/editor.pug +++ b/services/web/app/views/project/editor.pug @@ -25,7 +25,6 @@ block content .global-alerts(ng-cloak ng-hide="editor.error_state") .alert.alert-danger.small(ng-if="connection.forced_disconnect") strong #{translate("disconnected")} - | #{translate("please_refresh")} .alert.alert-warning.small(ng-if="connection.reconnection_countdown") strong #{translate("lost_connection")}. diff --git a/services/web/frontend/js/ide/connection/ConnectionManager.js b/services/web/frontend/js/ide/connection/ConnectionManager.js index bf0e130e67..c2fa64adc9 100644 --- a/services/web/frontend/js/ide/connection/ConnectionManager.js +++ b/services/web/frontend/js/ide/connection/ConnectionManager.js @@ -249,22 +249,25 @@ export default ConnectionManager = (function() { // Site administrators can send the forceDisconnect event to all users - this.ide.socket.on('forceDisconnect', message => { + this.ide.socket.on('forceDisconnect', (message, delay = 10) => { this.updateConnectionManagerState('inactive') + this.shuttingDown = true // prevent reconnection attempts this.$scope.$apply(() => { this.$scope.permissions.write = false return (this.$scope.connection.forced_disconnect = true) }) - this.ide.socket.disconnect() - this.ide.showGenericMessageModal( - 'Please Refresh', + // flush changes before disconnecting + this.ide.$scope.$broadcast('flush-changes') + setTimeout(() => this.ide.socket.disconnect(), 1000) + this.ide.showLockEditorMessageModal( + 'Please wait', `\ -We're performing maintenance on Overleaf and you need to refresh the editor. +We're performing maintenance on Overleaf and you need to wait a moment. Sorry for any inconvenience. -The editor will refresh in automatically in 10 seconds.\ +The editor will refresh automatically in ${delay} seconds.\ ` ) - return setTimeout(() => location.reload(), 10 * 1000) + return setTimeout(() => location.reload(), delay * 1000) }) this.ide.socket.on('reconnectGracefully', () => {