from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel, EmailStr from typing import List, Optional, Any from db import SecretSantaDB from generator import SecretSantaGenerator app = FastAPI() database = SecretSantaDB() app.add_middleware( CORSMiddleware, allow_origins=[ "http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:5500", "http://127.0.0.1:5500", "http://localhost:3000", "http://127.0.0.1:3000", ], allow_credentials=True, allow_methods=["*"], ) class Participant(BaseModel): name: str email: EmailStr wish: str | None = None class CreateRoundRequest(BaseModel): round_name: Optional[str] participants: List[Participant] class CreateRoundResponse(BaseModel): round_id: int created_at: str class RevealRequest(BaseModel): email: EmailStr choice_index: Optional[int] = None class RoundChoice(BaseModel): index: int round_name: str created_at: str participants: list[str] class RevealResponse(BaseModel): giver: Optional[str] = None receiver: Optional[str] = None wish: Optional[str] = None choices: Optional[List[RoundChoice]] = None @app.post("/api/rounds", response_model=CreateRoundResponse) def create_round(req: CreateRoundRequest): participants_list = req.participants round_name = req.round_name if len(participants_list) < 3: raise HTTPException(status_code=400, detail="Mindestens 3 Teilnehmer nötig.") participants = { participant.name: {"email": str(participant.email), "wish": participant.wish} for participant in participants_list } generator = SecretSantaGenerator(imp_size=len(participants_list), db=database) round_id, created_at = generator.create_new_round(round_name, participants) return { "round_id": round_id, "created_at": created_at } @app.post("/api/reveal", response_model=RevealResponse) def reveal(req: RevealRequest): email = str(req.email).strip().lower() rows = database.get_rows_from_email(email) appearances = len(rows) if appearances > 1: choices = get_choices(email) response_choice = req.choice_index if response_choice is None: public_choices = [ RoundChoice(index=i, created_at=choice["date"], participants=choice.get("participants", []), round_name=choice["round_name"]) for i, choice in choices.items() ] return RevealResponse(choices=public_choices) if response_choice not in choices: raise HTTPException(status_code=400, detail="Ungültige Auswahl.") round_id = choices[response_choice]["round_id"] giver = database.get_name_from_email_and_round_id(email, round_id) imp_pairs = database.get_pairs(round_id) else: giver = database.get_name_from_email(email) try: round_id = database.get_round_id_from_email(email) imp_pairs = database.get_pairs(round_id) except Exception: raise RuntimeError("Bitte erst eine Runde erstellen...") if giver and imp_pairs: try: receiver = imp_pairs[giver] receiver_id = database.get_imp_id_from_name(round_id, receiver) wish = database.get_wish_from_id_and_round_id(receiver_id, round_id) return {"giver": giver, "receiver": receiver, "wish": wish} except Exception as e: raise HTTPException(status_code=500, detail=f"Etwas ist schiefgelaufen: {e}") def get_choices(email) -> dict[int, dict[str, list[str] | Any]]: choices = {} rows = database.get_dates_with_round_ids_and_round_names_from_email(email) for i, row in enumerate(rows, start=1): round_id = row[0] participants = database.get_participants_from_round_id(round_id) choices[i] = {"round_id": row[0], "round_name": row[1], "date": row[2], "participants": participants} return choices