Files
polylan-submitter/polylan_submitter/clock/api.py
T

80 lines
2.5 KiB
Python

from datetime import timedelta
from django.http import HttpRequest
from django.utils import timezone
from ninja import Router
from ninja.decorators import decorate_view
from games.decorators import require_game_enabled
from .models import PRESS_BONUS_SECONDS, ClockTimer, Press
from .schemas import ClockStateOut, PlayerStatsOut
from .scoring import ranked_players
router = Router()
PREFIX = "/events/{event_path}/clock"
@router.get(f"{PREFIX}/current", response=ClockStateOut)
@decorate_view(require_game_enabled(path="clock"))
def current_state(request: HttpRequest, event_path: str):
timer = ClockTimer.current(request.event)
timer.reset_if_expired()
now = timezone.now()
next_press_at = None
cooldown_seconds = None
if request.user.is_authenticated:
last_press = (
Press.objects.filter(player=request.user, event=request.event)
.order_by("-pressed_at")
.first()
)
if last_press is not None:
candidate = last_press.pressed_at + timedelta(
seconds=last_press.cooldown_seconds
)
if candidate > now:
next_press_at = candidate
cooldown_seconds = last_press.cooldown_seconds
return {
"server_time": now,
"end_time": timer.end_time,
"initial_duration": timer.initial_duration,
"press_bonus_seconds": PRESS_BONUS_SECONDS,
"next_press_at": next_press_at,
"cooldown_seconds": cooldown_seconds,
}
@router.get(f"{PREFIX}/me", response=PlayerStatsOut)
@decorate_view(require_game_enabled(path="clock"))
def my_stats(request: HttpRequest, event_path: str):
ranked = list(
ranked_players(request.event)
.values("id", "clock_points", "rank")
.order_by("-clock_points", "id")
)
total_players = len(ranked)
my_index = next(
(i for i, row in enumerate(ranked) if row["id"] == request.user.id), None
)
mine = ranked[my_index] if my_index is not None else None
above = ranked[my_index - 1] if my_index is not None and my_index > 0 else None
below = (
ranked[my_index + 1]
if my_index is not None and my_index + 1 < total_players
else None
)
return {
"points": mine["clock_points"] if mine else 0.0,
"rank": mine["rank"] if mine else total_players,
"total_players": total_players,
"points_above": above["clock_points"] if above else None,
"points_below": below["clock_points"] if below else None,
}