mirror of
https://gitlab.com/megazordpobeda/DataRush.git
synced 2026-05-22 23:17:09 +00:00
217 lines
6.8 KiB
Python
217 lines
6.8 KiB
Python
from http import HTTPStatus as status
|
|
from uuid import UUID
|
|
|
|
from django.shortcuts import get_object_or_404, get_list_or_404
|
|
from ninja import File, Router, UploadedFile
|
|
|
|
from api.v1.ping.schemas import PingOut
|
|
from api.v1.schemas import ForbiddenError, NotFoundError, UnauthorizedError
|
|
from api.v1.task.schemas import (
|
|
HistorySubmissionOut,
|
|
TaskAttachmentSchema,
|
|
TaskOutSchema,
|
|
TaskSubmissionOut,
|
|
TaskStatusSchema,
|
|
)
|
|
from apps.achievement.models import Achievement, UserAchievement
|
|
from apps.competition.models import State
|
|
from apps.task.models import (
|
|
Competition,
|
|
CompetitionTask,
|
|
CompetitionTaskAttachment,
|
|
CompetitionTaskSubmission,
|
|
)
|
|
from apps.task.tasks import analyze_data_task
|
|
|
|
router = Router(tags=["competition"])
|
|
|
|
|
|
@router.post(
|
|
"competitions/{competition_id}/start",
|
|
description="Start a competition completing (open access to tasks)",
|
|
response={
|
|
status.OK: PingOut,
|
|
status.UNAUTHORIZED: UnauthorizedError,
|
|
status.NOT_FOUND: NotFoundError,
|
|
},
|
|
)
|
|
def start_competition(request, competition_id: UUID) -> PingOut:
|
|
competition = get_object_or_404(Competition, pk=competition_id)
|
|
competition.participants.add(request.auth)
|
|
state_obj, _ = State.objects.update_or_create(
|
|
user=request.auth, competition=competition, state="started"
|
|
)
|
|
return status.OK, PingOut()
|
|
|
|
|
|
@router.get(
|
|
"competitions/{competition_id}/tasks",
|
|
description="Get all tasks of competition (works only if user started competition)",
|
|
response={
|
|
status.OK: list[TaskOutSchema],
|
|
status.UNAUTHORIZED: UnauthorizedError,
|
|
status.FORBIDDEN: ForbiddenError,
|
|
status.NOT_FOUND: NotFoundError,
|
|
},
|
|
)
|
|
def get_competition_tasks(
|
|
request, competition_id: UUID
|
|
) -> list[TaskOutSchema]:
|
|
competition = get_object_or_404(Competition, pk=competition_id)
|
|
state = State.objects.filter(
|
|
user=request.auth, competition=competition, state="started"
|
|
).first()
|
|
if not state:
|
|
return 403, ForbiddenError()
|
|
|
|
return status.OK, CompetitionTask.objects.filter(
|
|
competition=competition
|
|
).all()
|
|
|
|
|
|
@router.get(
|
|
"competitions/{competition_id}/tasks/{task_id}",
|
|
description="Get a task of competition task",
|
|
response={
|
|
status.OK: TaskOutSchema,
|
|
status.UNAUTHORIZED: UnauthorizedError,
|
|
status.FORBIDDEN: ForbiddenError,
|
|
status.NOT_FOUND: NotFoundError,
|
|
},
|
|
)
|
|
def get_task(request, competition_id: str, task_id: str) -> TaskOutSchema: ...
|
|
|
|
|
|
@router.post(
|
|
"competitions/{competition_id}/tasks/{task_id}/submit",
|
|
description="Submit task solution",
|
|
response={
|
|
status.OK: TaskSubmissionOut,
|
|
status.UNAUTHORIZED: UnauthorizedError,
|
|
status.FORBIDDEN: ForbiddenError,
|
|
status.NOT_FOUND: NotFoundError,
|
|
},
|
|
)
|
|
def submit_task(
|
|
request,
|
|
competition_id: str,
|
|
task_id: str,
|
|
content: UploadedFile = File(...), # TODO: вот это надо переделать
|
|
) -> TaskSubmissionOut:
|
|
user = request.auth
|
|
competition = get_object_or_404(Competition, id=competition_id)
|
|
task = get_object_or_404(
|
|
CompetitionTask, competition=competition, id=task_id
|
|
)
|
|
|
|
if not CompetitionTaskSubmission.objects.filter(user=user).exists():
|
|
first_steps_achievement = Achievement.objects.get(slug="first_steps")
|
|
UserAchievement.objects.create(
|
|
user=user, achievement=first_steps_achievement
|
|
)
|
|
|
|
total_attempts = CompetitionTaskSubmission.objects.filter(
|
|
user=user, task=task
|
|
).count()
|
|
if task.max_attempts == total_attempts:
|
|
return status.FORBIDDEN, ForbiddenError()
|
|
|
|
if task.type == CompetitionTask.CompetitionTaskType.INPUT:
|
|
user_input = content.read()
|
|
correct_answer = task.correct_answer_file.read()
|
|
verdict = user_input == correct_answer
|
|
submission = CompetitionTaskSubmission.objects.create(
|
|
user=user,
|
|
task=task,
|
|
status=CompetitionTaskSubmission.StatusChoices.CHECKED,
|
|
content=content,
|
|
result={
|
|
"correct": verdict
|
|
},
|
|
earned_points=task.points if verdict else 0
|
|
)
|
|
if task.type == CompetitionTask.CompetitionTaskType.REVIEW:
|
|
submission = CompetitionTaskSubmission.objects.create(
|
|
user=user,
|
|
task=task,
|
|
status=CompetitionTaskSubmission.StatusChoices.SENT,
|
|
content=content,
|
|
)
|
|
submission.send_on_review()
|
|
if task.type == CompetitionTask.CompetitionTaskType.CHECKER:
|
|
submission = CompetitionTaskSubmission.objects.create(
|
|
user=user,
|
|
task=task,
|
|
status=CompetitionTaskSubmission.StatusChoices.CHECKING,
|
|
content=content,
|
|
)
|
|
analyze_data_task.delay(submission_id=submission.id)
|
|
|
|
return TaskSubmissionOut(submission_id=submission.id)
|
|
|
|
|
|
@router.get(
|
|
"competitions/{competition_id}/tasks/{task_id}/history",
|
|
response={
|
|
status.OK: list[HistorySubmissionOut],
|
|
status.UNAUTHORIZED: UnauthorizedError,
|
|
},
|
|
)
|
|
def get_submissions_history(request, competition_id: UUID, task_id: UUID):
|
|
task = get_object_or_404(
|
|
CompetitionTask, competition_id=competition_id, id=task_id
|
|
)
|
|
submissions_history = CompetitionTaskSubmission.objects.filter(
|
|
task=task, user=request.auth
|
|
)
|
|
|
|
return status.OK, submissions_history
|
|
|
|
|
|
@router.get(
|
|
"competitions/{competition_id}/tasks/{task_id}/attachments",
|
|
response={
|
|
status.OK: list[TaskAttachmentSchema],
|
|
status.UNAUTHORIZED: UnauthorizedError,
|
|
},
|
|
)
|
|
def get_task_attachments(request, competition_id: UUID, task_id: UUID):
|
|
task = get_object_or_404(CompetitionTask, id=task_id)
|
|
return status.OK, CompetitionTaskAttachment.objects.filter(task=task).all()
|
|
|
|
|
|
@router.get(
|
|
"competitions/{competition_id}/results",
|
|
response={
|
|
status.OK: list[TaskStatusSchema],
|
|
status.UNAUTHORIZED: UnauthorizedError
|
|
},
|
|
)
|
|
def get_competition_results(request, competition_id: UUID):
|
|
tasks = get_list_or_404(CompetitionTask, competition_id=competition_id)
|
|
|
|
data = []
|
|
|
|
for task in tasks:
|
|
submissions = CompetitionTaskSubmission.objects.filter(
|
|
user=request.auth, task=task
|
|
).filter(status="checked").order_by("-earned_points").all()
|
|
if not submissions:
|
|
all_submissions_count = CompetitionTaskSubmission.objects.filter(
|
|
user=request.auth, task=task
|
|
).count()
|
|
if all_submissions_count == 0:
|
|
result = -2
|
|
else:
|
|
result = -1
|
|
else:
|
|
result = submissions[0].earned_points
|
|
data.append(TaskStatusSchema(
|
|
task_name=task.title,
|
|
result=result,
|
|
max_points=task.points,
|
|
position=task.in_competition_position
|
|
))
|
|
|
|
return status.OK, data
|