From baacef032a4aab88cf6508e6b01449db26648805 Mon Sep 17 00:00:00 2001 From: ITQ Date: Sat, 1 Mar 2025 02:44:45 +0300 Subject: [PATCH] SOME ABEBE --- services/backend/api/v1/user/views.py | 10 +++++-- services/backend/apps/competition/apps.py | 1 - services/backend/apps/core/apps.py | 3 -- services/backend/apps/task/__init__.py | 0 services/backend/apps/task/apps.py | 6 ++++ services/backend/apps/task/models.py | 34 +++++++++++++++++++++++ services/backend/apps/task/validators.py | 24 ++++++++++++++++ services/backend/apps/user/models.py | 6 ++-- 8 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 services/backend/apps/task/__init__.py create mode 100644 services/backend/apps/task/apps.py create mode 100644 services/backend/apps/task/models.py create mode 100644 services/backend/apps/task/validators.py diff --git a/services/backend/api/v1/user/views.py b/services/backend/api/v1/user/views.py index b253db9..29b27bb 100644 --- a/services/backend/api/v1/user/views.py +++ b/services/backend/api/v1/user/views.py @@ -3,9 +3,14 @@ from http import HTTPStatus as status from ninja import Router from ninja.errors import AuthenticationError -from api.v1.user.schemas import LoginSchema, RegisterSchema, TokenSchema, UserSchema from api.v1.auth import BearerAuth from api.v1.schemas import BadRequestError, ForbiddenError, NotFoundError +from api.v1.user.schemas import ( + LoginSchema, + RegisterSchema, + TokenSchema, + UserSchema, +) from apps.user.models import User router = Router(tags=["user"]) @@ -56,5 +61,4 @@ def sign_in(request, data: LoginSchema): status.NOT_FOUND: NotFoundError, }, ) -def get_user(request, user_id: str): - ... +def get_user(request, user_id: str): ... diff --git a/services/backend/apps/competition/apps.py b/services/backend/apps/competition/apps.py index 64e1839..ff3cb4b 100644 --- a/services/backend/apps/competition/apps.py +++ b/services/backend/apps/competition/apps.py @@ -2,6 +2,5 @@ from django.apps import AppConfig class CompetitionsConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" name = "apps.competition" label = "competition" diff --git a/services/backend/apps/core/apps.py b/services/backend/apps/core/apps.py index a37dd7d..3a9b191 100644 --- a/services/backend/apps/core/apps.py +++ b/services/backend/apps/core/apps.py @@ -1,7 +1,4 @@ -import contextlib - from django.apps import AppConfig -from django.core.cache import cache class CoreConfig(AppConfig): diff --git a/services/backend/apps/task/__init__.py b/services/backend/apps/task/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/backend/apps/task/apps.py b/services/backend/apps/task/apps.py new file mode 100644 index 0000000..46f853d --- /dev/null +++ b/services/backend/apps/task/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CompetitionsConfig(AppConfig): + name = "apps.task" + label = "task" diff --git a/services/backend/apps/task/models.py b/services/backend/apps/task/models.py new file mode 100644 index 0000000..eee9f4f --- /dev/null +++ b/services/backend/apps/task/models.py @@ -0,0 +1,34 @@ +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 + + +class CompetitionTask(BaseModel): + class CompetitionTaskType(models.TextChoices): + INPUT = "input" + CHECKER = "checker" + REVIEW = "review" + + def answer_file_upload_to(instance, filename) -> str: + return f"/tasks/{instance.id}/answer/{uuid4}" + + 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) + + # only when "input" or "checker" type + correct_answer_file = models.FileField(upload_to=answer_file_upload_to) + + # only when "checker" type + answer_file_path = models.TextField() + + # only when "review" type + criteries = models.JSONField(blank=True, null=True) + + def clean(self): + ContestTaskCriteriesValidator()(self) diff --git a/services/backend/apps/task/validators.py b/services/backend/apps/task/validators.py new file mode 100644 index 0000000..f028f52 --- /dev/null +++ b/services/backend/apps/task/validators.py @@ -0,0 +1,24 @@ +from django.core.exceptions import ValidationError +from pydantic import BaseModel +from pydantic import ValidationError as PydanticValidationError + + +class Criteria(BaseModel): + name: str + slug: str + max_value: int + min_value: int + + +class ContestTaskCriteriesValidator: + def __call__(self, instance): + if instance.criterties and not isinstance(instance.criterties, list): + err = "criteries must be a valid dictionary" + raise ValidationError(err) + + try: + for criteria in instance.criterties: + Criteria(**criteria) + except PydanticValidationError: + err = "invalid criteries data" + raise ValidationError(err) diff --git a/services/backend/apps/user/models.py b/services/backend/apps/user/models.py index ab52004..448020b 100644 --- a/services/backend/apps/user/models.py +++ b/services/backend/apps/user/models.py @@ -13,9 +13,11 @@ class User(BaseModel): username = models.SlugField(unique=True, verbose_name="Юзернейм") password = models.TextField(verbose_name="Пароль") - status = models.CharField(max_length=10, choices=UserRole.choices, default=UserRole.STUDENT) + status = models.CharField( + max_length=10, choices=UserRole.choices, default=UserRole.STUDENT + ) - def __str__(self): + def __str__(self) -> str: return self.username class Meta: