Web M&M
https://mam.matfyz.cz
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
812 lines
27 KiB
812 lines
27 KiB
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 ugettext 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, Organizator, Resitel, Novinky, Tema, Clanek # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci
|
|
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
|
|
from seminar import utils
|
|
from treenode import treelib
|
|
import treenode.templatetags as tnltt
|
|
import treenode.serializers as vr
|
|
from vysledkovky.utils import body_resitelu
|
|
from vysledkovky.views import vysledkovka_rocniku, vysledkovka_cisla
|
|
|
|
from datetime import date, datetime
|
|
from django.utils import timezone
|
|
from itertools import groupby
|
|
from collections import OrderedDict
|
|
import tempfile
|
|
import subprocess
|
|
import shutil
|
|
import os
|
|
import os.path as op
|
|
from django.conf import settings
|
|
import unicodedata
|
|
import logging
|
|
import time
|
|
|
|
from seminar.utils import aktivniResitele
|
|
|
|
# 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)
|
|
|
|
class ObalkovaniView(generic.ListView):
|
|
template_name = 'seminar/org/obalkovani.html'
|
|
|
|
def get_queryset(self):
|
|
rocnik = get_object_or_404(Rocnik,rocnik=self.kwargs['rocnik'])
|
|
cislo = get_object_or_404(Cislo,rocnik=rocnik,poradi=self.kwargs['cislo'])
|
|
self.cislo = cislo
|
|
self.hodnoceni = s.Hodnoceni.objects.filter(cislo_body=cislo)
|
|
self.reseni = Reseni.objects.filter(hodnoceni__in = self.hodnoceni).annotate(Sum('hodnoceni__body')).annotate(Count('hodnoceni')).order_by('resitele__osoba')
|
|
return self.reseni
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ObalkovaniView, self).get_context_data(**kwargs)
|
|
print(self.cislo)
|
|
context['cislo'] = self.cislo
|
|
return context
|
|
|
|
class TNLData(object):
|
|
def __init__(self,anode,parent=None, index=None):
|
|
self.node = anode
|
|
self.sernode = vr.TreeNodeSerializer(anode)
|
|
self.children = []
|
|
self.parent = parent
|
|
self.tema_in_path = False
|
|
self.index = index
|
|
|
|
if parent:
|
|
self.tema_in_path = parent.tema_in_path
|
|
if isinstance(anode, m.TemaVCisleNode):
|
|
self.tema_in_path = True
|
|
|
|
def add_edit_options(self):
|
|
self.deletable = tnltt.deletable(self)
|
|
self.editable_siblings = tnltt.editableSiblings(self)
|
|
self.editable_children = tnltt.editableChildren(self)
|
|
self.text_only_subtree = tnltt.textOnlySubtree(self)
|
|
self.can_podvesit_za = tnltt.canPodvesitZa(self)
|
|
self.can_podvesit_pred = tnltt.canPodvesitPred(self)
|
|
self.appendable_children = tnltt.appendableChildren(self)
|
|
print("appChld",self.appendable_children)
|
|
if self.parent:
|
|
self.appendable_siblings = tnltt.appendableChildren(self.parent)
|
|
else:
|
|
self.appendable_siblings = []
|
|
@classmethod
|
|
def public_above(cls, anode):
|
|
""" Returns output of verejne for closest Rocnik, Cislo or Problem above.
|
|
(All of them have method verejne.)"""
|
|
parent = anode # chceme začít už od konkrétního node včetně
|
|
while True:
|
|
rocnik = isinstance(parent, s.RocnikNode)
|
|
cislo = isinstance(parent, s.CisloNode)
|
|
uloha = (isinstance(parent, s.UlohaVzorakNode) or
|
|
isinstance(parent, s.UlohaZadaniNode))
|
|
tema = isinstance(parent, s.TemaVCisleNode)
|
|
|
|
if (rocnik or cislo or uloha or tema) or parent==None:
|
|
break
|
|
else:
|
|
parent = treelib.get_parent(parent)
|
|
if rocnik:
|
|
return parent.rocnik.verejne()
|
|
elif cislo:
|
|
return parent.cislo.verejne()
|
|
elif uloha:
|
|
return parent.uloha.verejne()
|
|
elif tema:
|
|
return parent.tema.verejne()
|
|
elif None:
|
|
print("Existuje TreeNode, který není pod číslem, ročníkem, úlohou"
|
|
"ani tématem. {}".format(anode))
|
|
return False
|
|
|
|
@classmethod
|
|
def all_public_children(cls, anode):
|
|
for ch in treelib.all_children(anode):
|
|
if TNLData.public_above(ch):
|
|
yield ch
|
|
else:
|
|
continue
|
|
|
|
@classmethod
|
|
def from_treenode(cls, anode, user, parent=None, index=None):
|
|
if TNLData.public_above(anode) or user.has_perm('auth.org'):
|
|
out = cls(anode,parent,index)
|
|
else:
|
|
raise PermissionDenied()
|
|
|
|
if user.has_perm('auth.org'):
|
|
enum_children = enumerate(treelib.all_children(anode))
|
|
else:
|
|
enum_children = enumerate(TNLData.all_public_children(anode))
|
|
|
|
for (idx,ch) in enum_children:
|
|
outitem = cls.from_treenode(ch, user, out, idx)
|
|
out.children.append(outitem)
|
|
out.add_edit_options()
|
|
return out
|
|
|
|
@classmethod
|
|
def from_tnldata_list(cls, tnllist):
|
|
"""Vyrobíme virtuální TNL, který nemá obsah, ale má za potomky všechna zadaná TNLData"""
|
|
result = cls(None)
|
|
for idx, tnl in enumerate(tnllist):
|
|
result.children.append(tnl)
|
|
tnl.parent = result
|
|
tnl.index = idx
|
|
result.add_edit_options()
|
|
return result
|
|
|
|
@classmethod
|
|
def filter_treenode(cls, treenode, predicate):
|
|
tnll = cls._filter_treenode_recursive(treenode, predicate) # TreeNodeList List :-)
|
|
return TNLData.from_tnldata_list(tnll)
|
|
|
|
@classmethod
|
|
def _filter_treenode_recursive(cls, treenode, predicate):
|
|
if predicate(treenode):
|
|
return [cls.from_treenode(treenode)]
|
|
else:
|
|
found = []
|
|
for tn in treelib.all_children(treenode):
|
|
result = cls.filter_treenode(tn, predicate)
|
|
# Result by v tuhle chvíli měl být seznam TNLDat odpovídající treenodům, jež matchnuly predikát.
|
|
for tnl in result:
|
|
found.append(tnl)
|
|
return found
|
|
|
|
def to_json(self):
|
|
#self.node = anode
|
|
#self.children = []
|
|
#self.parent = parent
|
|
#self.tema_in_path = False
|
|
#self.index = index
|
|
out = {}
|
|
out['node'] = self.sernode.data
|
|
out['children'] = [n.to_json() for n in self.children]
|
|
out['tema_in_path'] = self.tema_in_path
|
|
out['index'] = self.index
|
|
out['deletable'] = self.deletable
|
|
out['editable_siblings'] = self.editable_siblings
|
|
out['editable_children'] = self.editable_children
|
|
out['text_only_subtree'] = self.text_only_subtree
|
|
out['can_podvesit_za'] = self.can_podvesit_za
|
|
out['can_podvesit_pod'] = self.can_podvesit_pred
|
|
out['appendable_children'] = self.appendable_children
|
|
out['appendable_siblings'] = self.appendable_siblings
|
|
|
|
return out
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
return("TNL({})".format(self.node))
|
|
|
|
|
|
# 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 = 'seminar/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, 'seminar/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, 'seminar/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, '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})
|
|
#
|
|
|
|
def ZadaniAktualniVysledkovkaView(request):
|
|
nastaveni = get_object_or_404(Nastaveni)
|
|
# Aktualni verejna vysledkovka
|
|
rocnik = nastaveni.aktualni_rocnik
|
|
context = vysledkovka_rocniku(
|
|
rocnik=rocnik,
|
|
request=request,
|
|
sneverejnou=True
|
|
)
|
|
|
|
# kdyz neni verejna vysledkovka, tak zobraz starou
|
|
if len(context['cisla']) == 0:
|
|
try:
|
|
minuly_rocnik = Rocnik.objects.get(
|
|
prvni_rok=(rocnik.prvni_rok-1))
|
|
rocnik = minuly_rocnik
|
|
|
|
# Přepíšeme prázdnou výsledkovku výsledkovkou z minulého ročníku
|
|
context = vysledkovka_rocniku(
|
|
rocnik=rocnik,
|
|
context=context,
|
|
request=request,
|
|
sneverejnou=True
|
|
)
|
|
except ObjectDoesNotExist:
|
|
pass
|
|
|
|
context['rocnik'] = rocnik
|
|
return render(
|
|
request,
|
|
'seminar/zadani/AktualniVysledkovka.html',
|
|
context
|
|
)
|
|
|
|
|
|
### Titulni strana
|
|
|
|
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()
|
|
if not user.je_org:
|
|
qs = qs.filter(zverejneno=True)
|
|
return qs.order_by('-datum')
|
|
|
|
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')
|
|
|
|
|
|
class TitulniStranaView(generic.ListView):
|
|
template_name='seminar/titulnistrana.html'
|
|
|
|
def get_queryset(self):
|
|
return spravne_novinky(self.request)[:3]
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(TitulniStranaView, self).get_context_data(**kwargs)
|
|
nastaveni = get_object_or_404(Nastaveni)
|
|
|
|
deadline_soustredeni = (nastaveni.aktualni_cislo.datum_deadline_soustredeni, "soustredeni")
|
|
preddeadline = (nastaveni.aktualni_cislo.datum_preddeadline, "preddeadline")
|
|
deadline = (nastaveni.aktualni_cislo.datum_deadline, "deadline")
|
|
|
|
try:
|
|
nejblizsi_deadline = sorted(filter(lambda dl: dl[0] is not None and dl[0] >= date.today(), [deadline_soustredeni, preddeadline, deadline]))[0]
|
|
if nejblizsi_deadline[0] == deadline_soustredeni[0]:
|
|
nejblizsi_deadline = deadline_soustredeni
|
|
except IndexError:
|
|
nejblizsi_deadline = (None, None) # neni zadna aktualni deadline
|
|
|
|
if nejblizsi_deadline[0] is not None:
|
|
context['nejblizsi_deadline'] = datetime.combine(nejblizsi_deadline[0], datetime.max.time())
|
|
else:
|
|
context['nejblizsi_deadline'] = None
|
|
|
|
context['typ_deadline'] = nejblizsi_deadline[1]
|
|
|
|
# Aktuální témata
|
|
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)
|
|
|
|
return context
|
|
|
|
class StareNovinkyView(generic.ListView):
|
|
template_name = 'seminar/stare_novinky.html'
|
|
|
|
def get_queryset(self):
|
|
return spravne_novinky(self.request)
|
|
|
|
### Co je M&M
|
|
|
|
|
|
# Organizatori
|
|
def aktivniOrganizatori(datum=timezone.now()):
|
|
return Organizator.objects.exclude(
|
|
organizuje_do__isnull=False,
|
|
organizuje_do__lt=datum
|
|
).order_by('osoba__jmeno')
|
|
|
|
|
|
class CojemamOrganizatoriView(generic.ListView):
|
|
model = Organizator
|
|
template_name = 'seminar/cojemam/organizatori.html'
|
|
queryset = aktivniOrganizatori()
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(CojemamOrganizatoriView, self).get_context_data(**kwargs)
|
|
context['aktivni'] = True
|
|
return context
|
|
|
|
|
|
class CojemamOrganizatoriStariView(generic.ListView):
|
|
model = Organizator
|
|
template_name = 'seminar/cojemam/organizatori.html'
|
|
queryset = Organizator.objects.exclude(
|
|
id__in=aktivniOrganizatori()).order_by('-organizuje_do')
|
|
|
|
### Archiv
|
|
|
|
|
|
class ArchivView(generic.ListView):
|
|
model = Rocnik
|
|
template_name='seminar/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, "images", "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 = 'seminar/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):
|
|
start = time.time()
|
|
context = super(RocnikView, self).get_context_data(**kwargs)
|
|
context = vysledkovka_rocniku(
|
|
rocnik=context["rocnik"],
|
|
context=context,
|
|
request=self.request,
|
|
sneverejnou=True
|
|
)
|
|
end = time.time()
|
|
print("Kontext:", end-start)
|
|
|
|
return context
|
|
|
|
|
|
# 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
|
|
|
|
|
|
|
|
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 = 'seminar/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()
|
|
# vrátíme context (aktuálně obsahuje jen věci ohledně výsledkovky
|
|
return vysledkovka_cisla(cislo, context)
|
|
|
|
|
|
class ArchivTemataView(generic.ListView):
|
|
model = Problem
|
|
template_name = 'seminar/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 = 'seminar/archiv/odmeny.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
fromcislo = Cislo.objects.get(rocnik=self.kwargs.get('frocnik'), poradi=self.kwargs.get('fcislo'))
|
|
tocislo = Cislo.objects.get(rocnik=self.kwargs.get('trocnik'), poradi=self.kwargs.get('tcislo'))
|
|
resitele = aktivniResitele(tocislo)
|
|
frombody = body_resitelu(resitele, fromcislo)
|
|
tobody = body_resitelu(resitele, tocislo)
|
|
outlist = []
|
|
for (aid, tbody) in tobody.items():
|
|
fbody = frombody.get(aid,0)
|
|
resitel = Resitel.objects.get(pk=aid)
|
|
ftitul = resitel.get_titul(fbody)
|
|
ttitul = resitel.get_titul(tbody)
|
|
if ftitul != ttitul:
|
|
outlist.append({'jmeno': resitel.osoba.plne_jmeno(), 'ftitul': ftitul, 'ttitul': ttitul})
|
|
context['zmeny'] = outlist
|
|
return context
|
|
|
|
|
|
|
|
|
|
### Generovani vysledkovky
|
|
|
|
class CisloVysledkovkaView(CisloView):
|
|
"""View vytvořené pro stránku zobrazující výsledkovku čísla v TeXu."""
|
|
|
|
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
|
|
|
|
class RocnikVysledkovkaView(RocnikView):
|
|
""" View vytvořené pro stránku zobrazující výsledkovku ročníku v TeXu."""
|
|
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
|
|
|
|
def cisloObalkyView(request, rocnik, cislo):
|
|
realne_cislo = Cislo.objects.get(poradi=cislo, rocnik__rocnik=rocnik)
|
|
return obalkyView(request, aktivniResitele(realne_cislo))
|
|
|
|
|
|
def obalkyView(request, resitele):
|
|
tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content
|
|
|
|
tempdir = tempfile.mkdtemp()
|
|
with open(tempdir+"/obalky.tex","w") as texfile:
|
|
texfile.write(tex.decode())
|
|
shutil.copy(os.path.join(settings.STATIC_ROOT, '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')
|
|
shutil.rmtree(tempdir)
|
|
return response
|
|
|
|
|
|
def oldObalkovaniView(request, rocnik, cislo):
|
|
rocnik = Rocnik.objects.get(rocnik=rocnik)
|
|
cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo)
|
|
|
|
reseni = (
|
|
Reseni.objects.filter(cislo_body=cislo)
|
|
.order_by(
|
|
'resitel__prijmeni',
|
|
'resitel__jmeno',
|
|
'problem__typ',
|
|
'problem__kod'
|
|
)
|
|
)
|
|
|
|
problemy = sorted(set(r.problem for r in reseni), key=lambda p: (p.typ, p.kod))
|
|
return render(
|
|
request,
|
|
'seminar/archiv/cislo_obalkovani.html',
|
|
{'cislo': cislo, 'problemy': problemy, 'reseni': reseni}
|
|
)
|
|
|
|
|
|
### Tituly
|
|
|
|
def TitulyView(request, rocnik, cislo):
|
|
""" View pro stažení makra titulů v TeXu."""
|
|
rocnik_obj = Rocnik.objects.get(rocnik = rocnik)
|
|
resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok)
|
|
cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, poradi = cislo)
|
|
|
|
asciijmena = []
|
|
jmenovci = False # detekuje, zda jsou dva řešitelé jmenovci (modulo nabodeníčka),
|
|
# pokud ano, vrátí se jako true
|
|
slovnik_s_body = body_resitelu(resitele, cislo_obj)
|
|
|
|
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, 'seminar/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 = 'seminar/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)<F12>:
|
|
# 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')
|
|
|
|
|
|
### Status
|
|
|
|
def StavDatabazeView(request):
|
|
# nastaveni = Nastaveni.objects.get()
|
|
problemy = utils.seznam_problemu()
|
|
muzi = Resitel.objects.filter(osoba__pohlavi_muz=True)
|
|
zeny = Resitel.objects.filter(osoba__pohlavi_muz=False)
|
|
return render(request, 'seminar/stav_databaze.html',
|
|
{
|
|
# 'nastaveni': nastaveni,
|
|
'problemy': problemy,
|
|
|
|
'resitele': Resitel.objects.all(),
|
|
'muzi': muzi,
|
|
'zeny': zeny,
|
|
'jmena_muzu': utils.histogram([r.osoba.jmeno for r in muzi]),
|
|
'jmena_zen': utils.histogram([r.osoba.jmeno for r in zeny]),
|
|
})
|
|
|
|
|
|
# Interní, nemá se nikdy objevit v urls (jinak to účastníci vytrolí)
|
|
def formularOKView(request, text=''):
|
|
template_name = 'seminar/formular_ok.html'
|
|
odkazy = [
|
|
# (Text, odkaz)
|
|
('Vrátit se na titulní stránku', reverse('titulni_strana')),
|
|
('Zobrazit aktuální zadání', reverse('seminar_aktualni_zadani')),
|
|
]
|
|
context = {
|
|
'odkazy': odkazy,
|
|
'text': text,
|
|
}
|
|
return render(request, template_name, context)
|
|
|
|
#------------------ Jak řešit - možná má být udělané úplně jinak
|
|
|
|
class JakResitView(generic.ListView):
|
|
template_name = 'seminar/jak-resit.html'
|
|
|
|
def get_queryset(self):
|
|
return None
|
|
|
|
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)
|
|
|