From 9bace889d54f9898938f696912f16ec0e12e8941 Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sat, 4 Apr 2015 13:01:33 +0200 Subject: [PATCH 1/7] move registered persons into events collection --- angular_app/js/controllers.js | 8 ++--- angular_app/js/services.js | 2 ++ angular_app/person-detail.html | 12 +++---- backend.py | 30 +++++++++++++---- eventman_server.py | 61 +++++++++++++++++++++++++--------- 5 files changed, 81 insertions(+), 32 deletions(-) diff --git a/angular_app/js/controllers.js b/angular_app/js/controllers.js index 48c9018..e4271b7 100644 --- a/angular_app/js/controllers.js +++ b/angular_app/js/controllers.js @@ -74,13 +74,13 @@ eventManControllers.controller('PersonsListCtrl', ['$scope', 'Person', ); -eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', 'Person', 'Action', - function ($scope, $routeParams, Person, Action) { +eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', 'Person', + function ($scope, $routeParams, Person) { if ($routeParams.id) { $scope.person = Person.get($routeParams); - Action.get({person_id: $routeParams.id}, function(data) { + /* Action.get({person_id: $routeParams.id}, function(data) { $scope.actions = angular.fromJson(data).actions; - }); + }); */ } // store a new Person or update an existing one $scope.save = function() { diff --git a/angular_app/js/services.js b/angular_app/js/services.js index 4d3358f..b6ff1be 100644 --- a/angular_app/js/services.js +++ b/angular_app/js/services.js @@ -3,11 +3,13 @@ /* Services that are used to interact with the backend. */ var eventManServices = angular.module('eventManServices', ['ngResource']); +/* eventManServices.factory('Action', ['$resource', function($resource) { return $resource('actions'); }] ); +*/ eventManServices.factory('Event', ['$resource', function($resource) { diff --git a/angular_app/person-detail.html b/angular_app/person-detail.html index c791b28..3fec012 100644 --- a/angular_app/person-detail.html +++ b/angular_app/person-detail.html @@ -20,18 +20,18 @@
-
Actions
+
Events
- - + + - - - + + +
ActionEvent IDEventAttended
{{action.action}}{{action.event_id}}
{{event.title}}action.event_id
diff --git a/backend.py b/backend.py index 78965d3..5eb4867 100644 --- a/backend.py +++ b/backend.py @@ -132,12 +132,12 @@ class EventManDB(object): ret = db[collection].update(data, {'$set': data}, upsert=True) return ret['updatedExisting'] - def update(self, collection, _id, data): + def update(self, collection, _id_or_query, data, operator='$set'): """Update an existing document. :param collection: update a document in this collection :type collection: str - :param _id: unique ID of the document to be updatd + :param _id: unique ID of the document to be updated :type _id: str or :class:`~bson.objectid.ObjectId` :param data: the updated information to store :type data: dict @@ -147,12 +147,29 @@ class EventManDB(object): """ db = self.connect() data = data or {} + if _id_or_query is None: + _id_or_query = {'_id': None} + elif isinstance(_id_or_query, (list, tuple)): + _id_or_query = {'$or': self.buildSearchPattern(data, _id_or_query)} + elif not isinstance(_id_or_query, dict): + _id_or_query = {'_id': self.toID(_id_or_query)} if '_id' in data: del data['_id'] - db[collection].update({'_id': self.toID(_id)}, {'$set': data}) - return self.get(collection, _id) + res = db[collection].find_and_modify(query=_id_or_query, + update={operator: data}, full_response=True, new=True,upsert=True) + lastErrorObject = res.get('lastErrorObject') or {} + return lastErrorObject.get('updatedExisting', False), res.get('value') or {} - def merge(self, collection, data, searchBy): + def buildSearchPattern(self, data, searchBy): + _or = [] + for searchPattern in searchBy: + try: + _or.append(dict([(k, data[k]) for k in searchPattern])) + except KeyError: + continue + return _or + + def merge(self, collection, data, searchBy, operator='$set'): """Update an existing document. :param collection: update a document in this collection @@ -172,7 +189,8 @@ class EventManDB(object): continue if not _or: return False, None - ret = db[collection].update({'$or': _or}, {'$set': data}, upsert=True) + # Two-steps merge/find to count the number of merged documents + ret = db[collection].update({'$or': _or}, {operator: data}, upsert=True) _id = ret.get('upserted') if _id is None: newDoc = db[collection].find_one(data) diff --git a/eventman_server.py b/eventman_server.py index 260a6b6..078f9b1 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -80,11 +80,9 @@ class CollectionHandler(BaseHandler): def post(self, id_=None, **kwargs): data = escape.json_decode(self.request.body or {}) if id_ is None: - # insert a new document newData = self.db.add(self.collection, data) else: - # update an existing document - newData = self.db.update(self.collection, id_, data) + merged, newData = self.db.update(self.collection, id_, data) self.write(newData) # PUT (update an existing document) is handled by the POST (create a new document) method @@ -98,19 +96,36 @@ class CollectionHandler(BaseHandler): class PersonsHandler(CollectionHandler): """Handle requests for Persons.""" collection = 'persons' + object_id = 'person_id' + connect_to = 'events' + connect_id = 'event_id' - def handle_events(self, _id, **kwds): - return {'events': []} + def _handle_actions(self, id_, action=None, **kwds): + print id_, kwds + self.request.arguments + query = {self.object_id: self.db.toID(id_)} + if action: + query['action'] = action + actions = self.db.query('actions', query) + + return {self.connect_to: results} + + def handle_registered(self, id_, **kwds): + return self._handle_actions(id_, 'registered', **kwds) class EventsHandler(CollectionHandler): """Handle requests for Events.""" collection = 'events' + object_id = 'event_id' + connect_to = 'persons' + connect_id = 'person_id' class ActionsHandler(CollectionHandler): """Handle requests for Actions.""" collection = 'actions' + object_id = 'action_id' def get(self, *args, **kwargs): params = self.request.arguments or {} @@ -131,14 +146,18 @@ class EbCSVImportPersonsHandler(BaseHandler): 'Cognome acquirente': 'surname', 'Nome acquirente': 'name', 'E-mail acquirente': 'email', - 'Cognome': 'original_surname', - 'Nome': 'original_name', - 'E-mail': 'original_email', + 'Cognome': 'surname', + 'Nome': 'name', + 'E-mail': 'email', 'Tipologia biglietto': 'ticket_kind', 'Data partecipazione': 'attending_datetime', 'Data check-in': 'checkin_datetime', 'Ordine n.': 'order_nr', + 'ID ordine': 'order_nr', + 'Prefisso (Sig., Sig.ra, ecc.)': 'name_title', } + keepPersonData = ('name', 'surname', 'email') + @gen.coroutine def post(self, **kwargs): targetEvent = None @@ -146,7 +165,7 @@ class EbCSVImportPersonsHandler(BaseHandler): targetEvent = self.get_body_argument('targetEvent') except: pass - reply = dict(total=0, valid=0, merged=0) + reply = dict(total=0, valid=0, merged=0, new_in_event=0) for fieldname, contents in self.request.files.iteritems(): for content in contents: filename = content['filename'] @@ -154,17 +173,27 @@ class EbCSVImportPersonsHandler(BaseHandler): reply['total'] += parseStats['total'] reply['valid'] += parseStats['valid'] for person in persons: - merged, _id = self.db.merge('persons', person, - searchBy=[('email',), ('name', 'surname')]) + person_data = dict([(k, person[k]) for k in self.keepPersonData + if k in person]) + merged, person = self.db.update('persons', + [('email',), ('name', 'surname')], + person_data) if merged: reply['merged'] += 1 - if targetEvent and _id: + if targetEvent and person: + event_id = self.db.toID(targetEvent) + person_id = self.db.toID(person['_id']) registered_data = { - 'event_id': self.db.toID(targetEvent), - 'person_id': self.db.toID(_id), - 'action': 'registered', + 'person_id': person_id, + 'attended': False, 'from_file': filename} - self.db.insertOne('actions', registered_data) + person.update(registered_data) + if not self.db.query('events', + {'_id': event_id, 'registered.person_id': person_id}): + self.db.update('events', {'_id': event_id}, + {'registered': person}, + operator='$addToSet') + reply['new_in_event'] += 1 self.write(reply) From 134dc550fc1c0afdd166db719708ee24195a3158 Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sat, 4 Apr 2015 13:18:20 +0200 Subject: [PATCH 2/7] remove actions collection --- angular_app/js/controllers.js | 3 --- angular_app/js/services.js | 7 ------- backend.py | 4 ++-- eventman_server.py | 33 --------------------------------- 4 files changed, 2 insertions(+), 45 deletions(-) diff --git a/angular_app/js/controllers.js b/angular_app/js/controllers.js index e4271b7..ce0f464 100644 --- a/angular_app/js/controllers.js +++ b/angular_app/js/controllers.js @@ -78,9 +78,6 @@ eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', ' function ($scope, $routeParams, Person) { if ($routeParams.id) { $scope.person = Person.get($routeParams); - /* Action.get({person_id: $routeParams.id}, function(data) { - $scope.actions = angular.fromJson(data).actions; - }); */ } // store a new Person or update an existing one $scope.save = function() { diff --git a/angular_app/js/services.js b/angular_app/js/services.js index b6ff1be..e9b4c7b 100644 --- a/angular_app/js/services.js +++ b/angular_app/js/services.js @@ -3,13 +3,6 @@ /* Services that are used to interact with the backend. */ var eventManServices = angular.module('eventManServices', ['ngResource']); -/* -eventManServices.factory('Action', ['$resource', - function($resource) { - return $resource('actions'); - }] -); -*/ eventManServices.factory('Event', ['$resource', function($resource) { diff --git a/backend.py b/backend.py index 5eb4867..651f79f 100644 --- a/backend.py +++ b/backend.py @@ -132,7 +132,7 @@ class EventManDB(object): ret = db[collection].update(data, {'$set': data}, upsert=True) return ret['updatedExisting'] - def update(self, collection, _id_or_query, data, operator='$set'): + def update(self, collection, _id_or_query, data, operator='$set', create=True): """Update an existing document. :param collection: update a document in this collection @@ -156,7 +156,7 @@ class EventManDB(object): if '_id' in data: del data['_id'] res = db[collection].find_and_modify(query=_id_or_query, - update={operator: data}, full_response=True, new=True,upsert=True) + update={operator: data}, full_response=True, new=True, upsert=create) lastErrorObject = res.get('lastErrorObject') or {} return lastErrorObject.get('updatedExisting', False), res.get('value') or {} diff --git a/eventman_server.py b/eventman_server.py index 078f9b1..3b8f3e7 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -97,44 +97,12 @@ class PersonsHandler(CollectionHandler): """Handle requests for Persons.""" collection = 'persons' object_id = 'person_id' - connect_to = 'events' - connect_id = 'event_id' - - def _handle_actions(self, id_, action=None, **kwds): - print id_, kwds - self.request.arguments - query = {self.object_id: self.db.toID(id_)} - if action: - query['action'] = action - actions = self.db.query('actions', query) - - return {self.connect_to: results} - - def handle_registered(self, id_, **kwds): - return self._handle_actions(id_, 'registered', **kwds) class EventsHandler(CollectionHandler): """Handle requests for Events.""" collection = 'events' object_id = 'event_id' - connect_to = 'persons' - connect_id = 'person_id' - - -class ActionsHandler(CollectionHandler): - """Handle requests for Actions.""" - collection = 'actions' - object_id = 'action_id' - - def get(self, *args, **kwargs): - params = self.request.arguments or {} - if 'event_id' in params: - params['event_id'] = self.db.toID(params['event_id'][0]) - if 'person_id' in params: - params['person_id'] = self.db.toID(params['person_id'][0]) - data = self.db.query(self.collection, params) - self.write({'actions': data}) class EbCSVImportPersonsHandler(BaseHandler): @@ -220,7 +188,6 @@ def run(): application = tornado.web.Application([ (r"/persons/?(?P\w+)?/?(?P\w+)?", PersonsHandler, init_params), (r"/events/?(?P\w+)?", EventsHandler, init_params), - (r"/actions/?.*", ActionsHandler, init_params), (r"/(?:index.html)?", RootHandler, init_params), (r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params), (r'/(.*)', tornado.web.StaticFileHandler, {"path": "angular_app"}) From d75b8ad8f592c73bd63808a32c096e0a6620b3d6 Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sat, 4 Apr 2015 14:15:52 +0200 Subject: [PATCH 3/7] events list of a person --- angular_app/js/controllers.js | 3 +++ angular_app/js/services.js | 10 +++++++++- angular_app/person-detail.html | 4 ++-- eventman_server.py | 11 +++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/angular_app/js/controllers.js b/angular_app/js/controllers.js index ce0f464..36138fa 100644 --- a/angular_app/js/controllers.js +++ b/angular_app/js/controllers.js @@ -78,6 +78,9 @@ eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', ' function ($scope, $routeParams, Person) { if ($routeParams.id) { $scope.person = Person.get($routeParams); + Person.getEvents($routeParams, function(data) { + $scope.events = data; + }); } // store a new Person or update an existing one $scope.save = function() { diff --git a/angular_app/js/services.js b/angular_app/js/services.js index e9b4c7b..17d1ca6 100644 --- a/angular_app/js/services.js +++ b/angular_app/js/services.js @@ -42,7 +42,15 @@ eventManServices.factory('Person', ['$resource', return angular.fromJson(data).persons; } }, - update: {method: 'PUT'} + update: {method: 'PUT'}, + getEvents: { + method: 'GET', + url: 'persons/:id/events', + isArray: true, + transformResponse: function(data, headers) { + return angular.fromJson(data).events; + } + } }); }] ); diff --git a/angular_app/person-detail.html b/angular_app/person-detail.html index 3fec012..bf3cae2 100644 --- a/angular_app/person-detail.html +++ b/angular_app/person-detail.html @@ -30,8 +30,8 @@ - {{event.title}} - action.event_id + {{event.title}} + diff --git a/eventman_server.py b/eventman_server.py index 3b8f3e7..d8faba6 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -98,6 +98,17 @@ class PersonsHandler(CollectionHandler): collection = 'persons' object_id = 'person_id' + def handle_events(self, id_, **kwargs): + events = self.db.query('events', {'registered.person_id': self.db.toID(id_)}) + for event in events: + person_data = {} + for registered in event.get('registered') or []: + if str(registered.get('person_id')) == id_: + person_data = registered + break + event['person_data'] = person_data + return {'events': events} + class EventsHandler(CollectionHandler): """Handle requests for Events.""" From 227551f4b025d64264f8d928b22d4bbfe01c9549 Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sat, 4 Apr 2015 14:26:01 +0200 Subject: [PATCH 4/7] list of attendees in event details --- angular_app/event-detail.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/angular_app/event-detail.html b/angular_app/event-detail.html index 0d8448e..98a8eae 100644 --- a/angular_app/event-detail.html +++ b/angular_app/event-detail.html @@ -45,4 +45,22 @@ + +
+
Events
+ + + + + + + + + + + + + +
PersonAttended
{{person.name}} {{person.surname}}
+
From ab837c3829a029fef3c7b22eddf60579b8e89b39 Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sat, 4 Apr 2015 14:56:41 +0200 Subject: [PATCH 5/7] rename registered to persons --- angular_app/event-detail.html | 43 +++++++++++++++++++++++------------ eventman_server.py | 17 +++++++------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/angular_app/event-detail.html b/angular_app/event-detail.html index 98a8eae..e189547 100644 --- a/angular_app/event-detail.html +++ b/angular_app/event-detail.html @@ -48,19 +48,34 @@
Events
- - - - - - - - - - - - - -
PersonAttended
{{person.name}} {{person.surname}}
+
+
+
+ + +
+
+ + +
+
+ + + + + + + + + + + + + +
PersonAttended
{{person.name}} {{person.surname}}
+
diff --git a/eventman_server.py b/eventman_server.py index d8faba6..1275fc0 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -59,7 +59,7 @@ class CollectionHandler(BaseHandler): @gen.coroutine def get(self, id_=None, resource=None, **kwargs): if resource: - method = getattr(self, 'handle_%s' % resource, None) + method = getattr(self, 'handle_get_%s' % resource, None) if method and callable(method): try: self.write(method(id_, **kwargs)) @@ -98,13 +98,13 @@ class PersonsHandler(CollectionHandler): collection = 'persons' object_id = 'person_id' - def handle_events(self, id_, **kwargs): - events = self.db.query('events', {'registered.person_id': self.db.toID(id_)}) + def handle_get_events(self, id_, **kwargs): + events = self.db.query('events', {'persons.person_id': self.db.toID(id_)}) for event in events: person_data = {} - for registered in event.get('registered') or []: - if str(registered.get('person_id')) == id_: - person_data = registered + for persons in event.get('persons') or []: + if str(persons.get('person_id')) == id_: + person_data = persons break event['person_data'] = person_data return {'events': events} @@ -128,6 +128,7 @@ class EbCSVImportPersonsHandler(BaseHandler): 'Cognome': 'surname', 'Nome': 'name', 'E-mail': 'email', + 'Indirizzo e-mail': 'email', 'Tipologia biglietto': 'ticket_kind', 'Data partecipazione': 'attending_datetime', 'Data check-in': 'checkin_datetime', @@ -168,9 +169,9 @@ class EbCSVImportPersonsHandler(BaseHandler): 'from_file': filename} person.update(registered_data) if not self.db.query('events', - {'_id': event_id, 'registered.person_id': person_id}): + {'_id': event_id, 'persons.person_id': person_id}): self.db.update('events', {'_id': event_id}, - {'registered': person}, + {'persons': person}, operator='$addToSet') reply['new_in_event'] += 1 self.write(reply) From 045cca48c016e7dc0bbb8d00b2a3c38cd34eaef4 Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sat, 4 Apr 2015 17:26:00 +0200 Subject: [PATCH 6/7] deep recursion conversion for objects --- angular_app/event-detail.html | 4 ++- angular_app/js/controllers.js | 22 +++++++++++---- backend.py | 51 ++++++++++++++++++++--------------- eventman_server.py | 6 ++--- utils.py | 9 +++++-- 5 files changed, 60 insertions(+), 32 deletions(-) diff --git a/angular_app/event-detail.html b/angular_app/event-detail.html index e189547..43db7e9 100644 --- a/angular_app/event-detail.html +++ b/angular_app/event-detail.html @@ -72,7 +72,9 @@ {{person.name}} {{person.surname}} - + + + diff --git a/angular_app/js/controllers.js b/angular_app/js/controllers.js index 36138fa..2860db7 100644 --- a/angular_app/js/controllers.js +++ b/angular_app/js/controllers.js @@ -42,20 +42,32 @@ eventManControllers.controller('EventsListCtrl', ['$scope', 'Event', ); -eventManControllers.controller('EventDetailsCtrl', ['$scope', 'Event', '$routeParams', - function ($scope, Event, $routeParams) { +eventManControllers.controller('EventDetailsCtrl', ['$scope', 'Event', '$routeParams', '$log', + function ($scope, Event, $routeParams, $log) { if ($routeParams.id) { $scope.event = Event.get($routeParams); } // store a new Event or update an existing one $scope.save = function() { - if ($scope.event.id === undefined) { - $scope.event = Event.save($scope.event); + var this_event = angular.copy($scope.event); + if (this_event.persons) { + delete this_event.persons; + } + if (this_event.id === undefined) { + $scope.event = Event.save(this_event); } else { - $scope.event = Event.update($scope.event); + $scope.event = Event.update(this_event); } $scope.eventForm.$dirty = false; }; + + $scope.updateAttendee = function(person, data) { + $log.info('EventDetailsCtrl'); + $log.info('event_id: ' + $routeParams.id); + $log.info('person_id: ' + person.person_id); + $log.info('data:'); + $log.info(data); + }; }] ); diff --git a/backend.py b/backend.py index 651f79f..c61024c 100644 --- a/backend.py +++ b/backend.py @@ -16,9 +16,11 @@ See the License for the specific language governing permissions and limitations under the License. """ +import re import pymongo from bson.objectid import ObjectId +re_objectid = re.compile(r'[0-9a-f]{24}') class EventManDB(object): """MongoDB connector.""" @@ -54,18 +56,30 @@ class EventManDB(object): self.db = self.connection[self._dbName] return self.db - def toID(self, _id): - """Convert a string to a MongoDB ID. + def convert_obj(self, obj): + """Convert a string to an object for MongoDB. - :param _id: string to convert to :class:`~bson.objectid.ObjectId` - :type _id: str - - :return: MongoDB ID - :rtype: :class:`~bson.objectid.ObjectId` + :param obj: object to convert """ - if not isinstance(_id, ObjectId): - _id = ObjectId(_id) - return _id + try: + return ObjectId(obj) + except: + pass + try: + return int(obj) + except: + pass + return obj + + def convert(self, seq): + if isinstance(seq, dict): + d = {} + for key, item in seq.iteritems(): + d[key] = self.convert_obj(item) + return d + if isinstance(seq, (list, tuple)): + return [self.convert_obj(x) for x in seq] + return self.convert_obj(seq) def get(self, collection, _id): """Get a single document with the specified `_id`. @@ -78,8 +92,7 @@ class EventManDB(object): :return: the document with the given `_id` :rtype: dict """ - _id = self.toID(_id) - results = self.query(collection, {'_id': _id}) + results = self.query(collection, self.convert({'_id': _id})) return results and results[0] or {} def query(self, collection, query=None): @@ -94,13 +107,8 @@ class EventManDB(object): :rtype: list """ db = self.connect() - query = query or {} - if'_id' in query: - query['_id'] = self.toID(query['_id']) - results = list(db[collection].find(query)) - for result in results: - result['_id'] = str(result['_id']) - return results + query = self.convert(query or {}) + return list(db[collection].find(query)) def add(self, collection, data): """Insert a new document. @@ -152,7 +160,8 @@ class EventManDB(object): elif isinstance(_id_or_query, (list, tuple)): _id_or_query = {'$or': self.buildSearchPattern(data, _id_or_query)} elif not isinstance(_id_or_query, dict): - _id_or_query = {'_id': self.toID(_id_or_query)} + _id_or_query = {'_id': _id_or_query} + _id_or_query = self.convert(_id_or_query) if '_id' in data: del data['_id'] res = db[collection].find_and_modify(query=_id_or_query, @@ -212,6 +221,6 @@ class EventManDB(object): return db = self.connect() if not isinstance(_id_or_query, dict): - _id_or_query = self.toID(_id_or_query) + _id_or_query = {'_id': _id_or_query} db[collection].remove(_id_or_query) diff --git a/eventman_server.py b/eventman_server.py index 1275fc0..1fc3978 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -99,7 +99,7 @@ class PersonsHandler(CollectionHandler): object_id = 'person_id' def handle_get_events(self, id_, **kwargs): - events = self.db.query('events', {'persons.person_id': self.db.toID(id_)}) + events = self.db.query('events', {'persons.person_id': id_}) for event in events: person_data = {} for persons in event.get('persons') or []: @@ -161,8 +161,8 @@ class EbCSVImportPersonsHandler(BaseHandler): if merged: reply['merged'] += 1 if targetEvent and person: - event_id = self.db.toID(targetEvent) - person_id = self.db.toID(person['_id']) + event_id = targetEvent + person_id = person['_id'] registered_data = { 'person_id': person_id, 'attended': False, diff --git a/utils.py b/utils.py index 372ed23..6cd491c 100644 --- a/utils.py +++ b/utils.py @@ -16,6 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. """ +import re import csv import json import datetime @@ -72,13 +73,17 @@ def csvParse(csvStr, remap=None, merge=None): class ImprovedEncoder(json.JSONEncoder): - """Enhance the default JSON encoder to serialize datetime objects.""" + """Enhance the default JSON encoder to serialize datetime and ObjectId instances.""" def default(self, o): if isinstance(o, (datetime.datetime, datetime.date, datetime.time, datetime.timedelta, ObjectId)): - return str(o) + try: + return str(o) + except Exception, e: + pass return json.JSONEncoder.default(self, o) + # Inject our class as the default encoder. json._default_encoder = ImprovedEncoder() From ed6ea28ee684c3dd43c3496fc362ff9cba66ea4a Mon Sep 17 00:00:00 2001 From: Davide Alberani Date: Sun, 5 Apr 2015 00:55:59 +0200 Subject: [PATCH 7/7] mark person as attendee --- angular_app/event-detail.html | 2 +- angular_app/js/controllers.js | 59 +++++++++++++++++++++++++--------- angular_app/js/services.js | 28 ++++++++++++++-- angular_app/person-detail.html | 45 ++++++++++++++++++-------- eventman_server.py | 41 +++++++++++++++++++---- 5 files changed, 135 insertions(+), 40 deletions(-) diff --git a/angular_app/event-detail.html b/angular_app/event-detail.html index 43db7e9..9d68195 100644 --- a/angular_app/event-detail.html +++ b/angular_app/event-detail.html @@ -73,7 +73,7 @@ {{person.name}} {{person.surname}} - + diff --git a/angular_app/js/controllers.js b/angular_app/js/controllers.js index 2860db7..6cb4954 100644 --- a/angular_app/js/controllers.js +++ b/angular_app/js/controllers.js @@ -49,6 +49,7 @@ eventManControllers.controller('EventDetailsCtrl', ['$scope', 'Event', '$routePa } // store a new Event or update an existing one $scope.save = function() { + // avoid override of event.persons list. var this_event = angular.copy($scope.event); if (this_event.persons) { delete this_event.persons; @@ -61,12 +62,20 @@ eventManControllers.controller('EventDetailsCtrl', ['$scope', 'Event', '$routePa $scope.eventForm.$dirty = false; }; - $scope.updateAttendee = function(person, data) { - $log.info('EventDetailsCtrl'); - $log.info('event_id: ' + $routeParams.id); - $log.info('person_id: ' + person.person_id); - $log.info('data:'); - $log.info(data); + $scope.updateAttendee = function(person, attended) { + $log.debug('EventDetailsCtrl.event_id: ' + $routeParams.id); + $log.debug('EventDetailsCtrl.person_id: ' + person.person_id); + $log.debug('EventDetailsCtrl.attended: ' + attended); + Event.personAttended({ + _id: $routeParams.id, + person_id: person.person_id, + 'persons.$.attended': attended + }, + function(data) { + $log.debug('EventDetailsCtrl.personAttended.data'); + $log.debug(data); + $scope.event.persons = data; + }); }; }] ); @@ -86,8 +95,8 @@ eventManControllers.controller('PersonsListCtrl', ['$scope', 'Person', ); -eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', 'Person', - function ($scope, $routeParams, Person) { +eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', 'Person', 'Event', '$log', + function ($scope, $routeParams, Person, Event, $log) { if ($routeParams.id) { $scope.person = Person.get($routeParams); Person.getEvents($routeParams, function(data) { @@ -96,12 +105,30 @@ eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', ' } // store a new Person or update an existing one $scope.save = function() { - if ($scope.person.id === undefined) { - $scope.person = Person.save($scope.person); - } else { - $scope.person = Person.update($scope.person); - } + if ($scope.person.id === undefined) { + $scope.person = Person.save($scope.person); + } else { + $scope.person = Person.update($scope.person); + } }; + $scope.updateAttendee = function(event, attended) { + $log.debug('PersonDetailsCtrl.event_id: ' + $routeParams.id); + $log.debug('PersonDetailsCtrl.event_id: ' + event.event_id); + $log.debug('PersonDetailsCtrl.attended: ' + attended); + Event.personAttended({ + _id: event._id, + person_id: $routeParams.id, + 'persons.$.attended': attended + }, + function(data) { + Person.getEvents($routeParams, function(data) { + $log.debug('PersonDetailsCtrl.personAttended.data'); + $log.debug(data); + $scope.events = data; + }); + } + ); + } }] ); @@ -109,8 +136,8 @@ eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', ' eventManControllers.controller('ImportPersonsCtrl', ['$scope', '$log', function ($scope, $log) { $scope.ebCSVimport = function() { - $log.info("ImportPersonsCtrl"); - $log.info($scope); + $log.debug("ImportPersonsCtrl"); + $log.debug($scope); }; }] ); @@ -122,7 +149,7 @@ eventManControllers.controller('FileUploadCtrl', ['$scope', '$log', '$upload', ' $scope.reply = {}; $scope.events = Event.all(); $scope.upload = function(file, url) { - $log.info("FileUploadCtrl.upload"); + $log.debug("FileUploadCtrl.upload"); $upload.upload({ url: url, file: file, diff --git a/angular_app/js/services.js b/angular_app/js/services.js index 17d1ca6..a877d43 100644 --- a/angular_app/js/services.js +++ b/angular_app/js/services.js @@ -3,10 +3,26 @@ /* Services that are used to interact with the backend. */ var eventManServices = angular.module('eventManServices', ['ngResource']); +eventManServices.factory('Attendee', ['$resource', 'Event', + function($resource, Event) { + return $resource('events/:id/persons/:person_id', {id: '@_id', person_id: '@person_id'}, { + personAttended: { + method: 'PUT', + params: {'persons.$.attended': true}, + transformResponse: function(data, headers) { + console.log('reply'); + console.log(angular.fromJson(data)); + return angular.fromJson(data).event; + } + } + }); + }] +); + eventManServices.factory('Event', ['$resource', function($resource) { - return $resource('events/:id', {id: '@_id'}, { + return $resource('events/:id', {id: '@_id', person_id: '@person_id'}, { all: { method: 'GET', isArray: true, @@ -26,7 +42,15 @@ eventManServices.factory('Event', ['$resource', return data; } }, - update: {method: 'PUT'} + update: {method: 'PUT'}, + personAttended: { + method: 'PUT', + isArray: true, + url: 'events/:id/persons/:person_id', + transformResponse: function(data, headers) { + return angular.fromJson(data).event.persons; + } + } }); }] ); diff --git a/angular_app/person-detail.html b/angular_app/person-detail.html index bf3cae2..b66bd77 100644 --- a/angular_app/person-detail.html +++ b/angular_app/person-detail.html @@ -21,20 +21,37 @@
Events
- - - - - - - - - - - - - -
EventAttended
{{event.title}}
+
+
+
+ + +
+
+ + +
+
+ + + + + + + + + + + + + +
EventAttended
{{event.title}} + +
+
diff --git a/eventman_server.py b/eventman_server.py index 1fc3978..a241945 100755 --- a/eventman_server.py +++ b/eventman_server.py @@ -57,12 +57,12 @@ class CollectionHandler(BaseHandler): collection = None @gen.coroutine - def get(self, id_=None, resource=None, **kwargs): + def get(self, id_=None, resource=None, resource_id=None, **kwargs): if resource: method = getattr(self, 'handle_get_%s' % resource, None) if method and callable(method): try: - self.write(method(id_, **kwargs)) + self.write(method(id_, resource_id, **kwargs)) return except: pass @@ -77,8 +77,16 @@ class CollectionHandler(BaseHandler): self.write({self.collection: self.db.query(self.collection)}) @gen.coroutine - def post(self, id_=None, **kwargs): + def post(self, id_=None, resource=None, resource_id=None, **kwargs): data = escape.json_decode(self.request.body or {}) + if resource: + method = getattr(self, 'handle_%s_%s' % (self.request.method.lower(), resource), None) + if method and callable(method): + try: + self.write(method(id_, resource_id, data, **kwargs)) + return + except: + pass if id_ is None: newData = self.db.add(self.collection, data) else: @@ -98,8 +106,12 @@ class PersonsHandler(CollectionHandler): collection = 'persons' object_id = 'person_id' - def handle_get_events(self, id_, **kwargs): - events = self.db.query('events', {'persons.person_id': id_}) + def handle_get_events(self, id_, resource_id=None, **kwargs): + query = {'persons.person_id': id_} + if resource_id: + query['_id'] = resource_id + + events = self.db.query('events', query) for event in events: person_data = {} for persons in event.get('persons') or []: @@ -115,6 +127,21 @@ class EventsHandler(CollectionHandler): collection = 'events' object_id = 'event_id' + def handle_get_persons(self, id_, resource_id=None): + query = {'_id': id_} + event = self.db.query('events', query)[0] + if resource_id: + for person in event.get('persons', []): + if str(person.get('person_id')) == resource_id: + return {'person': person} + return {'persons': event.get('persons') or {}} + + def handle_put_persons(self, id_, person_id, data): + merged, doc = self.db.update('events', + {'_id': id_, 'persons.person_id': person_id}, + data, create=False) + return {'event': doc} + class EbCSVImportPersonsHandler(BaseHandler): """Importer for CSV files exported from eventbrite.""" @@ -198,8 +225,8 @@ def run(): init_params = dict(db=db_connector) application = tornado.web.Application([ - (r"/persons/?(?P\w+)?/?(?P\w+)?", PersonsHandler, init_params), - (r"/events/?(?P\w+)?", EventsHandler, init_params), + (r"/persons/?(?P\w+)?/?(?P\w+)?/?(?P\w+)?", PersonsHandler, init_params), + (r"/events/?(?P\w+)?/?(?P\w+)?/?(?P\w+)?", EventsHandler, init_params), (r"/(?:index.html)?", RootHandler, init_params), (r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params), (r'/(.*)', tornado.web.StaticFileHandler, {"path": "angular_app"})