diff --git a/tvorba/views/views_all.py b/tvorba/views/views_all.py deleted file mode 100644 index f960aac8..00000000 --- a/tvorba/views/views_all.py +++ /dev/null @@ -1,579 +0,0 @@ -from django.shortcuts import get_object_or_404, render -from django.http import HttpResponse -from django.urls import reverse -from django.core.exceptions import ObjectDoesNotExist -from django.views import generic -from django.utils.translation import gettext as _ -from django.http import Http404 -from django.db.models import Q, Sum, Count -from django.views.generic.base import RedirectView -from django.core.exceptions import PermissionDenied - -import seminar.models as s -import seminar.models as m -from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, \ - Resitel, Novinky, Tema, Clanek, \ - Deadline # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci -#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva -from treenode import treelib -import treenode.templatetags as tnltt -import treenode.serializers as vr -from vysledkovky.utils import body_resitelu, VysledkovkaCisla, \ - VysledkovkaRocniku, VysledkovkaDoTeXu - -from datetime import date, datetime -from itertools import groupby -from collections import OrderedDict -import os -import os.path as op -from django.conf import settings -import unicodedata -import logging -import time - -import personalni.views - -from .. import utils - -# ze starého modelu -#def verejna_temata(rocnik): -# """ -# Vrací queryset zveřejněných témat v daném ročníku. -# """ -# return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod') -# -#def temata_v_rocniku(rocnik): -# return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik) - -logger = logging.getLogger(__name__) - -def get_problemy_k_tematu(tema): - return Problem.objects.filter(nadproblem = tema) - - -# FIXME: Pozor, níž je ještě jeden ProblemView! -#class ProblemView(generic.DetailView): -# model = s.Problem -# # Zkopírujeme template_name od TreeNodeView, protože jsme prakticky jen trošku upravený TreeNodeView -# template_name = TreeNodeView.template_name -# -# def get_context_data(self, **kwargs): -# context = super().get_context_data(**kwargs) -# user = self.request.user -# # Teď potřebujeme doplnit tnldata do kontextu. -# # Ošklivý type switch, hezčí by bylo udělat to polymorfni. FIXME. -# if False: -# # Hezčí formátování zbytku :-P -# pass -# elif isinstance(self.object, s.Clanek) or isinstance(self.object, s.Konfera): -# # Tyhle Problémy mají ŘešeníNode -# context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user) -# elif isinstance(self.object, s.Uloha): -# # FIXME: Teď vždycky zobrazujeme i vzorák! Možná by bylo hezčí/lepší mít to stejně jako pro Téma: procházet jen dosažitelné z Ročníku / čísla / whatever -# tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user) -# tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user) -# context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak]) -# elif isinstance(self.object, s.Tema): -# rocniknode = self.object.rocnik.rocniknode -# context['tnldata'] = TNLData.filter_treenode(rocniknode, lambda x: isinstance(x, s.TemaVCisleNode)) -# else: -# raise ValueError("Obecný problém nejde zobrazit.") -# return context - - -#class AktualniZadaniView(generic.TemplateView): -# template_name = 'treenode/treenode.html' - -# TODO Co chceme vlastně zobrazovat na této stránce? Zatím je zde aktuální číslo, ale může tu být cokoli jiného... -#class AktualniZadaniView(TreeNodeView): -# def get_object(self): -# nastaveni = get_object_or_404(Nastaveni) -# return nastaveni.aktualni_cislo.cislonode -# -# def get_context_data(self,**kwargs): -# nastaveni = get_object_or_404(Nastaveni) -# context = super().get_context_data(**kwargs) -# verejne = nastaveni.aktualni_cislo.verejne() -# context['verejne'] = verejne -# return context - -def AktualniZadaniView(request): - nastaveni = get_object_or_404(Nastaveni) - verejne = nastaveni.aktualni_cislo.verejne() - return render(request, 'tvorba/zadani/AktualniZadani.html', - {'nastaveni': nastaveni, - 'verejne': verejne, - }, - ) - -def ZadaniTemataView(request): - nastaveni = get_object_or_404(Nastaveni) - verejne = nastaveni.aktualni_cislo.verejne() - akt_rocnik = nastaveni.aktualni_cislo.rocnik - temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') - return render(request, 'tvorba/tematka/rozcestnik.html', - { - 'tematka': temata, - 'verejne': verejne, - }, - ) - - -# nastaveni = get_object_or_404(Nastaveni) -# temata = verejna_temata(nastaveni.aktualni_rocnik) -# for t in temata: -# if request.user.is_staff: -# t.prispevky = t.prispevek_set.filter(problem=t) -# else: -# t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True) -# return render(request, 'tvorba/zadani/Temata.html', -# { -# 'temata': temata, -# } -# ) -# -# -# -#def TematkoView(request, rocnik, tematko): -# nastaveni = s.Nastaveni.objects.first() -# rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik) -# tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) -# seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode) -# for node, depth in seznam: -# if node.isinstance(node, s.KonferaNode): -# raise Exception("Not implemented yet") -# if node.isinstance(node, s.PohadkaNode): # Mohu ignorovat, má pod sebou -# pass -# -# return render(request, 'tvorba/tematka/toaletak.html', {}) -# -# -#def TemataRozcestnikView(request): -# print("=============================================") -# nastaveni = s.Nastaveni.objects.first() -# tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) -# tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku -# for tematko_object in tematka_objects: -# print("AKTUALNI TEMATKO") -# print(tematko_object.id) -# odkazy = vytahniZLesaSeznam(tematko_object, nastaveni.aktualni_rocnik().rocniknode, pouze_zajimave = True) #Odkazy jsou tuply (node, depth) v listu -# print(odkazy) -# cisla = [] # List tuplů (nazev cisla, list odkazů) -# vcisle = [] -# cislo = None -# for odkaz in odkazy: -# if odkaz[1] == 0: -# if cislo != None: -# cisla.append((cislo, vcisle)) -# cislo = (odkaz[0].getOdkazStr(), odkaz[0].getOdkaz()) -# vcisle = [] -# else: -# print(odkaz[0].getOdkaz()) -# vcisle.append((odkaz[0].getOdkazStr(), odkaz[0].getOdkaz())) -# if cislo != None: -# cisla.append((cislo, vcisle)) -# -# print(cisla) -# tematka.append({ -# "kod" : tematko_object.kod, -# "nazev" : tematko_object.nazev, -# "abstrakt" : tematko_object.abstrakt, -# "obrazek": tematko_object.obrazek, -# "cisla" : cisla -# }) -# return render(request, 'tvorba/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik}) -# - -def ZadaniAktualniVysledkovkaView(request): - nastaveni = get_object_or_404(Nastaveni) - # Aktualni verejna vysledkovka - rocnik = nastaveni.aktualni_rocnik - context = {'vysledkovka': VysledkovkaRocniku(rocnik, True)} - - # kdyz neni verejna vysledkovka, tak zobraz starou - if len(context['vysledkovka'].cisla_rocniku) == 0: - try: - minuly_rocnik = Rocnik.objects.get( - rocnik=(rocnik.rocnik-1)) - rocnik = minuly_rocnik - - # Přepíšeme prázdnou výsledkovku výsledkovkou z minulého ročníku - context['vysledkovka'] = VysledkovkaRocniku(rocnik, True) - except ObjectDoesNotExist: - pass - - context['rocnik'] = rocnik - return render( - request, - 'tvorba/zadani/AktualniVysledkovka.html', - context - ) - - -### Titulni strana - -def aktualni_temata(rocnik): - """ - Vrací PolymorphicQuerySet témat v daném ročníku, ke kterým se aktuálně dá něco odevzdat. - """ - return Tema.objects.filter(rocnik=rocnik, stav='zadany').order_by('kod') - - -### Archiv - - -class ArchivView(generic.ListView): - model = Rocnik - template_name = 'tvorba/archiv/cisla.html' - - def get_context_data(self, **kwargs): - context = super(ArchivView, self).get_context_data(**kwargs) - - cisla = Cislo.objects.filter(poradi=1) - if not self.request.user.je_org: - cisla = cisla.filter(verejne_db=True) - urls ={} - - for i, c in enumerate(cisla): - # Výchozí nastavení - if c.rocnik not in urls: - urls[c.rocnik] = op.join(settings.STATIC_URL, "tvorba", "no-picture.png") - # NOTE: tohle možná nastavuje poslední titulku - if c.titulka_nahled: - urls[c.rocnik] = c.titulka_nahled.url - - context["object_list"] = urls - - return context - - - - - -class RocnikView(generic.DetailView): - model = Rocnik - template_name = 'tvorba/archiv/rocnik.html' - - # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) - def get_object(self, queryset=None): - if queryset is None: - queryset = self.get_queryset() - - return get_object_or_404(queryset,rocnik=self.kwargs.get('rocnik')) - - def get_context_data(self, **kwargs): - context = super(RocnikView, self).get_context_data(**kwargs) - context["vysledkovka"] = VysledkovkaRocniku(context["rocnik"], True) - context["neprazdna_vysledkovka"] = len(context['vysledkovka'].cisla_rocniku) != 0 - context["vysledkovka_neverejna"] = VysledkovkaRocniku(context["rocnik"], False) - return context - -def resiteleRocnikuCsvExportView(request, rocnik): - from personalni.views import dataResiteluCsvResponse - assert request.method in ('GET', 'HEAD') - return dataResiteluCsvResponse( - utils.resi_v_rocniku( - get_object_or_404(m.Rocnik, rocnik=rocnik) - ) - ) - - -# FIXME: Pozor, výš je ještě jeden ProblemView! -#class ProblemView(generic.DetailView): -# model = Problem -# -# # Používáme funkci, protože přímo template_name neumí mít v přiřazení dost logiky. Ledaže by se to udělalo polymorfně... -# def get_template_names(self, **kwargs): -# # FIXME: Switch podle typu není hezký, ale nechtělo se mi to přepisovat celé. Správně by se tohle mělo řešit polymorfismem. -# spravne_templaty = { -# s.Uloha: "uloha", -# s.Tema: "tema", -# s.Konfera: "konfera", -# s.Clanek: "clanek", -# } -# context = super().get_context_data(**kwargs) -# return ['tvorba/archiv/problem_' + spravne_templaty[context['object'].__class__] + '.html'] -# -# def get_context_data(self, **kwargs): -# context = super().get_context_data(**kwargs) -# # Musí se používat context['object'], protože nevíme, jestli dostaneme úložku, téma, článek, .... a tyhle věci vyrábějí různé klíče. -# if not context['object'].verejne() and not self.request.user.je_org: -# raise PermissionDenied() -# if isinstance(context['object'], Clanek): -# context['reseni'] = Reseni.objects.filter(problem=context['object']).select_related('resitel').order_by('resitel__prijmeni') -# return context - - - -class CisloView(generic.DetailView): - # FIXME zobrazování témátek a vůbec, teď je tam jen odkaz na číslo v pdf - model = Cislo - template_name = 'tvorba/archiv/cislo.html' - - # Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik) - def get_object(self, queryset=None): - if queryset is None: - queryset = self.get_queryset() - rocnik_arg = self.kwargs.get('rocnik') - poradi_arg = self.kwargs.get('cislo') - queryset = queryset.filter(rocnik__rocnik=rocnik_arg, poradi=poradi_arg) - - try: - obj = queryset.get() - except queryset.model.DoesNotExist: - raise Http404(_("No %(verbose_name)s found matching the query") % - {'verbose_name': queryset.model._meta.verbose_name}) - return obj - - def get_context_data(self, **kwargs): - context = super(CisloView, self).get_context_data(**kwargs) - - cislo = context['cislo'] - context['prevcislo'] = Cislo.objects.filter((Q(rocnik__lt=self.object.rocnik) | Q(poradi__lt=self.object.poradi))&Q(rocnik__lte=self.object.rocnik)).first() - - deadliny = Deadline.objects.filter(cislo=cislo).reverse() - deadliny_s_vysledkovkami = [] - - nadpisy = { - m.Deadline.TYP_CISLA: "Výsledkovka", - m.Deadline.TYP_PRVNI: "Výsledkovka do prvního deadlinu", - m.Deadline.TYP_PRVNI_A_SOUS: "Výsledkovka do prvního deadlinu a deadlinu pro účast na soustředění", - m.Deadline.TYP_SOUS: "Výsledkovka do deadlinu pro účast na soustředění", - } - - for deadline in deadliny: - if self.request.user.je_org | deadline.verejna_vysledkovka: - deadliny_s_vysledkovkami.append((deadline, nadpisy[deadline.typ], VysledkovkaCisla(cislo, not self.request.user.je_org, deadline))) - - context['deadliny_s_vysledkovkami'] = deadliny_s_vysledkovkami - return context - - -class ArchivTemataView(generic.ListView): - model = Problem - template_name = 'tvorba/archiv/temata.html' - queryset = Tema.objects.filter(stav=Problem.STAV_ZADANY).select_related('rocnik').order_by('rocnik', 'kod') - - def get_context_data(self, *args, **kwargs): - ctx = super().get_context_data(*args, **kwargs) - ctx['rocniky'] = OrderedDict() - for rocnik, temata in groupby(ctx['object_list'], lambda tema: tema.rocnik): - ctx['rocniky'][rocnik] = list(temata) - return ctx - -class OdmenyView(generic.TemplateView): - template_name = 'tvorba/archiv/odmeny.html' - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - fromcislo = get_object_or_404(Cislo, rocnik=self.kwargs.get('frocnik'), poradi=self.kwargs.get('fcislo')) - tocislo = get_object_or_404(Cislo, rocnik=self.kwargs.get('trocnik'), poradi=self.kwargs.get('tcislo')) - resitele = utils.aktivniResitele(tocislo) - - def get_diff(from_deadline: Deadline, to_deadline: Deadline): - frombody = body_resitelu(resitele=resitele, jen_verejne=False, do=from_deadline) - tobody = body_resitelu(resitele=resitele, jen_verejne=False, do=to_deadline) - outlist = [] - for resitel in resitele: - fbody = frombody.get(resitel.id, 0) - tbody = tobody.get(resitel.id, 0) - ftitul = resitel.get_titul(fbody) - ttitul = resitel.get_titul(tbody) - if ftitul != ttitul: - outlist.append({'jmeno': resitel.osoba.plne_jmeno(), 'ftitul': ftitul, 'ttitul': ttitul}) - return outlist - - def posledni_deadline_oprava(cislo: Cislo) -> Deadline: - posledni_deadline = cislo.posledni_deadline - if posledni_deadline is None: - return Deadline.objects.filter(Q(cislo__poradi__lt=cislo.poradi, cislo__rocnik=cislo.rocnik) | Q(cislo__rocnik__rocnik__lt=cislo.rocnik.rocnik)).order_by("deadline").last() - return posledni_deadline - - context["from_cislo"] = fromcislo - context["to_cislo"] = tocislo - from_deadline = posledni_deadline_oprava(fromcislo) - to_deadline = posledni_deadline_oprava(tocislo) - context["from_deadline"] = from_deadline - context["to_deadline"] = to_deadline - context["zmeny"] = get_diff(from_deadline, to_deadline) - - return context - - - - -### Generovani vysledkovky - -class CisloVysledkovkaView(CisloView): - """View vytvořené pro stránku zobrazující výsledkovku čísla v TeXu.""" - - model = Cislo - template_name = 'tvorba/archiv/cislo_vysledkovka.tex' - #content_type = 'application/x-tex; charset=UTF8' - #umozni rovnou stahnout TeXovsky dokument - content_type = 'text/plain; charset=UTF8' - #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani - - def get_context_data(self, **kwargs): - context = super(CisloVysledkovkaView, self).get_context_data() - cislo = context['cislo'] - - cislopred = cislo.predchozi() - if cislopred is not None: - context['vysledkovka'] = VysledkovkaDoTeXu( - cislo, - od_vyjma=cislopred.zlomovy_deadline_pro_papirove_cislo(), - do_vcetne=cislo.zlomovy_deadline_pro_papirove_cislo(), - ) - else: - context['vysledkovka'] = VysledkovkaCisla( - cislo, - jen_verejne=False, - do_deadlinu=cislo.zlomovy_deadline_pro_papirove_cislo(), - ) - return context - - -# Podle předchozího -class PosledniCisloVysledkovkaView(generic.DetailView): - """View vytvořené pro zobrazení výsledkovky posledního čísla v TeXu.""" - - model = Rocnik - template_name = 'tvorba/archiv/cislo_vysledkovka.tex' - content_type = 'text/plain; charset=UTF8' - - def get_object(self, queryset=None): - if queryset is None: - queryset = self.get_queryset() - rocnik_arg = self.kwargs.get('rocnik') - queryset = queryset.filter(rocnik=rocnik_arg) - - try: - obj = queryset.get() - except queryset.model.DoesNotExist: - raise Http404(_("No %(verbose_name)s found matching the query") % - {'verbose_name': queryset.model._meta.verbose_name}) - return obj - - def get_context_data(self, **kwargs): - context = super(PosledniCisloVysledkovkaView, self).get_context_data() - rocnik = context['rocnik'] - cislo = rocnik.cisla.order_by("poradi").filter(deadline_v_cisle__isnull=False).last() - if cislo is None: - raise Http404(f"Ročník {rocnik.rocnik} nemá číslo s deadlinem.") - cislopred = cislo.predchozi() - context['vysledkovka'] = VysledkovkaDoTeXu( - cislo, - od_vyjma=cislopred.zlomovy_deadline_pro_papirove_cislo(), - do_vcetne=cislo.deadline_v_cisle.order_by("deadline").last(), - ) - return context - - -class RocnikVysledkovkaView(RocnikView): - """ View vytvořené pro stránku zobrazující výsledkovku ročníku v TeXu.""" - model = Rocnik - template_name = 'tvorba/archiv/rocnik_vysledkovka.tex' - #content_type = 'application/x-tex; charset=UTF8' - #umozni rovnou stahnout TeXovsky dokument - content_type = 'text/plain; charset=UTF8' - #vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani - -def cisloObalkyView(request, rocnik, cislo): - realne_cislo = get_object_or_404(Cislo, poradi=cislo, rocnik__rocnik=rocnik) - return personalni.views.obalkyView(request, utils.aktivniResitele(realne_cislo)) - - - -### Tituly -def TitulyViewRocnik(request, rocnik): - return TitulyView(request, rocnik, None) - - -def TitulyView(request, rocnik, cislo): - """ View pro stažení makra titulů v TeXu.""" - rocnik_obj = get_object_or_404(Rocnik, rocnik = rocnik) - resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok) - - asciijmena = [] - jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka), - # pokud ano, vrátí se jako true - if cislo is not None: - cislo_obj = get_object_or_404(Cislo, rocnik=rocnik_obj, poradi=cislo) - slovnik_s_body = body_resitelu(do=cislo_obj.zlomovy_deadline_pro_papirove_cislo(), jen_verejne=False) - else: - slovnik_s_body = body_resitelu(do=Deadline.objects.filter(cislo__rocnik=rocnik_obj).last(), jen_verejne=False) - - for resitel in resitele: - resitel.titul = resitel.get_titul(slovnik_s_body[resitel.id]) - jmeno = resitel.osoba.jmeno+resitel.osoba.prijmeni - # převedeme jména a příjmení řešitelů do ASCII - ascii_jmeno_bytes = unicodedata.normalize('NFKD', jmeno).encode("ascii","ignore") - # vrátí se byte string, převedeme na standardní string - ascii_jmeno_divnoznaky = str(ascii_jmeno_bytes, "utf-8", "ignore").replace(" ","") - resitel.ascii = ''.join(a for a in ascii_jmeno_divnoznaky if a.isalnum()) - if resitel.ascii not in asciijmena: - asciijmena.append(resitel.ascii) - else: - jmenovci = True - - return render(request, 'tvorba/archiv/tituly.tex', - {'resitele': resitele,'jmenovci':jmenovci},content_type="text/plain") - - -### Články -def group_by_rocnik(clanky): - ''' Vezme zadaný seznam článků a seskupí je podle ročníku. - Vrátí seznam seznamů článků ze stejného ročníku.''' - if len(clanky) == 0: - return clanky - clanky.order_by('cislo__rocnik__rocnik') - skupiny_clanku = [] - skupina = [] - - rocnik = clanky.first().cislo.rocnik.rocnik # první ročník - for clanek in clanky: - if clanek.cislo.rocnik.rocnik == rocnik: - skupina.append(clanek) - else: - skupiny_clanku.append(skupina) - skupina = [] - skupina.append(clanek) - rocnik = clanek.cislo.rocnik.rocnik - skupiny_clanku.append(skupina) - return skupiny_clanku - - -# FIXME: clanky jsou vsechny, pokud budou i neresitelske, tak se take zobrazi -# FIXME: Původně tu byl kód přímo v těle třídy, což rozbíjelo migrace. Opravil jsem, ale vůbec nevím, jestli to funguje. -class ClankyResitelView(generic.ListView): - model = Problem - template_name = 'tvorba/clanky/resitelske_clanky.html' - - # FIXME: QuerySet není pole! - def get_queryset(self): - clanky = Clanek.objects.filter(stav=Problem.STAV_VYRESENY).select_related('cislo__rocnik').order_by('-cislo__rocnik__rocnik') - queryset = [] - skupiny_clanku = group_by_rocnik(clanky) - for skupina in skupiny_clanku: - skupina.sort(key=lambda clanek: clanek.kod_v_rocniku) - for clanek in skupina: - queryset.append(clanek) - return queryset - -# FIXME: pokud chceme orgoclanky, tak nejak zavest do modelu a podle toho odkomentovat a upravit -#class ClankyOrganizatorView(generic.ListView): -# model = Problem -# template_name = 'tvorba/clanky/organizatorske_clanky.html' -# queryset = Problem.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod') - - - - -class AktualniRocnikRedirectView(RedirectView): - permanent=False - pattern_name = 'seminar_rocnik' - - def get_redirect_url(self, *args, **kwargs): - aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik.rocnik - return super().get_redirect_url(rocnik=aktualni_rocnik, *args, **kwargs)