from typing import Annotated from django.db.models import F, QuerySet from django.db.models.expressions import Window from django.db.models.functions import Rank from django.http import HttpRequest from ninja import Header from ninja.pagination import PageNumberPagination, paginate from app.api_base import CamelCaseRouter from scores.models import Score, Version from .schemas import ScoreIn, ScoreOut router = CamelCaseRouter() GameVersionHeader = Annotated[str | None, Header(alias="X-Game-Version")] # pyright: ignore[reportCallIssue] def resolve_version(name: str | None) -> Version: if name: version, _ = Version.objects.get_or_create(name=name) return version version, _ = Version.objects.get_or_create(name="default") return version @router.post("", response=ScoreOut) def submit_score( request: HttpRequest, payload: ScoreIn, x_game_version: GameVersionHeader = None, ) -> Score: version = resolve_version(x_game_version) return Score.objects.create(username=payload.username, points=payload.points, version=version) @router.get("", response=list[ScoreOut]) @paginate(PageNumberPagination, page_size=20) def list_scores( request: HttpRequest, x_game_version: GameVersionHeader = None, ) -> QuerySet[Score]: version = resolve_version(x_game_version) return ( Score.objects.filter(version=version) .select_related("version") .annotate( rank=Window( expression=Rank(), order_by=F("points").desc(), ) ) )