unique IDs
This commit is contained in:
parent
6a0f62cc60
commit
9596922b7d
7 changed files with 81 additions and 61 deletions
|
@ -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>
|
||||
|
|
5
angular_app/js/app.js
vendored
5
angular_app/js/app.js
vendored
|
@ -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) {
|
||||
|
|
42
angular_app/js/controllers.js
vendored
42
angular_app/js/controllers.js
vendored
|
@ -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);
|
||||
|
|
1
angular_app/js/services.js
vendored
1
angular_app/js/services.js
vendored
|
@ -32,6 +32,7 @@ eventManServices.factory('Event', ['$resource', '$rootScope',
|
|||
angular.forEach(data.events || [], function(event_, event_idx) {
|
||||
convert_dates(event_);
|
||||
});
|
||||
|
||||
return data.events;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in a new issue