diff --git a/services/backend/apps/task/admin.py b/services/backend/apps/task/admin.py index 3766cdf..ce7d553 100644 --- a/services/backend/apps/task/admin.py +++ b/services/backend/apps/task/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin -from apps.task.models import CompetitionTask, CompetitionTaskAttachment +from apps.task.models import CompetitionTask, CompetitionTaskAttachment, \ + CompetitionTaskSubmission class CompletionAttachmentInline(admin.StackedInline): @@ -13,6 +14,20 @@ class CompetitionTaskAdmin(admin.ModelAdmin): list_display = ("title", "type", "points") +@admin.register(CompetitionTaskSubmission) +class CompetitionTaskSubmissionAdmin(admin.ModelAdmin): + list_display = ("task", "user", "status",) + search_fields = ("task__id", "task__title", "user__username", "user__email") + filter = ("plagiarism_checked",) + ordering = "-timestamp" + + def has_add_permission(self, request, obj=None): + return False + + def has_delete_permission(self, request, obj=None): + return False + + class CompetitionTaskInline(admin.StackedInline): model = CompetitionTask extra = 0 diff --git a/services/backend/apps/task/models.py b/services/backend/apps/task/models.py index 471197c..40f543e 100644 --- a/services/backend/apps/task/models.py +++ b/services/backend/apps/task/models.py @@ -1,10 +1,12 @@ from uuid import uuid4 from django.db import models +from django.db.models import Count, Q from tinymce.models import HTMLField from apps.competition.models import Competition from apps.core.models import BaseModel +from apps.review.models import ReviewStatusChoices, Review from apps.user.models import User @@ -91,34 +93,51 @@ class CompetitionTaskSubmission(BaseModel): def submission_stdout_upload_to(instance, filename) -> str: return f"/submissions/{instance.id}/stdout" - user = models.ForeignKey(User, on_delete=models.CASCADE) - task = models.ForeignKey(CompetitionTask, on_delete=models.CASCADE) + 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="статус" ) # code or text or file - content = models.FileField(upload_to=submission_content_upload_to) + 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="вывод чекера" ) # 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) + 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) + earned_points = models.IntegerField(null=True, blank=True, + verbose_name="получено баллов") - checked_at = models.DateTimeField(null=True, blank=True) - plagiarism_checked = models.BooleanField(default=False) - timestamp = models.DateTimeField(auto_now_add=True) + 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="дата отправки") + + def __str__(self): + return str(self.id) + + class Meta: + verbose_name = "посылка" + verbose_name_plural = "посылки" def send_on_review(self): if not self.task.reviewers.exists(): @@ -139,7 +158,7 @@ class CompetitionTaskSubmission(BaseModel): .order_by("pending_count") .first() ) - review = Review.objects.create( + Review.objects.create( reviewer=reviewer, submission=self, )