WIP: Stáhnout řešení jako ZIP #84
2 changed files with 48 additions and 0 deletions
|
@ -11,7 +11,9 @@ urlpatterns = [
|
||||||
path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='odevzdavatko_resitel_odevzdana_reseni'),
|
path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='odevzdavatko_resitel_odevzdana_reseni'),
|
||||||
|
|
||||||
path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
||||||
|
path('org/reseni/zip/', org_required(views.OdevzdanaReseniVZipuView.as_view()), name='odevzdavatko_zip'),
|
||||||
path('org/reseni/rocnik/<int:rocnik>/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
path('org/reseni/rocnik/<int:rocnik>/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
||||||
|
path('org/reseni/rocnik/<int:rocnik>/zip/', org_required(views.OdevzdanaReseniVZipuView.as_view()), name='odevzdavatko_zip'),
|
||||||
path('org/reseni/<int:problem>/<int:resitel>/', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'),
|
path('org/reseni/<int:problem>/<int:resitel>/', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'),
|
||||||
path('org/reseni/<int:pk>', org_required(viewMethodSwitch(get=views.EditReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'),
|
path('org/reseni/<int:pk>', org_required(viewMethodSwitch(get=views.EditReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'),
|
||||||
path('org/reseni/all', org_required(views.SeznamReseniView.as_view())),
|
path('org/reseni/all', org_required(views.SeznamReseniView.as_view())),
|
||||||
|
|
|
@ -10,17 +10,22 @@ from django.shortcuts import redirect, get_object_or_404, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import datetime
|
import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
|
||||||
from . import forms as f
|
from . import forms as f
|
||||||
from .forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm
|
from .forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm
|
||||||
from .models import Hodnoceni, Reseni
|
from .models import Hodnoceni, Reseni
|
||||||
|
|
||||||
|
from odevzdavatko.templatetags.jmena import jmeno_jako_prefix
|
||||||
from personalni.models import Resitel, Osoba, Organizator
|
from personalni.models import Resitel, Osoba, Organizator
|
||||||
from tvorba.models import Problem, Deadline, Rocnik
|
from tvorba.models import Problem, Deadline, Rocnik
|
||||||
from tvorba.utils import resi_v_rocniku
|
from tvorba.utils import resi_v_rocniku
|
||||||
|
@ -175,6 +180,47 @@ class TabulkaOdevzdanychReseniView(ListView):
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
# Intuitivně se mi dědičnost nelíbí, neumím říct přesně proč… (Zhruba:
|
||||||
|
# vykoná/přikládá se spousta kódu, který ale souvisí jen s HTML, tím, že si
|
||||||
|
# píšeme vlastní .get(). Lepší by bylo společné ne-HTML části (e.g.
|
||||||
|
# inicializuj_osy_tabulky) vyrazit ven a v obou Views jen použít…)
|
||||||
|
class OdevzdanaReseniVZipuView(TabulkaOdevzdanychReseniView):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
# Inspirováno implementací django.views.generic.list.BaseListView
|
||||||
|
self.object_list = self.get_queryset()
|
||||||
|
# Teď už máme i `self.problemy`.
|
||||||
|
with tempfile.TemporaryDirectory() as d:
|
||||||
|
print(f'DBG: {d=}')
|
||||||
|
zfname = f"{d}/reseni.zip"
|
||||||
|
with zipfile.ZipFile(zfname, 'w', compression=zipfile.ZIP_LZMA) as zf: # `zip` is builtin :-/
|
||||||
|
print(f'DBG: .{self.reseni.count()=}')
|
||||||
|
# TODO: data z tabulky
|
||||||
|
for r in self.reseni:
|
||||||
|
if len(r.resitele.all()) < 1:
|
||||||
|
logger.error(f'Řešení {r.id} nemá řešitele??!!')
|
||||||
|
continue
|
||||||
|
# DBG!
|
||||||
|
if len(r.prilohy.all()) < 1: continue
|
||||||
|
# TODO: komentáře jmen souborů
|
||||||
|
# Pro konzistenci imitujeme `data-alt-filename="{{object.resitele.first.osoba | jmeno_jako_prefix }}_{{ object.id }}_{{ priloha.split | last}}"` z templates/odevzdavatko/detail.html.
|
||||||
|
jmeno_slozky = f'{jmeno_jako_prefix(r.resitele.first().osoba)}_{r.id}'
|
||||||
|
zf.mkdir(jmeno_slozky)
|
||||||
|
slozka = zipfile.Path(zf, jmeno_slozky)
|
||||||
|
print(f'DBG: .({jmeno_slozky=}, {r.prilohy.count()=})')
|
||||||
|
for pr in r.prilohy.all():
|
||||||
|
jmeno_souboru = f'{jmeno_slozky}_{pr.split()[-1]}'
|
||||||
|
print(f'DBG: .({os.path.join(jmeno_slozky, jmeno_souboru)=})')
|
||||||
|
zf.write(pr.soubor.path, os.path.join(jmeno_slozky, jmeno_souboru))
|
||||||
|
|
||||||
|
print(f'DBG: Done, sending')
|
||||||
|
# close&open k provedení všech zápisů
|
||||||
|
with open(zfname, 'rb') as zf:
|
||||||
|
print(f'DBG: .')
|
||||||
|
response = HttpResponse(zf.read(), content_type='application/zip')
|
||||||
|
response['Content-Disposition'] = 'attachment; filename="reseni.zip"'
|
||||||
|
print(f'DBG: .')
|
||||||
|
return response
|
||||||
|
|
||||||
# Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji?
|
# Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji?
|
||||||
class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View):
|
class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View):
|
||||||
"""Rozskok mezi více řešeními téhož problému od téhož řešitele.
|
"""Rozskok mezi více řešeními téhož problému od téhož řešitele.
|
||||||
|
|
Loading…
Reference in a new issue