Backend v1 (Prototype)
This commit is contained in:
commit
b926f604a9
131
api.py
Normal file
131
api.py
Normal file
@ -0,0 +1,131 @@
|
||||
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
|
||||
354
db.py
Normal file
354
db.py
Normal file
@ -0,0 +1,354 @@
|
||||
import datetime
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
|
||||
class SecretSantaDB:
|
||||
|
||||
def __init__(self):
|
||||
self.connection = sqlite3.connect("secret_santa_db.db", check_same_thread=False)
|
||||
self.connection.execute("PRAGMA foreign_keys = ON;")
|
||||
self.cursor = self.connection.cursor()
|
||||
self.create_tables()
|
||||
|
||||
|
||||
def create_tables(self):
|
||||
self.cursor.executescript(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS CYCLES
|
||||
(
|
||||
CYCLE_ID INTEGER PRIMARY KEY,
|
||||
CONSTELLATION_KEY TEXT NOT NULL,
|
||||
START_DATE TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ROUNDS
|
||||
(
|
||||
ROUND_ID INTEGER PRIMARY KEY,
|
||||
CYCLE_ID INTEGER NOT NULL,
|
||||
ROUND_NAME TEXT,
|
||||
CONSTELLATION_KEY TEXT NOT NULL,
|
||||
CREATION_DATE TEXT NOT NULL,
|
||||
FOREIGN KEY (CYCLE_ID) REFERENCES CYCLES (CYCLE_ID)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS PARTICIPANTS
|
||||
(
|
||||
IMP_ID INTEGER PRIMARY KEY,
|
||||
ROUND_ID INTEGER NOT NULL,
|
||||
NAME TEXT NOT NULL,
|
||||
WISH TEXT,
|
||||
EMAIL TEXT,
|
||||
FOREIGN KEY (ROUND_ID) REFERENCES ROUNDS (ROUND_ID),
|
||||
UNIQUE (ROUND_ID, EMAIL)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS PAIRS
|
||||
(
|
||||
ROUND_ID INTEGER NOT NULL,
|
||||
GIVER_IMP_ID INTEGER NOT NULL,
|
||||
RECEIVER_IMP_ID INTEGER NOT NULL,
|
||||
FOREIGN KEY (ROUND_ID) REFERENCES ROUNDS (ROUND_ID),
|
||||
FOREIGN KEY (GIVER_IMP_ID) REFERENCES PARTICIPANTS (IMP_ID),
|
||||
FOREIGN KEY (RECEIVER_IMP_ID) REFERENCES PARTICIPANTS (IMP_ID),
|
||||
UNIQUE (ROUND_ID, GIVER_IMP_ID),
|
||||
UNIQUE (ROUND_ID, RECEIVER_IMP_ID),
|
||||
CHECK (GIVER_IMP_ID != RECEIVER_IMP_ID)
|
||||
);
|
||||
|
||||
"""
|
||||
)
|
||||
self.commit_to_db()
|
||||
|
||||
def flush_tables(self):
|
||||
self.connection.execute("PRAGMA foreign_keys = OFF;")
|
||||
self.cursor.executescript(
|
||||
"""
|
||||
DROP TABLE ROUNDS;
|
||||
DROP TABLE PARTICIPANTS;
|
||||
DROP TABLE PAIRS;
|
||||
DROP TABLE CYCLES;
|
||||
"""
|
||||
)
|
||||
self.commit_to_db()
|
||||
self.connection.execute("PRAGMA foreign_keys = ON;")
|
||||
|
||||
def add_new_cycle(self, constellation_key: str) -> int:
|
||||
now = datetime.now().isoformat(timespec="seconds")
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO CYCLES (CONSTELLATION_KEY, START_DATE)
|
||||
VALUES (?, ?)
|
||||
""",
|
||||
(constellation_key, now,)
|
||||
)
|
||||
return self.cursor.lastrowid
|
||||
|
||||
def get_latest_cycle_id(self, constellation_key: str) -> int | None:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT CYCLE_ID
|
||||
FROM CYCLES
|
||||
WHERE CONSTELLATION_KEY = ?
|
||||
ORDER BY CYCLE_ID DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(constellation_key,)
|
||||
)
|
||||
row = self.cursor.fetchone()
|
||||
return row[0] if row else None
|
||||
|
||||
def count_rounds_in_cycle(self, cycle_id: int) -> int:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM ROUNDS
|
||||
WHERE CYCLE_ID = ?
|
||||
""",
|
||||
(cycle_id,)
|
||||
)
|
||||
return self.cursor.fetchone()[0]
|
||||
|
||||
def pair_used_in_cycle(self, cycle_id: int, giver_email: str, receiver_email: str) -> bool:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT 1
|
||||
FROM PAIRS p
|
||||
JOIN ROUNDS r ON r.ROUND_ID = p.ROUND_ID
|
||||
JOIN PARTICIPANTS g ON g.IMP_ID = p.GIVER_IMP_ID
|
||||
JOIN PARTICIPANTS rec ON rec.IMP_ID = p.RECEIVER_IMP_ID
|
||||
WHERE r.CYCLE_ID = ?
|
||||
AND lower(g.EMAIL) = lower(?)
|
||||
AND lower(rec.EMAIL) = lower(?)
|
||||
LIMIT 1
|
||||
""",
|
||||
(cycle_id, giver_email, receiver_email)
|
||||
)
|
||||
return self.cursor.fetchone() is not None
|
||||
|
||||
def add_participants(self, round_id:int, imps: dict):
|
||||
for name, data in imps.items():
|
||||
wish = data["wish"]
|
||||
email = data["email"]
|
||||
self.add_new_participant(round_id, name, wish, email)
|
||||
|
||||
def add_new_round(self,round_name:str, constellation_key: str, cycle_id: int) -> tuple[int, str]:
|
||||
created_at = datetime.now().isoformat(timespec="seconds")
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO ROUNDS (CREATION_DATE, CONSTELLATION_KEY, CYCLE_ID, ROUND_NAME)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(created_at, constellation_key, cycle_id, round_name,)
|
||||
)
|
||||
return self.cursor.lastrowid, created_at
|
||||
|
||||
def add_new_participant(self, round_id:int, name:str, wish: str | None, email: str) -> int:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO PARTICIPANTS (ROUND_ID, NAME, WISH, EMAIL)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(round_id, name, wish, email,)
|
||||
)
|
||||
return self.cursor.lastrowid
|
||||
|
||||
|
||||
def add_new_pair(self, round_id:int, giver_id:int, receiver_id:int):
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO PAIRS (ROUND_ID, GIVER_IMP_ID, RECEIVER_IMP_ID)
|
||||
VALUES (?, ?, ?)
|
||||
""",
|
||||
(round_id, giver_id, receiver_id,)
|
||||
)
|
||||
|
||||
def check_constellation(self, imps: dict) -> bool:
|
||||
prev_id = None
|
||||
for name, email, wish in imps.items():
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT ROUND_ID
|
||||
FROM PARTICIPANTS
|
||||
WHERE EMAIL = ?
|
||||
""",
|
||||
(imps[email])
|
||||
)
|
||||
row = self.cursor.fetchone()
|
||||
current_id = row[0]
|
||||
if prev_id is None:
|
||||
prev_id = current_id
|
||||
if current_id != prev_id:
|
||||
return False
|
||||
else:
|
||||
prev_id = current_id
|
||||
return True
|
||||
|
||||
|
||||
def get_imp_id_from_name(self, round_id, name:str) -> int | None:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT IMP_ID
|
||||
FROM PARTICIPANTS
|
||||
WHERE ROUND_ID = ? AND NAME = ?
|
||||
""",
|
||||
(round_id, name,)
|
||||
)
|
||||
|
||||
row = self.cursor.fetchone()
|
||||
return row[0] if row else None
|
||||
|
||||
def get_rows_from_email(self, email:str) -> list[tuple]:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT *
|
||||
FROM PARTICIPANTS
|
||||
WHERE EMAIL = ?
|
||||
""",
|
||||
(email,)
|
||||
)
|
||||
return self.cursor.fetchall()
|
||||
|
||||
def get_dates_with_round_ids_and_round_names_from_email(self, email:str) -> list[list]:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT rounds.ROUND_ID, rounds.ROUND_NAME, rounds.CREATION_DATE
|
||||
FROM ROUNDS rounds
|
||||
JOIN PARTICIPANTS participants ON participants.ROUND_ID = rounds.ROUND_ID AND participants.email = ?
|
||||
ORDER BY rounds.CREATION_DATE ASC
|
||||
""",
|
||||
(email,)
|
||||
)
|
||||
|
||||
return [[row[0], row[1], row[2]] for row in self.cursor.fetchall()]
|
||||
|
||||
def get_round_id_from_date(self, date:str) -> int:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT ROUND_ID
|
||||
FROM ROUNDS
|
||||
WHERE CREATION_DATE = ?
|
||||
""",
|
||||
(date,)
|
||||
)
|
||||
row = self.cursor.fetchone()
|
||||
return row[0]
|
||||
|
||||
def get_name_from_email_and_round_id(self, email:str, round_id:int) -> str:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT NAME
|
||||
FROM PARTICIPANTS
|
||||
WHERE EMAIL = ? AND ROUND_ID = ?
|
||||
""",
|
||||
(email, round_id,)
|
||||
)
|
||||
row = self.cursor.fetchone()
|
||||
return row[0]
|
||||
|
||||
def get_name_from_email(self, email:str) -> str:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT NAME
|
||||
FROM PARTICIPANTS
|
||||
WHERE EMAIL = ?
|
||||
""",
|
||||
(email,)
|
||||
)
|
||||
row = self.cursor.fetchone()
|
||||
return row[0]
|
||||
|
||||
def get_wish_from_id_and_round_id(self, imp_id:int, round_id:int) -> str:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT WISH
|
||||
FROM PARTICIPANTS
|
||||
WHERE IMP_ID = ? AND ROUND_ID = ?
|
||||
""",
|
||||
(imp_id, round_id,)
|
||||
)
|
||||
row = self.cursor.fetchone()
|
||||
return row[0]
|
||||
|
||||
|
||||
def get_participants_from_round_id(self, round_id:int) -> list[str]:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT NAME
|
||||
FROM PARTICIPANTS
|
||||
WHERE ROUND_ID = ?
|
||||
""",
|
||||
(round_id,)
|
||||
)
|
||||
rows = self.cursor.fetchall()
|
||||
return [row[0] for row in rows]
|
||||
|
||||
def get_round_id_from_email(self, email:str) -> int:
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT rounds.ROUND_ID
|
||||
FROM ROUNDS rounds
|
||||
JOIN PARTICIPANTS participants ON participants.ROUND_ID = rounds.ROUND_ID
|
||||
WHERE lower(participants.EMAIL) = lower(?)
|
||||
ORDER BY rounds.CREATION_DATE DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(email,)
|
||||
)
|
||||
row = self.cursor.fetchone()
|
||||
if not row:
|
||||
raise ValueError("Keine Runde für diese Email gefunden.")
|
||||
return row[0]
|
||||
|
||||
def get_pairs(self, round_id:int) -> dict:
|
||||
pairs = {}
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT giver.NAME AS giver_name,
|
||||
receiver.NAME AS receiver_name
|
||||
FROM PAIRS p
|
||||
JOIN PARTICIPANTS giver
|
||||
ON giver.IMP_ID = p.GIVER_IMP_ID AND giver.ROUND_ID = p.ROUND_ID
|
||||
JOIN PARTICIPANTS receiver
|
||||
ON receiver.IMP_ID = p.RECEIVER_IMP_ID AND receiver.ROUND_ID = p.ROUND_ID
|
||||
WHERE p.ROUND_ID = ?
|
||||
""",
|
||||
(round_id,)
|
||||
)
|
||||
rows = self.cursor.fetchall()
|
||||
for row in rows:
|
||||
giver_name = row[0]
|
||||
receiver_name = row[1]
|
||||
pairs[giver_name] = receiver_name
|
||||
|
||||
return pairs
|
||||
|
||||
def delete_round(self, round_id: int):
|
||||
self.cursor.execute("DELETE FROM PAIRS WHERE ROUND_ID = ?", (round_id,))
|
||||
self.cursor.execute("DELETE FROM PARTICIPANTS WHERE ROUND_ID = ?", (round_id,))
|
||||
self.cursor.execute("DELETE FROM ROUNDS WHERE ROUND_ID = ?", (round_id,))
|
||||
|
||||
def commit_to_db(self):
|
||||
try:
|
||||
self.connection.commit()
|
||||
except Exception:
|
||||
self.connection.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def debug_print_table(self, table: str, limit: int = 50):
|
||||
self.cursor.execute(f"SELECT * FROM {table} LIMIT ?", (limit,))
|
||||
rows = self.cursor.fetchall()
|
||||
print(f"--- {table} ({len(rows)} rows) ---")
|
||||
for r in rows:
|
||||
print(r)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
db_test = SecretSantaDB()
|
||||
#db_test.flush_tables()
|
||||
#db_test.create_tables()
|
||||
#db_test.debug_print_table("CYCLES")
|
||||
db_test.debug_print_table("ROUNDS")
|
||||
db_test.debug_print_table("PARTICIPANTS")
|
||||
db_test.debug_print_table("PAIRS")
|
||||
|
||||
120
generator.py
Normal file
120
generator.py
Normal file
@ -0,0 +1,120 @@
|
||||
import random
|
||||
from db import SecretSantaDB
|
||||
import hashlib
|
||||
|
||||
class SecretSantaGenerator:
|
||||
|
||||
def __init__(self, imp_size: int, db: SecretSantaDB):
|
||||
self.imp_size = imp_size
|
||||
self.db = db
|
||||
|
||||
def constellation_key(self, imps: dict) -> str:
|
||||
emails = sorted([data["email"].strip().lower() for data in imps.values()])
|
||||
raw = "|".join(emails)
|
||||
return hashlib.sha256(raw.encode("utf-8")).hexdigest()
|
||||
|
||||
def derangements(self, n: int) -> int:
|
||||
if n == 0: return 1
|
||||
if n == 1: return 0
|
||||
a, b = 1, 0
|
||||
for k in range(2, n + 1):
|
||||
a, b = b, (k - 1) * (a + b)
|
||||
return b
|
||||
|
||||
def pair_exists(self, cycle_id: int, imp_pairs: dict, giver: str, receiver: str, imps: dict) -> bool:
|
||||
if giver == receiver:
|
||||
return True
|
||||
if giver in imp_pairs:
|
||||
return True
|
||||
if receiver in imp_pairs.values():
|
||||
return True
|
||||
|
||||
giver_email = imps[giver]["email"]
|
||||
receiver_email = imps[receiver]["email"]
|
||||
|
||||
if self.db.pair_used_in_cycle(cycle_id, giver_email, receiver_email):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def generate_imp_pairs(self, round_id: int, imps: dict, cycle_id: int):
|
||||
names = list(imps.keys())
|
||||
n = len(names)
|
||||
|
||||
emails = {name: imps[name]["email"] for name in names}
|
||||
|
||||
def is_allowed(giver: str, receiver: str, current: dict) -> bool:
|
||||
if giver == receiver:
|
||||
return False
|
||||
if giver in current:
|
||||
return False
|
||||
if receiver in current.values():
|
||||
return False
|
||||
return not self.db.pair_used_in_cycle(cycle_id, emails[giver], emails[receiver])
|
||||
|
||||
givers = names[:]
|
||||
|
||||
def backtrack(i: int, current: dict) -> dict | None:
|
||||
if i == n:
|
||||
return current
|
||||
|
||||
giver = givers[i]
|
||||
|
||||
candidates = names[:]
|
||||
random.shuffle(candidates)
|
||||
|
||||
for receiver in candidates:
|
||||
if not is_allowed(giver, receiver, current):
|
||||
continue
|
||||
current[giver] = receiver
|
||||
result = backtrack(i + 1, current)
|
||||
if result is not None:
|
||||
return result
|
||||
del current[giver]
|
||||
|
||||
return None
|
||||
|
||||
pairs = backtrack(0, {})
|
||||
if pairs is None:
|
||||
raise RuntimeError("Keine gültige Zuordnung im aktuellen Cycle möglich. Neuer Cycle nötig.")
|
||||
|
||||
for giver, receiver in pairs.items():
|
||||
giver_id = self.db.get_imp_id_from_name(round_id, giver)
|
||||
receiver_id = self.db.get_imp_id_from_name(round_id, receiver)
|
||||
self.db.add_new_pair(round_id, giver_id, receiver_id)
|
||||
|
||||
def create_new_round(self,round_name: str, participants: dict[str, dict]) -> tuple[int, str]:
|
||||
|
||||
try:
|
||||
key = self.constellation_key(participants)
|
||||
|
||||
latest_cycle = self.db.get_latest_cycle_id(key)
|
||||
|
||||
max_permutations = self.derangements(len(participants))
|
||||
|
||||
if latest_cycle is None:
|
||||
cycle_id = self.db.add_new_cycle(key)
|
||||
else:
|
||||
used_permutations = self.db.count_rounds_in_cycle(latest_cycle)
|
||||
if used_permutations < max_permutations:
|
||||
cycle_id = latest_cycle
|
||||
else:
|
||||
cycle_id = self.db.add_new_cycle(key)
|
||||
|
||||
round_id, created_at = self.db.add_new_round(round_name, key, cycle_id)
|
||||
|
||||
self.db.add_participants(round_id, participants)
|
||||
try:
|
||||
self.generate_imp_pairs(round_id, participants, cycle_id)
|
||||
except RuntimeError:
|
||||
cycle_id = self.db.add_new_cycle(key)
|
||||
round_id, created_at = self.db.add_new_round(round_name, key, cycle_id)
|
||||
self.db.add_participants(round_id, participants)
|
||||
self.generate_imp_pairs(round_id, participants, cycle_id)
|
||||
|
||||
self.db.commit_to_db()
|
||||
return round_id, created_at
|
||||
|
||||
except Exception as e:
|
||||
self.db.connection.rollback()
|
||||
raise RuntimeError(f"Fehler beim Erstellen der Runde: {e}")
|
||||
BIN
secret_santa_db.db
Normal file
BIN
secret_santa_db.db
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user