from datetime import datetime from flask import Flask, render_template, request, abort, jsonify import peewee from playhouse.shortcuts import model_to_dict import database import util app = Flask(__name__) app.config["DEBUG"] = True @app.before_request def before_request(): database.instance.connect() @app.after_request def after_request(response): database.instance.close() return response @app.route("/") def home(): puppies = ['hollie', 'grace', 'loki'] return render_template('index.html', puppies=puppies) @app.route("/users") def users(): args = request.args.to_dict() if 'username' not in args: abort(400) username = args['username'].strip() try: return model_to_dict(database.User.get(database.User.username == username)) except peewee.DoesNotExist: abort(404) except: abort(500) @app.route("/transactions", methods=["GET", "POST"]) def transactions(): if request.method == "GET": args = request.args.to_dict() if 'user_id' not in args: abort(400) user_id = args['user_id'].strip() try: july_2022 = datetime(2022, 7, 1, 0) transactions = database.Transaction.select().where( (database.Transaction.user == user_id) & (database.Transaction.transaction_date > july_2022) ) return [model_to_dict(t) for t in transactions] except peewee.DoesNotExist: abort(404) except: abort(500) if request.method == "POST": body = request.get_json() try: user = database.User.get(database.User.uuid == body['user_id']) category = database.TransactionCategory.get(database.TransactionCategory.name == body['category']) database.Transaction.create( user=user, subcategory=category, transaction_date=body['transaction_date'], description=body['description'], amount=body['amount'], type=body['type'], notes=body['notes'] ) return ('', 200) except peewee.DoesNotExist: abort(404) except KeyError: abort(400) # Default if no method is hit abort(400) @app.route("/transactions/", methods=["PUT"]) def transaction(uuid=None): if request.method == "PUT": if not uuid: abort(400) body = request.get_json() if 'category' not in body or 'notes' not in body: abort(400) try: category = database.TransactionCategory.get(database.TransactionCategory.name == body['category']) transaction = database.Transaction.get(database.Transaction.primary_key == uuid) transaction.subcategory = category transaction.notes = body['notes'] transaction.save() return ('', 200) except peewee.DoesNotExist: abort(404) except: abort(500) # Default if no method is hit abort(400) @app.route("/transactions/visualize", methods=["GET"]) def visualize_transactions(): args = request.args.to_dict() required_args = ['user_id', 'period', 'date'] # Example date format: '2023-01-25' if not all(arg in args for arg in required_args): abort(400, "Missing required query parameters: user_id, period, date") user_id = args['user_id'].strip() period = args['period'].strip() try: date = datetime.strptime(args['date'], '%Y-%m-%d') except ValueError: abort(400, "Invalid date format, use YYYY-MM-DD") try: start_date, end_date = util.get_start_end_dates(period, date) result = util.aggregate_transactions_by_category(user_id, start_date, end_date) return jsonify(result) except ValueError as e: abort(400, str(e)) except peewee.DoesNotExist: abort(404) except Exception as e: abort(500, str(e)) @app.route("/categories", methods=["GET", "POST"]) def categories(): if request.method == "GET": try: raw_categories = database.TransactionCategory.select() categories = {} for category in raw_categories: if not category.parent: categories[category.name] = [] for category in raw_categories: if category.parent: categories[category.parent.name].append(category.name) return categories except peewee.DoesNotExist: abort(404) except: abort(500) if request.method == "POST": body = request.get_json() try: if 'parent' in body: parent = database.TransactionCategory.get(database.TransactionCategory.name == body['parent']) database.TransactionCategory.create(name=body['name'], parent=parent) else: database.TransactionCategory.create(name=body['name']) return ('', 200) except peewee.DoesNotExist: abort(404) except: abort(500) # Should never get here. abort(500) app.run()