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, Product, Variant 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_products', func='sync:Sync.sync_products', 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) product_fields = { 'id': flask_restful.fields.Integer(), 'name': flask_restful.fields.String(), 'product_name': flask_restful.fields.String(), 'price': flask_restful.fields.String(), 'time_left': flask_restful.fields.String(), 'days_left': flask_restful.fields.Integer(), 'url': flask_restful.fields.String(), 'image_url': flask_restful.fields.String(), } variant_fields = { 'id': flask_restful.fields.Integer(), 'color': flask_restful.fields.String(), 'front_url': flask_restful.fields.String(), 'back_url': flask_restful.fields.String(), } filter_parser = flask_restful.reqparse.RequestParser() filter_parser.add_argument('filter', type=str) filter_parser.add_argument('type', 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 ProductResource(flask_restful.Resource): @flask_restful.marshal_with(product_fields) def get(self, id): q = db.session.query(Product).filter(Product.id == id) product = q.first() if not product: flask_restful.abort(404, message='Product {0} does not exist'.format(id)) return product, 200 class ProductsResource(flask_restful.Resource): @flask_restful.marshal_with(product_fields) def get(self): args = filter_parser.parse_args() q = db.session.query(Product) if args['filter']: q = q.filter(Product.name.ilike('%{}%'.format(args['filter']))) if args['type']: q = q.filter(Product.product_name.ilike('%{}%'.format(args['type']))) count = q.count() if args['sort_order'] == 'random': q = q.order_by(sqlalchemy.func.random()) elif args['sort_by']: col = getattr(Product, 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']) products = q.all() return products, 200, {'X-Total-Count': count} class VariantResource(flask_restful.Resource): @flask_restful.marshal_with(variant_fields) def get(self, product_id, id): q = db.session.query(Variant).filter(Variant.product_id == product_id, Variant.id == id) variant = q.first() if not variant: flask_restful.abort(404, message='Variant {0} does not exist'.format(id)) return variant, 200 class VariantsResource(flask_restful.Resource): @flask_restful.marshal_with(variant_fields) def get(self, product_id): args = filter_parser.parse_args() q = db.session.query(Variant).filter(Variant.product_id == product_id) if args['filter']: q = q.filter(Variant.color.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(Variant, 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']) variants = q.all() return variants, 200, {'X-Total-Count': count} api.add_resource(ProductResource, '/products/') api.add_resource(ProductsResource, '/products') api.add_resource(VariantResource, '/products//variants/') api.add_resource(VariantsResource, '/products//variants') if __name__ == '__main__': scheduler.start() app.run(host='0.0.0.0', threaded=True, debug=False)