mirror of
https://gitlab.com/megazordpobeda/DataRush.git
synced 2026-05-23 03:57:09 +00:00
Merge branch 'master' of https://gitlab.prodcontest.ru/team-15/project
This commit is contained in:
@@ -109,7 +109,6 @@ deploy:
|
|||||||
cd ~/deploy
|
cd ~/deploy
|
||||||
docker system prune -a --force
|
docker system prune -a --force
|
||||||
docker compose pull > deploy.log 2>&1
|
docker compose pull > deploy.log 2>&1
|
||||||
docker compose down >> deploy.log 2>&1
|
|
||||||
docker compose up -d --remove-orphans --force-recreate >> deploy.log 2>&1
|
docker compose up -d --remove-orphans --force-recreate >> deploy.log 2>&1
|
||||||
docker compose ps >> deploy.log 2>&1
|
docker compose ps >> deploy.log 2>&1
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
+4
-1
@@ -400,6 +400,9 @@ services:
|
|||||||
- type: bind
|
- type: bind
|
||||||
source: /var/run/docker.sock
|
source: /var/run/docker.sock
|
||||||
target: /var/run/docker.sock
|
target: /var/run/docker.sock
|
||||||
|
- type: bind
|
||||||
|
source: /tmp
|
||||||
|
target: /tmp
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
image: docker.io/nginx:1.27-alpine3.21
|
image: docker.io/nginx:1.27-alpine3.21
|
||||||
@@ -410,7 +413,7 @@ services:
|
|||||||
test: ["CMD", "service", "nginx", "status", "||", " exit 1"]
|
test: ["CMD", "service", "nginx", "status", "||", " exit 1"]
|
||||||
interval: 1m30s
|
interval: 1m30s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
start_period: 5s
|
start_period: 15s
|
||||||
start_interval: 2s
|
start_interval: 2s
|
||||||
retries: 5
|
retries: 5
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from ninja import ModelSchema, Schema
|
from ninja import ModelSchema, Schema
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
@@ -19,6 +21,7 @@ class UserAchievementSchema(Schema):
|
|||||||
name: str = Field(..., alias="achievement.name")
|
name: str = Field(..., alias="achievement.name")
|
||||||
description: str = Field(..., alias="achievement.description")
|
description: str = Field(..., alias="achievement.description")
|
||||||
icon: str = Field(..., alias="achievement.icon")
|
icon: str = Field(..., alias="achievement.icon")
|
||||||
|
received_at: datetime
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = UserAchievement
|
model = UserAchievement
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class UserSchema(ModelSchema):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ["id", "email", "username", "created_at"]
|
fields = ["id", "avatar", "email", "username", "created_at"]
|
||||||
|
|
||||||
|
|
||||||
class StatSchema(Schema):
|
class StatSchema(Schema):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import apps.achievement.models
|
import apps.achievement.models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import apps.competition.models
|
import apps.competition.models
|
||||||
import datetime
|
import datetime
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ from django.contrib import admin
|
|||||||
from apps.task.models import (
|
from apps.task.models import (
|
||||||
CompetitionTask,
|
CompetitionTask,
|
||||||
CompetitionTaskAttachment,
|
CompetitionTaskAttachment,
|
||||||
|
CompetitionTaskCriteria,
|
||||||
CompetitionTaskSubmission,
|
CompetitionTaskSubmission,
|
||||||
CompetitionTaskCriteria
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -23,7 +23,10 @@ class CompetitionTaskAdmin(admin.ModelAdmin):
|
|||||||
list_display = ("title", "type", "points")
|
list_display = ("title", "type", "points")
|
||||||
filter_horizontal = ("reviewers",)
|
filter_horizontal = ("reviewers",)
|
||||||
list_filter = ("type",)
|
list_filter = ("type",)
|
||||||
inlines = (CompletionAttachmentInline, CompetitionCriteriaInline,)
|
inlines = (
|
||||||
|
CompletionAttachmentInline,
|
||||||
|
CompetitionCriteriaInline,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CompetitionTaskSubmission)
|
@admin.register(CompetitionTaskSubmission)
|
||||||
@@ -45,9 +48,6 @@ class CompetitionTaskSubmissionAdmin(admin.ModelAdmin):
|
|||||||
def has_add_permission(self, request, obj=None):
|
def has_add_permission(self, request, obj=None):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def has_delete_permission(self, request, obj=None):
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class CompetitionTaskInline(admin.StackedInline):
|
class CompetitionTaskInline(admin.StackedInline):
|
||||||
model = CompetitionTask
|
model = CompetitionTask
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import apps.task.models
|
import apps.task.models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import martor.models
|
import mdeditor.fields
|
||||||
import uuid
|
import uuid
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
@@ -22,17 +22,17 @@ class Migration(migrations.Migration):
|
|||||||
name='CompetitionTask',
|
name='CompetitionTask',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
('in_competition_position', models.PositiveSmallIntegerField()),
|
('in_competition_position', models.PositiveSmallIntegerField(verbose_name='позиция в соревновании')),
|
||||||
('title', models.CharField(max_length=50, verbose_name='заголовок')),
|
('title', models.CharField(max_length=50, verbose_name='заголовок')),
|
||||||
('description', martor.models.MartorField(verbose_name='описание')),
|
('description', mdeditor.fields.MDTextField(verbose_name='описание')),
|
||||||
('max_attempts', models.PositiveSmallIntegerField(blank=True, null=True)),
|
('max_attempts', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='максимальное кол-во попыток')),
|
||||||
('type', models.CharField(choices=[('input', 'Ввод правильного ответа'), ('checker', 'Ввод кода'), ('review', 'Ручная')], max_length=8, verbose_name='тип проверки')),
|
('type', models.CharField(choices=[('input', 'Ввод правильного ответа'), ('checker', 'Ввод кода'), ('review', 'Ручная')], max_length=8, verbose_name='тип проверки')),
|
||||||
('correct_answer_file', models.FileField(blank=True, null=True, upload_to=apps.task.models.CompetitionTask.answer_file_upload_to, verbose_name='файл с правильным ответом')),
|
('correct_answer_file', models.FileField(blank=True, help_text='Имеет смысл только при автоматической (ввод ответа или кода) проверке.', null=True, upload_to=apps.task.models.CompetitionTask.answer_file_upload_to, verbose_name='файл с правильным ответом')),
|
||||||
('points', models.IntegerField(blank=True, null=True, verbose_name='баллы за задание')),
|
('points', models.IntegerField(blank=True, null=True, verbose_name='общий балл за задание')),
|
||||||
('answer_file_path', models.TextField(blank=True, default='stdout', help_text='Путь до файла в котором ожидается результат. Пример: stdout или ./output.txt', null=True, verbose_name='куда сделать вывод программы участнику')),
|
('answer_file_path', models.TextField(blank=True, default='stdout', help_text='Путь до файла в котором ожидается результат. Пример: stdout или ./output.txt. Имеет смысл только при автоматическом типе проверки.', null=True, verbose_name='куда сделать вывод программы участнику')),
|
||||||
('submission_reviewers_count', models.PositiveSmallIntegerField(blank=True, default=1, null=True)),
|
('submission_reviewers_count', models.PositiveSmallIntegerField(blank=True, default=1, null=True, verbose_name='кол-во проверяющих для зачета задачи')),
|
||||||
('competition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.competition')),
|
('competition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.competition', verbose_name='привязанное соревнование')),
|
||||||
('reviewers', models.ManyToManyField(blank=True, help_text='Справа отображаются действующие проверяющие, слева - доступные для выбора. Для перемещения можно кликнуть 2 раза по проверяющему', to='review.reviewer', verbose_name='ревьюверы')),
|
('reviewers', models.ManyToManyField(blank=True, help_text='Справа отображаются действующие проверяющие, слева - доступные для выбора. Для перемещения можно кликнуть 2 раза по проверяющему. Имеет смысл только при ручном типе проверки.', to='review.reviewer', verbose_name='ревьюверы')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'задание',
|
'verbose_name': 'задание',
|
||||||
@@ -57,14 +57,15 @@ class Migration(migrations.Migration):
|
|||||||
name='CompetitionTaskCriteria',
|
name='CompetitionTaskCriteria',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
('name', models.TextField()),
|
('name', models.TextField(verbose_name='название')),
|
||||||
('slug', models.SlugField()),
|
('slug', models.SlugField(verbose_name='техническое название')),
|
||||||
('description', models.TextField()),
|
('description', models.TextField(verbose_name='описание критерии')),
|
||||||
('max_value', models.PositiveSmallIntegerField()),
|
('max_value', models.PositiveSmallIntegerField(verbose_name='максимальное кол-во баллов')),
|
||||||
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='criteries', to='task.competitiontask')),
|
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='criteries', to='task.competitiontask')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'abstract': False,
|
'verbose_name': 'критерий',
|
||||||
|
'verbose_name_plural': 'критерии',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
|
|||||||
@@ -22,12 +22,16 @@ class CompetitionTask(BaseModel):
|
|||||||
in_competition_position = models.PositiveSmallIntegerField(
|
in_competition_position = models.PositiveSmallIntegerField(
|
||||||
verbose_name="позиция в соревновании"
|
verbose_name="позиция в соревновании"
|
||||||
)
|
)
|
||||||
competition = models.ForeignKey(Competition, on_delete=models.CASCADE,
|
competition = models.ForeignKey(
|
||||||
verbose_name="привязанное соревнование")
|
Competition,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name="привязанное соревнование",
|
||||||
|
)
|
||||||
title = models.CharField(verbose_name="заголовок", max_length=50)
|
title = models.CharField(verbose_name="заголовок", max_length=50)
|
||||||
description = MDTextField(verbose_name="описание")
|
description = MDTextField(verbose_name="описание")
|
||||||
max_attempts = models.PositiveSmallIntegerField(null=True, blank=True,
|
max_attempts = models.PositiveSmallIntegerField(
|
||||||
verbose_name="максимальное кол-во попыток")
|
null=True, blank=True, verbose_name="максимальное кол-во попыток"
|
||||||
|
)
|
||||||
type = models.CharField(
|
type = models.CharField(
|
||||||
choices=CompetitionTaskType, max_length=8, verbose_name="тип проверки"
|
choices=CompetitionTaskType, max_length=8, verbose_name="тип проверки"
|
||||||
)
|
)
|
||||||
@@ -38,9 +42,10 @@ class CompetitionTask(BaseModel):
|
|||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name="файл с правильным ответом",
|
verbose_name="файл с правильным ответом",
|
||||||
|
help_text="Имеет смысл только при автоматической (ввод ответа или кода) проверке.",
|
||||||
)
|
)
|
||||||
points = models.IntegerField(
|
points = models.IntegerField(
|
||||||
null=True, blank=True, verbose_name="баллы за задание"
|
null=True, blank=True, verbose_name="общий балл за задание"
|
||||||
)
|
)
|
||||||
|
|
||||||
# only when "checker" type
|
# only when "checker" type
|
||||||
@@ -48,7 +53,10 @@ class CompetitionTask(BaseModel):
|
|||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name="куда сделать вывод программы участнику",
|
verbose_name="куда сделать вывод программы участнику",
|
||||||
help_text="Путь до файла в котором ожидается результат. Пример: stdout или ./output.txt",
|
help_text=(
|
||||||
|
"Путь до файла в котором ожидается результат. "
|
||||||
|
"Пример: stdout или ./output.txt. Имеет смысл только при автоматическом типе проверки."
|
||||||
|
),
|
||||||
default="stdout",
|
default="stdout",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,10 +65,17 @@ class CompetitionTask(BaseModel):
|
|||||||
Reviewer,
|
Reviewer,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name="ревьюверы",
|
verbose_name="ревьюверы",
|
||||||
help_text="Справа отображаются действующие проверяющие, слева - доступные для выбора. Для перемещения можно кликнуть 2 раза по проверяющему",
|
help_text=(
|
||||||
|
"Справа отображаются действующие проверяющие, слева - доступные для выбора. "
|
||||||
|
"Для перемещения можно кликнуть 2 раза по проверяющему. Имеет смысл только"
|
||||||
|
" при ручном типе проверки."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
submission_reviewers_count = models.PositiveSmallIntegerField(
|
submission_reviewers_count = models.PositiveSmallIntegerField(
|
||||||
default=1, null=True, blank=True, verbose_name="кол-во проверяющих для зачета задачи"
|
default=1,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="кол-во проверяющих для зачета задачи",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -76,15 +91,9 @@ class CompetitionTaskCriteria(BaseModel):
|
|||||||
CompetitionTask, on_delete=models.CASCADE, related_name="criteries"
|
CompetitionTask, on_delete=models.CASCADE, related_name="criteries"
|
||||||
)
|
)
|
||||||
|
|
||||||
name = models.TextField(
|
name = models.TextField(verbose_name="название")
|
||||||
verbose_name="название"
|
slug = models.SlugField(verbose_name="техническое название")
|
||||||
)
|
description = models.TextField(verbose_name="описание критерии")
|
||||||
slug = models.SlugField(
|
|
||||||
verbose_name="техническое название"
|
|
||||||
)
|
|
||||||
description = models.TextField(
|
|
||||||
verbose_name="описание критерии"
|
|
||||||
)
|
|
||||||
max_value = models.PositiveSmallIntegerField(
|
max_value = models.PositiveSmallIntegerField(
|
||||||
verbose_name="максимальное кол-во баллов"
|
verbose_name="максимальное кол-во баллов"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,28 +1,40 @@
|
|||||||
|
import hashlib
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
|
|
||||||
|
from apps.task.models import CompetitionTaskSubmission
|
||||||
|
|
||||||
|
|
||||||
@shared_task(bind=True, max_retries=3)
|
@shared_task(bind=True, max_retries=3)
|
||||||
def analyze_data_task(self, submission_id):
|
def analyze_data_task(self, submission_id):
|
||||||
from .models import CompetitionTaskSubmission
|
|
||||||
|
|
||||||
submission = CompetitionTaskSubmission.objects.get(id=submission_id)
|
submission = CompetitionTaskSubmission.objects.get(id=submission_id)
|
||||||
try:
|
try:
|
||||||
code = submission.content.read().decode()
|
code_url = (
|
||||||
|
f"{settings.MINIO_DEFAULT_CUSTOM_ENDPOINT_URL}{submission.path}"
|
||||||
|
)
|
||||||
files = [
|
files = [
|
||||||
(f.name, f.file.open("rb"))
|
{
|
||||||
for f in submission.task.attachments.filter(public=True)
|
"url": f"{settings.MINIO_DEFAULT_CUSTOM_ENDPOINT_URL}{attachment.path}",
|
||||||
|
"bind_path": attachment.bind_at,
|
||||||
|
}
|
||||||
|
for attachment in submission.task.attachments.filter(
|
||||||
|
bind_path__isnull=False
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
response = httpx.post(
|
response = httpx.post(
|
||||||
f"{settings.CHECKER_API_ENDPOINT}/execute",
|
f"{settings.CHECKER_API_ENDPOINT}/execute",
|
||||||
files=[("files", (f.name, f)) for f in files]
|
json={
|
||||||
+ [
|
"files": files,
|
||||||
("code", code),
|
"code_url": code_url,
|
||||||
("expected_hash", submission.task.correct_answer_hash),
|
"answer_file_path": submission.task.answer_file_path,
|
||||||
],
|
"expected_hash": hashlib.sha256(
|
||||||
|
submission.task.correct_answer_file.read().encode()
|
||||||
|
).hexdigest(),
|
||||||
|
},
|
||||||
timeout=30,
|
timeout=30,
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import uuid
|
import uuid
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.6 on 2025-03-03 07:20
|
# Generated by Django 5.1.6 on 2025-03-03 09:41
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@@ -17,11 +17,12 @@ class Migration(migrations.Migration):
|
|||||||
name='User',
|
name='User',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
|
('avatar', models.ImageField(blank=True, null=True, upload_to='', verbose_name='аватар')),
|
||||||
('email', models.EmailField(max_length=254, unique=True, verbose_name='почта')),
|
('email', models.EmailField(max_length=254, unique=True, verbose_name='почта')),
|
||||||
('username', models.SlugField(unique=True, verbose_name='юзернейм')),
|
('username', models.SlugField(unique=True, verbose_name='юзернейм')),
|
||||||
('password', models.TextField(verbose_name='пароль')),
|
('password', models.TextField(verbose_name='пароль')),
|
||||||
('created_at', models.DateTimeField(auto_now=True)),
|
('created_at', models.DateTimeField(auto_now=True, verbose_name='дата создания')),
|
||||||
('status', models.CharField(choices=[('student', 'Student'), ('metodist', 'Metodist')], default='student', max_length=10)),
|
('status', models.CharField(choices=[('student', 'Участник соревнований'), ('metodist', 'Методист (составитель заданий)')], default='student', max_length=10, verbose_name='роль участника')),
|
||||||
('achievements', models.ManyToManyField(blank=True, to='achievement.achievement', verbose_name='ачивки пользователя')),
|
('achievements', models.ManyToManyField(blank=True, to='achievement.achievement', verbose_name='ачивки пользователя')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
|||||||
@@ -11,11 +11,14 @@ class UserRole(models.TextChoices):
|
|||||||
|
|
||||||
|
|
||||||
class User(BaseModel):
|
class User(BaseModel):
|
||||||
|
avatar = models.ImageField(verbose_name="аватар", null=True, blank=True)
|
||||||
email = models.EmailField(unique=True, verbose_name="почта")
|
email = models.EmailField(unique=True, verbose_name="почта")
|
||||||
username = models.SlugField(unique=True, verbose_name="юзернейм")
|
username = models.SlugField(unique=True, verbose_name="юзернейм")
|
||||||
password = models.TextField(verbose_name="пароль")
|
password = models.TextField(verbose_name="пароль")
|
||||||
|
|
||||||
created_at = models.DateTimeField(auto_now=True, verbose_name="дата создания")
|
created_at = models.DateTimeField(
|
||||||
|
auto_now=True, verbose_name="дата создания"
|
||||||
|
)
|
||||||
|
|
||||||
achievements = models.ManyToManyField(
|
achievements = models.ManyToManyField(
|
||||||
Achievement, blank=True, verbose_name="ачивки пользователя"
|
Achievement, blank=True, verbose_name="ачивки пользователя"
|
||||||
@@ -29,8 +32,10 @@ class User(BaseModel):
|
|||||||
return check_password(self.password, password)
|
return check_password(self.password, password)
|
||||||
|
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
max_length=10, choices=UserRole.choices, default="student",
|
max_length=10,
|
||||||
verbose_name="роль участника"
|
choices=UserRole.choices,
|
||||||
|
default="student",
|
||||||
|
verbose_name="роль участника",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
|||||||
@@ -12,12 +12,8 @@ admin.site.index_title = "DataRush"
|
|||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# tinymce
|
|
||||||
path("tinymce/", include("tinymce.urls")),
|
|
||||||
# martor
|
|
||||||
path("martor/", include("martor.urls")),
|
|
||||||
# mdeditor
|
# mdeditor
|
||||||
path(r'mdeditor/', include('mdeditor.urls')),
|
path(r"mdeditor/", include("mdeditor.urls")),
|
||||||
# Admin urls
|
# Admin urls
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
# API urls
|
# API urls
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ async def execute_code(request: ExecutionRequest) -> ExecutionResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
|
print(tmp_dir)
|
||||||
bound_files = {}
|
bound_files = {}
|
||||||
if request.files:
|
if request.files:
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
|
|||||||
Reference in New Issue
Block a user