import logging import os import flask import flask_apscheduler import flask_restful import flask_restful.fields import flask_restful.reqparse import sqlalchemy import sqlalchemy.engine from db import db, Video, Comment, Association app = flask.Flask(__name__) app.logger.setLevel(logging.INFO) app.config.update( ERROR_404_HELP=False, SQLALCHEMY_TRACK_MODIFICATIONS=False, SQLALCHEMY_DATABASE_URI=os.getenv('SQLALCHEMY_DATABASE_URI'), SCHEDULER_TIMEZONE='UTC', SCHEDULER_JOBS=[dict( id='sync', func='sync:Sync.perform', args=(app, db), max_instances=1, trigger='interval', seconds=300)]) if app.config.get('SQLALCHEMY_DATABASE_URI', '').startswith('sqlite://'): @sqlalchemy.event.listens_for(sqlalchemy.engine.Engine, 'connect') def set_sqlite_pragma(dbapi_connection, connection_record): dbapi_connection.execute('PRAGMA journal_mode=WAL') dbapi_connection.execute('PRAGMA synchronous=NORMAL') db.init_app(app) db.create_all(app=app) scheduler = flask_apscheduler.APScheduler() scheduler.init_app(app) api = flask_restful.Api(app) video_fields = { 'id': flask_restful.fields.Integer(), 'broadcast_type': flask_restful.fields.String(), 'title': flask_restful.fields.String(), 'description': flask_restful.fields.String(), 'game': flask_restful.fields.String(), 'length': flask_restful.fields.Integer(), 'thumbnail_small': flask_restful.fields.String(), 'thumbnail_medium': flask_restful.fields.String(), 'thumbnail_large': flask_restful.fields.String(), 'created_at': flask_restful.fields.DateTime(dt_format='iso8601'), 'updated_at': flask_restful.fields.DateTime(dt_format='iso8601'), 'recorded_at': flask_restful.fields.DateTime(dt_format='iso8601'), 'published_at': flask_restful.fields.DateTime(dt_format='iso8601'), } comment_fields = { 'id': flask_restful.fields.String(attribute='comment.id'), 'video_id': flask_restful.fields.Integer(), 'offset': flask_restful.fields.Float(), 'commenter_id': flask_restful.fields.Integer(attribute='comment.commenter_id'), 'commenter_name': flask_restful.fields.String(attribute='comment.commenter_name'), 'commenter_display_name': flask_restful.fields.String(attribute='comment.commenter_display_name'), 'commenter_logo': flask_restful.fields.String(attribute='comment.commenter_logo'), 'source': flask_restful.fields.String(attribute='comment.source'), 'message_body': flask_restful.fields.String(attribute='comment.message_body'), 'message_user_color': flask_restful.fields.String(attribute='comment.message_user_color'), 'message_user_badges': flask_restful.fields.String(attribute='comment.message_user_badges'), 'created_at': flask_restful.fields.DateTime(dt_format='iso8601', attribute='comment.created_at'), 'updated_at': flask_restful.fields.DateTime(dt_format='iso8601', attribute='comment.updated_at'), } filter_parser = flask_restful.reqparse.RequestParser() filter_parser.add_argument('filter', type=str) filter_parser.add_argument('sort_by', type=str) filter_parser.add_argument('sort_order', type=str) filter_parser.add_argument('page_number', type=int) filter_parser.add_argument('page_size', type=int) class VideoResource(flask_restful.Resource): @flask_restful.marshal_with(video_fields) def get(self, id): q = db.session.query(Video).filter(Video.id == id) video = q.first() if not video: flask_restful.abort(404, message='Video {0} does not exist'.format(id)) return video, 200 class VideosResource(flask_restful.Resource): @flask_restful.marshal_with(video_fields) def get(self): args = filter_parser.parse_args() q = db.session.query(Video) if args['filter']: q = q.filter(Video.title.ilike('%{}%'.format(args['filter']))) count = q.count() if args['sort_order'] == 'random': q = q.order_by(sqlalchemy.func.random()) elif args['sort_by']: col = getattr(Video, args['sort_by'], None) if col: if args['sort_order']: order_by = getattr(col, args['sort_order'], None) if order_by: q = q.order_by(order_by()) else: q = q.order_by(col) if args['page_size']: q = q.limit(args['page_size']) if args['page_number'] and args['page_size']: q = q.offset(args['page_number'] * args['page_size']) videos = q.all() return videos, 200, {'X-Total-Count': count} class CommentResource(flask_restful.Resource): @flask_restful.marshal_with(comment_fields) def get(self, video_id, comment_id): q = db.session.query(Association).join(Comment).filter( Association.video_id == video_id, Comment.id == comment_id) assoc = q.first() if not assoc: flask_restful.abort(404, message='Video {0} or comment {1} does not exist'.format(video_id, comment_id)) return assoc, 200 class CommentsResource(flask_restful.Resource): @flask_restful.marshal_with(comment_fields) def get(self, id): args = filter_parser.parse_args() q = db.session.query(Association).join(Comment).filter(Association.video_id == id) if q.count() == 0: flask_restful.abort(404, message='Video {0} does not exist'.format(id)) if args['filter']: q = q.filter(Comment.message_body.ilike('%{}%'.format(args['filter']))) count = q.count() if args['sort_order'] == 'random': q = q.order_by(sqlalchemy.func.random()) elif args['sort_by']: col = getattr(Comment, args['sort_by'], None) if col: if args['sort_order']: order_by = getattr(col, args['sort_order'], None) if order_by: q = q.order_by(order_by()) else: q = q.order_by(col) if args['page_size']: q = q.limit(args['page_size']) if args['page_number'] and args['page_size']: q = q.offset(args['page_number'] * args['page_size']) assocs = q.all() return assocs, 200, {'X-Total-Count': count} api.add_resource(VideoResource, '/videos/') api.add_resource(VideosResource, '/videos') api.add_resource(CommentResource, '/videos//comments/') api.add_resource(CommentsResource, '/videos//comments') if __name__ == '__main__': scheduler.start() app.run(host='0.0.0.0', threaded=True, debug=False)