Files
Rolf 3a1da1482c Add full SkinsPins application
- 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>
2026-03-20 10:16:46 +01:00

113 lines
4.2 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("/", response_class=HTMLResponse)
async def dashboard(request: Request, user: dict = Depends(get_current_user),
db: aiosqlite.Connection = Depends(get_db)):
uid = user["id"]
# Games played (completed)
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]
# Victories: completed games where this user has the highest total points
# For each completed game the user played, rank players by total points
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,
MAX(hs.bingo + hs.bango + hs.bongo) AS top_hole_score
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:
game_id = row["game_id"]
my_total = row["my_total"]
# Get the max total among all players in this game
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
)""",
(game_id,),
) as c2:
max_total = (await c2.fetchone())[0] or 0
if my_total >= max_total and my_total > 0:
victories += 1
# Recent completed games with results
async with db.execute(
"""SELECT g.id, g.holes_count, g.created_at, g.format, c.name AS course_name
FROM games g
LEFT JOIN courses c ON c.id = g.course_id
JOIN game_players gp ON gp.game_id = g.id
WHERE gp.user_id = ? AND g.status = 'completed'
ORDER BY g.created_at DESC LIMIT 5""",
(uid,),
) as c:
recent_games = [dict(r) for r in await c.fetchall()]
# For each recent game, get player totals
for game in recent_games:
async with db.execute(
"""SELECT u.id, u.name, u.avatar,
SUM(hs.bingo + hs.bango + hs.bongo) AS total
FROM hole_scores hs JOIN users u ON hs.user_id = u.id
WHERE hs.game_id = ?
GROUP BY hs.user_id
ORDER BY total DESC""",
(game["id"],),
) as c:
game["results"] = [dict(r) for r in await c.fetchall()]
# All active games (social stream)
async with db.execute(
"""SELECT g.id, g.holes_count, g.created_at, g.format, c.name AS course_name
FROM games g
LEFT JOIN courses c ON c.id = g.course_id
WHERE g.status = 'active'
ORDER BY g.created_at DESC""",
) as c:
active_games = [dict(r) for r in await c.fetchall()]
for game in active_games:
async with db.execute(
"""SELECT u.id, u.name, u.avatar,
COALESCE(SUM(hs.bingo + hs.bango + hs.bongo), 0) AS total
FROM game_players gp
JOIN users u ON u.id = gp.user_id
LEFT JOIN hole_scores hs ON hs.game_id = gp.game_id AND hs.user_id = u.id
WHERE gp.game_id = ?
GROUP BY u.id
ORDER BY total DESC""",
(game["id"],),
) as c:
game["players"] = [dict(r) for r in await c.fetchall()]
game["is_participant"] = any(p["id"] == uid for p in game["players"])
return templates.TemplateResponse("dashboard/dashboard.html", {
"request": request, "user": user,
"games_played": games_played, "victories": victories,
"recent_games": recent_games,
"active_games": active_games,
})