|
@@ -18,58 +18,84 @@ from tornado import gen, escape
|
|
import backend
|
|
import backend
|
|
|
|
|
|
|
|
|
|
|
|
+class ImprovedEncoder(json.JSONEncoder):
|
|
|
|
+ """Enhance the default JSON encoder to serialize datetime objects."""
|
|
|
|
+ def default(self, o):
|
|
|
|
+ if isinstance(o, (datetime.datetime, datetime.date,
|
|
|
|
+ datetime.time, datetime.timedelta)):
|
|
|
|
+ return str(o)
|
|
|
|
+ return json.JSONEncoder.default(self, o)
|
|
|
|
+
|
|
|
|
+json._default_encoder = ImprovedEncoder()
|
|
|
|
+
|
|
|
|
+
|
|
class BaseHandler(tornado.web.RequestHandler):
|
|
class BaseHandler(tornado.web.RequestHandler):
|
|
|
|
+ """Base class for request handlers."""
|
|
def initialize(self, **kwargs):
|
|
def initialize(self, **kwargs):
|
|
|
|
+ """Add every passed (key, value) as attributes of the instance."""
|
|
for key, value in kwargs.iteritems():
|
|
for key, value in kwargs.iteritems():
|
|
setattr(self, key, value)
|
|
setattr(self, key, value)
|
|
|
|
|
|
|
|
|
|
class RootHandler(BaseHandler):
|
|
class RootHandler(BaseHandler):
|
|
|
|
+ """Handler for the / path."""
|
|
angular_app_path = os.path.join(os.path.dirname(__file__), "angular_app")
|
|
angular_app_path = os.path.join(os.path.dirname(__file__), "angular_app")
|
|
|
|
+
|
|
@gen.coroutine
|
|
@gen.coroutine
|
|
def get(self):
|
|
def get(self):
|
|
|
|
+ # serve the ./angular_app/index.html file
|
|
with open(self.angular_app_path + "/index.html", 'r') as fd:
|
|
with open(self.angular_app_path + "/index.html", 'r') as fd:
|
|
self.write(fd.read())
|
|
self.write(fd.read())
|
|
|
|
|
|
|
|
|
|
-class ImprovedEncoder(json.JSONEncoder):
|
|
|
|
- def default(self, o):
|
|
|
|
- if isinstance(o, datetime.datetime):
|
|
|
|
- return str(o)
|
|
|
|
- return json.JSONEncoder.default(self, o)
|
|
|
|
-
|
|
|
|
-json._default_encoder = ImprovedEncoder()
|
|
|
|
-
|
|
|
|
-
|
|
|
|
class CollectionHandler(BaseHandler):
|
|
class CollectionHandler(BaseHandler):
|
|
|
|
+ """Base class for handlers that need to interact with the database backend.
|
|
|
|
+
|
|
|
|
+ Introduce basic CRUD operations."""
|
|
|
|
+ # set of documents we're managing (a collection in MongoDB or a table in a SQL database)
|
|
collection = None
|
|
collection = None
|
|
|
|
|
|
@gen.coroutine
|
|
@gen.coroutine
|
|
def get(self, id_=None):
|
|
def get(self, id_=None):
|
|
if id_ is not None:
|
|
if id_ is not None:
|
|
|
|
+ # read a single document
|
|
self.write(self.db.get(self.collection, id_))
|
|
self.write(self.db.get(self.collection, id_))
|
|
else:
|
|
else:
|
|
|
|
+ # return an object containing the list of all objects in the collection;
|
|
|
|
+ # e.g.: {'events': [{'_id': 'obj1-id, ...}, {'_id': 'obj2-id, ...}, ...]}
|
|
|
|
+ # Please, never return JSON lists that are not encapsulated in an object,
|
|
|
|
+ # to avoid XSS vulnerabilities.
|
|
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, **kwargs):
|
|
data = escape.json_decode(self.request.body or {})
|
|
data = escape.json_decode(self.request.body or {})
|
|
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
|
|
newData = self.db.update(self.collection, id_, data)
|
|
newData = self.db.update(self.collection, id_, data)
|
|
self.write(newData)
|
|
self.write(newData)
|
|
|
|
|
|
|
|
+ # PUT is handled by the POST method
|
|
put = post
|
|
put = post
|
|
|
|
|
|
|
|
+
|
|
class PersonsHandler(CollectionHandler):
|
|
class PersonsHandler(CollectionHandler):
|
|
|
|
+ """Handle requests for Persons."""
|
|
collection = 'persons'
|
|
collection = 'persons'
|
|
|
|
|
|
|
|
+
|
|
class EventsHandler(CollectionHandler):
|
|
class EventsHandler(CollectionHandler):
|
|
|
|
+ """Handle requests for Events."""
|
|
collection = 'events'
|
|
collection = 'events'
|
|
|
|
|
|
|
|
|
|
-def main():
|
|
|
|
|
|
+def run():
|
|
|
|
+ """Run the Tornado web application."""
|
|
|
|
+ # command line arguments; can also be written in a configuration file,
|
|
|
|
+ # specified with the --config argument.
|
|
define("port", default=5242, help="run on the given port", type=int)
|
|
define("port", default=5242, help="run on the given port", type=int)
|
|
define("data", default=os.path.join(os.path.dirname(__file__), "data"),
|
|
define("data", default=os.path.join(os.path.dirname(__file__), "data"),
|
|
help="specify the directory used to store the data")
|
|
help="specify the directory used to store the data")
|
|
@@ -82,6 +108,7 @@ def main():
|
|
callback=lambda path: tornado.options.parse_config_file(path, final=False))
|
|
callback=lambda path: tornado.options.parse_config_file(path, final=False))
|
|
tornado.options.parse_command_line()
|
|
tornado.options.parse_command_line()
|
|
|
|
|
|
|
|
+ # database backend connector
|
|
db_connector = backend.EventManDB(url=options.mongodbURL, dbName=options.dbName)
|
|
db_connector = backend.EventManDB(url=options.mongodbURL, dbName=options.dbName)
|
|
init_params = dict(db=db_connector)
|
|
init_params = dict(db=db_connector)
|
|
|
|
|
|
@@ -100,5 +127,5 @@ def main():
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if __name__ == '__main__':
|
|
- main()
|
|
|
|
|
|
+ run()
|
|
|
|
|