diff --git a/services/backend/api/v1/router.py b/services/backend/api/v1/router.py index 241af1e..2c24b2b 100644 --- a/services/backend/api/v1/router.py +++ b/services/backend/api/v1/router.py @@ -6,6 +6,7 @@ from api.v1 import handlers from api.v1.auth import BearerAuth from api.v1.competition.views import router as competition_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 router = NinjaAPI( @@ -29,6 +30,10 @@ router.add_router( "", competition_router, ) +router.add_router( + "", + task_router, +) for exception, handler in handlers.exception_handlers: diff --git a/services/backend/api/v1/task/__init__.py b/services/backend/api/v1/task/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/backend/api/v1/task/schemas.py b/services/backend/api/v1/task/schemas.py new file mode 100644 index 0000000..4a3ec2e --- /dev/null +++ b/services/backend/api/v1/task/schemas.py @@ -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"] diff --git a/services/backend/api/v1/task/views.py b/services/backend/api/v1/task/views.py new file mode 100644 index 0000000..81301c8 --- /dev/null +++ b/services/backend/api/v1/task/views.py @@ -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: + ... diff --git a/services/backend/apps/task/models.py b/services/backend/apps/task/models.py index eee9f4f..3ff7ac4 100644 --- a/services/backend/apps/task/models.py +++ b/services/backend/apps/task/models.py @@ -1,11 +1,10 @@ from uuid import uuid4 -from competition.models import Competition -from core.models import BaseModel from django.db import models from apps.task.validators import ContestTaskCriteriesValidator - +from apps.competition.models import Competition +from apps.core.models import BaseModel class CompetitionTask(BaseModel): class CompetitionTaskType(models.TextChoices): @@ -19,7 +18,7 @@ class CompetitionTask(BaseModel): competition = models.ForeignKey(Competition, on_delete=models.CASCADE) title = models.TextField(verbose_name="заголовок", max_length=50) 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 correct_answer_file = models.FileField(upload_to=answer_file_upload_to) diff --git a/services/backend/config/settings.py b/services/backend/config/settings.py index c3a64da..ffae770 100644 --- a/services/backend/config/settings.py +++ b/services/backend/config/settings.py @@ -445,6 +445,7 @@ INSTALLED_APPS = [ "apps.core", "apps.user", "apps.competition", + "apps.task", ] # GUID