basic acl checks
This commit is contained in:
parent
aa7250656f
commit
82432eaa04
4 changed files with 31 additions and 19 deletions
|
@ -30,22 +30,24 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><strong>{{'Event' | translate}}</strong></th>
|
<th><strong>{{'Event' | translate}}</strong></th>
|
||||||
<th class="hcenter"><strong>{{'Attendees / Registered' | translate}}</strong></th>
|
<th ng-if="hasPermission('event|update')" class="hcenter"><strong>{{'Attendees / Registered' | translate}}</strong></th>
|
||||||
<th><strong>{{'Delete' | translate}}</strong></th>
|
<th ng-if="hasPermission('event|update')"><strong>{{'Actions' | translate}}</strong></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="event in events | splittedFilter:query | orderBy:eventsOrderProp">
|
<tr ng-repeat="event in events | splittedFilter:query | orderBy:eventsOrderProp">
|
||||||
<td>
|
<td>
|
||||||
<span><strong><a ui-sref="event.info({id: event._id})">{{event.title}}</a></strong></span>
|
<span><strong>{{event.title}}</strong></span>
|
||||||
<p>{{'Begins:' | translate}} {{event['begin-date'] | date:'fullDate'}} {{event['begin-time'] | date:'HH:mm'}}<br/>
|
<p>{{'Begins:' | translate}} {{event['begin-date'] | date:'fullDate'}} {{event['begin-time'] | date:'HH:mm'}}<br/>
|
||||||
{{'Ends:' | translate}} {{event['end-date'] | date:'fullDate' }} {{event['end-time'] | date:'HH:mm'}}</p>
|
{{'Ends:' | translate}} {{event['end-date'] | date:'fullDate' }} {{event['end-time'] | date:'HH:mm'}}</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="hcenter">
|
<td ng-if="hasPermission('persons|read')" class="hcenter">
|
||||||
<p><span ng-init="attendeesNr = (event.persons | attendeesFilter).length">{{attendeesNr}}</span> / {{event.persons.length || 0}} ({{((attendeesNr / (event.persons.length || 0) * 100) || 0).toFixed()}}%)</p>
|
<p><span ng-init="attendeesNr = (event.persons | attendeesFilter).length">{{attendeesNr}}</span> / {{event.persons.length || 0}} ({{((attendeesNr / (event.persons.length || 0) * 100) || 0).toFixed()}}%)</p>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td ng-if="hasPermission('event|update')">
|
||||||
<button ng-click="remove(event._id)" type="button" class="btn btn-link fa fa-trash fa-lg"></button>
|
<button ng-if="hasPermission('ticket|create')" ng-click="$state.go('ticket.new', {id: event._id})" class="btn btn-link fa fa-user-plus" type="button" title="{{'Register' | translate}}"></button>
|
||||||
|
<button ng-if="hasPermission('persons|update')" ng-click="$state.go('event.info', {id: event._id})" class="btn btn-link fa fa-list" type="button" title="{{'Manage attendees' | translate}}"></button>
|
||||||
|
<button ng-if="hasPermission('event|delete')" ng-click="remove(event._id)" type="button" class="btn btn-link fa fa-trash fa-lg" title="{{'Delete' | translate}}"></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -52,8 +52,7 @@
|
||||||
<div ng-if="logo.imgURL" class="navbar-brand"><a ng-if="logo.link" href="{{logo.link}}" target="_blank"><img src="{{logo.imgURL}}" /></a></div>
|
<div ng-if="logo.imgURL" class="navbar-brand"><a ng-if="logo.link" href="{{logo.link}}" target="_blank"><img src="{{logo.imgURL}}" /></a></div>
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li ng-class="{active: isActive('/events') || isActive('/event')}"><a ui-sref="events">{{'Events' | translate}}</a></li>
|
<li ng-class="{active: isActive('/events') || isActive('/event')}"><a ui-sref="events">{{'Events' | translate}}</a></li>
|
||||||
<!-- li ng-if="hasPermission('persons|read')" ng-class="{active: isActive('/persons') || isActive('/person') || isActive('/import/persons')}"><a ui-sref="persons">{{'Persons' | translate}}</a></li -->
|
<li ng-if="hasPermission('persons|read')" ng-class="{active: isActive('/persons') || isActive('/person') || isActive('/import/persons')}"><a ui-sref="persons">{{'Persons' | translate}}</a></li>
|
||||||
<li ng-class="{active: isActive('/persons') || isActive('/person') || isActive('/import/persons')}"><a ui-sref="persons">{{'Persons' | translate}}</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse navbar-collapse">
|
<div class="collapse navbar-collapse">
|
||||||
|
|
1
angular_app/js/app.js
vendored
1
angular_app/js/app.js
vendored
|
@ -73,7 +73,6 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
|
||||||
granted = true;
|
granted = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return granted;
|
return granted;
|
||||||
|
|
|
@ -141,9 +141,7 @@ class BaseHandler(tornado.web.RequestHandler):
|
||||||
:returns: True if the user is allowed to perform the action or False
|
:returns: True if the user is allowed to perform the action or False
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
user_info = self.current_user_info
|
user_info = self.current_user_info or {}
|
||||||
if not user_info:
|
|
||||||
return False
|
|
||||||
user_permissions = user_info.get('permissions') or []
|
user_permissions = user_info.get('permissions') or []
|
||||||
global_permission = '%s|all' % permission.split('|')[0]
|
global_permission = '%s|all' % permission.split('|')[0]
|
||||||
if 'admin|all' in user_permissions or global_permission in user_permissions or permission in user_permissions:
|
if 'admin|all' in user_permissions or global_permission in user_permissions or permission in user_permissions:
|
||||||
|
@ -263,11 +261,11 @@ class CollectionHandler(BaseHandler):
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
@authenticated
|
@authenticated
|
||||||
def get(self, id_=None, resource=None, resource_id=None, **kwargs):
|
def get(self, id_=None, resource=None, resource_id=None, acl=True, **kwargs):
|
||||||
if resource:
|
if resource:
|
||||||
# Handle access to sub-resources.
|
# Handle access to sub-resources.
|
||||||
permission = '%s:%s|read' % (self.document, resource)
|
permission = '%s:%s|read' % (self.document, resource)
|
||||||
if not self.has_permission(permission):
|
if acl and not self.has_permission(permission):
|
||||||
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
|
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
|
||||||
method = getattr(self, 'handle_get_%s' % resource, None)
|
method = getattr(self, 'handle_get_%s' % resource, None)
|
||||||
if method and callable(method):
|
if method and callable(method):
|
||||||
|
@ -276,7 +274,7 @@ class CollectionHandler(BaseHandler):
|
||||||
if id_ is not None:
|
if id_ is not None:
|
||||||
# read a single document
|
# read a single document
|
||||||
permission = '%s|read' % self.document
|
permission = '%s|read' % self.document
|
||||||
if not self.has_permission(permission):
|
if acl and not self.has_permission(permission):
|
||||||
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
|
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
|
||||||
self.write(self.db.get(self.collection, id_))
|
self.write(self.db.get(self.collection, id_))
|
||||||
else:
|
else:
|
||||||
|
@ -285,9 +283,9 @@ class CollectionHandler(BaseHandler):
|
||||||
# Please, never return JSON lists that are not encapsulated into an object,
|
# Please, never return JSON lists that are not encapsulated into an object,
|
||||||
# to avoid XSS vulnerabilities.
|
# to avoid XSS vulnerabilities.
|
||||||
permission = '%s|read' % self.collection
|
permission = '%s|read' % self.collection
|
||||||
if not self.has_permission(permission):
|
if acl and not self.has_permission(permission):
|
||||||
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
|
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
|
||||||
self.write({self.collection: self.db.query(self.collection)})
|
self.write({self.collection: self.db.query(self.collection, self.arguments)})
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
@authenticated
|
@authenticated
|
||||||
|
@ -423,6 +421,7 @@ class PersonsHandler(CollectionHandler):
|
||||||
document = 'person'
|
document = 'person'
|
||||||
collection = 'persons'
|
collection = 'persons'
|
||||||
object_id = 'person_id'
|
object_id = 'person_id'
|
||||||
|
permissions = {}
|
||||||
|
|
||||||
def handle_get_events(self, id_, resource_id=None, **kwargs):
|
def handle_get_events(self, id_, resource_id=None, **kwargs):
|
||||||
# Get a list of events attended by this person.
|
# Get a list of events attended by this person.
|
||||||
|
@ -563,6 +562,16 @@ class EventsHandler(CollectionHandler):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class TicketsHandler(CollectionHandler):
|
||||||
|
"""Handle requests for Tickets."""
|
||||||
|
document = 'ticket'
|
||||||
|
collection = 'tickets'
|
||||||
|
object_id = 'ticket_id'
|
||||||
|
permissions = {
|
||||||
|
'ticket|read': True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class EbCSVImportPersonsHandler(BaseHandler):
|
class EbCSVImportPersonsHandler(BaseHandler):
|
||||||
"""Importer for CSV files exported from eventbrite."""
|
"""Importer for CSV files exported from eventbrite."""
|
||||||
csvRemap = {
|
csvRemap = {
|
||||||
|
@ -689,7 +698,7 @@ class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler):
|
||||||
try:
|
try:
|
||||||
if self in _ws_clients.get(self._clean_url(self.request.uri), []):
|
if self in _ws_clients.get(self._clean_url(self.request.uri), []):
|
||||||
_ws_clients[self._clean_url(self.request.uri)].remove(self)
|
_ws_clients[self._clean_url(self.request.uri)].remove(self)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
logging.warn('WebSocketEventUpdatesHandler.on_close error closing websocket: %s', str(e))
|
logging.warn('WebSocketEventUpdatesHandler.on_close error closing websocket: %s', str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@ -810,11 +819,14 @@ def run():
|
||||||
_ws_handler = (r"/ws/+event/+(?P<event_id>\w+)/+updates/?", WebSocketEventUpdatesHandler)
|
_ws_handler = (r"/ws/+event/+(?P<event_id>\w+)/+updates/?", WebSocketEventUpdatesHandler)
|
||||||
_persons_path = r"/persons/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
|
_persons_path = r"/persons/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
|
||||||
_events_path = r"/events/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
|
_events_path = r"/events/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
|
||||||
|
_tickets_path = r"/tickets/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
|
||||||
application = tornado.web.Application([
|
application = tornado.web.Application([
|
||||||
(_persons_path, PersonsHandler, init_params),
|
(_persons_path, PersonsHandler, init_params),
|
||||||
(r'/v%s%s' % (API_VERSION, _persons_path), PersonsHandler, init_params),
|
(r'/v%s%s' % (API_VERSION, _persons_path), PersonsHandler, init_params),
|
||||||
(_events_path, EventsHandler, init_params),
|
(_events_path, EventsHandler, init_params),
|
||||||
(r'/v%s%s' % (API_VERSION, _events_path), EventsHandler, init_params),
|
(r'/v%s%s' % (API_VERSION, _events_path), EventsHandler, init_params),
|
||||||
|
(_tickets_path, TicketsHandler, init_params),
|
||||||
|
(r'/v%s%s' % (API_VERSION, _tickets_path), TicketsHandler, init_params),
|
||||||
(r"/(?:index.html)?", RootHandler, init_params),
|
(r"/(?:index.html)?", RootHandler, init_params),
|
||||||
(r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params),
|
(r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params),
|
||||||
(r"/settings", SettingsHandler, init_params),
|
(r"/settings", SettingsHandler, init_params),
|
||||||
|
@ -841,7 +853,7 @@ def run():
|
||||||
http_server.listen(options.port, options.address)
|
http_server.listen(options.port, options.address)
|
||||||
|
|
||||||
# Also listen on options.port+1 for our local ws connection.
|
# Also listen on options.port+1 for our local ws connection.
|
||||||
ws_application = tornado.web.Application([_ws_handler,], debug=options.debug)
|
ws_application = tornado.web.Application([_ws_handler], debug=options.debug)
|
||||||
ws_http_server = tornado.httpserver.HTTPServer(ws_application)
|
ws_http_server = tornado.httpserver.HTTPServer(ws_application)
|
||||||
ws_http_server.listen(options.port+1, address='127.0.0.1')
|
ws_http_server.listen(options.port+1, address='127.0.0.1')
|
||||||
logger.debug('Starting WebSocket on ws://127.0.0.1:%d', options.port+1)
|
logger.debug('Starting WebSocket on ws://127.0.0.1:%d', options.port+1)
|
||||||
|
|
Loading…
Reference in a new issue