Skip to content

Commit

Permalink
feat(maintenance): added maintenance mode #475
Browse files Browse the repository at this point in the history
  • Loading branch information
polonel committed Feb 20, 2022
1 parent 7603f4c commit a04f15b
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 23 deletions.
77 changes: 63 additions & 14 deletions src/client/containers/Settings/Server/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,20 @@ import SettingItem from 'components/Settings/SettingItem'
import helpers from 'lib/helpers'
import axios from 'axios'
import Log from '../../../logger'
import EnableSwitch from 'components/Settings/EnableSwitch'
import { observer } from 'mobx-react'
import { makeObservable, observable } from 'mobx'
import UIKit from 'uikit'

@observer
class ServerSettingsController extends React.Component {
@observable maintenanceModeEnabled = false

constructor (props) {
super(props)

makeObservable(this)

this.state = {
restarting: false
}
Expand All @@ -39,23 +48,14 @@ class ServerSettingsController extends React.Component {
// helpers.UI.inputs()
}

componentDidUpdate () {
componentDidUpdate (prevProps) {
// helpers.UI.reRenderInputs()
if (prevProps.settings !== this.props.settings) {
if (this.maintenanceModeEnabled !== this.getSetting('maintenanceMode'))
this.maintenanceModeEnabled = this.getSetting('maintenanceMode')
}
}

// static getDerivedStateFromProps (nextProps, state) {
// if (nextProps.settings) {
// let stateObj = { ...state }
// if (!state.tpsUsername)
// stateObj.tpsUsername = nextProps.settings.getIn(['settings', 'tpsUsername', 'value']) || ''
// if (!state.tpsApiKey) stateObj.tpsApiKey = nextProps.settings.getIn(['settings', 'tpsApiKey', 'value']) || ''
//
// return stateObj
// }
//
// return null
// }

restartServer () {
this.setState({ restarting: true })

Expand All @@ -78,6 +78,43 @@ class ServerSettingsController extends React.Component {
: ''
}

onMaintenanceModeChange (e) {
const self = this
const val = e.target.checked

if (val === true) {
UIKit.modal.confirm(
`<h2>Are you sure?</h2>
<p style="font-size: 15px;">
<span class="uk-text-danger" style="font-size: 15px;">This will force logout every user and prevent non-administrators from logging in.</span>
</p>
`,
() => {
this.props
.updateSetting({
name: 'maintenanceMode:enable',
value: val,
stateName: 'maintenanceMode',
noSnackbar: true
})
.then(() => {
self.maintenanceModeEnabled = val
})
},
{
labels: { Ok: 'Yes', Cancel: 'No' },
confirmButtonClass: 'md-btn-danger'
}
)
} else {
this.props
.updateSetting({ name: 'maintenanceMode:enable', value: val, stateName: 'maintenanceMode', noSnackbar: true })
.then(() => {
self.maintenanceModeEnabled = val
})
}
}

render () {
const { active } = this.props
return (
Expand All @@ -97,6 +134,18 @@ class ServerSettingsController extends React.Component {
/>
}
/>
<SettingItem
title={'Maintenance Mode'}
subtitle={'Only Administrators are allowed to login.'}
component={
<EnableSwitch
stateName={'maintenanceMode'}
label={'Enable'}
checked={this.maintenanceModeEnabled}
onChange={e => this.onMaintenanceModeChange(e)}
/>
}
/>
</div>
)
}
Expand Down
18 changes: 18 additions & 0 deletions src/middleware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ module.exports = function (app, db, callback) {

// CORS
app.use(allowCrossDomain)

// Maintenance Mode
app.use(function (req, res, next) {
var settings = require('../settings/settingsUtil')
settings.getSettings(function (err, setting) {
if (err) return winston.warn(err)
var maintenanceMode = setting.data.settings.maintenanceMode

if (req.user) {
if (maintenanceMode.value === true && !req.user.role.isAdmin) {
return res.render('maintenance', { layout: false })
}
}

return next()
})
})

// Mobile
app.use('/mobile', express.static(path.join(__dirname, '../../', 'mobile')))

Expand Down
24 changes: 15 additions & 9 deletions src/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ function mainRoutes (router, middleware, controllers) {
router.get('/install', function (req, res) {
return res.redirect('/')
})
router.get(
'/dashboard',
middleware.redirectToLogin,
middleware.redirectIfUser,
middleware.loadCommonData,
controllers.main.dashboard
)

router.get('/login', function (req, res) {
return res.redirect('/')
Expand Down Expand Up @@ -81,6 +74,19 @@ function mainRoutes (router, middleware, controllers) {
})
})

// Maintenance
router.get('/maintenance', function (req, res) {
return res.redirect('/')
})

router.get(
'/dashboard',
middleware.redirectToLogin,
middleware.redirectIfUser,
middleware.loadCommonData,
controllers.main.dashboard
)

// Tickets
router.get(
'/tickets',
Expand Down Expand Up @@ -449,8 +455,8 @@ function handleErrors (err, req, res) {
var status = err.status || 500
res.status(err.status)

if (status === 404) {
res.render('404', { layout: false })
if (status === 500) {
res.render('500', { layout: false })
return
}

Expand Down
20 changes: 20 additions & 0 deletions src/settings/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,23 @@ function installationID (callback) {
})
}

function maintenanceModeDefault (callback) {
SettingsSchema.getSettingByName('maintenanceMode:enable', function (err, setting) {
if (err) return callback(err)
if (!setting) {
SettingsSchema.create(
{
name: 'maintenanceMode:enable',
value: false
},
callback
)
} else {
return callback()
}
})
}

settingsDefaults.init = function (callback) {
winston.debug('Checking Default Settings...')
async.series(
Expand Down Expand Up @@ -714,6 +731,9 @@ settingsDefaults.init = function (callback) {
function (done) {
return elasticSearchConfToDB(done)
},
function (done) {
return maintenanceModeDefault(done)
},
function (done) {
return installationID(done)
}
Expand Down
2 changes: 2 additions & 0 deletions src/settings/settingsUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ util.getSettings = function (callback) {
s.privacyPolicy = parseSetting(settings, 'legal:privacypolicy', '')
s.privacyPolicy.value = jsStringEscape(s.privacyPolicy.value)

s.maintenanceMode = parseSetting(settings, 'maintenanceMode:enable', false)

async.parallel(
[
function (done) {
Expand Down
120 changes: 120 additions & 0 deletions src/views/500.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html>
<head>
<title>Trudesk</title>
<link href='http://fonts.googleapis.com/css?family=Roboto:200,400,300,600,700' rel='stylesheet' type='text/css'>
<style type="text/css">
html {
overflow-x: hidden;
}
body {
background: #eee;
text-align: center;
font-family: "Roboto", Arial, sans-serif;
}
.wrapper {
width: 400px;
height: 400px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
img {
margin-bottom: 55px;
}
label {
text-align: left
}
button {
font-family: "Roboto", Arial, sans-serif;
width: 340px;
height: 20px;
text-align: left;
padding: 15px 20px;
background: #384b5f;
border: 1px solid #1c2937;
font-size: 20px;
color: #fff;
margin-bottom: 15px;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
font-weight: 300;
}
button.button {
width: 380px;
height: auto;
text-align: center;
background: #e74b3b;
border: none;
text-transform: uppercase;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
button.button:hover {
background: #f15849;
cursor: pointer;
}
*:focus {
outline: 0;
}
a {
display: inline-block;
padding-right: 10px;
color: #727272;
font-size: 14px;
float: right;
text-decoration: none;
font-weight: 300;
}
a:hover {
color: #A5A5A5;
}
::-webkit-input-placeholder { /* WebKit browsers */
color: #222;
}
:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
color: #222;
opacity: 1;
}
::-moz-placeholder { /* Mozilla Firefox 19+ */
color: #222;
opacity: 1;
}
:-ms-input-placeholder { /* Internet Explorer 10+ */
color: #222;
}
h2,h4 {
text-align: center;
font-family: "Roboto", Arial, sans-serif;
font-size: 150px;
font-weight: 300;
margin: 0;
color: #343434;
}
h4 {
font-size: 32px;
color: #222;
}
</style>
</head>
<body>
<a href="/" ><img src="/img/td_3@2x.png" alt="Trudesk Logo" style="display: block; position: absolute; top: 15px; left: 15px; height: 75px" /></a>
<div class="wrapper">
<h2>500</h2>
<h4>Unknown Server Error</h4>
</div>
</body>
</html>

0 comments on commit a04f15b

Please sign in to comment.