dump
This commit is contained in:
parent
76a74efbe7
commit
80e0867526
30
Main/migrations/0028_dump.py
Normal file
30
Main/migrations/0028_dump.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 3.2.4 on 2022-03-15 19:08
|
||||||
|
|
||||||
|
import Main.models.mixins
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('Main', '0027_task_allow_sharing'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Dump',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
('fs_id', models.IntegerField(null=True)),
|
||||||
|
('ready', models.BooleanField(default=False)),
|
||||||
|
('executor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
('task', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='Main.task')),
|
||||||
|
],
|
||||||
|
bases=(Main.models.mixins.FileStorageMixin, models.Model),
|
||||||
|
),
|
||||||
|
]
|
17
Main/migrations/0029_remove_dump_ready.py
Normal file
17
Main/migrations/0029_remove_dump_ready.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.4 on 2022-03-15 19:20
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Main', '0028_dump'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='dump',
|
||||||
|
name='ready',
|
||||||
|
),
|
||||||
|
]
|
@ -10,3 +10,4 @@ from Main.models.progress import Progress
|
|||||||
from Main.models.solution_file import SolutionFile
|
from Main.models.solution_file import SolutionFile
|
||||||
from Main.models.friendship import Friendship
|
from Main.models.friendship import Friendship
|
||||||
from Main.models.language_apply import LanguageApply
|
from Main.models.language_apply import LanguageApply
|
||||||
|
from Main.models.dump import Dump
|
||||||
|
25
Main/models/dump.py
Normal file
25
Main/models/dump.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from .mixins import FileStorageMixin
|
||||||
|
|
||||||
|
|
||||||
|
class Dump(FileStorageMixin, models.Model):
|
||||||
|
timestamp = models.DateTimeField(default=timezone.now)
|
||||||
|
fs_id = models.IntegerField(null=True)
|
||||||
|
executor = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
task = models.ForeignKey("Task", on_delete=models.CASCADE, null=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ready(self):
|
||||||
|
return self.fs_id is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def str_date(self):
|
||||||
|
return self.timestamp.strftime("%Y-%m-%dT%H:%M:%S")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filename(self):
|
||||||
|
if self.task is not None:
|
||||||
|
return f"dump-task-{self.task.id}-{self.str_date}"
|
@ -2,6 +2,7 @@ from django.contrib.postgres.fields import ArrayField
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from Main.models.dump import Dump
|
||||||
from Main.models.extrafile import ExtraFile
|
from Main.models.extrafile import ExtraFile
|
||||||
|
|
||||||
|
|
||||||
@ -21,6 +22,10 @@ class Task(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dumps(self):
|
||||||
|
return Dump.objects.filter(task=self).order_by("-timestamp")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def files(self):
|
def files(self):
|
||||||
return ExtraFile.objects.filter(task=self, is_test=False)
|
return ExtraFile.objects.filter(task=self, is_test=False)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
|
||||||
from Main.models import ExtraFile
|
from Main.models import ExtraFile, Dump
|
||||||
from SprintLib.BaseView import BaseView, AccessError
|
from SprintLib.BaseView import BaseView, AccessError
|
||||||
|
from SprintLib.queue import send_to_queue
|
||||||
|
|
||||||
|
|
||||||
class TaskSettingsView(BaseView):
|
class TaskSettingsView(BaseView):
|
||||||
@ -23,6 +24,11 @@ class TaskSettingsView(BaseView):
|
|||||||
self.entities.task.save()
|
self.entities.task.save()
|
||||||
return f"/admin/task?task_id={self.entities.task.id}"
|
return f"/admin/task?task_id={self.entities.task.id}"
|
||||||
|
|
||||||
|
def post_dump(self):
|
||||||
|
dump = Dump.objects.create(executor=self.request.user, task=self.entities.task)
|
||||||
|
send_to_queue("files", {"id": dump.id})
|
||||||
|
return f"/admin/task?task_id={self.entities.task.id}"
|
||||||
|
|
||||||
def _upload(self, is_test):
|
def _upload(self, is_test):
|
||||||
filename = self.request.FILES["file"].name
|
filename = self.request.FILES["file"].name
|
||||||
ef, created = None, None
|
ef, created = None, None
|
||||||
|
@ -1,9 +1,68 @@
|
|||||||
|
import json
|
||||||
|
from os import mkdir, listdir, remove
|
||||||
|
from os.path import exists, join
|
||||||
|
from shutil import rmtree
|
||||||
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from Main.models import Dump, ExtraFile
|
||||||
from SprintLib.queue import MessagingSupport
|
from SprintLib.queue import MessagingSupport
|
||||||
|
from SprintLib.utils import write_bytes
|
||||||
|
|
||||||
|
|
||||||
class Command(MessagingSupport):
|
class Command(MessagingSupport):
|
||||||
help = "starts file generator"
|
help = "starts file generator"
|
||||||
queue_name = "files"
|
queue_name = "files"
|
||||||
|
|
||||||
|
def process_task(self, dump):
|
||||||
|
task_fields = [
|
||||||
|
'name',
|
||||||
|
'public',
|
||||||
|
'legend',
|
||||||
|
'input_format',
|
||||||
|
'output_format',
|
||||||
|
'specifications',
|
||||||
|
'time_limit',
|
||||||
|
'time_estimation',
|
||||||
|
]
|
||||||
|
task_data = {field: getattr(dump.task, field) for field in task_fields}
|
||||||
|
files_fields = [
|
||||||
|
'id',
|
||||||
|
'filename',
|
||||||
|
'is_test',
|
||||||
|
'is_sample',
|
||||||
|
'readable',
|
||||||
|
'test_number'
|
||||||
|
]
|
||||||
|
task_data['files'] = [
|
||||||
|
{
|
||||||
|
field: getattr(file, field)
|
||||||
|
for field in files_fields
|
||||||
|
}
|
||||||
|
for file in ExtraFile.objects.filter(task=dump.task)
|
||||||
|
]
|
||||||
|
tempdir = "/var/tmp/dump/"
|
||||||
|
dump_filename = 'dump.zip'
|
||||||
|
try:
|
||||||
|
mkdir(tempdir)
|
||||||
|
with open(join(tempdir, 'meta.json'), 'w') as fs:
|
||||||
|
json.dump(task_data, fs)
|
||||||
|
for ef in ExtraFile.objects.filter(task=dump.task):
|
||||||
|
with open(join(tempdir, ef.id), 'wb') as fs:
|
||||||
|
fs.write(ef.bytes)
|
||||||
|
with ZipFile(dump_filename, 'w') as zipfile:
|
||||||
|
for file in listdir(tempdir):
|
||||||
|
zipfile.write(join(tempdir, file))
|
||||||
|
fs_id = write_bytes(open(dump_filename, 'rb').read())
|
||||||
|
dump.fs_id = fs_id
|
||||||
|
dump.save()
|
||||||
|
finally:
|
||||||
|
if exists(tempdir):
|
||||||
|
rmtree(tempdir)
|
||||||
|
if exists(dump_filename):
|
||||||
|
remove(dump_filename)
|
||||||
|
|
||||||
def process(self, payload: dict):
|
def process(self, payload: dict):
|
||||||
...
|
id = payload['id']
|
||||||
|
dump = Dump.objects.get(id=id)
|
||||||
|
if dump.task:
|
||||||
|
self.process_task(dump)
|
||||||
|
@ -311,5 +311,28 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<hr><hr>
|
||||||
|
<h3>Дампы</h3>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<th scope="col">Id дампа</th>
|
||||||
|
<th scope="col">Время запроса</th>
|
||||||
|
<th scope="col">Инициатор</th>
|
||||||
|
<th scope="col">Готовность</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for dump in task.dumps %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ dump.id }}</td>
|
||||||
|
<td>{{ dump.timestamp }}</td>
|
||||||
|
<td>{{ dump.executor.username }}</td>
|
||||||
|
<td>{% if dump.ready %}<a href="#">Скачать</a>{% else %}<badge class="badge badge-info"><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="circle-notch" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="width: 20px;" class="svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg"><path fill="currentColor" d="M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z" class=""></path></svg> В процессе</badge>{% endif %}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" name="action" value="dump" class="btn btn-primary"><i class="fa fa-arrow-right"></i> Создать дамп</button>
|
||||||
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user