2026-01-09 16:53:37 +01:00

131 lines
4.0 KiB
Python

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