improve permissions

This commit is contained in:
Davide Alberani 2016-07-09 17:41:16 +02:00
parent bb3fb40995
commit a27f9b0db9
5 changed files with 34 additions and 20 deletions

View file

@ -5,7 +5,7 @@
<h1> <h1>
{{event.title}} {{event.title}}
<span ng-if="hasPermission('event|create') && !event._id">{{'New event' | translate}}</span> <span ng-if="hasPermission('event|create') && !event._id">{{'New event' | translate}}</span>
&nbsp;<button ng-if="event._id && hasPermission('tickets-all|read')" ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-success"> &nbsp;<button ng-if="event._id && hasPermission('event:tickets-all|read')" ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-success">
<span class="fa fa-ticket vcenter"></span> <span class="fa fa-ticket vcenter"></span>
{{'Tickets' | translate}} {{'Tickets' | translate}}
</button> </button>

View file

@ -47,11 +47,11 @@
<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 ng-if="hasPermission('tickets-all|read')" class="hcenter"> <td ng-if="hasPermission('event:tickets-all|read')" class="hcenter">
<p><span ng-init="attendeesNr = ((event.tickets || []) | attendeesFilter).length">{{attendeesNr}}</span> / {{((event.tickets || []) | registeredFilter).length}} ({{((attendeesNr / ((event.tickets || []) | registeredFilter).length * 100) || 0).toFixed()}}%)</p> <p><span ng-init="attendeesNr = ((event.tickets || []) | attendeesFilter).length">{{attendeesNr}}</span> / {{((event.tickets || []) | registeredFilter).length}} ({{((attendeesNr / ((event.tickets || []) | registeredFilter).length * 100) || 0).toFixed()}}%)</p>
</td> </td>
<td> <td>
<button ng-if="hasPermission('event:tickets|create')" ng-click="$state.go('event.ticket.new', {id: event._id})" class="btn btn-link fa fa-user-plus" type="button" title="{{'Join this event' | translate}}"></button> <button ng-if="hasPermission('event:tickets-all|create')" ng-click="$state.go('event.ticket.new', {id: event._id})" class="btn btn-link fa fa-user-plus" type="button" title="{{'Join this event' | translate}}"></button>
<button ng-if="hasPermission('tickets|update')" ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-link fa fa-list" type="button" title="{{'Manage attendees' | translate}}"></button> <button ng-if="hasPermission('tickets|update')" ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-link fa fa-list" type="button" title="{{'Manage attendees' | translate}}"></button>
<button ng-if="hasPermission('event|update')" ng-click="$state.go('event.edit', {id: event._id})" type="button" class="btn btn-link fa fa-cog fa-lg" title="{{'Edit' | translate}}"></button> <button ng-if="hasPermission('event|update')" ng-click="$state.go('event.edit', {id: event._id})" type="button" class="btn btn-link fa fa-cog fa-lg" title="{{'Edit' | 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> <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>

View file

@ -312,6 +312,9 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
}; };
$scope._localUpdateTicket = function(ticket) { $scope._localUpdateTicket = function(ticket) {
if (!$state.is('event.tickets')) {
return;
}
if (!$scope.event.tickets) { if (!$scope.event.tickets) {
$scope.event.tickets = []; $scope.event.tickets = [];
} }
@ -362,19 +365,22 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
if (!(data && data._id && data.ticket)) { if (!(data && data._id && data.ticket)) {
return; return;
} }
if (callback) {
callback(data);
}
if (!$state.is('event.tickets')) {
return;
}
var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) { var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
return data._id == el._id; return data._id == el._id;
}); });
if (ticket_idx == -1) { if (ticket_idx == -1) {
$log.warn('unable to find ticket _id ' + _id); $log.warn('unable to find ticket _id ' + data._id);
return; return;
} }
if ($scope.event.tickets[ticket_idx] != data.ticket) { if ($scope.event.tickets[ticket_idx] != data.ticket) {
$scope.event.tickets[ticket_idx] = data.ticket; $scope.event.tickets[ticket_idx] = data.ticket;
} }
if (callback) {
callback(data);
}
if (key === 'attended' && !hideMessage) { if (key === 'attended' && !hideMessage) {
var msg = {}; var msg = {};
if (value) { if (value) {

View file

@ -20,7 +20,7 @@
<span class="fa fa-calendar vcenter"></span> <span class="fa fa-calendar vcenter"></span>
{{'Edit event' | translate}} {{'Edit event' | translate}}
</button> </button>
&nbsp;<button ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-success" ng-if="event._id && hasPermission('tickets-all|read')"> &nbsp;<button ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-success" ng-if="event._id && hasPermission('event:tickets-all|read')">
<span class="fa fa-ticket vcenter"></span> <span class="fa fa-ticket vcenter"></span>
{{'Tickets' | translate}} {{'Tickets' | translate}}
</button> </button>

View file

@ -46,9 +46,12 @@ API_VERSION = '1.0'
re_env_key = re.compile('[^A-Z_]+') re_env_key = re.compile('[^A-Z_]+')
re_slashes = re.compile(r'//+') re_slashes = re.compile(r'//+')
# Keep track of WebSocket connections.
_ws_clients = {}
def authenticated(method): def authenticated(method):
"""Decorator to handle authentication.""" """Decorator to handle forced authentication."""
original_wrapper = tornado.web.authenticated(method) original_wrapper = tornado.web.authenticated(method)
@tornado.web.functools.wraps(method) @tornado.web.functools.wraps(method)
def my_wrapper(self, *args, **kwargs): def my_wrapper(self, *args, **kwargs):
@ -85,7 +88,9 @@ class BaseHandler(tornado.web.RequestHandler):
"""Base class for request handlers.""" """Base class for request handlers."""
permissions = { permissions = {
'event|read': True, 'event|read': True,
'event:tickets|all': True, 'event:tickets|read': True,
'event:tickets|create': True,
'event:tickets|update': True,
'event:tickets-all|create': True, 'event:tickets-all|create': True,
'events|read': True, 'events|read': True,
'users|create': True 'users|create': True
@ -228,7 +233,13 @@ class BaseHandler(tornado.web.RequestHandler):
return (False, {}) return (False, {})
def build_error(self, message='', status=400): def build_error(self, message='', status=400):
"""Build and write an error message.""" """Build and write an error message.
:param message: textual message
:type message: str
:param status: HTTP status code
:type status: int
"""
self.set_status(status) self.set_status(status)
self.write({'error': True, 'message': message}) self.write({'error': True, 'message': message})
@ -250,9 +261,6 @@ class RootHandler(BaseHandler):
self.write(fd.read()) self.write(fd.read())
# Keep track of WebSocket connections.
_ws_clients = {}
class CollectionHandler(BaseHandler): class CollectionHandler(BaseHandler):
"""Base class for handlers that need to interact with the database backend. """Base class for handlers that need to interact with the database backend.
@ -856,7 +864,7 @@ class SettingsHandler(BaseHandler):
"""Handle requests for Settings.""" """Handle requests for Settings."""
@gen.coroutine @gen.coroutine
@authenticated @authenticated
def get(self, **kwds): def get(self, **kwargs):
query = self.arguments_tobool() query = self.arguments_tobool()
settings = self.db.query('settings', query) settings = self.db.query('settings', query)
self.write({'settings': settings}) self.write({'settings': settings})
@ -865,7 +873,7 @@ class SettingsHandler(BaseHandler):
class InfoHandler(BaseHandler): class InfoHandler(BaseHandler):
"""Handle requests for information about the logged in user.""" """Handle requests for information about the logged in user."""
@gen.coroutine @gen.coroutine
def get(self, **kwds): def get(self, **kwargs):
info = {} info = {}
user_info = self.current_user_info user_info = self.current_user_info
if user_info: if user_info:
@ -879,7 +887,7 @@ class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler):
def _clean_url(self, url): def _clean_url(self, url):
return re_slashes.sub('/', url) return re_slashes.sub('/', url)
def open(self, event_id, *args, **kwds): def open(self, event_id, *args, **kwargs):
logging.debug('WebSocketEventUpdatesHandler.on_open event_id:%s' % event_id) logging.debug('WebSocketEventUpdatesHandler.on_open event_id:%s' % event_id)
_ws_clients.setdefault(self._clean_url(self.request.uri), set()).add(self) _ws_clients.setdefault(self._clean_url(self.request.uri), set()).add(self)
logging.debug('WebSocketEventUpdatesHandler.on_open %s clients connected' % len(_ws_clients)) logging.debug('WebSocketEventUpdatesHandler.on_open %s clients connected' % len(_ws_clients))
@ -907,7 +915,7 @@ class LoginHandler(RootHandler):
"""Handle user authentication requests.""" """Handle user authentication requests."""
@gen.coroutine @gen.coroutine
def get(self, **kwds): def get(self, **kwargs):
# show the login page # show the login page
if self.is_api(): if self.is_api():
self.set_status(401) self.set_status(401)
@ -943,7 +951,7 @@ class LoginHandler(RootHandler):
class LogoutHandler(BaseHandler): class LogoutHandler(BaseHandler):
"""Handle user logout requests.""" """Handle user logout requests."""
@gen.coroutine @gen.coroutine
def get(self, **kwds): def get(self, **kwargs):
# log the user out # log the user out
logging.info('logout') logging.info('logout')
self.logout() self.logout()
@ -1020,7 +1028,7 @@ def run():
template_path=os.path.join(os.path.dirname(__file__), "templates"), template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"), static_path=os.path.join(os.path.dirname(__file__), "static"),
cookie_secret='__COOKIE_SECRET__', cookie_secret='__COOKIE_SECRET__',
login_url='/#/login', login_url='/login',
debug=options.debug) debug=options.debug)
ssl_options = {} ssl_options = {}
if os.path.isfile(options.ssl_key) and os.path.isfile(options.ssl_cert): if os.path.isfile(options.ssl_key) and os.path.isfile(options.ssl_cert):