selecta-highscore/highscore/scores/api/views.py

56 lines
1.5 KiB
Python

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(),
)
)
)