Merge pull request #14 from alberanid/master
interactions between persons and events
This commit is contained in:
commit
7fb2a181f9
7 changed files with 286 additions and 101 deletions
|
@ -45,4 +45,39 @@
|
||||||
|
|
||||||
<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;"/>
|
<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;"/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<div class="panel panel-primary table-striped top5">
|
||||||
|
<div class="panel-heading">Events</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-inline">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="query-persons">Search:</label>
|
||||||
|
<input type="text" id="query-persons" class="form-control" placeholder="Name or email" ng-model="query">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="persons-order">Sort by:</label>
|
||||||
|
<select id="persons-order" class="form-control" ng-model="orderProp">
|
||||||
|
<option value="name" ng-selected="selected">Alphabetical</option>
|
||||||
|
<option value="_id">ID</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Person</th>
|
||||||
|
<th>Attended</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="person in event.persons | filter:query | orderBy:orderProp">
|
||||||
|
<td><a href="/#/persons/{{person.person_id}}">{{person.name}} {{person.surname}}</a></td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-link" name="switch-attended" ng-click="updateAttendee(person, !person.attended)"><span class="glyphicon {{(person.attended) && 'glyphicon-ok-sign text-success' || 'glyphicon-remove-sign text-danger'}}"></span></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
63
angular_app/js/controllers.js
vendored
63
angular_app/js/controllers.js
vendored
|
@ -42,20 +42,41 @@ eventManControllers.controller('EventsListCtrl', ['$scope', 'Event',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
eventManControllers.controller('EventDetailsCtrl', ['$scope', 'Event', '$routeParams',
|
eventManControllers.controller('EventDetailsCtrl', ['$scope', 'Event', '$routeParams', '$log',
|
||||||
function ($scope, Event, $routeParams) {
|
function ($scope, Event, $routeParams, $log) {
|
||||||
if ($routeParams.id) {
|
if ($routeParams.id) {
|
||||||
$scope.event = Event.get($routeParams);
|
$scope.event = Event.get($routeParams);
|
||||||
}
|
}
|
||||||
// store a new Event or update an existing one
|
// store a new Event or update an existing one
|
||||||
$scope.save = function() {
|
$scope.save = function() {
|
||||||
if ($scope.event.id === undefined) {
|
// avoid override of event.persons list.
|
||||||
$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 {
|
} else {
|
||||||
$scope.event = Event.update($scope.event);
|
$scope.event = Event.update(this_event);
|
||||||
}
|
}
|
||||||
$scope.eventForm.$dirty = false;
|
$scope.eventForm.$dirty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$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;
|
||||||
|
});
|
||||||
|
};
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -74,12 +95,12 @@ eventManControllers.controller('PersonsListCtrl', ['$scope', 'Person',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', 'Person', 'Action',
|
eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', 'Person', 'Event', '$log',
|
||||||
function ($scope, $routeParams, Person, Action) {
|
function ($scope, $routeParams, Person, Event, $log) {
|
||||||
if ($routeParams.id) {
|
if ($routeParams.id) {
|
||||||
$scope.person = Person.get($routeParams);
|
$scope.person = Person.get($routeParams);
|
||||||
Action.get({person_id: $routeParams.id}, function(data) {
|
Person.getEvents($routeParams, function(data) {
|
||||||
$scope.actions = angular.fromJson(data).actions;
|
$scope.events = data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// store a new Person or update an existing one
|
// store a new Person or update an existing one
|
||||||
|
@ -90,6 +111,24 @@ eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', '
|
||||||
$scope.person = Person.update($scope.person);
|
$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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -97,8 +136,8 @@ eventManControllers.controller('PersonDetailsCtrl', ['$scope', '$routeParams', '
|
||||||
eventManControllers.controller('ImportPersonsCtrl', ['$scope', '$log',
|
eventManControllers.controller('ImportPersonsCtrl', ['$scope', '$log',
|
||||||
function ($scope, $log) {
|
function ($scope, $log) {
|
||||||
$scope.ebCSVimport = function() {
|
$scope.ebCSVimport = function() {
|
||||||
$log.info("ImportPersonsCtrl");
|
$log.debug("ImportPersonsCtrl");
|
||||||
$log.info($scope);
|
$log.debug($scope);
|
||||||
};
|
};
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
@ -110,7 +149,7 @@ eventManControllers.controller('FileUploadCtrl', ['$scope', '$log', '$upload', '
|
||||||
$scope.reply = {};
|
$scope.reply = {};
|
||||||
$scope.events = Event.all();
|
$scope.events = Event.all();
|
||||||
$scope.upload = function(file, url) {
|
$scope.upload = function(file, url) {
|
||||||
$log.info("FileUploadCtrl.upload");
|
$log.debug("FileUploadCtrl.upload");
|
||||||
$upload.upload({
|
$upload.upload({
|
||||||
url: url,
|
url: url,
|
||||||
file: file,
|
file: file,
|
||||||
|
|
39
angular_app/js/services.js
vendored
39
angular_app/js/services.js
vendored
|
@ -3,15 +3,26 @@
|
||||||
/* Services that are used to interact with the backend. */
|
/* Services that are used to interact with the backend. */
|
||||||
var eventManServices = angular.module('eventManServices', ['ngResource']);
|
var eventManServices = angular.module('eventManServices', ['ngResource']);
|
||||||
|
|
||||||
eventManServices.factory('Action', ['$resource',
|
eventManServices.factory('Attendee', ['$resource', 'Event',
|
||||||
function($resource) {
|
function($resource, Event) {
|
||||||
return $resource('actions');
|
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',
|
eventManServices.factory('Event', ['$resource',
|
||||||
function($resource) {
|
function($resource) {
|
||||||
return $resource('events/:id', {id: '@_id'}, {
|
return $resource('events/:id', {id: '@_id', person_id: '@person_id'}, {
|
||||||
all: {
|
all: {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
isArray: true,
|
isArray: true,
|
||||||
|
@ -31,7 +42,15 @@ eventManServices.factory('Event', ['$resource',
|
||||||
return data;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
@ -47,7 +66,15 @@ eventManServices.factory('Person', ['$resource',
|
||||||
return angular.fromJson(data).persons;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,21 +20,38 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="panel panel-primary table-striped top5">
|
<div class="panel panel-primary table-striped top5">
|
||||||
<div class="panel-heading">Actions</div>
|
<div class="panel-heading">Events</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-inline">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="query-persons">Search:</label>
|
||||||
|
<input type="text" id="query-persons" class="form-control" placeholder="Name or email" ng-model="query">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="events-order">Sort by:</label>
|
||||||
|
<select id="events-order" class="form-control" ng-model="orderProp">
|
||||||
|
<option value="name" ng-selected="selected">Alphabetical</option>
|
||||||
|
<option value="date">Date</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Action</th>
|
<th>Event</th>
|
||||||
<th>Event ID</th>
|
<th>Attended</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="action in actions">
|
<tr ng-repeat="event in events">
|
||||||
<td>{{action.action}}</td>
|
<td><a href="/#/events/{{event._id}}">{{event.title}}</a></td>
|
||||||
<td>{{action.event_id}}</td>
|
<td>
|
||||||
|
<button class="btn btn-link" name="switch-attended" ng-click="updateAttendee(event, !event.person_data.attended)"><span class="glyphicon {{(event.person_data.attended) && 'glyphicon-ok-sign text-success' || 'glyphicon-remove-sign text-danger'}}"></span></button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
79
backend.py
79
backend.py
|
@ -16,9 +16,11 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
import pymongo
|
import pymongo
|
||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
|
|
||||||
|
re_objectid = re.compile(r'[0-9a-f]{24}')
|
||||||
|
|
||||||
class EventManDB(object):
|
class EventManDB(object):
|
||||||
"""MongoDB connector."""
|
"""MongoDB connector."""
|
||||||
|
@ -54,18 +56,30 @@ class EventManDB(object):
|
||||||
self.db = self.connection[self._dbName]
|
self.db = self.connection[self._dbName]
|
||||||
return self.db
|
return self.db
|
||||||
|
|
||||||
def toID(self, _id):
|
def convert_obj(self, obj):
|
||||||
"""Convert a string to a MongoDB ID.
|
"""Convert a string to an object for MongoDB.
|
||||||
|
|
||||||
:param _id: string to convert to :class:`~bson.objectid.ObjectId`
|
:param obj: object to convert
|
||||||
:type _id: str
|
|
||||||
|
|
||||||
:return: MongoDB ID
|
|
||||||
:rtype: :class:`~bson.objectid.ObjectId`
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(_id, ObjectId):
|
try:
|
||||||
_id = ObjectId(_id)
|
return ObjectId(obj)
|
||||||
return _id
|
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):
|
def get(self, collection, _id):
|
||||||
"""Get a single document with the specified `_id`.
|
"""Get a single document with the specified `_id`.
|
||||||
|
@ -78,8 +92,7 @@ class EventManDB(object):
|
||||||
:return: the document with the given `_id`
|
:return: the document with the given `_id`
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
_id = self.toID(_id)
|
results = self.query(collection, self.convert({'_id': _id}))
|
||||||
results = self.query(collection, {'_id': _id})
|
|
||||||
return results and results[0] or {}
|
return results and results[0] or {}
|
||||||
|
|
||||||
def query(self, collection, query=None):
|
def query(self, collection, query=None):
|
||||||
|
@ -94,13 +107,8 @@ class EventManDB(object):
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
db = self.connect()
|
db = self.connect()
|
||||||
query = query or {}
|
query = self.convert(query or {})
|
||||||
if'_id' in query:
|
return list(db[collection].find(query))
|
||||||
query['_id'] = self.toID(query['_id'])
|
|
||||||
results = list(db[collection].find(query))
|
|
||||||
for result in results:
|
|
||||||
result['_id'] = str(result['_id'])
|
|
||||||
return results
|
|
||||||
|
|
||||||
def add(self, collection, data):
|
def add(self, collection, data):
|
||||||
"""Insert a new document.
|
"""Insert a new document.
|
||||||
|
@ -132,12 +140,12 @@ class EventManDB(object):
|
||||||
ret = db[collection].update(data, {'$set': data}, upsert=True)
|
ret = db[collection].update(data, {'$set': data}, upsert=True)
|
||||||
return ret['updatedExisting']
|
return ret['updatedExisting']
|
||||||
|
|
||||||
def update(self, collection, _id, data):
|
def update(self, collection, _id_or_query, data, operator='$set', create=True):
|
||||||
"""Update an existing document.
|
"""Update an existing document.
|
||||||
|
|
||||||
:param collection: update a document in this collection
|
:param collection: update a document in this collection
|
||||||
:type collection: str
|
: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`
|
:type _id: str or :class:`~bson.objectid.ObjectId`
|
||||||
:param data: the updated information to store
|
:param data: the updated information to store
|
||||||
:type data: dict
|
:type data: dict
|
||||||
|
@ -147,12 +155,30 @@ class EventManDB(object):
|
||||||
"""
|
"""
|
||||||
db = self.connect()
|
db = self.connect()
|
||||||
data = data or {}
|
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': _id_or_query}
|
||||||
|
_id_or_query = self.convert(_id_or_query)
|
||||||
if '_id' in data:
|
if '_id' in data:
|
||||||
del data['_id']
|
del data['_id']
|
||||||
db[collection].update({'_id': self.toID(_id)}, {'$set': data})
|
res = db[collection].find_and_modify(query=_id_or_query,
|
||||||
return self.get(collection, _id)
|
update={operator: data}, full_response=True, new=True, upsert=create)
|
||||||
|
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.
|
"""Update an existing document.
|
||||||
|
|
||||||
:param collection: update a document in this collection
|
:param collection: update a document in this collection
|
||||||
|
@ -172,7 +198,8 @@ class EventManDB(object):
|
||||||
continue
|
continue
|
||||||
if not _or:
|
if not _or:
|
||||||
return False, None
|
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')
|
_id = ret.get('upserted')
|
||||||
if _id is None:
|
if _id is None:
|
||||||
newDoc = db[collection].find_one(data)
|
newDoc = db[collection].find_one(data)
|
||||||
|
@ -194,6 +221,6 @@ class EventManDB(object):
|
||||||
return
|
return
|
||||||
db = self.connect()
|
db = self.connect()
|
||||||
if not isinstance(_id_or_query, dict):
|
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)
|
db[collection].remove(_id_or_query)
|
||||||
|
|
||||||
|
|
|
@ -57,12 +57,12 @@ class CollectionHandler(BaseHandler):
|
||||||
collection = None
|
collection = None
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def get(self, id_=None, resource=None, **kwargs):
|
def get(self, id_=None, resource=None, resource_id=None, **kwargs):
|
||||||
if resource:
|
if resource:
|
||||||
method = getattr(self, 'handle_%s' % resource, None)
|
method = getattr(self, 'handle_get_%s' % resource, None)
|
||||||
if method and callable(method):
|
if method and callable(method):
|
||||||
try:
|
try:
|
||||||
self.write(method(id_, **kwargs))
|
self.write(method(id_, resource_id, **kwargs))
|
||||||
return
|
return
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -77,14 +77,20 @@ class CollectionHandler(BaseHandler):
|
||||||
self.write({self.collection: self.db.query(self.collection)})
|
self.write({self.collection: self.db.query(self.collection)})
|
||||||
|
|
||||||
@gen.coroutine
|
@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 {})
|
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:
|
if id_ is None:
|
||||||
# insert a new document
|
|
||||||
newData = self.db.add(self.collection, data)
|
newData = self.db.add(self.collection, data)
|
||||||
else:
|
else:
|
||||||
# update an existing document
|
merged, newData = self.db.update(self.collection, id_, data)
|
||||||
newData = self.db.update(self.collection, id_, data)
|
|
||||||
self.write(newData)
|
self.write(newData)
|
||||||
|
|
||||||
# PUT (update an existing document) is handled by the POST (create a new document) method
|
# PUT (update an existing document) is handled by the POST (create a new document) method
|
||||||
|
@ -98,28 +104,43 @@ class CollectionHandler(BaseHandler):
|
||||||
class PersonsHandler(CollectionHandler):
|
class PersonsHandler(CollectionHandler):
|
||||||
"""Handle requests for Persons."""
|
"""Handle requests for Persons."""
|
||||||
collection = 'persons'
|
collection = 'persons'
|
||||||
|
object_id = 'person_id'
|
||||||
|
|
||||||
def handle_events(self, _id, **kwds):
|
def handle_get_events(self, id_, resource_id=None, **kwargs):
|
||||||
return {'events': []}
|
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 []:
|
||||||
|
if str(persons.get('person_id')) == id_:
|
||||||
|
person_data = persons
|
||||||
|
break
|
||||||
|
event['person_data'] = person_data
|
||||||
|
return {'events': events}
|
||||||
|
|
||||||
|
|
||||||
class EventsHandler(CollectionHandler):
|
class EventsHandler(CollectionHandler):
|
||||||
"""Handle requests for Events."""
|
"""Handle requests for Events."""
|
||||||
collection = 'events'
|
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 {}}
|
||||||
|
|
||||||
class ActionsHandler(CollectionHandler):
|
def handle_put_persons(self, id_, person_id, data):
|
||||||
"""Handle requests for Actions."""
|
merged, doc = self.db.update('events',
|
||||||
collection = 'actions'
|
{'_id': id_, 'persons.person_id': person_id},
|
||||||
|
data, create=False)
|
||||||
def get(self, *args, **kwargs):
|
return {'event': doc}
|
||||||
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):
|
class EbCSVImportPersonsHandler(BaseHandler):
|
||||||
|
@ -131,14 +152,19 @@ class EbCSVImportPersonsHandler(BaseHandler):
|
||||||
'Cognome acquirente': 'surname',
|
'Cognome acquirente': 'surname',
|
||||||
'Nome acquirente': 'name',
|
'Nome acquirente': 'name',
|
||||||
'E-mail acquirente': 'email',
|
'E-mail acquirente': 'email',
|
||||||
'Cognome': 'original_surname',
|
'Cognome': 'surname',
|
||||||
'Nome': 'original_name',
|
'Nome': 'name',
|
||||||
'E-mail': 'original_email',
|
'E-mail': 'email',
|
||||||
|
'Indirizzo e-mail': 'email',
|
||||||
'Tipologia biglietto': 'ticket_kind',
|
'Tipologia biglietto': 'ticket_kind',
|
||||||
'Data partecipazione': 'attending_datetime',
|
'Data partecipazione': 'attending_datetime',
|
||||||
'Data check-in': 'checkin_datetime',
|
'Data check-in': 'checkin_datetime',
|
||||||
'Ordine n.': 'order_nr',
|
'Ordine n.': 'order_nr',
|
||||||
|
'ID ordine': 'order_nr',
|
||||||
|
'Prefisso (Sig., Sig.ra, ecc.)': 'name_title',
|
||||||
}
|
}
|
||||||
|
keepPersonData = ('name', 'surname', 'email')
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def post(self, **kwargs):
|
def post(self, **kwargs):
|
||||||
targetEvent = None
|
targetEvent = None
|
||||||
|
@ -146,7 +172,7 @@ class EbCSVImportPersonsHandler(BaseHandler):
|
||||||
targetEvent = self.get_body_argument('targetEvent')
|
targetEvent = self.get_body_argument('targetEvent')
|
||||||
except:
|
except:
|
||||||
pass
|
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 fieldname, contents in self.request.files.iteritems():
|
||||||
for content in contents:
|
for content in contents:
|
||||||
filename = content['filename']
|
filename = content['filename']
|
||||||
|
@ -154,17 +180,27 @@ class EbCSVImportPersonsHandler(BaseHandler):
|
||||||
reply['total'] += parseStats['total']
|
reply['total'] += parseStats['total']
|
||||||
reply['valid'] += parseStats['valid']
|
reply['valid'] += parseStats['valid']
|
||||||
for person in persons:
|
for person in persons:
|
||||||
merged, _id = self.db.merge('persons', person,
|
person_data = dict([(k, person[k]) for k in self.keepPersonData
|
||||||
searchBy=[('email',), ('name', 'surname')])
|
if k in person])
|
||||||
|
merged, person = self.db.update('persons',
|
||||||
|
[('email',), ('name', 'surname')],
|
||||||
|
person_data)
|
||||||
if merged:
|
if merged:
|
||||||
reply['merged'] += 1
|
reply['merged'] += 1
|
||||||
if targetEvent and _id:
|
if targetEvent and person:
|
||||||
|
event_id = targetEvent
|
||||||
|
person_id = person['_id']
|
||||||
registered_data = {
|
registered_data = {
|
||||||
'event_id': self.db.toID(targetEvent),
|
'person_id': person_id,
|
||||||
'person_id': self.db.toID(_id),
|
'attended': False,
|
||||||
'action': 'registered',
|
|
||||||
'from_file': filename}
|
'from_file': filename}
|
||||||
self.db.insertOne('actions', registered_data)
|
person.update(registered_data)
|
||||||
|
if not self.db.query('events',
|
||||||
|
{'_id': event_id, 'persons.person_id': person_id}):
|
||||||
|
self.db.update('events', {'_id': event_id},
|
||||||
|
{'persons': person},
|
||||||
|
operator='$addToSet')
|
||||||
|
reply['new_in_event'] += 1
|
||||||
self.write(reply)
|
self.write(reply)
|
||||||
|
|
||||||
|
|
||||||
|
@ -189,9 +225,8 @@ def run():
|
||||||
init_params = dict(db=db_connector)
|
init_params = dict(db=db_connector)
|
||||||
|
|
||||||
application = tornado.web.Application([
|
application = tornado.web.Application([
|
||||||
(r"/persons/?(?P<id_>\w+)?/?(?P<resource>\w+)?", PersonsHandler, init_params),
|
(r"/persons/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?", PersonsHandler, init_params),
|
||||||
(r"/events/?(?P<id_>\w+)?", EventsHandler, init_params),
|
(r"/events/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?", EventsHandler, init_params),
|
||||||
(r"/actions/?.*", ActionsHandler, 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'/(.*)', tornado.web.StaticFileHandler, {"path": "angular_app"})
|
(r'/(.*)', tornado.web.StaticFileHandler, {"path": "angular_app"})
|
||||||
|
|
7
utils.py
7
utils.py
|
@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
import csv
|
import csv
|
||||||
import json
|
import json
|
||||||
import datetime
|
import datetime
|
||||||
|
@ -72,13 +73,17 @@ def csvParse(csvStr, remap=None, merge=None):
|
||||||
|
|
||||||
|
|
||||||
class ImprovedEncoder(json.JSONEncoder):
|
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):
|
def default(self, o):
|
||||||
if isinstance(o, (datetime.datetime, datetime.date,
|
if isinstance(o, (datetime.datetime, datetime.date,
|
||||||
datetime.time, datetime.timedelta, ObjectId)):
|
datetime.time, datetime.timedelta, ObjectId)):
|
||||||
|
try:
|
||||||
return str(o)
|
return str(o)
|
||||||
|
except Exception, e:
|
||||||
|
pass
|
||||||
return json.JSONEncoder.default(self, o)
|
return json.JSONEncoder.default(self, o)
|
||||||
|
|
||||||
|
|
||||||
# Inject our class as the default encoder.
|
# Inject our class as the default encoder.
|
||||||
json._default_encoder = ImprovedEncoder()
|
json._default_encoder = ImprovedEncoder()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue