589 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			589 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Dočsasné views
 | |
| from .docasne import *
 | |
| 
 | |
| # Zbytek
 | |
| 
 | |
| 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
 | |
| 
 | |
| from personalni.models import Resitel
 | |
| from soustredeni.models import Konfera
 | |
| from tvorba.models import Problem, Cislo, Rocnik, Tema, Clanek, Deadline, Uloha
 | |
| from treenode.models import TemaVCisleNode, PohadkaNode
 | |
| from various.models import Nastaveni
 | |
| 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 = 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, Clanek) or  isinstance(self.object, Konfera):
 | |
| #			# Tyhle Problémy mají ŘešeníNode
 | |
| #			context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user)
 | |
| #		elif isinstance(self.object, 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, Tema):
 | |
| #			rocniknode = self.object.rocnik.rocniknode
 | |
| #			context['tnldata'] = TNLData.filter_treenode(rocniknode, lambda x: isinstance(x, 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 = 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 = Nastaveni.objects.first()
 | |
| #	rocnik_object = Rocnik.objects.filter(rocnik=rocnik)
 | |
| #	tematko_object = 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, KonferaNode): # FIXME neexistuje
 | |
| #			raise Exception("Not implemented yet")
 | |
| #		if node.isinstance(node, PohadkaNode): # Mohu ignorovat, má pod sebou
 | |
| #			pass
 | |
| #
 | |
| #	return render(request, 'tvorba/tematka/toaletak.html', {})
 | |
| #
 | |
| #
 | |
| #def TemataRozcestnikView(request):
 | |
| #	print("=============================================")
 | |
| #	nastaveni = Nastaveni.objects.first()
 | |
| #	tematka_objects = 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(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 = {
 | |
| #				Uloha: "uloha",
 | |
| #				Tema: "tema",
 | |
| #				Konfera: "konfera",
 | |
| #				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 = {
 | |
| 			Deadline.TYP_CISLA: "Výsledkovka",
 | |
| 			Deadline.TYP_CISLA_A_SOUS: "Výsledkovka celého čísla a deadlinu pro účast na soustředění",
 | |
| 			Deadline.TYP_PRVNI: "Výsledkovka do prvního deadlinu",
 | |
| 			Deadline.TYP_PRVNI_A_SOUS: "Výsledkovka do prvního deadlinu a deadlinu pro účast na soustředění",
 | |
| 			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, probody=False):
 | |
| 			"""Co je probody? pokud True, funkce vrací všechny rešitele a k nim potřebné informace, pokud False, vrací jen ty, kteří mají změnu v titulu."""
 | |
| 			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 probody:
 | |
| 					outlist.append({'jmeno': resitel.osoba.plne_jmeno(), 'fbody': fbody, 'tbody': tbody, 'ftitul': ftitul, 'ttitul': ttitul, 'bodydiff': tbody - fbody, "neposilame": not(resitel.zasilat_cislo_papirove)})
 | |
| 				else:
 | |
| 					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)
 | |
| 		context["resitele"] = get_diff(from_deadline, to_deadline, probody=resitele.order_by("osoba__prijmeni"))
 | |
| 
 | |
| 		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,'cislo':cislo},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)<F12>:
 | |
| #	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 = 'tvorba_rocnik'
 | |
| 
 | |
| 	def get_redirect_url(self, *args, **kwargs):
 | |
| 		aktualni_rocnik = Nastaveni.get_solo().aktualni_rocnik.rocnik
 | |
| 		return super().get_redirect_url(rocnik=aktualni_rocnik, *args, **kwargs)
 |