import asyncio import logging import uuid from contextlib import asynccontextmanager from sqlalchemy.orm import Session from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from database import SessionLocal, get_db from database_functions import fill_card_pool from models import Card as CardModel from models import User as UserModel from card import _get_cards_async from auth import hash_password, verify_password, create_access_token, decode_access_token logger = logging.getLogger("app") # Auth oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") class RegisterRequest(BaseModel): username: str email: str password: str def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)) -> UserModel: user_id = decode_access_token(token) if not user_id: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token") user = db.query(UserModel).filter(UserModel.id == uuid.UUID(user_id)).first() if not user: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found") return user @asynccontextmanager async def lifespan(app: FastAPI): asyncio.create_task(fill_card_pool()) yield app = FastAPI(lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:5173"], # SvelteKit's default dev port allow_methods=["*"], allow_headers=["*"], ) @app.get("/pack/{size}") async def open_pack(size: int = 10, user: UserModel = Depends(get_current_user)): cards = await _get_cards_async(size) return [ {**card._asdict(), "card_type": card.card_type.name, "card_rarity": card.card_rarity.name} for card in cards ] @app.post("/register") def register(req: RegisterRequest, db: Session = Depends(get_db)): if db.query(UserModel).filter(UserModel.username == req.username).first(): raise HTTPException(status_code=400, detail="Username already taken") if db.query(UserModel).filter(UserModel.email == req.email).first(): raise HTTPException(status_code=400, detail="Email already registered") user = UserModel( id=uuid.uuid4(), username=req.username, email=req.email, password_hash=hash_password(req.password), ) db.add(user) db.commit() return {"message": "User created"} @app.post("/login") def login(form: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)): user = db.query(UserModel).filter(UserModel.username == form.username).first() if not user or not verify_password(form.password, user.password_hash): raise HTTPException(status_code=400, detail="Invalid username or password") token = create_access_token(str(user.id)) return {"access_token": token, "token_type": "bearer"}