This commit is contained in:
rngsurrounded
2025-03-03 17:37:07 +09:00
6 changed files with 48 additions and 79 deletions
+7 -1
View File
@@ -4,6 +4,7 @@ from apps.task.models import (
CompetitionTask,
CompetitionTaskAttachment,
CompetitionTaskSubmission,
CompetitionTaskCriteria
)
@@ -12,12 +13,17 @@ class CompletionAttachmentInline(admin.StackedInline):
extra = 0
class CompetitionCriteriaInline(admin.StackedInline):
model = CompetitionTaskCriteria
extra = 0
@admin.register(CompetitionTask)
class CompetitionTaskAdmin(admin.ModelAdmin):
list_display = ("title", "type", "points")
filter_horizontal = ("reviewers",)
list_filter = ("type",)
inlines = (CompletionAttachmentInline,)
inlines = (CompletionAttachmentInline, CompetitionCriteriaInline,)
@admin.register(CompetitionTaskSubmission)
+29 -10
View File
@@ -2,7 +2,7 @@ from uuid import uuid4
from django.db import models
from django.db.models import Count, Q
from martor.models import MartorField
from mdeditor.fields import MDTextField
from apps.competition.models import Competition
from apps.core.models import BaseModel
@@ -19,11 +19,15 @@ class CompetitionTask(BaseModel):
def answer_file_upload_to(instance, filename) -> str:
return f"tasks/{instance.id}/answer/{uuid4()}/{filename}"
in_competition_position = models.PositiveSmallIntegerField()
competition = models.ForeignKey(Competition, on_delete=models.CASCADE)
in_competition_position = models.PositiveSmallIntegerField(
verbose_name="позиция в соревновании"
)
competition = models.ForeignKey(Competition, on_delete=models.CASCADE,
verbose_name="привязанное соревнование")
title = models.CharField(verbose_name="заголовок", max_length=50)
description = MartorField(verbose_name="описание")
max_attempts = models.PositiveSmallIntegerField(null=True, blank=True)
description = MDTextField(verbose_name="описание")
max_attempts = models.PositiveSmallIntegerField(null=True, blank=True,
verbose_name="максимальное кол-во попыток")
type = models.CharField(
choices=CompetitionTaskType, max_length=8, verbose_name="тип проверки"
)
@@ -56,7 +60,7 @@ class CompetitionTask(BaseModel):
help_text="Справа отображаются действующие проверяющие, слева - доступные для выбора. Для перемещения можно кликнуть 2 раза по проверяющему",
)
submission_reviewers_count = models.PositiveSmallIntegerField(
default=1, null=True, blank=True
default=1, null=True, blank=True, verbose_name="кол-во проверяющих для зачета задачи"
)
def __str__(self):
@@ -72,10 +76,25 @@ class CompetitionTaskCriteria(BaseModel):
CompetitionTask, on_delete=models.CASCADE, related_name="criteries"
)
name = models.TextField()
slug = models.SlugField()
description = models.TextField()
max_value = models.PositiveSmallIntegerField()
name = models.TextField(
verbose_name="название"
)
slug = models.SlugField(
verbose_name="техническое название"
)
description = models.TextField(
verbose_name="описание критерии"
)
max_value = models.PositiveSmallIntegerField(
verbose_name="максимальное кол-во баллов"
)
def __str__(self):
return self.name
class Meta:
verbose_name = "критерий"
verbose_name_plural = "критерии"
class CompetitionTaskAttachment(BaseModel):
+6 -5
View File
@@ -5,9 +5,9 @@ from apps.achievement.models import Achievement
from apps.core.models import BaseModel
class UserRole(models.Choices):
STUDENT = "student"
METODIST = "metodist"
class UserRole(models.TextChoices):
STUDENT = "student", "Участник соревнований"
METODIST = "metodist", "Методист (составитель заданий)"
class User(BaseModel):
@@ -15,7 +15,7 @@ class User(BaseModel):
username = models.SlugField(unique=True, verbose_name="юзернейм")
password = models.TextField(verbose_name="пароль")
created_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now=True, verbose_name="дата создания")
achievements = models.ManyToManyField(
Achievement, blank=True, verbose_name="ачивки пользователя"
@@ -29,7 +29,8 @@ class User(BaseModel):
return check_password(self.password, password)
status = models.CharField(
max_length=10, choices=UserRole, default="student"
max_length=10, choices=UserRole.choices, default="student",
verbose_name="роль участника"
)
def __str__(self) -> str:
+3 -61
View File
@@ -271,6 +271,8 @@ DEFAULT_CHARSET = "utf-8"
FORCE_SCRIPT_NAME = None
X_FRAME_OPTIONS = "SAMEORIGIN"
INTERNAL_IPS = env(
"DJANGO_INTERNAL_IPS",
list,
@@ -438,8 +440,7 @@ INSTALLED_APPS = [
"django_guid",
"ninja",
"minio_storage",
"tinymce",
"martor",
"mdeditor",
# Internal apps
"apps.core",
"apps.user",
@@ -450,65 +451,6 @@ INSTALLED_APPS = [
"apps.achievement",
]
# tinymce
TINYMCE_DEFAULT_CONFIG = {
"theme": "silver",
"height": 500,
"menubar": False,
"plugins": "advlist,autolink,lists,link,image,charmap,print,preview,anchor,"
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,paste,"
"code,help,wordcount,markdown",
"toolbar": "undo redo | formatselect | "
"bold italic backcolor | alignleft aligncenter "
"alignright alignjustify | bullist numlist outdent indent | "
"removeformat | help",
"skin": "oxide-dark",
"content_css": "dark",
"textpattern_patterns": [
{"start": "*", "end": "*", "format": "italic"},
{"start": "**", "end": "**", "format": "bold"},
{"start": "#", "format": "h1"},
{"start": "##", "format": "h2"},
{"start": "###", "format": "h3"},
{"start": "####", "format": "h4"},
{"start": "#####", "format": "h5"},
{"start": "######", "format": "h6"},
{"start": "1. ", "cmd": "InsertOrderedList"},
{"start": "* ", "cmd": "InsertUnorderedList"},
{"start": "- ", "cmd": "InsertUnorderedList"},
],
}
# martor
MARTOR_THEME = "bootstrap"
MARTOR_ENABLE_CONFIGS = {
"emoji": "true", # to enable/disable emoji icons.
"imgur": "true", # to enable/disable imgur/custom uploader.
"mention": "false", # to enable/disable mention
"jquery": "true", # to include/revoke jquery (require for admin default django)
"living": "false", # to enable/disable live updates in preview
"spellcheck": "false", # to enable/disable spellcheck in form textareas
"hljs": "true", # to enable/disable hljs highlighting in preview
}
MARTOR_TOOLBAR_BUTTONS = [
"bold",
"italic",
"horizontal",
"heading",
"pre-code",
"blockquote",
"unordered-list",
"ordered-list",
"link",
"emoji",
"direct-mention",
"toggle-maximize",
"help",
]
# GUID
DJANGO_GUID = {
+2
View File
@@ -16,6 +16,8 @@ urlpatterns = [
path("tinymce/", include("tinymce.urls")),
# martor
path("martor/", include("martor.urls")),
# mdeditor
path(r'mdeditor/', include('mdeditor.urls')),
# Admin urls
path("admin/", admin.site.urls),
# API urls
+1 -2
View File
@@ -12,14 +12,13 @@ dependencies = [
"django-extensions>=3.2.3",
"django-guid>=3.5.0",
"django-health-check>=3.18.3",
"django-mdeditor>=0.1.20",
"django-minio-storage>=0.5.7",
"django-ninja>=1.3.0",
"django-pagedown>=2.2.1",
"django-stubs-ext>=5.1.3",
"django-tinymce>=4.1.0",
"gunicorn>=23.0.0",
"httpx>=0.28.1",
"martor>=1.6.45",
"pillow>=11.1.0",
"psycopg2-binary>=2.9.10",
"pydantic>=2.10.5",