@@ -0,0 +1,100 @@
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import permissions, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .models import Contest, ContestAttempt, RealtimeMatch
|
||||
from .services import (
|
||||
find_match,
|
||||
match_payload,
|
||||
start_attempt,
|
||||
submit_attempt,
|
||||
)
|
||||
|
||||
|
||||
class ContestListView(APIView):
|
||||
permission_classes = [permissions.AllowAny]
|
||||
|
||||
def get(self, request):
|
||||
contests = Contest.objects.filter(status=Contest.Status.PUBLISHED).order_by(
|
||||
"kind", "title"
|
||||
)
|
||||
return Response(
|
||||
[
|
||||
{
|
||||
"slug": contest.slug,
|
||||
"title": contest.title,
|
||||
"kind": contest.kind,
|
||||
"track": contest.track,
|
||||
"duration_seconds": contest.duration_seconds,
|
||||
"starts_at": contest.starts_at,
|
||||
"ends_at": contest.ends_at,
|
||||
}
|
||||
for contest in contests
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class AttemptStartView(APIView):
|
||||
def post(self, request, slug):
|
||||
contest = get_object_or_404(Contest, slug=slug)
|
||||
return Response(start_attempt(request.user, contest), status=status.HTTP_201_CREATED)
|
||||
|
||||
|
||||
class AttemptSubmitView(APIView):
|
||||
def post(self, request, attempt_id):
|
||||
get_object_or_404(ContestAttempt, id=attempt_id, user=request.user)
|
||||
payload = submit_attempt(
|
||||
user=request.user,
|
||||
attempt_id=attempt_id,
|
||||
raw_answers=request.data.get("answers", []),
|
||||
submission_key=request.headers.get("Idempotency-Key"),
|
||||
)
|
||||
return Response(payload)
|
||||
|
||||
|
||||
class MatchmakingView(APIView):
|
||||
def post(self, request, slug):
|
||||
contest = get_object_or_404(Contest, slug=slug)
|
||||
match = find_match(request.user, contest)
|
||||
return Response(match_payload(match, request.user), status=status.HTTP_202_ACCEPTED)
|
||||
|
||||
|
||||
class MatchStateView(APIView):
|
||||
def get(self, request, match_id):
|
||||
match = get_object_or_404(
|
||||
RealtimeMatch.objects.select_related("player_one", "player_two"),
|
||||
id=match_id,
|
||||
)
|
||||
if request.user.id not in (match.player_one_id, match.player_two_id):
|
||||
return Response(status=status.HTTP_403_FORBIDDEN)
|
||||
return Response(match_payload(match, request.user))
|
||||
|
||||
|
||||
class LeaderboardView(APIView):
|
||||
permission_classes = [permissions.AllowAny]
|
||||
|
||||
def get(self, request, slug):
|
||||
contest = get_object_or_404(Contest, slug=slug)
|
||||
attempts = (
|
||||
ContestAttempt.objects.filter(
|
||||
contest=contest,
|
||||
status=ContestAttempt.Status.SUBMITTED,
|
||||
cheat_flags__isnull=True,
|
||||
)
|
||||
.select_related("user")
|
||||
.order_by("-score", "duration_ms", "submitted_at")[:100]
|
||||
)
|
||||
return Response(
|
||||
[
|
||||
{
|
||||
"rank": index,
|
||||
"nickname": attempt.user.nickname,
|
||||
"track": attempt.user.track,
|
||||
"score": attempt.score,
|
||||
"correct_count": attempt.correct_count,
|
||||
"duration_ms": attempt.duration_ms,
|
||||
}
|
||||
for index, attempt in enumerate(attempts, start=1)
|
||||
]
|
||||
)
|
||||
Reference in New Issue
Block a user