Feature: Added a maintenance mode which locks all other users out
This commit is contained in:
parent
cb7e6e89a5
commit
fdcedb262c
|
@ -4,7 +4,7 @@ from sqlalchemy import engine_from_config
|
||||||
|
|
||||||
from pyramid.authentication import AuthTktAuthenticationPolicy
|
from pyramid.authentication import AuthTktAuthenticationPolicy
|
||||||
from pyramid.authorization import ACLAuthorizationPolicy
|
from pyramid.authorization import ACLAuthorizationPolicy
|
||||||
from pyramid.session import UnencryptedCookieSessionFactoryConfig
|
from pyramid.session import SignedCookieSessionFactory
|
||||||
from brewman.factories import add_route
|
from brewman.factories import add_route
|
||||||
from brewman.models import initialize_sql
|
from brewman.models import initialize_sql
|
||||||
from brewman.renderers import json_renderer, CSVRenderer
|
from brewman.renderers import json_renderer, CSVRenderer
|
||||||
|
@ -19,7 +19,7 @@ def main(global_config, **settings):
|
||||||
engine = engine_from_config(settings, 'sqlalchemy.')
|
engine = engine_from_config(settings, 'sqlalchemy.')
|
||||||
initialize_sql(engine)
|
initialize_sql(engine)
|
||||||
|
|
||||||
session_factory = UnencryptedCookieSessionFactoryConfig('secret')
|
session_factory = SignedCookieSessionFactory('secret')
|
||||||
|
|
||||||
authentication_policy = AuthTktAuthenticationPolicy('brewman', timeout=900, reissue_time=90, callback=groupfinder)
|
authentication_policy = AuthTktAuthenticationPolicy('brewman', timeout=900, reissue_time=90, callback=groupfinder)
|
||||||
authorization_policy = ACLAuthorizationPolicy()
|
authorization_policy = ACLAuthorizationPolicy()
|
||||||
|
@ -31,8 +31,6 @@ def main(global_config, **settings):
|
||||||
authorization_policy=authorization_policy,
|
authorization_policy=authorization_policy,
|
||||||
session_factory=session_factory
|
session_factory=session_factory
|
||||||
)
|
)
|
||||||
# This changes in pyramid 1.4 to something similar to "config.add_renderer('myjson', JSON(indent=4))"
|
|
||||||
# http://docs.pylonsproject.org/projects/pyramid/en/master/api/renderers.html#pyramid.renderers.JSON
|
|
||||||
config.add_renderer(name='json', factory=json_renderer)
|
config.add_renderer(name='json', factory=json_renderer)
|
||||||
config.add_renderer(name='csv', factory=CSVRenderer)
|
config.add_renderer(name='csv', factory=CSVRenderer)
|
||||||
|
|
||||||
|
@ -99,6 +97,7 @@ def main(global_config, **settings):
|
||||||
|
|
||||||
config.add_route('settings', '/Settings')
|
config.add_route('settings', '/Settings')
|
||||||
config.add_route('api_lock_info', '/api/LockInfo')
|
config.add_route('api_lock_info', '/api/LockInfo')
|
||||||
|
config.add_route('api_maintenance', '/api/Maintenance')
|
||||||
|
|
||||||
add_route(config, 'attendance', '/Attendance', has_list=False, variable='date')
|
add_route(config, 'attendance', '/Attendance', has_list=False, variable='date')
|
||||||
config.add_route('api_attendance_types', '/api/AttendanceTypes')
|
config.add_route('api_attendance_types', '/api/AttendanceTypes')
|
||||||
|
|
|
@ -83,7 +83,8 @@ def fixtures(engine):
|
||||||
Role('Reconcile', uuid.UUID('a5cb51cb-e38e-4705-84a7-cc1e9a8b866b')),
|
Role('Reconcile', uuid.UUID('a5cb51cb-e38e-4705-84a7-cc1e9a8b866b')),
|
||||||
Role('Stock Movement', uuid.UUID('20b707ee-2b59-41ad-be87-76d5fe1efca8')),
|
Role('Stock Movement', uuid.UUID('20b707ee-2b59-41ad-be87-76d5fe1efca8')),
|
||||||
Role('Purchases', uuid.UUID('cf7019c8-3fd3-45b0-9a42-601029ce5b71')),
|
Role('Purchases', uuid.UUID('cf7019c8-3fd3-45b0-9a42-601029ce5b71')),
|
||||||
Role('Dashboard', uuid.UUID('53eecc09-bd06-4890-b6f5-6885dda762d4'))]
|
Role('Dashboard', uuid.UUID('53eecc09-bd06-4890-b6f5-6885dda762d4')),
|
||||||
|
Role('Maintenance', uuid.UUID('770532e4-21de-4712-8a6b-4ff9fd63a503'))]
|
||||||
|
|
||||||
for role in roles:
|
for role in roles:
|
||||||
DBSession.add(role)
|
DBSession.add(role)
|
||||||
|
|
|
@ -132,8 +132,23 @@
|
||||||
<label class="col-md-2 control-label">Integrity Check</label>
|
<label class="col-md-2 control-label">Integrity Check</label>
|
||||||
|
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<button class="btn btn-block btn-danger" ng-click="checkDb()">Check Database <i
|
<button class="btn btn-block btn-success" ng-click="checkDb()">Check Database <i
|
||||||
class="glyphicon glyphicon-certificate"></i></button>
|
class="glyphicon glyphicon-certificate"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label">Maintenance Mode</label>
|
||||||
|
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button class="btn btn-block btn-danger" ng-click="setMaintenance(true)">Enable <i
|
||||||
|
class="glyphicon glyphicon-eye-close"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button class="btn btn-block btn-success" ng-click="setMaintenance(false)">Disable <i
|
||||||
|
class="glyphicon glyphicon-eye-open"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
Maintenance mode is <strong>{{MaintenanceEnabled()}}</strong> by user <strong>{{maintenance.User}}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var SettingsController = ['$scope', '$http', 'asDateFilter', '$modal', 'lockInfo', 'Product', function ($scope, $http, asDate, $modal, lockInfo, Product) {
|
var SettingsController = ['$scope', '$http', 'asDateFilter', '$modal', 'lockInfo', 'maintenance', 'Product', function ($scope, $http, asDate, $modal, lockInfo, maintenance, Product) {
|
||||||
$scope.lockInfo = lockInfo.data;
|
$scope.lockInfo = lockInfo.data;
|
||||||
|
$scope.maintenance = maintenance.data;
|
||||||
|
$scope.MaintenanceEnabled = function (){
|
||||||
|
return $scope.maintenance.Enabled ? 'Enabled' : 'Disabled';
|
||||||
|
};
|
||||||
$scope.rebaseDate = '';
|
$scope.rebaseDate = '';
|
||||||
$scope.setLockDate = function () {
|
$scope.setLockDate = function () {
|
||||||
if ($scope.lockInfo.Start.Locked) {
|
if ($scope.lockInfo.Start.Locked) {
|
||||||
|
@ -110,7 +114,11 @@ var SettingsController = ['$scope', '$http', 'asDateFilter', '$modal', 'lockInfo
|
||||||
var resetDate = asDate($scope.resetDate);
|
var resetDate = asDate($scope.resetDate);
|
||||||
var stockDate = asDate($scope.stockDate);
|
var stockDate = asDate($scope.stockDate);
|
||||||
var qty = Number($scope.qty);
|
var qty = Number($scope.qty);
|
||||||
$http({method: 'POST', url: '/api/ResetStock/' + $scope.product.ProductID, params: {StockDate: stockDate, ResetDate: resetDate, Quantity: qty}}).
|
$http({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/ResetStock/' + $scope.product.ProductID,
|
||||||
|
params: {StockDate: stockDate, ResetDate: resetDate, Quantity: qty}
|
||||||
|
}).
|
||||||
success(function () {
|
success(function () {
|
||||||
$scope.toasts.push({Type: 'Success', Message: 'Data rebased!'});
|
$scope.toasts.push({Type: 'Success', Message: 'Data rebased!'});
|
||||||
}).
|
}).
|
||||||
|
@ -131,6 +139,17 @@ var SettingsController = ['$scope', '$http', 'asDateFilter', '$modal', 'lockInfo
|
||||||
$scope.toasts.push({Type: 'Danger', Message: errorMessage});
|
$scope.toasts.push({Type: 'Danger', Message: errorMessage});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.setMaintenance = function (status) {
|
||||||
|
return $http.post('/api/Maintenance', {Enabled: status}).
|
||||||
|
success(function (data) {
|
||||||
|
$scope.maintenance = data;
|
||||||
|
$scope.toasts.push({Type: 'Success', Message: ''});
|
||||||
|
}).
|
||||||
|
error(function (errorMessage) {
|
||||||
|
$scope.toasts.push({Type: 'Danger', Message: errorMessage});
|
||||||
|
});
|
||||||
|
};
|
||||||
}];
|
}];
|
||||||
|
|
||||||
SettingsController.resolve = {
|
SettingsController.resolve = {
|
||||||
|
@ -138,6 +157,11 @@ SettingsController.resolve = {
|
||||||
return $http.get('/api/LockInfo', {}).then(function (data) {
|
return $http.get('/api/LockInfo', {}).then(function (data) {
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
|
}],
|
||||||
|
maintenance: ['$http', function ($http) {
|
||||||
|
return $http.get('/api/Maintenance', {}).then(function (data) {
|
||||||
|
return data;
|
||||||
|
});
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
from pyramid.events import subscriber, NewRequest
|
from pyramid.events import subscriber, NewRequest
|
||||||
|
from pyramid.httpexceptions import HTTPServiceUnavailable
|
||||||
|
from brewman.models.master import DbSetting
|
||||||
|
|
||||||
|
|
||||||
@subscriber(NewRequest)
|
@subscriber(NewRequest)
|
||||||
def csrf_validation(event):
|
def maintenance_mode(event):
|
||||||
pass
|
maintenance = DbSetting.by_name('Maintenance')
|
||||||
# print(event.request.method, event.request.url, event.request.query_string)
|
if maintenance is not None and maintenance.data != event.request.authenticated_userid:
|
||||||
# if event.request.method == "POST" and not event.request.is_xhr:
|
raise HTTPServiceUnavailable
|
||||||
# token = event.request.POST.get("_csrf")
|
|
||||||
# print('CSRF POST token is ' + token + ' vs Server ' + event.request.session.get_csrf_token())
|
|
||||||
|
|
||||||
# if token is None or token != event.request.session.get_csrf_token():
|
|
||||||
# raise HTTPForbidden('CSRF token is missing or invalid ' + token + ' Original ' + event.request.session.get_csrf_token())
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from pyramid.response import FileResponse
|
from pyramid.response import FileResponse
|
||||||
|
|
||||||
from pyramid.view import view_config
|
from pyramid.view import view_config
|
||||||
import transaction
|
import transaction
|
||||||
from brewman.models import DBSession
|
|
||||||
|
|
||||||
|
from brewman.models import DBSession
|
||||||
|
from brewman.models.auth import User
|
||||||
from brewman.models.master import DbSetting
|
from brewman.models.master import DbSetting
|
||||||
from brewman.models.validation_exception import TryCatchFunction
|
from brewman.models.validation_exception import TryCatchFunction
|
||||||
|
|
||||||
|
@ -80,3 +81,30 @@ def get_lock_info(request):
|
||||||
else:
|
else:
|
||||||
info['Finish']['Date'] = data['Finish']['Date'].strftime('%d-%b-%Y')
|
info['Finish']['Date'] = data['Finish']['Date'].strftime('%d-%b-%Y')
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
@view_config(request_method='GET', route_name='api_maintenance', renderer='json', permission='Authenticated')
|
||||||
|
def get_maintenance(request):
|
||||||
|
data = DbSetting.by_name('Maintenance')
|
||||||
|
if data is None:
|
||||||
|
return {'Enabled': False, 'User': ''}
|
||||||
|
user = User.by_id(data.data)
|
||||||
|
return {'Enabled': True, 'User': user.name}
|
||||||
|
|
||||||
|
|
||||||
|
@view_config(request_method='POST', route_name='api_maintenance', renderer='json', permission='Maintenance')
|
||||||
|
@TryCatchFunction
|
||||||
|
def set_maintenance(request):
|
||||||
|
status = request.json_body['Enabled']
|
||||||
|
maintenance = DbSetting.by_name('Maintenance')
|
||||||
|
if status is False and maintenance is not None:
|
||||||
|
DBSession.delete(maintenance)
|
||||||
|
elif status is True and maintenance is None:
|
||||||
|
maintenance = DbSetting(name='Maintenance', data=request.authenticated_userid)
|
||||||
|
DBSession.add(maintenance)
|
||||||
|
elif status is True and maintenance.data != request.authenticated_userid:
|
||||||
|
maintenance.data = request.authenticated_userid
|
||||||
|
transaction.commit()
|
||||||
|
return get_maintenance(request)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue