Files
WeightTracker/app/routes/leaderboard.py
2026-02-24 21:12:45 +11:00

84 lines
3.0 KiB
Python

from flask import Blueprint, render_template
from app.auth import login_required
from app.db import query, query_one
from app import SYDNEY_TZ
from app.utils import calculate_streak
from datetime import timezone
bp = Blueprint("leaderboard", __name__)
@bp.route("/leaderboard")
@login_required
def index():
# Get all users with their weight stats
users = query("""
SELECT
u.id,
u.display_name,
u.username,
u.starting_weight_kg,
u.goal_weight_kg,
(SELECT weight_kg FROM checkins WHERE user_id = u.id ORDER BY checked_in_at ASC LIMIT 1) as first_weight,
(SELECT weight_kg FROM checkins WHERE user_id = u.id ORDER BY checked_in_at DESC LIMIT 1) as current_weight,
(SELECT COUNT(*) FROM checkins WHERE user_id = u.id) as total_checkins,
(SELECT checked_in_at FROM checkins WHERE user_id = u.id ORDER BY checked_in_at DESC LIMIT 1) as last_checkin
FROM users u
WHERE u.is_private = FALSE
ORDER BY u.created_at
""")
# Calculate rankings
ranked = []
for u in users:
start_w = float(u["starting_weight_kg"] or u["first_weight"] or 0)
current_w = float(u["current_weight"] or start_w)
if start_w > 0:
weight_lost = start_w - current_w
pct_lost = round((weight_lost / start_w) * 100, 1)
else:
weight_lost = 0
pct_lost = 0
goal = float(u["goal_weight_kg"]) if u["goal_weight_kg"] else None
goal_progress = None
if goal and start_w > goal:
total_to_lose = start_w - goal
goal_progress = min(100, round((weight_lost / total_to_lose) * 100, 1)) if total_to_lose > 0 else 0
streak = calculate_streak(u["id"])
ranked.append({
**u,
"weight_lost": round(weight_lost, 1),
"pct_lost": pct_lost,
"goal_progress": goal_progress,
"streak": streak["current"],
})
# Sort by % lost (descending)
ranked.sort(key=lambda x: x["pct_lost"], reverse=True)
# Get earliest and latest check-in dates for date pickers
date_range = query_one("""
SELECT
MIN(c.checked_in_at) AS earliest,
MAX(c.checked_in_at) AS latest
FROM checkins c
JOIN users u ON u.id = c.user_id
WHERE u.is_private = FALSE
""")
earliest = ""
latest = ""
if date_range and date_range["earliest"]:
e = date_range["earliest"]
l = date_range["latest"]
if e.tzinfo is None:
e = e.replace(tzinfo=timezone.utc)
if l.tzinfo is None:
l = l.replace(tzinfo=timezone.utc)
earliest = e.astimezone(SYDNEY_TZ).strftime("%Y-%m-%d")
latest = l.astimezone(SYDNEY_TZ).strftime("%Y-%m-%d")
return render_template("leaderboard.html", ranked=ranked, earliest=earliest, latest=latest)