mirror of
https://gitlab.com/megazordpobeda/DataRush.git
synced 2026-05-23 02:47:10 +00:00
Merge branch 'master' of https://gitlab.prodcontest.ru/team-15/project
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
from ninja import ModelSchema, Schema
|
from ninja import ModelSchema
|
||||||
|
|
||||||
from apps.achievement.models import Achievement
|
from apps.achievement.models import Achievement
|
||||||
|
|
||||||
@@ -6,4 +6,9 @@ from apps.achievement.models import Achievement
|
|||||||
class AchievementSchema(ModelSchema):
|
class AchievementSchema(ModelSchema):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Achievement
|
model = Achievement
|
||||||
fields = ("id", "name", "description", "icon",)
|
fields = (
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"icon",
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ from http import HTTPStatus as status
|
|||||||
|
|
||||||
from ninja import Router
|
from ninja import Router
|
||||||
|
|
||||||
from apps.achievement.models import Achievement
|
|
||||||
from api.v1.achievement.schemas import AchievementSchema
|
from api.v1.achievement.schemas import AchievementSchema
|
||||||
from api.v1.schemas import UnauthorizedError
|
from api.v1.schemas import UnauthorizedError
|
||||||
|
from apps.achievement.models import Achievement
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ router = Router()
|
|||||||
response={
|
response={
|
||||||
status.OK: list[AchievementSchema],
|
status.OK: list[AchievementSchema],
|
||||||
status.UNAUTHORIZED: UnauthorizedError,
|
status.UNAUTHORIZED: UnauthorizedError,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
def get_all_achievements(request):
|
def get_all_achievements(request):
|
||||||
return Achievement.objects.all()
|
return Achievement.objects.all()
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ def evaluate_submission(
|
|||||||
review.submission.checked_at = datetime.now()
|
review.submission.checked_at = datetime.now()
|
||||||
review.save()
|
review.save()
|
||||||
|
|
||||||
submission_evaluations = Review.objects.filter(submission=submission).values_list('evaluation', flat=True)
|
submission_evaluations = Review.objects.filter(
|
||||||
|
submission=submission
|
||||||
|
).values_list("evaluation", flat=True)
|
||||||
|
|
||||||
marks = []
|
marks = []
|
||||||
for evaluation in submission_evaluations:
|
for evaluation in submission_evaluations:
|
||||||
@@ -97,9 +99,7 @@ def evaluate_submission(
|
|||||||
marks.append(mark)
|
marks.append(mark)
|
||||||
earned_points = median(marks)
|
earned_points = median(marks)
|
||||||
|
|
||||||
review.submission.earned_points = (
|
review.submission.earned_points = earned_points
|
||||||
earned_points
|
|
||||||
)
|
|
||||||
|
|
||||||
all_checked = not submission.reviews.exclude(
|
all_checked = not submission.reviews.exclude(
|
||||||
state=ReviewStatusChoices.CHECKED
|
state=ReviewStatusChoices.CHECKED
|
||||||
|
|||||||
@@ -2,17 +2,24 @@ from typing import Literal
|
|||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from ninja import ModelSchema, Schema
|
from ninja import ModelSchema, Schema
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from apps.task.models import CompetitionTask, CompetitionTaskSubmission, CompetitionTaskAttachment
|
from apps.task.models import (
|
||||||
|
CompetitionTask,
|
||||||
|
CompetitionTaskAttachment,
|
||||||
|
CompetitionTaskSubmission,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TaskOutSchema(ModelSchema):
|
class TaskOutSchema(ModelSchema):
|
||||||
status: Literal["sent", "checked", "checking", "not_submitted"] = None
|
status: Literal["sent", "checked", "checking", "not_submitted"] = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_status(self, context) -> Literal["sent", "checked", "checking", "not_submitted"]:
|
def resolve_status(
|
||||||
if submission := CompetitionTaskSubmission.objects.filter(task=self, user=context.get("request").auth).first():
|
self, context
|
||||||
|
) -> Literal["sent", "checked", "checking", "not_submitted"]:
|
||||||
|
if submission := CompetitionTaskSubmission.objects.filter(
|
||||||
|
task=self, user=context.get("request").auth
|
||||||
|
).first():
|
||||||
return submission.status
|
return submission.status
|
||||||
return "not_submitted"
|
return "not_submitted"
|
||||||
|
|
||||||
@@ -38,10 +45,19 @@ class HistorySubmissionOut(ModelSchema):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CompetitionTaskSubmission
|
model = CompetitionTaskSubmission
|
||||||
fields = ("id", "earned_points", "timestamp", "content",)
|
fields = (
|
||||||
|
"id",
|
||||||
|
"earned_points",
|
||||||
|
"timestamp",
|
||||||
|
"content",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TaskAttachmentSchema(ModelSchema):
|
class TaskAttachmentSchema(ModelSchema):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CompetitionTaskAttachment
|
model = CompetitionTaskAttachment
|
||||||
fields = ("id", "file", "public",)
|
fields = (
|
||||||
|
"id",
|
||||||
|
"file",
|
||||||
|
"public",
|
||||||
|
)
|
||||||
|
|||||||
@@ -5,5 +5,11 @@ from apps.achievement.models import Achievement
|
|||||||
|
|
||||||
@admin.register(Achievement)
|
@admin.register(Achievement)
|
||||||
class AchievementAdmin(admin.ModelAdmin):
|
class AchievementAdmin(admin.ModelAdmin):
|
||||||
list_display = ("id", "name",)
|
list_display = (
|
||||||
search_fields = ("name", "description",)
|
"id",
|
||||||
|
"name",
|
||||||
|
)
|
||||||
|
search_fields = (
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ from django.apps import AppConfig
|
|||||||
|
|
||||||
|
|
||||||
class AchievementConfig(AppConfig):
|
class AchievementConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = 'apps.achievement'
|
name = "apps.achievement"
|
||||||
verbose_name = "Ачивки"
|
verbose_name = "Ачивки"
|
||||||
|
|||||||
@@ -2,24 +2,24 @@ from django.db import models
|
|||||||
|
|
||||||
from apps.core.models import BaseModel
|
from apps.core.models import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class Achievement(BaseModel):
|
class Achievement(BaseModel):
|
||||||
class AchievementType(models.TextChoices):
|
class AchievementType(models.TextChoices):
|
||||||
CORRECT_TASKS = "correct_tasks", "Выполненные задания"
|
CORRECT_TASKS = "correct_tasks", "Выполненные задания"
|
||||||
|
|
||||||
def image_url_upload_to(instance, filename):
|
def image_url_upload_to(instance, filename):
|
||||||
return f"/achievements/{instance.id}/icon"
|
return f"achievements/{instance.id}/icon/{filename}"
|
||||||
|
|
||||||
name = models.CharField(max_length=30, verbose_name="название",
|
name = models.CharField(
|
||||||
unique=True)
|
max_length=30, verbose_name="название", unique=True
|
||||||
|
)
|
||||||
description = models.TextField(verbose_name="описание")
|
description = models.TextField(verbose_name="описание")
|
||||||
icon = models.FileField(
|
icon = models.FileField(
|
||||||
verbose_name="иконка достижения",
|
verbose_name="иконка достижения",
|
||||||
upload_to=image_url_upload_to,
|
upload_to=image_url_upload_to,
|
||||||
)
|
)
|
||||||
|
|
||||||
slug = models.SlugField(
|
slug = models.SlugField(verbose_name="слаг", unique=True)
|
||||||
verbose_name="слаг", unique=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Competition(BaseModel):
|
|||||||
SOLO = "solo", "Индивидуальный"
|
SOLO = "solo", "Индивидуальный"
|
||||||
|
|
||||||
def image_url_upload_to(instance, filename):
|
def image_url_upload_to(instance, filename):
|
||||||
return f"/competitions/{instance.id}/image"
|
return f"competitions/{instance.id}/image/{filename}"
|
||||||
|
|
||||||
title = models.CharField(max_length=100, verbose_name="название")
|
title = models.CharField(max_length=100, verbose_name="название")
|
||||||
description = models.TextField(verbose_name="описание")
|
description = models.TextField(verbose_name="описание")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group
|
||||||
|
|
||||||
admin.site.unregister(Group)
|
admin.site.unregister(Group)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from django.core.management.base import BaseCommand
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from apps.competition.models import Competition, State
|
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.task.models import CompetitionTask, CompetitionTaskSubmission
|
||||||
from apps.user.models import User, UserRole
|
from apps.user.models import User, UserRole
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from apps.review.models import Review, Reviewer
|
from apps.review.models import Reviewer
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Reviewer)
|
@admin.register(Reviewer)
|
||||||
class ReviewersAdmin(admin.ModelAdmin):
|
class ReviewersAdmin(admin.ModelAdmin):
|
||||||
list_display = ("name", "surname",)
|
list_display = (
|
||||||
search_fields = ("name", "surname",)
|
"name",
|
||||||
|
"surname",
|
||||||
|
)
|
||||||
|
search_fields = (
|
||||||
|
"name",
|
||||||
|
"surname",
|
||||||
|
)
|
||||||
|
|||||||
@@ -24,22 +24,24 @@ class ReviewStatusChoices(models.TextChoices):
|
|||||||
|
|
||||||
|
|
||||||
class Review(BaseModel):
|
class Review(BaseModel):
|
||||||
reviewer = models.ForeignKey(Reviewer, on_delete=models.CASCADE,
|
reviewer = models.ForeignKey(
|
||||||
verbose_name="проверяющий")
|
Reviewer, on_delete=models.CASCADE, verbose_name="проверяющий"
|
||||||
|
)
|
||||||
submission = models.ForeignKey(
|
submission = models.ForeignKey(
|
||||||
"task.CompetitionTaskSubmission",
|
"task.CompetitionTaskSubmission",
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
related_name="reviews",
|
related_name="reviews",
|
||||||
verbose_name="посылка"
|
verbose_name="посылка",
|
||||||
)
|
)
|
||||||
|
|
||||||
evaluation = models.JSONField(default=list, null=True, blank=True,
|
evaluation = models.JSONField(
|
||||||
verbose_name="выполнение")
|
default=list, null=True, blank=True, verbose_name="выполнение"
|
||||||
|
)
|
||||||
state = models.CharField(
|
state = models.CharField(
|
||||||
choices=ReviewStatusChoices.choices,
|
choices=ReviewStatusChoices.choices,
|
||||||
default=ReviewStatusChoices.NOT_CHECKED.value,
|
default=ReviewStatusChoices.NOT_CHECKED.value,
|
||||||
max_length=11,
|
max_length=11,
|
||||||
verbose_name="состояние"
|
verbose_name="состояние",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from apps.task.models import CompetitionTask, CompetitionTaskAttachment, \
|
from apps.task.models import (
|
||||||
CompetitionTaskSubmission
|
CompetitionTask,
|
||||||
|
CompetitionTaskAttachment,
|
||||||
|
CompetitionTaskSubmission,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CompletionAttachmentInline(admin.StackedInline):
|
class CompletionAttachmentInline(admin.StackedInline):
|
||||||
@@ -12,15 +15,22 @@ class CompletionAttachmentInline(admin.StackedInline):
|
|||||||
@admin.register(CompetitionTask)
|
@admin.register(CompetitionTask)
|
||||||
class CompetitionTaskAdmin(admin.ModelAdmin):
|
class CompetitionTaskAdmin(admin.ModelAdmin):
|
||||||
list_display = ("title", "type", "points")
|
list_display = ("title", "type", "points")
|
||||||
filter_horizontal = (
|
filter_horizontal = ("reviewers",)
|
||||||
"reviewers",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CompetitionTaskSubmission)
|
@admin.register(CompetitionTaskSubmission)
|
||||||
class CompetitionTaskSubmissionAdmin(admin.ModelAdmin):
|
class CompetitionTaskSubmissionAdmin(admin.ModelAdmin):
|
||||||
list_display = ("task", "user", "status",)
|
list_display = (
|
||||||
search_fields = ("task__id", "task__title", "user__username", "user__email")
|
"task",
|
||||||
|
"user",
|
||||||
|
"status",
|
||||||
|
)
|
||||||
|
search_fields = (
|
||||||
|
"task__id",
|
||||||
|
"task__title",
|
||||||
|
"user__username",
|
||||||
|
"user__email",
|
||||||
|
)
|
||||||
filter = ("plagiarism_checked",)
|
filter = ("plagiarism_checked",)
|
||||||
ordering = ["-timestamp"]
|
ordering = ["-timestamp"]
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ from uuid import uuid4
|
|||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Count, Q
|
from django.db.models import Count, Q
|
||||||
from tinymce.models import HTMLField
|
|
||||||
from martor.models import MartorField
|
from martor.models import MartorField
|
||||||
|
|
||||||
from apps.competition.models import Competition
|
from apps.competition.models import Competition
|
||||||
from apps.core.models import BaseModel
|
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
|
from apps.user.models import User
|
||||||
|
|
||||||
|
|
||||||
@@ -18,7 +17,7 @@ class CompetitionTask(BaseModel):
|
|||||||
REVIEW = "review", "Ручная"
|
REVIEW = "review", "Ручная"
|
||||||
|
|
||||||
def answer_file_upload_to(instance, filename) -> str:
|
def answer_file_upload_to(instance, filename) -> str:
|
||||||
return f"/tasks/{instance.id}/answer/{uuid4()}/filename"
|
return f"tasks/{instance.id}/answer/{uuid4()}/{filename}"
|
||||||
|
|
||||||
in_competition_position = models.PositiveSmallIntegerField(
|
in_competition_position = models.PositiveSmallIntegerField(
|
||||||
null=True, blank=True
|
null=True, blank=True
|
||||||
@@ -56,9 +55,11 @@ class CompetitionTask(BaseModel):
|
|||||||
Reviewer,
|
Reviewer,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name="ревьюверы",
|
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):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
@@ -81,12 +82,12 @@ class CompetitionTaskCriteria(BaseModel):
|
|||||||
|
|
||||||
class CompetitionTaskAttachment(BaseModel):
|
class CompetitionTaskAttachment(BaseModel):
|
||||||
def file_upload_at(instance, filename):
|
def file_upload_at(instance, filename):
|
||||||
return f"/attachment/{instance.id}/file"
|
return f"attachment/{instance.id}/file/{filename}"
|
||||||
|
|
||||||
task = models.ForeignKey(CompetitionTask, on_delete=models.CASCADE,
|
task = models.ForeignKey(
|
||||||
verbose_name="задание")
|
CompetitionTask, on_delete=models.CASCADE, verbose_name="задание"
|
||||||
file = models.FileField(upload_to=file_upload_at,
|
)
|
||||||
verbose_name="файл")
|
file = models.FileField(upload_to=file_upload_at, verbose_name="файл")
|
||||||
bind_at = models.FilePathField(verbose_name="путь сохранения")
|
bind_at = models.FilePathField(verbose_name="путь сохранения")
|
||||||
public = models.BooleanField(default=False, verbose_name="публичный")
|
public = models.BooleanField(default=False, verbose_name="публичный")
|
||||||
|
|
||||||
@@ -98,50 +99,61 @@ class CompetitionTaskSubmission(BaseModel):
|
|||||||
CHECKED = "checked"
|
CHECKED = "checked"
|
||||||
|
|
||||||
def submission_content_upload_to(instance, filename) -> str:
|
def submission_content_upload_to(instance, filename) -> str:
|
||||||
return f"submissions/{instance.id}/content"
|
return f"submissions/{instance.id}/content/{filename}"
|
||||||
|
|
||||||
def submission_stdout_upload_to(instance, filename) -> str:
|
def submission_stdout_upload_to(instance, filename) -> str:
|
||||||
return f"/submissions/{instance.id}/stdout"
|
return f"submissions/{instance.id}/stdout/{filename}"
|
||||||
|
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE,
|
user = models.ForeignKey(
|
||||||
verbose_name="пользователь")
|
User, on_delete=models.CASCADE, verbose_name="пользователь"
|
||||||
task = models.ForeignKey(CompetitionTask, on_delete=models.CASCADE,
|
)
|
||||||
verbose_name="задание")
|
task = models.ForeignKey(
|
||||||
|
CompetitionTask, on_delete=models.CASCADE, verbose_name="задание"
|
||||||
|
)
|
||||||
|
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
choices=StatusChoices.choices,
|
choices=StatusChoices.choices,
|
||||||
default=StatusChoices.SENT,
|
default=StatusChoices.SENT,
|
||||||
max_length=8,
|
max_length=8,
|
||||||
verbose_name="статус"
|
verbose_name="статус",
|
||||||
)
|
)
|
||||||
|
|
||||||
# code or text or file
|
# code or text or file
|
||||||
content = models.FileField(upload_to=submission_content_upload_to,
|
content = models.FileField(
|
||||||
verbose_name="содержание посылки")
|
upload_to=submission_content_upload_to,
|
||||||
|
verbose_name="содержание посылки",
|
||||||
|
)
|
||||||
|
|
||||||
# only if task type is checker
|
# only if task type is checker
|
||||||
stdout = models.FileField(
|
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="вывод программы",
|
verbose_name="вывод программы",
|
||||||
help_text="Используется только при проверке чекером"
|
help_text="Используется только при проверке чекером",
|
||||||
)
|
)
|
||||||
|
|
||||||
# depends on task type:
|
# depends on task type:
|
||||||
# - input: {"correct": boolean}
|
# - input: {"correct": boolean}
|
||||||
# - file: {"total_points": integer, "by_criteria": ["criteria_name": integer]}
|
# - file: {"total_points": integer, "by_criteria": ["criteria_name": integer]}
|
||||||
# - code: {"correct": boolean}
|
# - code: {"correct": boolean}
|
||||||
result = models.JSONField(default=None, null=True, blank=True,
|
result = models.JSONField(
|
||||||
verbose_name="результат проверки")
|
default=None, null=True, blank=True, verbose_name="результат проверки"
|
||||||
|
)
|
||||||
# just more readable result representation, maybe will be calcuated somehow more complex depends on criteria
|
# 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(
|
||||||
verbose_name="баллы за задание")
|
null=True, blank=True, verbose_name="баллы за задание"
|
||||||
|
)
|
||||||
|
|
||||||
checked_at = models.DateTimeField(null=True, blank=True,
|
checked_at = models.DateTimeField(
|
||||||
verbose_name="дата проверки")
|
null=True, blank=True, verbose_name="дата проверки"
|
||||||
plagiarism_checked = models.BooleanField(default=False,
|
)
|
||||||
verbose_name="проверено на плагиат")
|
plagiarism_checked = models.BooleanField(
|
||||||
timestamp = models.DateTimeField(auto_now_add=True,
|
default=False, verbose_name="проверено на плагиат"
|
||||||
verbose_name="дата отправки")
|
)
|
||||||
|
timestamp = models.DateTimeField(
|
||||||
|
auto_now_add=True, verbose_name="дата отправки"
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "посылка"
|
verbose_name = "посылка"
|
||||||
@@ -156,16 +168,18 @@ class CompetitionTaskSubmission(BaseModel):
|
|||||||
|
|
||||||
reviewers_count = self.task.submission_reviewers_count
|
reviewers_count = self.task.submission_reviewers_count
|
||||||
reviewers = self.task.reviewers.annotate(
|
reviewers = self.task.reviewers.annotate(
|
||||||
pending_count=Count(
|
pending_count=Count(
|
||||||
"review",
|
"review",
|
||||||
filter=Q(
|
filter=Q(
|
||||||
review__state__in=[
|
review__state__in=[
|
||||||
ReviewStatusChoices.NOT_CHECKED,
|
ReviewStatusChoices.NOT_CHECKED,
|
||||||
ReviewStatusChoices.CHECKING,
|
ReviewStatusChoices.CHECKING,
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
).order_by("pending_count")[:reviewers_count] # да это медленно работает и чо
|
).order_by("pending_count")[
|
||||||
|
:reviewers_count
|
||||||
|
] # да это медленно работает и чо
|
||||||
|
|
||||||
for reviewer in reviewers:
|
for reviewer in reviewers:
|
||||||
Review.objects.create(
|
Review.objects.create(
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import sys
|
|||||||
import tempfile
|
import tempfile
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
from config.celery import app
|
|
||||||
from apps.task.models import CompetitionTaskSubmission
|
from apps.task.models import CompetitionTaskSubmission
|
||||||
|
from config.celery import app
|
||||||
|
|
||||||
ALLOWED_MODULES = {
|
ALLOWED_MODULES = {
|
||||||
"pandas",
|
"pandas",
|
||||||
@@ -119,7 +119,12 @@ def secure_exec(code_str, result_path, input_files=None):
|
|||||||
|
|
||||||
@app.task(bind=True)
|
@app.task(bind=True)
|
||||||
def analyze_data_task(
|
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:
|
try:
|
||||||
validate_code(code_str)
|
validate_code(code_str)
|
||||||
@@ -130,7 +135,9 @@ def analyze_data_task(
|
|||||||
expected_hash = hashlib.sha256(expected_bytes).hexdigest()
|
expected_hash = hashlib.sha256(expected_bytes).hexdigest()
|
||||||
|
|
||||||
with contextlib.suppress(CompetitionTaskSubmission.DoesNotExist):
|
with contextlib.suppress(CompetitionTaskSubmission.DoesNotExist):
|
||||||
submission = CompetitionTaskSubmission.objects.get(id=submission_id)
|
submission = CompetitionTaskSubmission.objects.get(
|
||||||
|
id=submission_id
|
||||||
|
)
|
||||||
submission.result = {"correct": True}
|
submission.result = {"correct": True}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -28,5 +28,3 @@ with open("file.txt") as f:
|
|||||||
print(result)
|
print(result)
|
||||||
self.assertTrue(result["success"])
|
self.assertTrue(result["success"])
|
||||||
self.assertTrue(result["match"])
|
self.assertTrue(result["match"])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ class User(BaseModel):
|
|||||||
|
|
||||||
created_at = models.DateTimeField(auto_now=True)
|
created_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
achievements = models.ManyToManyField(Achievement, blank=True,
|
achievements = models.ManyToManyField(
|
||||||
verbose_name="ачивки пользователя")
|
Achievement, blank=True, verbose_name="ачивки пользователя"
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_password(password: str):
|
def make_password(password: str):
|
||||||
|
|||||||
@@ -478,29 +478,38 @@ TINYMCE_DEFAULT_CONFIG = {
|
|||||||
{"start": "######", "format": "h6"},
|
{"start": "######", "format": "h6"},
|
||||||
{"start": "1. ", "cmd": "InsertOrderedList"},
|
{"start": "1. ", "cmd": "InsertOrderedList"},
|
||||||
{"start": "* ", "cmd": "InsertUnorderedList"},
|
{"start": "* ", "cmd": "InsertUnorderedList"},
|
||||||
{"start": "- ", "cmd": "InsertUnorderedList"}
|
{"start": "- ", "cmd": "InsertUnorderedList"},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
# martor
|
# martor
|
||||||
|
|
||||||
MARTOR_THEME = 'bootstrap'
|
MARTOR_THEME = "bootstrap"
|
||||||
|
|
||||||
MARTOR_ENABLE_CONFIGS = {
|
MARTOR_ENABLE_CONFIGS = {
|
||||||
'emoji': 'true', # to enable/disable emoji icons.
|
"emoji": "true", # to enable/disable emoji icons.
|
||||||
'imgur': 'true', # to enable/disable imgur/custom uploader.
|
"imgur": "true", # to enable/disable imgur/custom uploader.
|
||||||
'mention': 'false', # to enable/disable mention
|
"mention": "false", # to enable/disable mention
|
||||||
'jquery': 'true', # to include/revoke jquery (require for admin default django)
|
"jquery": "true", # to include/revoke jquery (require for admin default django)
|
||||||
'living': 'false', # to enable/disable live updates in preview
|
"living": "false", # to enable/disable live updates in preview
|
||||||
'spellcheck': 'false', # to enable/disable spellcheck in form textareas
|
"spellcheck": "false", # to enable/disable spellcheck in form textareas
|
||||||
'hljs': 'true', # to enable/disable hljs highlighting in preview
|
"hljs": "true", # to enable/disable hljs highlighting in preview
|
||||||
}
|
}
|
||||||
|
|
||||||
MARTOR_TOOLBAR_BUTTONS = [
|
MARTOR_TOOLBAR_BUTTONS = [
|
||||||
'bold', 'italic', 'horizontal', 'heading', 'pre-code',
|
"bold",
|
||||||
'blockquote', 'unordered-list', 'ordered-list',
|
"italic",
|
||||||
'link', 'emoji',
|
"horizontal",
|
||||||
'direct-mention', 'toggle-maximize', 'help'
|
"heading",
|
||||||
|
"pre-code",
|
||||||
|
"blockquote",
|
||||||
|
"unordered-list",
|
||||||
|
"ordered-list",
|
||||||
|
"link",
|
||||||
|
"emoji",
|
||||||
|
"direct-mention",
|
||||||
|
"toggle-maximize",
|
||||||
|
"help",
|
||||||
]
|
]
|
||||||
|
|
||||||
# GUID
|
# GUID
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ urlpatterns = [
|
|||||||
# tinymce
|
# tinymce
|
||||||
path("tinymce/", include("tinymce.urls")),
|
path("tinymce/", include("tinymce.urls")),
|
||||||
# martor
|
# martor
|
||||||
path('martor/', include('martor.urls')),
|
path("martor/", include("martor.urls")),
|
||||||
# Admin urls
|
# Admin urls
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
# API urls
|
# API urls
|
||||||
|
|||||||
Reference in New Issue
Block a user