Files
gh-christianlouis-leagueledger/app/views/leaderboard.py
T
Christian Krakau-Louis 15e1dc227b Add multi-league foundation
2026-05-22 20:47:28 +02:00

101 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""
Leaderboard views for displaying team rankings.
"""
from fastapi import APIRouter, Depends, Request, Query
from fastapi.responses import HTMLResponse
from sqlalchemy.orm import Session
from sqlalchemy import func, desc
from datetime import datetime, timedelta
from ..db import SessionLocal
from ..models import Team, TeamMembership, QRCode, User
from ..league_context import get_active_leagues, resolve_selected_league
from ..templates_config import templates
router = APIRouter()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@router.get("/", response_class=HTMLResponse)
async def show_leaderboard(
request: Request,
timeframe: str = Query("all", regex="^(week|month|all)$"),
league_id: int = Query(None),
db: Session = Depends(get_db)
):
"""Show the leaderboard with team rankings."""
# Get user from session for navbar
user = None
user_id = request.session.get("user_id")
if user_id:
user = db.query(User).get(user_id)
selected_league = resolve_selected_league(db, league_id)
leagues = get_active_leagues(db)
# Define cutoff date based on timeframe
cutoff_date = None
if timeframe == "week":
cutoff_date = datetime.now() - timedelta(days=7)
time_label = "This Week"
elif timeframe == "month":
cutoff_date = datetime.now() - timedelta(days=30)
time_label = "This Month"
else:
timeframe = "all" # Ensure valid value
time_label = "All Time"
# Base query to get teams
query = db.query(
Team.id,
Team.name,
func.coalesce(func.sum(QRCode.points), 0).label('total_points')
).join(
QRCode,
QRCode.redeemed_at_team == Team.id,
isouter=True
).filter(Team.league_id == selected_league.id)
# Apply time filter if needed
if cutoff_date:
# Filter by redeemed_at timestamp if available
query = query.filter(QRCode.redeemed_at >= cutoff_date)
# Group and order
teams_ranking = query.group_by(Team.id, Team.name).order_by(desc('total_points')).all()
# Add ranks
ranked_teams = []
for idx, team in enumerate(teams_ranking):
ranked_teams.append({
'rank': idx + 1,
'id': team.id,
'name': team.name,
'points': team.total_points,
'change': 0 # Placeholder for rank change - would require historical data
})
# Get top 3 teams for podium display
top_teams = ranked_teams[:3] if len(ranked_teams) >= 3 else ranked_teams + [None] * (3 - len(ranked_teams))
return templates.TemplateResponse(
"leaderboard.html",
{
"request": request,
"teams": ranked_teams,
"top_teams": top_teams,
"timeframe": timeframe,
"time_label": time_label,
"leagues": leagues,
"selected_league": selected_league,
"user": user # Add user to the context
}
)