add basic openapi scheme for competitions tasks

This commit is contained in:
Timur
2025-03-01 09:04:51 +03:00
parent ba54b501eb
commit 077074d424
6 changed files with 83 additions and 4 deletions
+5
View File
@@ -6,6 +6,7 @@ from api.v1 import handlers
from api.v1.auth import BearerAuth from api.v1.auth import BearerAuth
from api.v1.competition.views import router as competition_router from api.v1.competition.views import router as competition_router
from api.v1.ping.views import router as ping_router from api.v1.ping.views import router as ping_router
from api.v1.task.views import router as task_router
from api.v1.user.views import router as user_router from api.v1.user.views import router as user_router
router = NinjaAPI( router = NinjaAPI(
@@ -29,6 +30,10 @@ router.add_router(
"", "",
competition_router, competition_router,
) )
router.add_router(
"",
task_router,
)
for exception, handler in handlers.exception_handlers: for exception, handler in handlers.exception_handlers:
+10
View File
@@ -0,0 +1,10 @@
from ninja import ModelSchema, Schema
from apps.competition.models import State
from apps.task.models import CompetitionTask
class TaskOutSchema(ModelSchema):
class Meta:
model = CompetitionTask
fields = ["id", "competition", "title", "description", "type"]
+64
View File
@@ -0,0 +1,64 @@
from http import HTTPStatus as status
from ninja import Router
from api.v1.schemas import NotFoundError, UnauthorizedError, ForbiddenError
from api.v1.ping.schemas import PingOut
from api.v1.task.schemas import TaskOutSchema
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: str) -> 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: str) -> list[TaskOutSchema]:
...
@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: PingOut, # todo maybe I should write an other schema for this
status.UNAUTHORIZED: UnauthorizedError,
status.FORBIDDEN: ForbiddenError,
status.NOT_FOUND: NotFoundError,
}
)
def submit_task(request, competition_id: str, task_id: str) -> PingOut:
...
+3 -4
View File
@@ -1,11 +1,10 @@
from uuid import uuid4 from uuid import uuid4
from competition.models import Competition
from core.models import BaseModel
from django.db import models from django.db import models
from apps.task.validators import ContestTaskCriteriesValidator from apps.task.validators import ContestTaskCriteriesValidator
from apps.competition.models import Competition
from apps.core.models import BaseModel
class CompetitionTask(BaseModel): class CompetitionTask(BaseModel):
class CompetitionTaskType(models.TextChoices): class CompetitionTaskType(models.TextChoices):
@@ -19,7 +18,7 @@ class CompetitionTask(BaseModel):
competition = models.ForeignKey(Competition, on_delete=models.CASCADE) competition = models.ForeignKey(Competition, on_delete=models.CASCADE)
title = models.TextField(verbose_name="заголовок", max_length=50) title = models.TextField(verbose_name="заголовок", max_length=50)
description = models.TextField(verbose_name="описание", max_length=300) description = models.TextField(verbose_name="описание", max_length=300)
type = models.CharField(choices=CompetitionTaskType) type = models.CharField(choices=CompetitionTaskType, max_length=8)
# only when "input" or "checker" type # only when "input" or "checker" type
correct_answer_file = models.FileField(upload_to=answer_file_upload_to) correct_answer_file = models.FileField(upload_to=answer_file_upload_to)
+1
View File
@@ -445,6 +445,7 @@ INSTALLED_APPS = [
"apps.core", "apps.core",
"apps.user", "apps.user",
"apps.competition", "apps.competition",
"apps.task",
] ]
# GUID # GUID