Integrate join codes, player management, and themes
This update introduces "join codes" for games to simplify game joining. Enhancements include player role and winner management for better organization. Additionally, theme preferences are now user-configurable and persisted server-side.
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from .db import Base, engine, SessionLocal
|
||||
from .models import User, Entry, Category, Role
|
||||
from .models import User, Entry, Category, Role, Game, GameMember
|
||||
from .security import hash_password
|
||||
from .routes.auth import router as auth_router
|
||||
from .routes.admin import router as admin_router
|
||||
@@ -14,7 +19,10 @@ app = FastAPI(title="Cluedo Sheet")
|
||||
# Intern: Frontend läuft auf :8081
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:8081", "http://127.0.0.1:8081"],
|
||||
allow_origins=[
|
||||
"http://localhost:8081",
|
||||
"http://127.0.0.1:8081",
|
||||
],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
@@ -24,9 +32,71 @@ app.include_router(auth_router)
|
||||
app.include_router(admin_router)
|
||||
app.include_router(games_router)
|
||||
|
||||
def _rand_join_code(n: int = 6) -> str:
|
||||
# digits only (kahoot style)
|
||||
return "".join(random.choice(string.digits) for _ in range(n))
|
||||
|
||||
def _auto_migrate(db: Session):
|
||||
"""
|
||||
Very small, pragmatic auto-migration (no alembic).
|
||||
- creates missing tables via create_all
|
||||
- adds missing columns via ALTER TABLE (best effort)
|
||||
"""
|
||||
# Users.theme_key
|
||||
try:
|
||||
db.execute(text("ALTER TABLE users ADD COLUMN theme_key VARCHAR DEFAULT 'default'"))
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
|
||||
# Games.join_code + winner_user_id
|
||||
try:
|
||||
db.execute(text("ALTER TABLE games ADD COLUMN join_code VARCHAR"))
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
|
||||
try:
|
||||
db.execute(text("ALTER TABLE games ADD COLUMN winner_user_id VARCHAR"))
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
|
||||
# SheetState.chip_code
|
||||
try:
|
||||
db.execute(text("ALTER TABLE sheet_state ADD COLUMN chip_code VARCHAR"))
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
|
||||
# Ensure unique index for join_code (best effort)
|
||||
try:
|
||||
db.execute(text("CREATE UNIQUE INDEX IF NOT EXISTS ix_games_join_code ON games (join_code)"))
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
|
||||
# Backfill join_code for existing games
|
||||
games = db.query(Game).filter((Game.join_code == None) | (Game.join_code == "")).all() # noqa: E711
|
||||
if games:
|
||||
used = set([r[0] for r in db.execute(text("SELECT join_code FROM games WHERE join_code IS NOT NULL")).all() if r[0]])
|
||||
for g in games:
|
||||
code = _rand_join_code()
|
||||
while code in used:
|
||||
code = _rand_join_code()
|
||||
g.join_code = code
|
||||
used.add(code)
|
||||
db.commit()
|
||||
|
||||
# Backfill membership: ensure owner is member
|
||||
all_games = db.query(Game).all()
|
||||
for g in all_games:
|
||||
exists = db.query(GameMember).filter(GameMember.game_id == g.id, GameMember.user_id == g.owner_user_id).first()
|
||||
if not exists:
|
||||
db.add(GameMember(game_id=g.id, user_id=g.owner_user_id))
|
||||
db.commit()
|
||||
|
||||
def seed_entries(db: Session):
|
||||
# Du kannst hier deine HP-Edition Einträge reinschreiben.
|
||||
# (Für rein private Nutzung ok – öffentlich würde ich’s generisch machen.)
|
||||
if db.query(Entry).count() > 0:
|
||||
return
|
||||
suspects = ["Draco Malfoy","Crabbe & Goyle","Lucius Malfoy","Dolores Umbridge","Peter Pettigrew","Bellatrix Lestrange"]
|
||||
@@ -46,14 +116,24 @@ def ensure_admin(db: Session):
|
||||
admin_pw = os.environ.get("ADMIN_PASSWORD", "ChangeMeNow123!")
|
||||
u = db.query(User).filter(User.email == admin_email).first()
|
||||
if not u:
|
||||
db.add(User(email=admin_email, password_hash=hash_password(admin_pw), role=Role.admin.value))
|
||||
db.add(
|
||||
User(
|
||||
email=admin_email,
|
||||
password_hash=hash_password(admin_pw),
|
||||
role=Role.admin.value,
|
||||
theme_key="default",
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
|
||||
@app.on_event("startup")
|
||||
def on_startup():
|
||||
# create new tables
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
_auto_migrate(db)
|
||||
ensure_admin(db)
|
||||
seed_entries(db)
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user