İlk commit: Stepstead backend (FastAPI)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jts 2026-07-11 11:30:24 +03:00
commit ea049b8ccd
45 changed files with 6751 additions and 0 deletions

59
routers/leaderboard.py Normal file
View file

@ -0,0 +1,59 @@
"""
Liderlik tablosu adım (lifetime), level ve gold sıralamaları.
GET /leaderboard?by=steps|level|gold top 20 + kendi sıran.
"""
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select, text
from sqlalchemy.ext.asyncio import AsyncSession
from deps import get_current_user
from models import Character, User, get_db
router = APIRouter(prefix="/leaderboard", tags=["leaderboard"])
ORDER_COLS = {"steps": "step_lifetime", "level": "total_xp", "gold": "gold"}
class LeaderRow(BaseModel):
rank: int
name: str
level: int
value: int # sıralama kriterinin değeri
me: bool
class LeaderboardOut(BaseModel):
by: str
rows: list[LeaderRow]
my_rank: int
@router.get("", response_model=LeaderboardOut)
async def leaderboard(by: str = "steps",
user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
if by not in ORDER_COLS:
raise HTTPException(400, "by: steps | level | gold")
col = ORDER_COLS[by]
char = (await db.execute(select(Character).where(Character.user_id == user.id))).scalar_one_or_none()
if not char:
raise HTTPException(404, "Karakter yok")
rows = (await db.execute(text(f"""
SELECT rank, name, level, val, id FROM (
SELECT id, name, level, {col} AS val,
RANK() OVER (ORDER BY {col} DESC, id) AS rank
FROM characters
) t WHERE rank <= 20 OR id = :me
ORDER BY rank
"""), {"me": char.id})).all()
my_rank = 0
out: list[LeaderRow] = []
for r in rows:
me = r[4] == char.id
if me:
my_rank = int(r[0])
if int(r[0]) <= 20:
out.append(LeaderRow(rank=int(r[0]), name=r[1], level=int(r[2]), value=int(r[3]), me=me))
return LeaderboardOut(by=by, rows=out, my_rank=my_rank)