from flask import Flask, make_response, request, current_app, abort from simplejson import dumps from pymongo import MongoClient, DESCENDING # ASCENDING import datetime import dateutil.parser import bson from settings import mongo_config from datetime import timedelta from functools import update_wrapper def crossdomain(origin=None, methods=None, headers=None, max_age=21600, attach_to_all=True, automatic_options=True): if methods is not None: methods = ', '.join(sorted(x.upper() for x in methods)) if headers is not None and not isinstance(headers, basestring): headers = ', '.join(x.upper() for x in headers) if not isinstance(origin, basestring): origin = ', '.join(origin) if isinstance(max_age, timedelta): max_age = max_age.total_seconds() def get_methods(): if methods is not None: return methods options_resp = current_app.make_default_options_response() return options_resp.headers['allow'] def decorator(f): def wrapped_function(*args, **kwargs): if automatic_options and request.method == 'OPTIONS': resp = current_app.make_default_options_response() else: resp = make_response(f(*args, **kwargs)) if not attach_to_all and request.method != 'OPTIONS': return resp h = resp.headers h['Access-Control-Allow-Origin'] = origin h['Access-Control-Allow-Methods'] = get_methods() h['Access-Control-Max-Age'] = str(max_age) if headers is not None: h['Access-Control-Allow-Headers'] = headers return resp f.provide_automatic_options = False return update_wrapper(wrapped_function, f) return decorator app = Flask(__name__) client = MongoClient(mongo_config) db = client.showtimes miscObjHandler = lambda obj: ( obj.isoformat() if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) else str(obj) if isinstance(obj, bson.objectid.ObjectId) else None) @app.route('/flask/') @crossdomain(origin='*') def hello_world(): return 'This comes from Flask ^_^' @app.route('/movies/', methods=['GET'], defaults={'lang': 'en'}) @app.route('/movies//', methods=['GET']) @crossdomain(origin='*') def movie_list(lang): result = db.movies.find().sort('release_date', DESCENDING) movies = [] for i in result: if 'original' in i['title']: i['original_title'] = i['title']['original'] i['title'] = i['title'][lang] i['cast'] = i['cast'][lang] i['tagline'] = i['tagline'][lang] i['storyline'] = i['storyline'][lang] i['director'] = i['director'][lang] movies.append(i) json_dict = { 'meta': { 'total_count': len(movies) }, 'objects': movies } r = make_response(dumps(json_dict, default=miscObjHandler)) r.mimetype = 'application/json' return r @app.route('/movie//', methods=['GET'], defaults={'lang': 'en'}) @app.route('/movie///', methods=['GET']) @crossdomain(origin='*') def movie_item(mid, lang): lang = lang if lang in ('en', 'th') else 'en' try: movie = db.movies.find_one({'tmdb_id': int(mid)}) except ValueError: movie = db.movies.find_one({'_id': bson.objectid.ObjectId(mid)}) if not movie: movie = {} for k in ('title', 'tagline', 'director', 'cast', 'storyline'): if movie[k][lang]: movie[k] = movie[k][lang] else: movie[k] = movie[k]['th' if lang == 'en' else lang] try: del movie['indexes'] except KeyError: pass r = make_response(dumps(movie, default=miscObjHandler)) r.mimetype = 'application/json' return r @app.route('/groups/', methods=['GET']) @crossdomain(origin='*') def groups(): result = db.groups.find() known_groups = [] # ['sf', 'major', 'etc'] print result.count() if result.count() == 0: for i in ('sf', 'major', 'etc'): db.groups.insert({'name': str(i)}) known_groups.append({'name': str(i)}) for i in result: known_groups.append(i) json_dict = { 'meta': { 'total_count': len(known_groups) }, 'objects': known_groups } r = make_response(dumps(json_dict, default=miscObjHandler)) r.mimetype = 'application/json' return r @app.route('/group//', methods=['GET', 'POST']) @crossdomain(origin='*') def group(group_id): if request.method == 'GET': result = db.groups.find_one({'_id': bson.objectid.ObjectId(group_id)}) r = make_response(dumps(result, default=miscObjHandler)) r.mimetype = 'application/json' return r ## This is POST -- updating with information provided if not request.json or not 'name' in request.json: abort(400) try: key = {'_id': bson.objectid.ObjectId(group_id)} result = db.groups.update(key, {'$set': request.json}, False) r = make_response(dumps(result, default=miscObjHandler)) r.mimetype = 'application/json' return r except bson.errors.InvalidId: abort(500) @app.route('/theaters/', methods=['GET']) @app.route('/theaters//', methods=['GET']) @crossdomain(origin='*') def list_theaters(group=None): if not group: result = db.theater.find() else: result = db.theater.find({'group': group}) items = [i for i in result] json_dict = { 'meta': { 'total_count': len(items) }, 'objects': items } r = make_response(dumps(json_dict, default=miscObjHandler)) r.mimetype = 'application/json' return r @app.route('/theater//', methods=['GET', 'POST']) @crossdomain(origin='*') def get_theater(theater_id): ''' TODO: cannot add theater yet ''' if request.method == 'GET': result = db.theater.find_one({'_id': bson.objectid.ObjectId(theater_id)}) r = make_response(dumps(result, default=miscObjHandler)) r.mimetype = 'application/json' return r ## This is POST -- updating with information provided if not request.json or \ not 'name' in request.json or \ not 'group' in request.json or not 'code' in request.json: abort(400) try: key = {'_id': bson.objectid.ObjectId(theater_id)} prev = db.theater.find_one(key) if not prev: abort(500) is_allowed = True for k in ['code', 'group', 'name']: if request.json[k] != prev[k]: is_allowed = False if is_allowed: result = db.theater.update(key, {'$set': request.json}, False) else: result = { # mimicking mongo update result for consistency 'updatedExisting': False, 'ok': 0, 'nModified': 0, 'error': "cannot alter mandatory fields", } r = make_response(dumps(result, default=miscObjHandler)) r.mimetype = 'application/json' return r except bson.errors.InvalidId: abort(500) @app.route('/showtimes//', methods=['GET']) @app.route('/showtimes///', methods=['GET']) @crossdomain(origin='*') def list_showtimes(group=None, code=None): day = request.args.get('d', '') q = {} if day: q['date'] = dateutil.parser.parse(day) if group: q['group'] = group if code: q['theater'] = code result = db.showtimes.find(q).sort('date', DESCENDING) items = [i for i in result[:300]] json_dict = { 'meta': { 'total_count': len(items) }, 'objects': items } r = make_response(dumps(json_dict, default=miscObjHandler)) r.mimetype = 'application/json' return r if __name__ == '__main__': app.run(debug=True)