init
This commit is contained in:
73
app/routers/leaderboard.py
Normal file
73
app/routers/leaderboard.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlmodel import Session, select, func
|
||||
|
||||
from app.database import get_session
|
||||
from app.models.user import User
|
||||
from app.models.zone import Zone
|
||||
from app.models.score import Score
|
||||
from app.models.friendship import Friendship
|
||||
from app.schemas.score import LeaderboardEntry
|
||||
from app.auth.dependencies import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/leaderboard", tags=["leaderboard"])
|
||||
|
||||
|
||||
@router.get("", response_model=list[LeaderboardEntry])
|
||||
def get_leaderboard(
|
||||
current_user: User = Depends(get_current_user),
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
"""Friend leaderboard sorted by total points.
|
||||
|
||||
Includes the current user and all their friends.
|
||||
"""
|
||||
# Get friend IDs + self
|
||||
friend_ids = list(
|
||||
session.exec(
|
||||
select(Friendship.friend_id).where(Friendship.user_id == current_user.id)
|
||||
).all()
|
||||
)
|
||||
user_ids = friend_ids + [current_user.id]
|
||||
|
||||
entries: list[LeaderboardEntry] = []
|
||||
for uid in user_ids:
|
||||
user = session.get(User, uid)
|
||||
if not user:
|
||||
continue
|
||||
|
||||
# Latest score
|
||||
latest_score = session.exec(
|
||||
select(Score).where(Score.user_id == uid).order_by(Score.date.desc()) # type: ignore[union-attr]
|
||||
).first()
|
||||
total_pts = latest_score.total_pts if latest_score else 0
|
||||
|
||||
# Total area
|
||||
total_area = session.exec(
|
||||
select(func.coalesce(func.sum(Zone.area_m2), 0.0)).where(
|
||||
Zone.owner_id == uid
|
||||
)
|
||||
).one()
|
||||
|
||||
# Zone count
|
||||
zone_count = session.exec(
|
||||
select(func.count()).select_from(Zone).where(Zone.owner_id == uid)
|
||||
).one()
|
||||
|
||||
entries.append(
|
||||
LeaderboardEntry(
|
||||
user_id=uid,
|
||||
username=user.username,
|
||||
avatar_url=user.avatar_url,
|
||||
total_pts=total_pts,
|
||||
total_area_m2=float(total_area),
|
||||
zone_count=zone_count,
|
||||
rank=0, # calculated below
|
||||
)
|
||||
)
|
||||
|
||||
# Sort by total_pts descending, assign rank
|
||||
entries.sort(key=lambda e: e.total_pts, reverse=True)
|
||||
for i, entry in enumerate(entries):
|
||||
entry.rank = i + 1
|
||||
|
||||
return entries
|
||||
Reference in New Issue
Block a user