3a1da1482c
- FastAPI + SQLite + Alpine.js + HTMX PWA for Bingo Bango Bongo golf scoring - Passwordless magic link auth with email (aiosmtplib) and admin invite system - Real-time score entry via WebSocket with drag-and-drop player ordering - Course management with per-hole par and stroke index - Scorecard with golf score markers (birdie, eagle, bogey, etc.) - Two-step new game form with tee selection per player - Dashboard with stats, live games social stream, and recent game history - Game summary view (read-only scorecard with leaderboard) - User profile pages with win stats - PWA install support with generated PNG icons - Admin panel for users, courses, games, and invitations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
from fastapi import APIRouter, Depends, Request
|
|
from fastapi.responses import HTMLResponse
|
|
import aiosqlite
|
|
|
|
from app.database import get_db
|
|
from app.dependencies import get_current_user
|
|
from app.templates_config import templates
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/users/{user_id}", response_class=HTMLResponse)
|
|
async def user_profile(user_id: str, request: Request,
|
|
user: dict = Depends(get_current_user),
|
|
db: aiosqlite.Connection = Depends(get_db)):
|
|
async with db.execute(
|
|
"SELECT id, name, handicap, avatar FROM users WHERE id = ? AND is_onboarded = 1",
|
|
(user_id,),
|
|
) as c:
|
|
profile = await c.fetchone()
|
|
if not profile:
|
|
from fastapi.responses import RedirectResponse
|
|
return RedirectResponse("/", status_code=302)
|
|
|
|
uid = user_id
|
|
|
|
async with db.execute(
|
|
"""SELECT COUNT(*) FROM games
|
|
WHERE status = 'completed'
|
|
AND id IN (SELECT game_id FROM game_players WHERE user_id = ?)""",
|
|
(uid,),
|
|
) as c:
|
|
games_played = (await c.fetchone())[0]
|
|
|
|
async with db.execute(
|
|
"""SELECT gp.game_id,
|
|
SUM(CASE WHEN hs.user_id = ? THEN hs.bingo + hs.bango + hs.bongo ELSE 0 END) AS my_total
|
|
FROM game_players gp
|
|
JOIN games g ON g.id = gp.game_id
|
|
JOIN hole_scores hs ON hs.game_id = gp.game_id
|
|
WHERE gp.user_id = ? AND g.status = 'completed'
|
|
GROUP BY gp.game_id""",
|
|
(uid, uid),
|
|
) as c:
|
|
game_rows = await c.fetchall()
|
|
|
|
victories = 0
|
|
for row in game_rows:
|
|
async with db.execute(
|
|
"""SELECT MAX(player_total) FROM (
|
|
SELECT user_id, SUM(bingo + bango + bongo) AS player_total
|
|
FROM hole_scores WHERE game_id = ? GROUP BY user_id
|
|
)""",
|
|
(row["game_id"],),
|
|
) as c2:
|
|
max_total = (await c2.fetchone())[0] or 0
|
|
if row["my_total"] >= max_total and row["my_total"] > 0:
|
|
victories += 1
|
|
|
|
win_pct = round((victories / games_played) * 100) if games_played > 0 else None
|
|
|
|
return templates.TemplateResponse(
|
|
"users/profile.html",
|
|
{"request": request, "user": user, "profile": dict(profile),
|
|
"games_played": games_played, "victories": victories, "win_pct": win_pct},
|
|
)
|