80 lines
2.5 KiB
Python
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,
|
|
}
|