This commit is contained in:
Redsandy
2026-03-14 18:48:57 +03:00
parent 1d1350fc13
commit 3ea4fb4771
40 changed files with 2150 additions and 0 deletions

View 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