# UGE / L2 / Intro to relational databases / Python project prototype # Author: Pacien TRAN-GIRARD # Licence: EUPL-1.2 from decimal import Decimal from fastapi import APIRouter, Form, Depends, status from embrace.exceptions import IntegrityError from psycopg2.errors import CheckViolation from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE from app_sessions import UserSession from app_database import db_transaction router = APIRouter() # TODO: add paging for the transaction history @router.get('/wallet') def wallet( session: UserSession=Depends(UserSession.authenticated), ): with db_transaction() as tx: history = tx.fetch_transactions(user_id=session.get_user_id()) return list(history) @router.post('/wallet/transfer') def wallet_transfer( session: UserSession=Depends(UserSession.authenticated), recipient: str=Form(...), amount: Decimal=Form(...), ): if amount <= 0: return 'error: Invalid transaction amount.' try: with db_transaction(ISOLATION_LEVEL_SERIALIZABLE) as tx: recipient_user = tx.fetch_account_username(username=recipient) if recipient_user is None: raise LookupError('Could not find recipient') tx.transfer( from_user_id=session.get_user_id(), to_user_id=recipient_user.id, amount=amount, fee=amount * Decimal(0.10)) return 'Your business is appreciated.' except LookupError as exception: return 'error: ' + str(exception) except IntegrityError as exception: if isinstance(exception.__cause__, CheckViolation): return 'error: Insufficient funds.' else: raise exception @router.post('/wallet/deposit') def wallet_deposit( session: UserSession=Depends(UserSession.authenticated), amount: Decimal=Form(...), ): if amount <= 0: return 'error: Invalid transaction amount.' with db_transaction(ISOLATION_LEVEL_SERIALIZABLE) as tx: tx.deposit(user_id=session.get_user_id(), amount=amount) return 'Your business is appreciated.' @router.post('/wallet/withdraw') def wallet_withdraw( session: UserSession=Depends(UserSession.authenticated), amount: Decimal=Form(...), ): if amount <= 0: return 'error: Invalid transaction amount.' try: with db_transaction(ISOLATION_LEVEL_SERIALIZABLE) as tx: tx.withdraw(user_id=session.get_user_id(), amount=amount) return 'Annnnnd... It\'s gone.' except IntegrityError as exception: if isinstance(exception.__cause__, CheckViolation): return 'error: Insufficient funds.' else: raise exception