unique IDs

This commit is contained in:
Davide Alberani 2016-06-06 21:44:04 +02:00
parent 6a0f62cc60
commit 9596922b7d
7 changed files with 81 additions and 61 deletions

View file

@ -31,25 +31,25 @@
<tr>
<th><strong>{{'Event' | translate}}</strong></th>
<th ng-if="hasPermission('event|update')" class="hcenter"><strong>{{'Attendees / Registered' | translate}}</strong></th>
<th ng-if="hasPermission('event|update')"><strong>{{'Actions' | translate}}</strong></th>
<th><strong>{{'Actions' | translate}}</strong></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="event in events | splittedFilter:query | orderBy:eventsOrderProp">
<td>
<span><strong>{{event.title}}</strong></span>
<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>
</td>
<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>
</td>
<td ng-if="hasPermission('event|update')">
<button ng-if="hasPermission('ticket|create')" ng-click="$state.go('event.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>
</tr>
<tr ng-repeat="event in events | splittedFilter:query | orderBy:eventsOrderProp">
<td>
<span><strong>{{event.title}}</strong></span>
<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>
</td>
<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>
</td>
<td>
<button ng-if="hasPermission('event:ticket|create')" ng-click="$state.go('event.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>
</tr>
</tbody>
</table>
</div>

View file

@ -59,13 +59,12 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
/* Check GUI privileges. */
$rootScope.hasPermission = function(permission) {
if (!($rootScope.info && $rootScope.info.user &&
$rootScope.info.user.username && $rootScope.info.user.permissions)) {
if (!($rootScope.info && $rootScope.info.user && $rootScope.info.user.permissions)) {
return false;
}
var granted = false;
var splitted_permission = permission.split('|');
var global_permission = splitted_permission + '|all';
var global_permission = splitted_permission[0] + '|all';
angular.forEach($rootScope.info.user.permissions || [],
function(value, idx) {

View file

@ -221,6 +221,21 @@ eventManControllers.controller('EventDetailsCtrl', ['$scope', '$state', 'Event',
return false;
}
$scope.event.persons.push(person);
};
$scope._addAttendee = function(person) {
person.person_id = person._id;
person._id = $stateParams.id; // that's the id of the event, not the person.
Event.addPerson(person, function() {
if (!$scope.newTicket) {
$scope._localAddAttendee(person);
}
});
$scope.query = '';
return person;
};
$scope._setAttended = function(person) {
$scope.setPersonAttribute(person, 'attended', true, function() {
var all_person_idx = $scope.allPersons.findIndex(function(el, idx, array) {
return person.person_id == el.person_id;
@ -228,18 +243,7 @@ eventManControllers.controller('EventDetailsCtrl', ['$scope', '$state', 'Event',
if (all_person_idx != -1) {
$scope.allPersons.splice(all_person_idx, 1);
}
}, hideMessage);
};
$scope._addAttendee = function(person) {
person.person_id = person._id;
person._id = $stateParams.id;
Event.addPerson(person, function() {
if (!$scope.newTicket) {
$scope._localAddAttendee(person);
}
});
$scope.query = '';
}, true);
};
$scope.fastAddAttendee = function(person, isNew) {
@ -248,14 +252,24 @@ eventManControllers.controller('EventDetailsCtrl', ['$scope', '$state', 'Event',
if (isNew) {
var personObj = new Person(person);
personObj.$save(function(p) {
$scope._addAttendee(angular.copy(p));
person = $scope._addAttendee(angular.copy(p));
if (!$scope.newTicket) {
$scope._setAttended(person);
}
$scope.newPerson = {};
});
} else {
$scope._addAttendee(angular.copy(person));
person = $scope._addAttendee(angular.copy(person));
if (!$scope.newTicket) {
$scope._setAttended(person);
}
}
};
$scope.addRegisteredPerson = function(person) {
$scope.fastAddAttendee(person, true);
};
$scope.setPersonAttribute = function(person, key, value, callback, hideMessage) {
$log.debug('EventDetailsCtrl.setPersonAttribute.event_id: ' + $stateParams.id);
$log.debug('EventDetailsCtrl.setPersonAttribute.person_id: ' + person.person_id);

View file

@ -32,6 +32,7 @@ eventManServices.factory('Event', ['$resource', '$rootScope',
angular.forEach(data.events || [], function(event_, event_idx) {
convert_dates(event_);
});
return data.events;
}
},

View file

@ -37,7 +37,7 @@
<input name="job_title" class="form-control" placeholder="{{'Evil Ruler' | translate}}" ng-model="newPerson.job_title">
</div>
<button reset-focus ng-disabled="!(newPerson.name && newPerson.surname)" ng-click="fastAddAttendee(newPerson, true)" class="btn btn-success top5">
<button reset-focus ng-disabled="!(newPerson.name && newPerson.surname)" ng-click="addRegisteredPerson(newPerson, true)" class="btn btn-success top5">
<span class="fa fa-plus-circle vcenter"></span>
{{'Add' | translate}}
</button>

View file

@ -146,19 +146,23 @@ class EventManDB(object):
query = convert(query or {})
return list(db[collection].find(query))
def add(self, collection, data):
def add(self, collection, data, _id=None):
"""Insert a new document.
:param collection: insert the document in this collection
:type collection: str
:param data: the document to store
:type data: dict
:param _id: the _id of the document to store; if None, it's generated
:type _id: object
:return: the document, as created in the database
:rtype: dict
"""
db = self.connect()
data = convert(data)
if _id is not None:
data['_id'] = _id
_id = db[collection].insert(data)
return self.get(collection, _id)

View file

@ -21,6 +21,9 @@ import os
import re
import glob
import json
import time
import string
import random
import logging
import datetime
@ -62,7 +65,13 @@ def authenticated(method):
class BaseHandler(tornado.web.RequestHandler):
"""Base class for request handlers."""
permissions = {}
permissions = {
'event|read': True,
'events|read': True,
'event:ticket|all': True,
'event:persons|all': True,
'person|create': True
}
# A property to access the first value of each argument.
arguments = property(lambda self: dict([(k, v[0])
@ -122,15 +131,15 @@ class BaseHandler(tornado.web.RequestHandler):
@property
def current_user_info(self):
current_user = self.current_user
user_info = {'permissions': set([k for (k, v) in self.permissions.iteritems() if v is True])}
if current_user:
user_info = {}
user_info['username'] = current_user
res = self.db.query('users', {'username': current_user})
if res:
user = res[0]
user_info['permissions'] = user.get('permissions') or []
return user_info
return {}
user_info['permissions'].update(set(user.get('permissions') or []))
user_info['permissions'] = list(user_info['permissions'])
return user_info
def has_permission(self, permission):
"""Check permissions of the current user.
@ -188,6 +197,8 @@ class CollectionHandler(BaseHandler):
# set of documents used to store incremental sequences
counters_collection = 'counters'
_id_chars = string.ascii_lowercase + string.digits
def get_next_seq(self, seq):
"""Increment and return the new value of a ever-incrementing counter.
@ -205,6 +216,12 @@ class CollectionHandler(BaseHandler):
operation='increment')
return doc.get('seq', 0)
def gen_id(self, seq='ids'):
t = str(time.time())
seq = str(self.get_next_seq(seq)).replace('.', '_')
rand = ''.join([random.choice(self._id_chars) for x in xrange(32)])
return '-'.join((t, seq, rand))
def _filter_results(self, results, params):
"""Filter a list using keys and values from a dictionary.
@ -306,7 +323,7 @@ class CollectionHandler(BaseHandler):
permission = '%s|%s' % (self.document, 'create' if method == 'post' else 'update')
if not self.has_permission(permission):
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
newData = self.db.add(self.collection, data)
newData = self.db.add(self.collection, data, _id=self.gen_id())
else:
permission = '%s|%s' % (self.collection, 'create' if method == 'post' else 'update')
if not self.has_permission(permission):
@ -421,7 +438,6 @@ class PersonsHandler(CollectionHandler):
document = 'person'
collection = 'persons'
object_id = 'person_id'
permissions = {}
def handle_get_events(self, id_, resource_id=None, **kwargs):
# Get a list of events attended by this person.
@ -459,9 +475,6 @@ class EventsHandler(CollectionHandler):
document = 'event'
collection = 'events'
object_id = 'event_id'
permissions = {
'events|read': True
}
def _get_person_data(self, person_id_or_query, persons):
"""Filter a list of persons returning the first item with a given person_id
@ -498,6 +511,7 @@ class EventsHandler(CollectionHandler):
del data['_id']
self.send_ws_message('event/%s/updates' % id_, json.dumps(ret))
if not doc:
data['_id'] = self.gen_id()
merged, doc = self.db.update('events',
{'_id': id_},
{'persons': data},
@ -562,16 +576,6 @@ class EventsHandler(CollectionHandler):
return ret
class TicketsHandler(CollectionHandler):
"""Handle requests for Tickets."""
document = 'ticket'
collection = 'tickets'
object_id = 'ticket_id'
permissions = {
'ticket|read': True
}
class EbCSVImportPersonsHandler(BaseHandler):
"""Importer for CSV files exported from eventbrite."""
csvRemap = {
@ -816,17 +820,15 @@ def run():
db_connector.add('settings',
{'setting': 'server_cookie_secret', 'cookie_secret': cookie_secret})
_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+)?"
_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+)?"
_ws_handler = (r"/ws/+event/+(?P<event_id>[\w\d_-]+)/+updates/?", WebSocketEventUpdatesHandler)
_persons_path = r"/persons/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
_events_path = r"/events/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
_events_path = r"/events/?(?P<id_>[\w\d_-]+)?/?(?P<resource>[\w\d_-]+)?/?(?P<resource_id>[\w\d_-]+)?"
application = tornado.web.Application([
(_persons_path, PersonsHandler, init_params),
(r'/v%s%s' % (API_VERSION, _persons_path), PersonsHandler, init_params),
(_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"/ebcsvpersons", EbCSVImportPersonsHandler, init_params),
(r"/settings", SettingsHandler, init_params),