2021-11-07 10:25:34 +01:00
from django . shortcuts import get_object_or_404 , render
from django . http import HttpResponse
2021-10-08 10:36:59 +02:00
from django . urls import reverse
from django . core . exceptions import ObjectDoesNotExist
2015-03-13 20:08:18 +01:00
from django . views import generic
2023-10-30 23:33:13 +01:00
from django . utils . translation import gettext as _
2021-10-08 10:36:59 +02:00
from django . http import Http404
2020-01-29 22:22:54 +01:00
from django . db . models import Q , Sum , Count
2021-10-08 18:06:02 +02:00
from django . views . generic . base import RedirectView
2020-12-01 23:52:03 +01:00
from django . core . exceptions import PermissionDenied
2024-03-03 23:05:39 +01:00
from django . contrib . staticfiles . finders import find
2015-06-08 22:38:13 +02:00
2019-12-05 00:50:04 +01:00
import seminar . models as s
2020-04-15 22:58:47 +02:00
import seminar . models as m
2022-10-01 22:08:21 +02:00
from seminar . models import Problem , Cislo , Reseni , Nastaveni , Rocnik , \
Organizator , Resitel , Novinky , Tema , Clanek , \
Deadline # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci
2019-04-23 23:26:37 +02:00
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
2021-11-07 10:25:34 +01:00
from seminar import utils
from treenode import treelib
import treenode . templatetags as tnltt
import treenode . serializers as vr
2022-10-01 21:47:15 +02:00
from vysledkovky . utils import body_resitelu , VysledkovkaCisla , \
2022-10-03 16:56:38 +02:00
VysledkovkaRocniku , VysledkovkaDoTeXu
2015-03-27 21:38:48 +01:00
2021-10-08 10:36:59 +02:00
from datetime import date , datetime
2019-08-14 14:29:24 +02:00
from django . utils import timezone
2015-09-08 21:27:10 +02:00
from itertools import groupby
2020-05-06 23:07:04 +02:00
from collections import OrderedDict
2015-11-15 15:14:21 +01:00
import tempfile
import subprocess
import shutil
import os
2017-02-04 23:28:54 +01:00
import os . path as op
2015-11-15 15:14:21 +01:00
from django . conf import settings
2015-11-15 17:06:50 +01:00
import unicodedata
2019-09-01 16:35:20 +02:00
import logging
2020-04-15 22:30:58 +02:00
import time
2023-06-19 20:31:59 +02:00
from collections . abc import Sequence
2024-03-03 23:06:43 +01:00
import http
2016-02-17 16:17:11 +01:00
2021-10-08 18:06:02 +02:00
from seminar . utils import aktivniResitele
2015-09-03 22:09:35 +02:00
2020-07-15 11:21:16 +02:00
# 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)
2020-01-29 22:22:54 +01:00
2021-09-04 22:07:13 +02:00
logger = logging . getLogger ( __name__ )
2020-01-29 22:22:54 +01:00
def get_problemy_k_tematu ( tema ) :
2020-06-25 19:50:30 +02:00
return Problem . objects . filter ( nadproblem = tema )
2020-01-29 22:22:54 +01:00
2020-09-03 23:02:28 +02:00
2021-09-07 14:42:56 +02:00
# 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
2020-04-23 00:41:04 +02:00
2019-12-05 00:50:04 +01:00
2021-02-09 21:43:07 +01:00
#class AktualniZadaniView(generic.TemplateView):
# template_name = 'seminar/treenode.html'
2020-10-21 08:41:20 +02:00
# 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
2020-03-19 00:50:39 +01:00
2021-02-09 21:43:07 +01:00
def AktualniZadaniView ( request ) :
nastaveni = get_object_or_404 ( Nastaveni )
verejne = nastaveni . aktualni_cislo . verejne ( )
return render ( request , ' seminar/zadani/AktualniZadani.html ' ,
{ ' nastaveni ' : nastaveni ,
' verejne ' : verejne ,
} ,
)
2020-10-27 23:28:23 +01:00
def ZadaniTemataView ( request ) :
2020-12-01 23:52:03 +01:00
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 , ' seminar/tematka/rozcestnik.html ' ,
{
' tematka ' : temata ,
' verejne ' : verejne ,
} ,
)
2020-10-27 23:28:23 +01:00
2020-03-19 00:50:39 +01:00
# 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, 'seminar/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, 'seminar/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, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik})
2020-09-01 23:04:19 +02:00
#
2016-07-24 23:16:06 +02:00
2021-03-02 21:49:12 +01:00
def ZadaniAktualniVysledkovkaView ( request ) :
nastaveni = get_object_or_404 ( Nastaveni )
# Aktualni verejna vysledkovka
2021-09-06 15:25:54 +02:00
rocnik = nastaveni . aktualni_rocnik
2022-10-01 21:47:15 +02:00
context = { ' vysledkovka ' : VysledkovkaRocniku ( rocnik , True ) }
2021-10-07 19:30:28 +02:00
2021-03-02 21:49:12 +01:00
# kdyz neni verejna vysledkovka, tak zobraz starou
2022-10-01 21:47:15 +02:00
if len ( context [ ' vysledkovka ' ] . cisla_rocniku ) == 0 :
2021-03-02 21:49:12 +01:00
try :
minuly_rocnik = Rocnik . objects . get (
2022-10-01 21:47:15 +02:00
rocnik = ( rocnik . rocnik - 1 ) )
2021-09-06 15:25:54 +02:00
rocnik = minuly_rocnik
2021-10-07 19:30:28 +02:00
# Přepíšeme prázdnou výsledkovku výsledkovkou z minulého ročníku
2022-10-01 21:47:15 +02:00
context [ ' vysledkovka ' ] = VysledkovkaRocniku ( rocnik , True )
2021-03-02 21:49:12 +01:00
except ObjectDoesNotExist :
pass
2021-10-07 19:30:28 +02:00
context [ ' rocnik ' ] = rocnik
2021-03-02 21:49:12 +01:00
return render (
request ,
' seminar/zadani/AktualniVysledkovka.html ' ,
2021-10-07 19:30:28 +02:00
context
2021-03-02 21:49:12 +01:00
)
2015-09-23 17:28:14 +02:00
2015-09-03 22:09:35 +02:00
### Titulni strana
2020-06-26 02:12:01 +02:00
def spravne_novinky ( request ) :
"""
Vrátí správný QuerySet novinek , tedy ten , který daný uživatel smí vidět .
Tj . Organizátorům všechny , ostatním jen veřejné
"""
user = request . user
# Využíváme líné vyhodnocování QuerySetů
qs = Novinky . objects . all ( )
2021-02-24 00:54:39 +01:00
if not user . je_org :
2020-06-26 02:12:01 +02:00
qs = qs . filter ( zverejneno = True )
return qs . order_by ( ' -datum ' )
2020-07-15 11:21:16 +02:00
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 ' )
2020-06-26 02:12:01 +02:00
2015-09-03 22:09:35 +02:00
class TitulniStranaView ( generic . ListView ) :
2022-09-28 09:51:19 +02:00
template_name = ' seminar/titulnistrana/titulnistrana.html '
2020-06-26 01:37:58 +02:00
def get_queryset ( self ) :
2020-07-15 21:12:00 +02:00
return spravne_novinky ( self . request ) [ : 3 ]
2019-05-11 01:15:05 +02:00
def get_context_data ( self , * * kwargs ) :
context = super ( TitulniStranaView , self ) . get_context_data ( * * kwargs )
nastaveni = get_object_or_404 ( Nastaveni )
2021-09-02 19:35:21 +02:00
2022-10-09 09:52:46 +02:00
deadline = m . Deadline . objects . filter ( deadline__gte = timezone . now ( ) ) . order_by ( " deadline " ) . first ( )
context [ ' nejblizsi_deadline ' ] = deadline
2020-07-14 23:21:55 +02:00
# Aktuální témata
2020-07-15 11:21:16 +02:00
nazvy_a_odkazy_na_aktualni_temata = [ ]
akt_temata = aktualni_temata ( nastaveni . aktualni_rocnik )
for tema in akt_temata :
# FIXME: netuším, jestli funguje tema.verejne_url(), nemáme testdata na témátka - je to asi url vzhledem k ročníku
nazvy_a_odkazy_na_aktualni_temata . append ( { ' nazev ' : tema . nazev , ' url ' : tema . verejne_url ( ) } )
context [ ' aktualni_temata ' ] = nazvy_a_odkazy_na_aktualni_temata
print ( context )
2020-07-14 23:21:55 +02:00
2019-05-11 01:15:05 +02:00
return context
2015-09-07 17:00:19 +02:00
2015-09-12 00:22:17 +02:00
class StareNovinkyView ( generic . ListView ) :
2019-05-11 01:15:05 +02:00
template_name = ' seminar/stare_novinky.html '
2020-06-26 02:12:01 +02:00
def get_queryset ( self ) :
return spravne_novinky ( self . request )
2015-09-12 00:22:17 +02:00
2015-06-29 17:51:18 +02:00
### Co je M&M
2015-06-03 14:16:30 +02:00
2017-01-20 12:13:25 +01:00
# Organizatori
2019-08-14 14:29:24 +02:00
def aktivniOrganizatori ( datum = timezone . now ( ) ) :
2019-05-11 01:15:05 +02:00
return Organizator . objects . exclude (
organizuje_do__isnull = False ,
organizuje_do__lt = datum
2019-07-25 21:20:15 +02:00
) . order_by ( ' osoba__jmeno ' )
2017-01-20 12:13:25 +01:00
2015-08-23 15:06:47 +02:00
2015-06-28 22:07:27 +02:00
class CojemamOrganizatoriView ( generic . ListView ) :
2019-05-11 01:15:05 +02:00
model = Organizator
template_name = ' seminar/cojemam/organizatori.html '
queryset = aktivniOrganizatori ( )
2017-01-20 12:13:25 +01:00
2019-05-11 01:15:05 +02:00
def get_context_data ( self , * * kwargs ) :
context = super ( CojemamOrganizatoriView , self ) . get_context_data ( * * kwargs )
context [ ' aktivni ' ] = True
return context
2015-08-23 15:06:47 +02:00
2017-01-20 12:13:25 +01:00
2015-08-23 15:06:47 +02:00
class CojemamOrganizatoriStariView ( generic . ListView ) :
2019-05-11 01:15:05 +02:00
model = Organizator
template_name = ' seminar/cojemam/organizatori.html '
queryset = Organizator . objects . exclude (
id__in = aktivniOrganizatori ( ) ) . order_by ( ' -organizuje_do ' )
2015-06-03 14:16:30 +02:00
2015-06-29 17:51:18 +02:00
### Archiv
2020-03-25 23:57:11 +01:00
2017-02-04 23:28:54 +01:00
class ArchivView ( generic . ListView ) :
2019-05-11 01:15:05 +02:00
model = Rocnik
template_name = ' seminar/archiv/cisla.html '
def get_context_data ( self , * * kwargs ) :
context = super ( ArchivView , self ) . get_context_data ( * * kwargs )
2020-04-15 21:03:10 +02:00
cisla = Cislo . objects . filter ( poradi = 1 )
2021-11-15 21:21:03 +01:00
if not self . request . user . je_org :
cisla = cisla . filter ( verejne_db = True )
2020-04-01 23:09:58 +02:00
urls = { }
2019-05-11 01:15:05 +02:00
for i , c in enumerate ( cisla ) :
2021-09-02 19:30:21 +02:00
# Výchozí nastavení
if c . rocnik not in urls :
urls [ c . rocnik ] = op . join ( settings . STATIC_URL , " images " , " no-picture.png " )
# NOTE: tohle možná nastavuje poslední titulku
2020-04-15 21:03:10 +02:00
if c . titulka_nahled :
urls [ c . rocnik ] = c . titulka_nahled . url
2020-04-01 23:09:58 +02:00
context [ " object_list " ] = urls
2021-09-02 19:35:21 +02:00
2019-05-11 01:15:05 +02:00
return context
2017-02-04 23:28:54 +01:00
2021-09-02 19:35:21 +02:00
2021-02-16 22:42:05 +01:00
2015-09-23 17:28:14 +02:00
2015-04-01 14:01:13 +02:00
class RocnikView ( generic . DetailView ) :
2019-05-11 01:15:05 +02:00
model = Rocnik
template_name = ' seminar/archiv/rocnik.html '
2015-04-01 14:01:13 +02:00
2019-05-11 01:15:05 +02:00
# Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik)
def get_object ( self , queryset = None ) :
if queryset is None :
queryset = self . get_queryset ( )
2015-06-08 22:38:13 +02:00
2021-02-23 23:48:20 +01:00
return get_object_or_404 ( queryset , rocnik = self . kwargs . get ( ' rocnik ' ) )
2015-06-08 22:38:13 +02:00
2019-05-11 01:15:05 +02:00
def get_context_data ( self , * * kwargs ) :
context = super ( RocnikView , self ) . get_context_data ( * * kwargs )
2022-10-01 21:47:15 +02:00
context [ " vysledkovka " ] = VysledkovkaRocniku ( context [ " rocnik " ] , True )
context [ " neprazdna_vysledkovka " ] = len ( context [ ' vysledkovka ' ] . cisla_rocniku ) != 0
context [ " vysledkovka_neverejna " ] = VysledkovkaRocniku ( context [ " rocnik " ] , False )
2019-05-11 01:15:05 +02:00
return context
2015-08-13 10:52:43 +02:00
2021-11-23 23:44:00 +01:00
def resiteleRocnikuCsvExportView ( request , rocnik ) :
2021-11-25 21:46:17 +01:00
from personalni . views import dataResiteluCsvResponse
2021-11-23 23:44:00 +01:00
assert request . method in ( ' GET ' , ' HEAD ' )
return dataResiteluCsvResponse (
utils . resi_v_rocniku (
2023-01-02 21:52:19 +01:00
get_object_or_404 ( m . Rocnik , rocnik = rocnik )
2021-11-23 23:44:00 +01:00
)
)
2015-09-13 15:31:34 +02:00
2021-09-07 14:42:56 +02:00
# 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 ['seminar/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
2015-09-13 15:31:34 +02:00
2015-12-19 23:11:50 +01:00
2020-03-25 23:57:11 +01:00
2019-07-26 00:01:23 +02:00
class CisloView ( generic . DetailView ) :
2020-09-03 23:03:08 +02:00
# FIXME zobrazování témátek a vůbec, teď je tam jen odkaz na číslo v pdf
2019-07-26 00:01:23 +02:00
model = Cislo
template_name = ' seminar/archiv/cislo.html '
2020-06-25 19:50:30 +02:00
# Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik)
2019-07-26 00:01:23 +02:00
def get_object ( self , queryset = None ) :
if queryset is None :
queryset = self . get_queryset ( )
rocnik_arg = self . kwargs . get ( ' rocnik ' )
2020-01-09 00:45:20 +01:00
poradi_arg = self . kwargs . get ( ' cislo ' )
queryset = queryset . filter ( rocnik__rocnik = rocnik_arg , poradi = poradi_arg )
2019-07-26 00:01:23 +02:00
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 ' ]
2021-01-05 22:54:16 +01:00
context [ ' prevcislo ' ] = Cislo . objects . filter ( ( Q ( rocnik__lt = self . object . rocnik ) | Q ( poradi__lt = self . object . poradi ) ) & Q ( rocnik__lte = self . object . rocnik ) ) . first ( )
2022-10-01 22:41:25 +02:00
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
2022-10-01 21:47:15 +02:00
return context
2019-07-26 00:01:23 +02:00
2015-03-13 20:08:18 +01:00
2015-09-09 22:52:06 +02:00
class ArchivTemataView ( generic . ListView ) :
2019-05-11 01:15:05 +02:00
model = Problem
template_name = ' seminar/archiv/temata.html '
2020-05-06 23:26:06 +02:00
queryset = Tema . objects . filter ( stav = Problem . STAV_ZADANY ) . select_related ( ' rocnik ' ) . order_by ( ' rocnik ' , ' kod ' )
2020-05-06 23:07:04 +02:00
def get_context_data ( self , * args , * * kwargs ) :
ctx = super ( ) . get_context_data ( * args , * * kwargs )
ctx [ ' rocniky ' ] = OrderedDict ( )
2020-05-06 23:26:06 +02:00
for rocnik , temata in groupby ( ctx [ ' object_list ' ] , lambda tema : tema . rocnik ) :
ctx [ ' rocniky ' ] [ rocnik ] = list ( temata )
2020-05-06 23:07:04 +02:00
return ctx
2015-09-09 22:52:06 +02:00
2021-01-05 22:21:26 +01:00
class OdmenyView ( generic . TemplateView ) :
template_name = ' seminar/archiv/odmeny.html '
def get_context_data ( self , * * kwargs ) :
context = super ( ) . get_context_data ( * * kwargs )
2023-01-02 21:20:00 +01:00
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 ' ) )
2021-01-05 22:21:26 +01:00
resitele = aktivniResitele ( tocislo )
2022-10-06 10:35:14 +02:00
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 = [ ]
2023-01-02 21:09:56 +01:00
for resitel in resitele :
fbody = frombody . get ( resitel . id , 0 )
tbody = tobody . get ( resitel . id , 0 )
2022-10-06 10:35:14 +02:00
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
2022-10-06 12:38:31 +02:00
def posledni_deadline_oprava ( cislo : Cislo ) - > Deadline :
posledni_deadline = cislo . posledni_deadline
if posledni_deadline is None :
2022-10-06 12:40:02 +02:00
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 ( )
2022-10-06 12:38:31 +02:00
return posledni_deadline
2022-10-06 10:35:14 +02:00
context [ " from_cislo " ] = fromcislo
context [ " to_cislo " ] = tocislo
2022-11-14 23:32:33 +01:00
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 )
2022-10-06 10:35:14 +02:00
2021-01-05 22:21:26 +01:00
return context
2021-09-02 19:35:21 +02:00
2021-01-05 22:21:26 +01:00
2015-07-06 21:43:06 +02:00
### Generovani vysledkovky
2020-04-15 22:30:58 +02:00
class CisloVysledkovkaView ( CisloView ) :
2020-04-22 23:16:26 +02:00
""" View vytvořené pro stránku zobrazující výsledkovku čísla v TeXu. """
2020-04-15 22:30:58 +02:00
model = Cislo
template_name = ' seminar/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
2022-10-03 16:56:38 +02:00
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 = ' seminar/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 ' ]
2023-06-19 21:52:01 +02:00
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. " )
2022-10-03 16:56:38 +02:00
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
2020-04-08 23:44:06 +02:00
class RocnikVysledkovkaView ( RocnikView ) :
2020-04-22 23:16:26 +02:00
""" View vytvořené pro stránku zobrazující výsledkovku ročníku v TeXu. """
2020-04-08 23:44:06 +02:00
model = Rocnik
template_name = ' seminar/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
2015-08-13 10:52:43 +02:00
2020-05-21 00:12:27 +02:00
def cisloObalkyView ( request , rocnik , cislo ) :
2023-01-02 21:52:19 +01:00
realne_cislo = get_object_or_404 ( Cislo , poradi = cislo , rocnik__rocnik = rocnik )
2020-06-25 19:50:30 +02:00
return obalkyView ( request , aktivniResitele ( realne_cislo ) )
2015-11-15 15:14:21 +01:00
2020-05-21 00:12:27 +02:00
def obalkyView ( request , resitele ) :
2024-03-03 22:44:59 +01:00
if len ( resitele ) == 0 :
2024-03-03 23:06:43 +01:00
return HttpResponse (
render ( request , ' universal.html ' , {
' title ' : ' Není pro koho vyrobit obálky. ' ,
' text ' : ' Právě ses pokusil/a vygenerovat obálky pro prázdnou množinu lidí. Můžeš to zkusit změnit, případně se zeptej webařů :-) ' ,
} ) ,
status = http . HTTPStatus . NOT_FOUND ,
)
2019-05-11 01:15:05 +02:00
tex = render ( request , ' seminar/archiv/obalky.tex ' , { ' resitele ' : resitele } ) . content
2015-11-15 15:14:21 +01:00
2024-03-03 23:07:51 +01:00
with tempfile . TemporaryDirectory ( ) as tempdir :
with open ( tempdir + " /obalky.tex " , " w " ) as texfile :
texfile . write ( tex . decode ( ) )
shutil . copy ( find ( ' seminar/lisak.pdf ' ) , tempdir )
subprocess . call ( [ " pdflatex " , " obalky.tex " ] , cwd = tempdir )
with open ( tempdir + " /obalky.pdf " , " rb " ) as pdffile :
response = HttpResponse ( pdffile . read ( ) , content_type = ' application/pdf ' )
2019-05-11 01:15:05 +02:00
return response
2015-11-15 15:14:21 +01:00
2017-04-06 11:58:01 +02:00
2015-11-15 16:14:07 +01:00
### Tituly
2022-10-01 22:08:21 +02:00
def TitulyViewRocnik ( request , rocnik ) :
return TitulyView ( request , rocnik , None )
2015-11-15 16:14:07 +01:00
2020-04-16 00:51:38 +02:00
def TitulyView ( request , rocnik , cislo ) :
2020-04-22 23:16:26 +02:00
""" View pro stažení makra titulů v TeXu. """
2023-01-02 21:52:19 +01:00
rocnik_obj = get_object_or_404 ( Rocnik , rocnik = rocnik )
2020-04-16 00:51:38 +02:00
resitele = Resitel . objects . filter ( rok_maturity__gte = rocnik_obj . prvni_rok )
asciijmena = [ ]
2021-09-02 19:35:21 +02:00
jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka),
2020-04-22 23:16:26 +02:00
# pokud ano, vrátí se jako true
2022-10-01 22:08:21 +02:00
if cislo is not None :
2023-01-02 21:52:19 +01:00
cislo_obj = get_object_or_404 ( Cislo , rocnik = rocnik_obj , poradi = cislo )
2022-10-08 11:31:30 +02:00
slovnik_s_body = body_resitelu ( do = cislo_obj . zlomovy_deadline_pro_papirove_cislo ( ) , jen_verejne = False )
2022-10-01 22:08:21 +02:00
else :
2022-10-08 11:31:30 +02:00
slovnik_s_body = body_resitelu ( do = Deadline . objects . filter ( cislo__rocnik = rocnik_obj ) . last ( ) , jen_verejne = False )
2020-04-16 00:51:38 +02:00
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
2021-09-02 19:35:21 +02:00
2020-04-16 00:51:38 +02:00
return render ( request , ' seminar/archiv/tituly.tex ' ,
{ ' resitele ' : resitele , ' jmenovci ' : jmenovci } , content_type = " text/plain " )
2015-11-15 15:35:47 +01:00
2015-09-13 15:31:34 +02:00
### Články
2020-08-23 18:46:47 +02:00
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 . '''
2020-09-03 16:07:52 +02:00
if len ( clanky ) == 0 :
return clanky
2020-08-23 18:46:47 +02:00
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
2021-09-02 19:35:21 +02:00
2015-09-13 15:31:34 +02:00
2019-04-23 23:26:37 +02:00
# FIXME: clanky jsou vsechny, pokud budou i neresitelske, tak se take zobrazi
2020-09-04 15:37:04 +02:00
# 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.
2015-09-13 15:31:34 +02:00
class ClankyResitelView ( generic . ListView ) :
2019-05-11 01:15:05 +02:00
model = Problem
template_name = ' seminar/clanky/resitelske_clanky.html '
2020-09-04 15:37:04 +02:00
# FIXME: QuerySet není pole!
def get_queryset ( self ) :
2021-02-16 20:10:34 +01:00
clanky = Clanek . objects . filter ( stav = Problem . STAV_VYRESENY ) . select_related ( ' cislo__rocnik ' ) . order_by ( ' -cislo__rocnik__rocnik ' )
2020-09-04 15:37:04 +02:00
queryset = [ ]
skupiny_clanku = group_by_rocnik ( clanky )
for skupina in skupiny_clanku :
2021-11-22 21:51:12 +01:00
skupina . sort ( key = lambda clanek : clanek . kod_v_rocniku )
2020-09-04 15:37:04 +02:00
for clanek in skupina :
queryset . append ( clanek )
return queryset
2015-09-13 15:31:34 +02:00
2019-04-23 23:26:37 +02:00
# FIXME: pokud chceme orgoclanky, tak nejak zavest do modelu a podle toho odkomentovat a upravit
#class ClankyOrganizatorView(generic.ListView)<F12>:
2019-05-11 02:00:41 +02:00
# model = Problem
# template_name = 'seminar/clanky/organizatorske_clanky.html'
# queryset = Problem.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod')
2015-09-13 15:31:34 +02:00
2015-07-29 11:46:08 +02:00
### Status
def StavDatabazeView ( request ) :
2019-05-11 02:00:41 +02:00
# nastaveni = Nastaveni.objects.get()
2019-05-11 01:15:05 +02:00
problemy = utils . seznam_problemu ( )
2024-04-13 15:36:21 +02:00
muzi = Resitel . objects . filter ( osoba__osloveni = m . Osoba . OSLOVENI_MUZSKE )
zeny = Resitel . objects . filter ( osoba__osloveni = m . Osoba . OSLOVENI_ZENSKE )
2019-05-11 01:15:05 +02:00
return render ( request , ' seminar/stav_databaze.html ' ,
{
2019-05-11 02:00:41 +02:00
# 'nastaveni': nastaveni,
2019-05-11 01:15:05 +02:00
' problemy ' : problemy ,
2015-07-30 11:56:29 +02:00
2019-05-11 01:15:05 +02:00
' resitele ' : Resitel . objects . all ( ) ,
' muzi ' : muzi ,
' zeny ' : zeny ,
2020-06-04 00:38:28 +02:00
' jmena_muzu ' : utils . histogram ( [ r . osoba . jmeno for r in muzi ] ) ,
' jmena_zen ' : utils . histogram ( [ r . osoba . jmeno for r in zeny ] ) ,
2019-05-11 01:15:05 +02:00
} )
2016-02-17 16:17:11 +01:00
2020-09-04 18:05:33 +02:00
# Interní, nemá se nikdy objevit v urls (jinak to účastníci vytrolí)
2023-06-19 20:31:59 +02:00
def formularOKView ( request , text = ' ' , dalsi_odkazy : Sequence [ tuple [ str , str ] ] = ( ) ) :
2020-09-04 18:05:33 +02:00
template_name = ' seminar/formular_ok.html '
2023-05-15 23:06:52 +02:00
odkazy = list ( dalsi_odkazy ) + [
2020-09-04 18:05:33 +02:00
# (Text, odkaz)
( ' Vrátit se na titulní stránku ' , reverse ( ' titulni_strana ' ) ) ,
( ' Zobrazit aktuální zadání ' , reverse ( ' seminar_aktualni_zadani ' ) ) ,
]
context = {
' odkazy ' : odkazy ,
2022-12-01 13:07:09 +01:00
' text ' : text ,
2020-09-04 18:05:33 +02:00
}
return render ( request , template_name , context )
2020-09-21 13:19:07 +02:00
#------------------ Jak řešit - možná má být udělané úplně jinak
2021-09-02 19:35:21 +02:00
2020-09-21 13:19:07 +02:00
class JakResitView ( generic . ListView ) :
2022-09-28 09:51:19 +02:00
template_name = ' seminar/jakresit/jak-resit.html '
2021-09-02 19:35:21 +02:00
2020-09-21 13:19:07 +02:00
def get_queryset ( self ) :
2020-10-13 23:25:39 +02:00
return None
2021-04-28 21:26:30 +02:00
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 )