formatted :)

This commit is contained in:
Андрей Сумин
2025-03-02 16:45:11 +03:00
parent 7032ba2770
commit b30f0c7df2
18 changed files with 174 additions and 100 deletions
+8 -2
View File
@@ -5,5 +5,11 @@ from apps.achievement.models import Achievement
@admin.register(Achievement)
class AchievementAdmin(admin.ModelAdmin):
list_display = ("id", "name",)
search_fields = ("name", "description",)
list_display = (
"id",
"name",
)
search_fields = (
"name",
"description",
)
+2 -2
View File
@@ -2,6 +2,6 @@ from django.apps import AppConfig
class AchievementConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.achievement'
default_auto_field = "django.db.models.BigAutoField"
name = "apps.achievement"
verbose_name = "Ачивки"
+5 -5
View File
@@ -2,6 +2,7 @@ from django.db import models
from apps.core.models import BaseModel
class Achievement(BaseModel):
class AchievementType(models.TextChoices):
CORRECT_TASKS = "correct_tasks", "Выполненные задания"
@@ -9,17 +10,16 @@ class Achievement(BaseModel):
def image_url_upload_to(instance, filename):
return f"achievements/{instance.id}/icon/{filename}"
name = models.CharField(max_length=30, verbose_name="название",
unique=True)
name = models.CharField(
max_length=30, verbose_name="название", unique=True
)
description = models.TextField(verbose_name="описание")
icon = models.FileField(
verbose_name="иконка достижения",
upload_to=image_url_upload_to,
)
slug = models.SlugField(
verbose_name="слаг", unique=True
)
slug = models.SlugField(verbose_name="слаг", unique=True)
def __str__(self):
return self.name
+1 -1
View File
@@ -1,4 +1,4 @@
from django.contrib import admin
from django.contrib.auth.models import Group, User
from django.contrib.auth.models import Group
admin.site.unregister(Group)
@@ -8,7 +8,7 @@ from django.core.management.base import BaseCommand
from django.utils import timezone
from apps.competition.models import Competition, State
from apps.review.models import Review, Reviewer
from apps.review.models import Reviewer
from apps.task.models import CompetitionTask, CompetitionTaskSubmission
from apps.user.models import User, UserRole
+9 -3
View File
@@ -1,9 +1,15 @@
from django.contrib import admin
from apps.review.models import Review, Reviewer
from apps.review.models import Reviewer
@admin.register(Reviewer)
class ReviewersAdmin(admin.ModelAdmin):
list_display = ("name", "surname",)
search_fields = ("name", "surname",)
list_display = (
"name",
"surname",
)
search_fields = (
"name",
"surname",
)
+8 -6
View File
@@ -24,22 +24,24 @@ class ReviewStatusChoices(models.TextChoices):
class Review(BaseModel):
reviewer = models.ForeignKey(Reviewer, on_delete=models.CASCADE,
verbose_name="проверяющий")
reviewer = models.ForeignKey(
Reviewer, on_delete=models.CASCADE, verbose_name="проверяющий"
)
submission = models.ForeignKey(
"task.CompetitionTaskSubmission",
on_delete=models.CASCADE,
related_name="reviews",
verbose_name="посылка"
verbose_name="посылка",
)
evaluation = models.JSONField(default=list, null=True, blank=True,
verbose_name="выполнение")
evaluation = models.JSONField(
default=list, null=True, blank=True, verbose_name="выполнение"
)
state = models.CharField(
choices=ReviewStatusChoices.choices,
default=ReviewStatusChoices.NOT_CHECKED.value,
max_length=11,
verbose_name="состояние"
verbose_name="состояние",
)
def __str__(self):
+17 -7
View File
@@ -1,7 +1,10 @@
from django.contrib import admin
from apps.task.models import CompetitionTask, CompetitionTaskAttachment, \
CompetitionTaskSubmission
from apps.task.models import (
CompetitionTask,
CompetitionTaskAttachment,
CompetitionTaskSubmission,
)
class CompletionAttachmentInline(admin.StackedInline):
@@ -12,15 +15,22 @@ class CompletionAttachmentInline(admin.StackedInline):
@admin.register(CompetitionTask)
class CompetitionTaskAdmin(admin.ModelAdmin):
list_display = ("title", "type", "points")
filter_horizontal = (
"reviewers",
)
filter_horizontal = ("reviewers",)
@admin.register(CompetitionTaskSubmission)
class CompetitionTaskSubmissionAdmin(admin.ModelAdmin):
list_display = ("task", "user", "status",)
search_fields = ("task__id", "task__title", "user__username", "user__email")
list_display = (
"task",
"user",
"status",
)
search_fields = (
"task__id",
"task__title",
"user__username",
"user__email",
)
filter = ("plagiarism_checked",)
ordering = ["-timestamp"]
+51 -37
View File
@@ -2,12 +2,11 @@ from uuid import uuid4
from django.db import models
from django.db.models import Count, Q
from tinymce.models import HTMLField
from martor.models import MartorField
from apps.competition.models import Competition
from apps.core.models import BaseModel
from apps.review.models import Review, ReviewStatusChoices, Reviewer
from apps.review.models import Review, Reviewer, ReviewStatusChoices
from apps.user.models import User
@@ -56,9 +55,11 @@ class CompetitionTask(BaseModel):
Reviewer,
blank=True,
verbose_name="ревьюверы",
help_text="Справа отображаются действующие проверяющие, слева - доступные для выбора. Для перемещения можно кликнуть 2 раза по проверяющему"
help_text="Справа отображаются действующие проверяющие, слева - доступные для выбора. Для перемещения можно кликнуть 2 раза по проверяющему",
)
submission_reviewers_count = models.PositiveSmallIntegerField(
default=1, null=True, blank=True
)
submission_reviewers_count = models.PositiveSmallIntegerField(default=1, null=True, blank=True)
def __str__(self):
return self.title
@@ -83,10 +84,10 @@ class CompetitionTaskAttachment(BaseModel):
def file_upload_at(instance, filename):
return f"attachment/{instance.id}/file/{filename}"
task = models.ForeignKey(CompetitionTask, on_delete=models.CASCADE,
verbose_name="задание")
file = models.FileField(upload_to=file_upload_at,
verbose_name="файл")
task = models.ForeignKey(
CompetitionTask, on_delete=models.CASCADE, verbose_name="задание"
)
file = models.FileField(upload_to=file_upload_at, verbose_name="файл")
bind_at = models.FilePathField(verbose_name="путь сохранения")
public = models.BooleanField(default=False, verbose_name="публичный")
@@ -103,45 +104,56 @@ class CompetitionTaskSubmission(BaseModel):
def submission_stdout_upload_to(instance, filename) -> str:
return f"submissions/{instance.id}/stdout/{filename}"
user = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="пользователь")
task = models.ForeignKey(CompetitionTask, on_delete=models.CASCADE,
verbose_name="задание")
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name="пользователь"
)
task = models.ForeignKey(
CompetitionTask, on_delete=models.CASCADE, verbose_name="задание"
)
status = models.CharField(
choices=StatusChoices.choices,
default=StatusChoices.SENT,
max_length=8,
verbose_name="статус"
verbose_name="статус",
)
# code or text or file
content = models.FileField(upload_to=submission_content_upload_to,
verbose_name="содержание посылки")
content = models.FileField(
upload_to=submission_content_upload_to,
verbose_name="содержание посылки",
)
# only if task type is checker
stdout = models.FileField(
upload_to=submission_stdout_upload_to, null=True, blank=True,
upload_to=submission_stdout_upload_to,
null=True,
blank=True,
verbose_name="вывод программы",
help_text="Используется только при проверке чекером"
help_text="Используется только при проверке чекером",
)
# depends on task type:
# - input: {"correct": boolean}
# - file: {"total_points": integer, "by_criteria": ["criteria_name": integer]}
# - code: {"correct": boolean}
result = models.JSONField(default=None, null=True, blank=True,
verbose_name="результат проверки")
result = models.JSONField(
default=None, null=True, blank=True, verbose_name="результат проверки"
)
# just more readable result representation, maybe will be calcuated somehow more complex depends on criteria
earned_points = models.IntegerField(null=True, blank=True,
verbose_name="баллы за задание")
earned_points = models.IntegerField(
null=True, blank=True, verbose_name="баллы за задание"
)
checked_at = models.DateTimeField(null=True, blank=True,
verbose_name="дата проверки")
plagiarism_checked = models.BooleanField(default=False,
verbose_name="проверено на плагиат")
timestamp = models.DateTimeField(auto_now_add=True,
verbose_name="дата отправки")
checked_at = models.DateTimeField(
null=True, blank=True, verbose_name="дата проверки"
)
plagiarism_checked = models.BooleanField(
default=False, verbose_name="проверено на плагиат"
)
timestamp = models.DateTimeField(
auto_now_add=True, verbose_name="дата отправки"
)
class Meta:
verbose_name = "посылка"
@@ -156,16 +168,18 @@ class CompetitionTaskSubmission(BaseModel):
reviewers_count = self.task.submission_reviewers_count
reviewers = self.task.reviewers.annotate(
pending_count=Count(
"review",
filter=Q(
review__state__in=[
ReviewStatusChoices.NOT_CHECKED,
ReviewStatusChoices.CHECKING,
]
),
)
).order_by("pending_count")[:reviewers_count] # да это медленно работает и чо
pending_count=Count(
"review",
filter=Q(
review__state__in=[
ReviewStatusChoices.NOT_CHECKED,
ReviewStatusChoices.CHECKING,
]
),
)
).order_by("pending_count")[
:reviewers_count
] # да это медленно работает и чо
for reviewer in reviewers:
Review.objects.create(
+10 -3
View File
@@ -6,8 +6,8 @@ import sys
import tempfile
from io import StringIO
from config.celery import app
from apps.task.models import CompetitionTaskSubmission
from config.celery import app
ALLOWED_MODULES = {
"pandas",
@@ -119,7 +119,12 @@ def secure_exec(code_str, result_path, input_files=None):
@app.task(bind=True)
def analyze_data_task(
self, code_str, result_path, expected_file_link, submission_id, input_files=[]
self,
code_str,
result_path,
expected_file_link,
submission_id,
input_files=[],
):
try:
validate_code(code_str)
@@ -130,7 +135,9 @@ def analyze_data_task(
expected_hash = hashlib.sha256(expected_bytes).hexdigest()
with contextlib.suppress(CompetitionTaskSubmission.DoesNotExist):
submission = CompetitionTaskSubmission.objects.get(id=submission_id)
submission = CompetitionTaskSubmission.objects.get(
id=submission_id
)
submission.result = {"correct": True}
return {
@@ -28,5 +28,3 @@ with open("file.txt") as f:
print(result)
self.assertTrue(result["success"])
self.assertTrue(result["match"])
+3 -2
View File
@@ -17,8 +17,9 @@ class User(BaseModel):
created_at = models.DateTimeField(auto_now=True)
achievements = models.ManyToManyField(Achievement, blank=True,
verbose_name="ачивки пользователя")
achievements = models.ManyToManyField(
Achievement, blank=True, verbose_name="ачивки пользователя"
)
@staticmethod
def make_password(password: str):