Spaces:
Sleeping
Sleeping
| """``/api/leaderboard`` — top users ranked by XP.""" | |
| import httpx | |
| from fastapi import APIRouter | |
| from app.core.config import SUPABASE_URL, SUPABASE_ANON_KEY | |
| from app.services.supabase_service import supabase_headers | |
| router = APIRouter() | |
| async def get_leaderboard(limit: int = 50): | |
| """Fetch top users ranked by XP from the public ``leaderboard`` view.""" | |
| headers = { | |
| "apikey": SUPABASE_ANON_KEY, | |
| "Authorization": f"Bearer {SUPABASE_ANON_KEY}", | |
| "Content-Type": "application/json", | |
| } | |
| safe_limit = max(1, min(limit, 100)) | |
| url = ( | |
| f"{SUPABASE_URL}/rest/v1/leaderboard" | |
| f"?select=id,name,xp,completed_trainings,avatar_url" | |
| f"&order=xp.desc" | |
| f"&limit={safe_limit}" | |
| ) | |
| try: | |
| async with httpx.AsyncClient(timeout=20) as client: | |
| resp = await client.get(url, headers=headers) | |
| if resp.status_code != 200: | |
| print(f"Leaderboard fetch error: {resp.status_code} {resp.text}") | |
| return {"users": [], "total": 0} | |
| rows = resp.json() | |
| except Exception as e: | |
| print(f"Leaderboard exception: {e}") | |
| return {"users": [], "total": 0} | |
| cleaned = [] | |
| for i, row in enumerate(rows, start=1): | |
| cleaned.append({ | |
| "rank": i, | |
| "id": row.get("id"), | |
| "name": row.get("name") or "مشغل", | |
| "xp": int(row.get("xp") or 0), | |
| "completed_trainings": int(row.get("completed_trainings") or 0), | |
| "avatar_url": row.get("avatar_url") or "", | |
| }) | |
| return {"users": cleaned, "total": len(cleaned)} | |