Merge pull request #173 from alberanid/master

grant super cow powers to users
This commit is contained in:
Davide Alberani 2017-04-03 22:17:08 +02:00 committed by GitHub
commit a448d15481
5 changed files with 50 additions and 16 deletions

View file

@ -94,7 +94,6 @@ Notes on some special features
Some notes about the event registration form:
- field names are important (case is not considered). You can use whatever you want, but "name", "surname" and "email" are internally used to show the tickets list, so please add at least one of them
- please notice that the "Email" field type has a very silly regular expression and will create a lot of problems: please use "Text input" and names the field "Email"
About the "Group ID" of events and "Unregistered persons" list:
- "Group ID" is a random non-guessable identifier associated to an event. You can use whatever you want; if left empty, it will be autogenerated. It's not the same as the Event ID (the \_id key in the db): the Group ID is supposed to be secret

11
angular_app/js/app.js vendored
View file

@ -75,16 +75,19 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
}
};
/* Check GUI privileges. */
$rootScope.hasPermission = function(permission) {
if (!($rootScope.info && $rootScope.info.user && $rootScope.info.user.permissions)) {
/* Check privileges of the currently logged in user or of the one specified with the second parameter. */
$rootScope.hasPermission = function(permission, user) {
if (!(user || ($rootScope.info && $rootScope.info.user && $rootScope.info.user.permissions))) {
return false;
}
if (!user) {
user = $rootScope.info.user;
}
var granted = false;
var splitted_permission = permission.split('|');
var global_permission = splitted_permission[0] + '|all';
angular.forEach($rootScope.info.user.permissions || [],
angular.forEach(user.permissions || [],
function(value, idx) {
if (value === 'admin|all' || value === global_permission || value === permission) {
granted = true;

View file

@ -687,6 +687,7 @@ eventManControllers.controller('UsersCtrl', ['$scope', '$rootScope', '$state', '
if ($state.is('user.edit') && $state.params.id) {
$scope.user = User.get({id: $state.params.id}, function() {
$scope.updateUserInfo = $scope.user;
$scope.updateUserInfo.isAdmin = $rootScope.hasPermission('admin|all', $scope.updateUserInfo);
});
}

View file

@ -20,6 +20,11 @@
<span class="input-group-addon min150">{{'New password' | translate}}</span>
<input type="password" id="new-password" name="new-password" ng-model="updateUserInfo.new_password" class="form-control">
</div>
<div class="checkbox">
<label>
<input type="checkbox" ng-model="updateUserInfo.isAdmin"> {{'is admin' | translate}}
</label>
</div>
<button type="submit" ng-click="updateUser()" class="btn btn-success top10">{{'update' | translate}}</button>
</form>
</div>

View file

@ -191,6 +191,23 @@ class BaseHandler(tornado.web.RequestHandler):
self._users_cache[current_user] = user_info
return user_info
def add_access_info(self, doc):
"""Add created/updated by/at to a document (modified in place and returned).
:param doc: the doc to be updated
:type doc: dict
:returns: the updated document
:rtype: dict"""
user_id = self.current_user
now = datetime.datetime.utcnow()
if 'created_by' not in doc:
doc['created_by'] = user_id
if 'created_at' not in doc:
doc['created_at'] = now
doc['updated_by'] = user_id
doc['updated_at'] = now
return doc
def has_permission(self, permission):
"""Check permissions of the current user.
@ -343,7 +360,8 @@ class CollectionHandler(BaseHandler):
:type data: dict"""
if isinstance(data, dict):
for key in list(data.keys()):
if isinstance(key, str) and key.startswith('$'):
if (isinstance(key, str) and key.startswith('$')) or key in ('_id', 'created_by', 'created_at',
'updated_by', 'updated_at', 'isRegistered'):
del data[key]
return data
@ -419,17 +437,12 @@ class CollectionHandler(BaseHandler):
self._clean_dict(data)
method = self.request.method.lower()
crud_method = 'create' if method == 'post' else 'update'
now = datetime.datetime.now()
user_info = self.current_user_info
user_id = user_info.get('_id')
env = {}
if id_ is not None:
env['%s_ID' % self.document.upper()] = id_
if crud_method == 'create':
data['created_by'] = user_id
data['created_at'] = now
data['updated_by'] = user_id
data['updated_at'] = now
self.add_access_info(data)
if resource:
permission = '%s:%s%s|%s' % (self.document, resource, '-all' if resource_id is None else '', crud_method)
if not self.has_permission(permission):
@ -633,6 +646,7 @@ class EventsHandler(CollectionHandler):
if not self.has_permission('event|update'):
if 'attended' in data:
del data['attended']
self.add_access_info(data)
return data
filter_input_put_tickets = filter_input_post_tickets
@ -745,6 +759,7 @@ class EventsHandler(CollectionHandler):
data['seq'] = self.get_next_seq('event_%s_tickets' % id_)
data['seq_hex'] = '%06X' % data['seq']
data['_id'] = ticket_id = self.gen_id()
self.add_access_info(data)
ret = {'action': 'add', 'ticket': data, 'uuid': uuid}
merged, doc = self.db.update('events',
{'_id': id_},
@ -790,6 +805,7 @@ class EventsHandler(CollectionHandler):
if 'number_of_tickets' in current_event and old_ticket_data.get('cancelled') and not data.get('cancelled'):
self._check_number_of_tickets(current_event)
self.add_access_info(data)
merged, doc = self.db.update('events', query,
data, updateList='tickets', create=False)
new_ticket_data = self._get_ticket_data(ticket_query,
@ -909,9 +925,18 @@ class UsersHandler(CollectionHandler):
del data['_id']
if 'username' in data:
del data['username']
# for the moment, prevent the ability to update permissions via web
if 'permissions' in data:
del data['permissions']
if not self.has_permission('admin|all'):
if 'permissions' in data:
del data['permissions']
else:
if 'isAdmin' in data:
if not 'permissions' in data:
data['permissions'] = []
if 'admin|all' in data['permissions'] and not data['isAdmin']:
data['permissions'].remove('admin|all')
elif 'admin|all' not in data['permissions'] and data['isAdmin']:
data['permissions'].append('admin|all')
del data['isAdmin']
return data
@gen.coroutine
@ -991,6 +1016,7 @@ class EbCSVImportPersonsHandler(BaseHandler):
reply['valid'] += 1
person['attended'] = False
person['from_file'] = filename
self.add_access_info(person)
duplicate_check = '%s_%s_%s' % (person.get('name'), person.get('surname'), person.get('email'))
if duplicate_check in all_emails:
continue
@ -1197,7 +1223,7 @@ def run():
ws_application = tornado.web.Application([_ws_handler], debug=options.debug)
ws_http_server = tornado.httpserver.HTTPServer(ws_application)
ws_http_server.listen(options.port+1, address='127.0.0.1')
logger.debug('Starting WebSocket on %s://127.0.0.1:%d', 'wss' if ssl_options else 'ws', options.port+1)
logger.debug('Starting WebSocket on ws://127.0.0.1:%d', options.port+1)
tornado.ioloop.IOLoop.instance().start()