Rozstřílení seminářové aplikace #60
					 1 changed files with 582 additions and 2 deletions
				
			
		|  | @ -1,4 +1,584 @@ | ||||||
| from .views_all import * |  | ||||||
| 
 |  | ||||||
| # Dočsasné views | # Dočsasné views | ||||||
| from .docasne import * | 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 | ||||||
|  | 
 | ||||||
|  | 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)<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 = '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) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue