Podezřelé semináře (#1465) #65
					 20 changed files with 232 additions and 213 deletions
				
			
		|  | @ -5,7 +5,9 @@ from dal import autocomplete | ||||||
| from django.shortcuts import get_object_or_404 | from django.shortcuts import get_object_or_404 | ||||||
| from django.db.models import Q | from django.db.models import Q | ||||||
| 
 | 
 | ||||||
| import seminar.models as m | from personalni.models import Skola, Resitel | ||||||
|  | from tvorba.models import Problem | ||||||
|  | from various.models import Nastaveni | ||||||
| from .helpers import LoginRequiredAjaxMixin | from .helpers import LoginRequiredAjaxMixin | ||||||
| 
 | 
 | ||||||
| # TODO filosofie - zkratky, jak v databázi, tak ve vyhledávání (SPŠE, GASOŠ, Kpt., soukr) | # TODO filosofie - zkratky, jak v databázi, tak ve vyhledávání (SPŠE, GASOŠ, Kpt., soukr) | ||||||
|  | @ -13,7 +15,7 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView): | ||||||
| 	""" View k :mod:`dal.autocomplete` pro vyhledávání škol hlavně při registraci. """ | 	""" View k :mod:`dal.autocomplete` pro vyhledávání škol hlavně při registraci. """ | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		# Don't forget to filter out results depending on the visitor ! | 		# Don't forget to filter out results depending on the visitor ! | ||||||
| 		qs = m.Skola.objects.all() | 		qs = Skola.objects.all() | ||||||
| 		if self.q: | 		if self.q: | ||||||
| 			words = self.q.split(' ') #TODO re split podle bileho znaku | 			words = self.q.split(' ') #TODO re split podle bileho znaku | ||||||
| 			partq = Q() | 			partq = Q() | ||||||
|  | @ -31,7 +33,7 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView): | ||||||
| class ResitelAutocomplete(LoginRequiredAjaxMixin,autocomplete.Select2QuerySetView): | class ResitelAutocomplete(LoginRequiredAjaxMixin,autocomplete.Select2QuerySetView): | ||||||
| 	""" View k :mod:`dal.autocomplete` pro vyhledávání řešitelů především v odevzdávátku. """ | 	""" View k :mod:`dal.autocomplete` pro vyhledávání řešitelů především v odevzdávátku. """ | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		qs = m.Resitel.objects.all() | 		qs = Resitel.objects.all() | ||||||
| 		if self.q: | 		if self.q: | ||||||
| 			parts = self.q.split() | 			parts = self.q.split() | ||||||
| 			query = Q() | 			query = Q() | ||||||
|  | @ -51,8 +53,8 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer | ||||||
| 		především v odevzdávátku. | 		především v odevzdávátku. | ||||||
| 	""" | 	""" | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		letos = m.Nastaveni.get_solo().aktualni_rocnik | 		letos = Nastaveni.get_solo().aktualni_rocnik | ||||||
| 		qs = m.Resitel.objects.filter( | 		qs = Resitel.objects.filter( | ||||||
| 			rok_maturity__gte=letos.druhy_rok() | 			rok_maturity__gte=letos.druhy_rok() | ||||||
| 		).filter( | 		).filter( | ||||||
| 			prezdivka_resitele__isnull=False | 			prezdivka_resitele__isnull=False | ||||||
|  | @ -70,7 +72,7 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer | ||||||
| class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView): | class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView): | ||||||
| 	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """ | 	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """ | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		qs = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY) | 		qs = Problem.objects.filter(stav=Problem.STAV_ZADANY) | ||||||
| 		if self.q: | 		if self.q: | ||||||
| 			qs = qs.filter( | 			qs = qs.filter( | ||||||
| 					Q(nazev__icontains=self.q)) | 					Q(nazev__icontains=self.q)) | ||||||
|  | @ -87,12 +89,12 @@ class ProblemAutocomplete(autocomplete.Select2QuerySetView): | ||||||
| 	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """ | 	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """ | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		# FIXME i starší úlohy | 		# FIXME i starší úlohy | ||||||
| 		nastaveni = get_object_or_404(m.Nastaveni) | 		nastaveni = get_object_or_404(Nastaveni) | ||||||
| 		rocnik = nastaveni.aktualni_rocnik | 		rocnik = nastaveni.aktualni_rocnik | ||||||
| 		temaQ = Q(Tema___rocnik = rocnik) | 		temaQ = Q(Tema___rocnik = rocnik) | ||||||
| 		ulohaQ = Q(Uloha___cislo_zadani__rocnik=rocnik) | 		ulohaQ = Q(Uloha___cislo_zadani__rocnik=rocnik) | ||||||
| 		clanekQ = Q(Clanek___cislo__rocnik=rocnik) | 		clanekQ = Q(Clanek___cislo__rocnik=rocnik) | ||||||
| 		qs = m.Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev") | 		qs = Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev") | ||||||
| 		if self.q: | 		if self.q: | ||||||
| 			qs = qs.filter( | 			qs = qs.filter( | ||||||
| 					Q(nazev__icontains=self.q)) | 					Q(nazev__icontains=self.q)) | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ def get_app_list(self, request, app_label=None): | ||||||
| 
 | 
 | ||||||
| 	app_dict = self._build_app_dict(request, label=app_label) | 	app_dict = self._build_app_dict(request, label=app_label) | ||||||
| 	aplikace_nahore = [ | 	aplikace_nahore = [ | ||||||
| 		'seminar', | 		'tvorba', | ||||||
| 		'personalni', | 		'personalni', | ||||||
| 		'novinky', | 		'novinky', | ||||||
| 		'korektury', | 		'korektury', | ||||||
|  | @ -57,7 +57,7 @@ def get_app_list(self, request, app_label=None): | ||||||
| 
 | 
 | ||||||
| 	# Sort the models alphabetically within each app. | 	# Sort the models alphabetically within each app. | ||||||
| 	for app in app_list: | 	for app in app_list: | ||||||
| 		app['models'].sort(key=lambda x: locale.strxfrm('žž' + x['name'].lower()) if (x['name'].endswith("(Node)")) else locale.strxfrm(x['name'].lower())) | 		app['models'].sort(key=lambda x: locale.strxfrm(x['name'].lower())) | ||||||
| 
 | 
 | ||||||
| 	return app_list | 	return app_list | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,7 +5,10 @@ from django.forms.models import inlineformset_factory | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| 
 | 
 | ||||||
| from personalni.models import Resitel | from personalni.models import Resitel | ||||||
| import seminar.models as m | from tvorba.models import Problem, Deadline | ||||||
|  | from various.models import Nastaveni | ||||||
|  | 
 | ||||||
|  | from odevzdavatko.models import Reseni, PrilohaReseni, Hodnoceni | ||||||
| 
 | 
 | ||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
|  | @ -22,7 +25,7 @@ class DateInput(forms.DateInput): | ||||||
| 
 | 
 | ||||||
| class PosliReseniForm(forms.Form): | class PosliReseniForm(forms.Form): | ||||||
| 	problem = forms.ModelMultipleChoiceField( | 	problem = forms.ModelMultipleChoiceField( | ||||||
| 		queryset=m.Problem.objects.all(), | 		queryset=Problem.objects.all(), | ||||||
| 		label="Problémy", | 		label="Problémy", | ||||||
| 		widget=autocomplete.ModelSelect2Multiple( | 		widget=autocomplete.ModelSelect2Multiple( | ||||||
| 			url='autocomplete_problem', | 			url='autocomplete_problem', | ||||||
|  | @ -58,7 +61,7 @@ class PosliReseniForm(forms.Form): | ||||||
| 
 | 
 | ||||||
| 	#cas_doruceni = models.DateTimeField('čas_doručení', default=timezone.now, blank=True) | 	#cas_doruceni = models.DateTimeField('čas_doručení', default=timezone.now, blank=True) | ||||||
| 
 | 
 | ||||||
| 	forma = forms.ChoiceField(label="Forma řešení",choices = m.Reseni.FORMA_CHOICES) | 	forma = forms.ChoiceField(label="Forma řešení",choices = Reseni.FORMA_CHOICES) | ||||||
| 	#forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False, | 	#forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False, | ||||||
| 	#	 default=FORMA_EMAIL) | 	#	 default=FORMA_EMAIL) | ||||||
| 
 | 
 | ||||||
|  | @ -69,7 +72,7 @@ class PosliReseniForm(forms.Form): | ||||||
| 
 | 
 | ||||||
| class NahrajReseniForm(forms.ModelForm): | class NahrajReseniForm(forms.ModelForm): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Reseni | 		model = Reseni | ||||||
| 		fields = ('problem', 'resitele') | 		fields = ('problem', 'resitele') | ||||||
| 		help_texts = {'problem':''} # Nezobrazovat help text ve formuláři | 		help_texts = {'problem':''} # Nezobrazovat help text ve formuláři | ||||||
| 		 | 		 | ||||||
|  | @ -109,11 +112,11 @@ class NahrajReseniForm(forms.ModelForm): | ||||||
| 	def clean_problem(self): | 	def clean_problem(self): | ||||||
| 		problem = self.cleaned_data.get('problem') | 		problem = self.cleaned_data.get('problem') | ||||||
| 		for p in problem: | 		for p in problem: | ||||||
| 			if p.stav != m.Problem.STAV_ZADANY: | 			if p.stav != Problem.STAV_ZADANY: | ||||||
| 				raise forms.ValidationError("Problém " + str(p) + " již nelze řešit!") | 				raise forms.ValidationError("Problém " + str(p) + " již nelze řešit!") | ||||||
| 		return problem | 		return problem | ||||||
| 
 | 
 | ||||||
| ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni,  | ReseniSPrilohamiFormSet = inlineformset_factory(Reseni, PrilohaReseni, | ||||||
| 		form = NahrajReseniForm, | 		form = NahrajReseniForm, | ||||||
| 		fields = ('soubor','res_poznamka'), | 		fields = ('soubor','res_poznamka'), | ||||||
| 		widgets = {'res_poznamka':forms.TextInput()}, | 		widgets = {'res_poznamka':forms.TextInput()}, | ||||||
|  | @ -125,7 +128,7 @@ ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni, | ||||||
| 
 | 
 | ||||||
| class JednoHodnoceniForm(forms.ModelForm): | class JednoHodnoceniForm(forms.ModelForm): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Hodnoceni | 		model = Hodnoceni | ||||||
| 		fields = ('problem', 'body', 'deadline_body', 'feedback',) | 		fields = ('problem', 'body', 'deadline_body', 'feedback',) | ||||||
| 		widgets = { | 		widgets = { | ||||||
| 			'problem': autocomplete.ModelSelect2( | 			'problem': autocomplete.ModelSelect2( | ||||||
|  | @ -158,7 +161,7 @@ OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm, | ||||||
| 
 | 
 | ||||||
| class PoznamkaReseniForm(forms.ModelForm): | class PoznamkaReseniForm(forms.ModelForm): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Reseni | 		model = Reseni | ||||||
| 		fields = ('poznamka',) | 		fields = ('poznamka',) | ||||||
| 
 | 
 | ||||||
| # FIXME: Ideálně by mělo být součástí třídy níž, ale neumím to udělat | # FIXME: Ideálně by mělo být součástí třídy níž, ale neumím to udělat | ||||||
|  | @ -198,7 +201,7 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form): | ||||||
| 		 | 		 | ||||||
| 		from django.db.utils import OperationalError | 		from django.db.utils import OperationalError | ||||||
| 		try: | 		try: | ||||||
| 			aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik | 			aktualni_rocnik = Nastaveni.get_solo().aktualni_rocnik | ||||||
| 		except OperationalError: | 		except OperationalError: | ||||||
| 			# django.db.utils.OperationalError: no such table: seminar_nastaveni | 			# django.db.utils.OperationalError: no such table: seminar_nastaveni | ||||||
| 			# Nemáme databázi, takže to selhalo. Pro jistotu vrátíme aspoň dvě možnosti, ať to nepadá dál | 			# Nemáme databázi, takže to selhalo. Pro jistotu vrátíme aspoň dvě možnosti, ať to nepadá dál | ||||||
|  | @ -214,7 +217,7 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form): | ||||||
| 
 | 
 | ||||||
| 		result.append(("0001-01-01", f"Odjakživa")) | 		result.append(("0001-01-01", f"Odjakživa")) | ||||||
| 
 | 
 | ||||||
| 		for deadline in m.Deadline.objects.filter( | 		for deadline in Deadline.objects.filter( | ||||||
| 				deadline__lte=timezone.now(), | 				deadline__lte=timezone.now(), | ||||||
| 				cislo__rocnik=aktualni_rocnik | 				cislo__rocnik=aktualni_rocnik | ||||||
| 				).order_by("deadline"): | 				).order_by("deadline"): | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ from django.urls import reverse_lazy | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| 
 | 
 | ||||||
| import tvorba.models as am | from tvorba.models import Problem, Deadline, Cislo, Uloha, aux_generate_filename | ||||||
| from seminar.models import base as bm | from seminar.models import base as bm | ||||||
| 
 | 
 | ||||||
| from odevzdavatko.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet | from odevzdavatko.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet | ||||||
|  | @ -29,7 +29,7 @@ class Reseni(bm.SeminarModelBase): | ||||||
| 	id = models.AutoField(primary_key = True) | 	id = models.AutoField(primary_key = True) | ||||||
| 
 | 
 | ||||||
| 	# Ke každé dvojici řešní a problém existuje nanejvýš jedno hodnocení, doplnění vazby. | 	# Ke každé dvojici řešní a problém existuje nanejvýš jedno hodnocení, doplnění vazby. | ||||||
| 	problem = models.ManyToManyField(am.Problem, verbose_name='problém', help_text='Problém', | 	problem = models.ManyToManyField(Problem, verbose_name='problém', help_text='Problém', | ||||||
| 									 through='Hodnoceni') | 									 through='Hodnoceni') | ||||||
| 
 | 
 | ||||||
| 	resitele = models.ManyToManyField(Resitel, verbose_name='autoři řešení', | 	resitele = models.ManyToManyField(Resitel, verbose_name='autoři řešení', | ||||||
|  | @ -79,7 +79,7 @@ class Reseni(bm.SeminarModelBase): | ||||||
| 	# NOTE: Potenciální DB HOG (bez select_related) | 	# NOTE: Potenciální DB HOG (bez select_related) | ||||||
| 
 | 
 | ||||||
| 	def deadline_reseni(self): | 	def deadline_reseni(self): | ||||||
| 		return am.Deadline.objects.filter(deadline__gte=self.cas_doruceni).order_by("deadline").first() | 		return Deadline.objects.filter(deadline__gte=self.cas_doruceni).order_by("deadline").first() | ||||||
| 
 | 
 | ||||||
| ## Pravdepodobne uz nebude potreba: | ## Pravdepodobne uz nebude potreba: | ||||||
| #	def save(self, *args, **kwargs): | #	def save(self, *args, **kwargs): | ||||||
|  | @ -101,16 +101,16 @@ class Hodnoceni(bm.SeminarModelBase): | ||||||
| 	body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='body', | 	body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='body', | ||||||
| 							   blank=True, null=True) | 							   blank=True, null=True) | ||||||
| 
 | 
 | ||||||
| 	cislo_body = models.ForeignKey(am.Cislo, verbose_name='číslo pro body', | 	cislo_body = models.ForeignKey(Cislo, verbose_name='číslo pro body', | ||||||
| 								   related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT) | 								   related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT) | ||||||
| 
 | 
 | ||||||
| 	# V ročníku < 26 nastaveno na deadline vygenerovaný pro původní cislo_body | 	# V ročníku < 26 nastaveno na deadline vygenerovaný pro původní cislo_body | ||||||
| 	deadline_body = models.ForeignKey(am.Deadline, verbose_name='deadline pro body', | 	deadline_body = models.ForeignKey(Deadline, verbose_name='deadline pro body', | ||||||
| 								   related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT) | 								   related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT) | ||||||
| 
 | 
 | ||||||
| 	reseni = models.ForeignKey(Reseni, verbose_name='řešení', on_delete=models.CASCADE) | 	reseni = models.ForeignKey(Reseni, verbose_name='řešení', on_delete=models.CASCADE) | ||||||
| 
 | 
 | ||||||
| 	problem = models.ForeignKey(am.Problem, verbose_name='problém', | 	problem = models.ForeignKey(Problem, verbose_name='problém', | ||||||
| 								related_name='hodnoceni', on_delete=models.PROTECT) | 								related_name='hodnoceni', on_delete=models.PROTECT) | ||||||
| 
 | 
 | ||||||
| 	feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)') | 	feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)') | ||||||
|  | @ -166,7 +166,7 @@ class Hodnoceni(bm.SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 	@property | 	@property | ||||||
| 	def body_neprepocitane_max(self): | 	def body_neprepocitane_max(self): | ||||||
| 		if not isinstance(self.problem.get_real_instance(), am.Uloha): | 		if not isinstance(self.problem.get_real_instance(), Uloha): | ||||||
| 			return None | 			return None | ||||||
| 		return self.problem.uloha.max_body | 		return self.problem.uloha.max_body | ||||||
| 
 | 
 | ||||||
|  | @ -176,7 +176,7 @@ class Hodnoceni(bm.SeminarModelBase): | ||||||
| def generate_filename(self, filename): | def generate_filename(self, filename): | ||||||
| 	return os.path.join( | 	return os.path.join( | ||||||
| 		settings.SEMINAR_RESENI_DIR, | 		settings.SEMINAR_RESENI_DIR, | ||||||
| 		am.aux_generate_filename(self, filename) | 		aux_generate_filename(self, filename) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,10 +17,14 @@ from decimal import Decimal | ||||||
| from itertools import groupby | from itertools import groupby | ||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| import seminar.models as m |  | ||||||
| from . import forms as f | from . import forms as f | ||||||
| from .forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm | from .forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm | ||||||
|  | from .models import Hodnoceni, Reseni | ||||||
|  | 
 | ||||||
|  | from personalni.models import Resitel, Osoba, Organizator | ||||||
|  | from tvorba.models import Problem, Deadline, Rocnik | ||||||
| from tvorba.utils import resi_v_rocniku | from tvorba.utils import resi_v_rocniku | ||||||
|  | from various.models import Nastaveni | ||||||
| from various.views.pomocne import formularOKView | from various.views.pomocne import formularOKView | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
|  | @ -40,20 +44,20 @@ logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
| class TabulkaOdevzdanychReseniView(ListView): | class TabulkaOdevzdanychReseniView(ListView): | ||||||
| 	template_name = 'odevzdavatko/tabulka.html' | 	template_name = 'odevzdavatko/tabulka.html' | ||||||
| 	model = m.Hodnoceni | 	model = Hodnoceni | ||||||
| 
 | 
 | ||||||
| 	def inicializuj_osy_tabulky(self): | 	def inicializuj_osy_tabulky(self): | ||||||
| 		"""Vyrobí prvotní querysety pro sloupce a řádky, tj. seznam všech řešitelů a problémů""" | 		"""Vyrobí prvotní querysety pro sloupce a řádky, tj. seznam všech řešitelů a problémů""" | ||||||
| 		# FIXME: jméno metody není vypovídající... | 		# FIXME: jméno metody není vypovídající... | ||||||
| 		# NOTE: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistují ty objekty (?). TODO: Otestovat | 		# NOTE: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistují ty objekty (?). TODO: Otestovat | ||||||
| 		# TODO: Prefetches, Select related, ... | 		# TODO: Prefetches, Select related, ... | ||||||
| 		self.resitele = m.Resitel.objects.all() | 		self.resitele = Resitel.objects.all() | ||||||
| 		self.problemy = m.Problem.objects.all() | 		self.problemy = Problem.objects.all() | ||||||
| 		self.reseni = m.Reseni.objects.all() | 		self.reseni = Reseni.objects.all() | ||||||
| 
 | 
 | ||||||
| 		self.aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik	# .get_solo() vrátí tu jedinou instanci | 		self.aktualni_rocnik = Nastaveni.get_solo().aktualni_rocnik	# .get_solo() vrátí tu jedinou instanci | ||||||
| 		if 'rocnik' in self.kwargs: | 		if 'rocnik' in self.kwargs: | ||||||
| 			self.aktualni_rocnik = get_object_or_404(m.Rocnik, rocnik=self.kwargs['rocnik']) | 			self.aktualni_rocnik = get_object_or_404(Rocnik, rocnik=self.kwargs['rocnik']) | ||||||
| 
 | 
 | ||||||
| 		form = FiltrForm(self.request.GET, rocnik=self.aktualni_rocnik) | 		form = FiltrForm(self.request.GET, rocnik=self.aktualni_rocnik) | ||||||
| 		if form.is_valid(): | 		if form.is_valid(): | ||||||
|  | @ -86,14 +90,14 @@ class TabulkaOdevzdanychReseniView(ListView): | ||||||
| 			self.resitele = self.resitele.filter(rok_maturity__gt=self.aktualni_rocnik.prvni_rok) | 			self.resitele = self.resitele.filter(rok_maturity__gt=self.aktualni_rocnik.prvni_rok) | ||||||
| 
 | 
 | ||||||
| 		if problemy == FiltrForm.PROBLEMY_MOJE: | 		if problemy == FiltrForm.PROBLEMY_MOJE: | ||||||
| 			org = m.Organizator.objects.get(osoba__user=self.request.user) | 			org = Organizator.objects.get(osoba__user=self.request.user) | ||||||
| 			self.problemy = self.problemy.filter( | 			self.problemy = self.problemy.filter( | ||||||
| 					Q(autor=org)|Q(garant=org)|Q(opravovatele=org), | 					Q(autor=org)|Q(garant=org)|Q(opravovatele=org), | ||||||
| 					Q(stav=m.Problem.STAV_ZADANY)|Q(stav=m.Problem.STAV_VYRESENY), | 					Q(stav=Problem.STAV_ZADANY)|Q(stav=Problem.STAV_VYRESENY), | ||||||
| 					) | 					) | ||||||
| 		elif problemy == FiltrForm.PROBLEMY_LETOSNI: | 		elif problemy == FiltrForm.PROBLEMY_LETOSNI: | ||||||
| 			self.problemy = self.problemy.filter( | 			self.problemy = self.problemy.filter( | ||||||
| 					Q(stav=m.Problem.STAV_ZADANY)|Q(stav=m.Problem.STAV_VYRESENY), | 					Q(stav=Problem.STAV_ZADANY)|Q(stav=Problem.STAV_VYRESENY), | ||||||
| 					) | 					) | ||||||
| 			#self.problemy = list(filter(lambda problem: problem.rocnik() == self.aktualni_rocnik, self.problemy)) # DB HOG? # FIXME: některé problémy nemají ročník.... | 			#self.problemy = list(filter(lambda problem: problem.rocnik() == self.aktualni_rocnik, self.problemy)) # DB HOG? # FIXME: některé problémy nemají ročník.... | ||||||
| 		# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy. | 		# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy. | ||||||
|  | @ -121,8 +125,8 @@ class TabulkaOdevzdanychReseniView(ListView): | ||||||
| 		ctx = super().get_context_data(*args, **kwargs) | 		ctx = super().get_context_data(*args, **kwargs) | ||||||
| 		ctx['problemy'] = self.problemy | 		ctx['problemy'] = self.problemy | ||||||
| 		ctx['resitele'] = self.resitele | 		ctx['resitele'] = self.resitele | ||||||
| 		tabulka: dict[m.Problem, dict[m.Resitel, list[tuple[m.Reseni, m.Hodnoceni]]]] = dict() | 		tabulka: dict[Problem, dict[Resitel, list[tuple[Reseni, Hodnoceni]]]] = dict() | ||||||
| 		soucty: dict[m.Problem, dict[m.Resitel, Decimal]] = dict() | 		soucty: dict[Problem, dict[Resitel, Decimal]] = dict() | ||||||
| 
 | 
 | ||||||
| 		def pridej_reseni(resitel, hodnoceni): | 		def pridej_reseni(resitel, hodnoceni): | ||||||
| 			problem = hodnoceni.problem | 			problem = hodnoceni.problem | ||||||
|  | @ -143,11 +147,11 @@ class TabulkaOdevzdanychReseniView(ListView): | ||||||
| 			for resitel in hodnoceni.reseni.resitele.all(): | 			for resitel in hodnoceni.reseni.resitele.all(): | ||||||
| 				pridej_reseni(resitel, hodnoceni) | 				pridej_reseni(resitel, hodnoceni) | ||||||
| 
 | 
 | ||||||
| 		hodnoty: list[list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy + jejich součty, v každé buňce seznam řešení k danému řešiteli a problému. | 		hodnoty: list[list[tuple[Decimal,list[tuple[Reseni, Hodnoceni]]]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy + jejich součty, v každé buňce seznam řešení k danému řešiteli a problému. | ||||||
| 		resitele_do_tabulky: list[m.Resitel] = [] | 		resitele_do_tabulky: list[Resitel] = [] | ||||||
| 		for resitel in self.resitele: | 		for resitel in self.resitele: | ||||||
| 			dostal_body = False | 			dostal_body = False | ||||||
| 			resiteluv_radek: list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]] = [] # podle pořadí v self.problemy | 			resiteluv_radek: list[tuple[Decimal,list[tuple[Reseni, Hodnoceni]]]] = [] # podle pořadí v self.problemy | ||||||
| 			for problem in self.problemy: | 			for problem in self.problemy: | ||||||
| 				if problem in tabulka and resitel in tabulka[problem]: | 				if problem in tabulka and resitel in tabulka[problem]: | ||||||
| 					resiteluv_radek.append((soucty[problem][resitel], tabulka[problem][resitel])) | 					resiteluv_radek.append((soucty[problem][resitel], tabulka[problem][resitel])) | ||||||
|  | @ -162,7 +166,7 @@ class TabulkaOdevzdanychReseniView(ListView): | ||||||
| 		# Pro použití hacku na automatické {{form.media}} v template: | 		# Pro použití hacku na automatické {{form.media}} v template: | ||||||
| 		ctx['form'] = ctx['filtr'] | 		ctx['form'] = ctx['filtr'] | ||||||
| 		# Pro maximum v přesměrovátku ročníků | 		# Pro maximum v přesměrovátku ročníků | ||||||
| 		ctx['aktualni_rocnik'] = m.Nastaveni.get_solo().aktualni_rocnik | 		ctx['aktualni_rocnik'] = Nastaveni.get_solo().aktualni_rocnik | ||||||
| 		ctx['barvicky'] = self.barvicky | 		ctx['barvicky'] = self.barvicky | ||||||
| 		if 'rocnik' in self.kwargs: | 		if 'rocnik' in self.kwargs: | ||||||
| 			ctx['rocnik'] = self.kwargs['rocnik'] | 			ctx['rocnik'] = self.kwargs['rocnik'] | ||||||
|  | @ -178,7 +182,7 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi | ||||||
| 	Asi už bude zastaralý v okamžiku, kdy se tenhle komentář nasadí na produkci :-) | 	Asi už bude zastaralý v okamžiku, kdy se tenhle komentář nasadí na produkci :-) | ||||||
| 
 | 
 | ||||||
| 	V případě, že takové řešení existuje jen jedno, tak na něj přesměruje.""" | 	V případě, že takové řešení existuje jen jedno, tak na něj přesměruje.""" | ||||||
| 	model = m.Reseni | 	model = Reseni | ||||||
| 	template_name = 'odevzdavatko/seznam.html' | 	template_name = 'odevzdavatko/seznam.html' | ||||||
| 	 | 	 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
|  | @ -190,8 +194,8 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi | ||||||
| 		if problem_id is None: | 		if problem_id is None: | ||||||
| 			raise ValueError("Nemám problém! (To je problém!)") | 			raise ValueError("Nemám problém! (To je problém!)") | ||||||
| 		 | 		 | ||||||
| 		resitel = m.Resitel.objects.get(id=resitel_id) | 		resitel = Resitel.objects.get(id=resitel_id) | ||||||
| 		problem = m.Problem.objects.get(id=problem_id) | 		problem = Problem.objects.get(id=problem_id) | ||||||
| 		qs = qs.filter( | 		qs = qs.filter( | ||||||
| 			problem__in=[problem], | 			problem__in=[problem], | ||||||
| 			resitele__in=[resitel], | 			resitele__in=[resitel], | ||||||
|  | @ -221,13 +225,13 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi | ||||||
| ## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex | ## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex | ||||||
| class DetailReseniView(DetailView): | class DetailReseniView(DetailView): | ||||||
| 	""" Náhled na řešení. Editace je v :py:class:`EditReseniView`. """ | 	""" Náhled na řešení. Editace je v :py:class:`EditReseniView`. """ | ||||||
| 	model = m.Reseni | 	model = Reseni | ||||||
| 	template_name = 'odevzdavatko/detail.html' | 	template_name = 'odevzdavatko/detail.html' | ||||||
| 	 | 	 | ||||||
| 	def aktualni_hodnoceni(self): | 	def aktualni_hodnoceni(self): | ||||||
| 		self.reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk']) | 		self.reseni = get_object_or_404(Reseni, id=self.kwargs['pk']) | ||||||
| 		result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet | 		result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet | ||||||
| 		for hodn in m.Hodnoceni.objects.filter(reseni=self.reseni): | 		for hodn in Hodnoceni.objects.filter(reseni=self.reseni): | ||||||
| 			seznam_atributu = [ | 			seznam_atributu = [ | ||||||
| 				"problem", | 				"problem", | ||||||
| 				"body", | 				"body", | ||||||
|  | @ -284,7 +288,7 @@ class EditReseniView(DetailReseniView): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def hodnoceniReseniView(request, pk, *args, **kwargs): | def hodnoceniReseniView(request, pk, *args, **kwargs): | ||||||
| 	reseni = get_object_or_404(m.Reseni, pk=pk) | 	reseni = get_object_or_404(Reseni, pk=pk) | ||||||
| 	success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk}) | 	success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk}) | ||||||
| 
 | 
 | ||||||
| 	# FIXME: Použit initial i tady a nebastlit hodnocení tak nízkoúrovňově | 	# FIXME: Použit initial i tady a nebastlit hodnocení tak nízkoúrovňově | ||||||
|  | @ -300,7 +304,7 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): | ||||||
| 		poznamka_form.save() | 		poznamka_form.save() | ||||||
| 
 | 
 | ||||||
| 		# Smažeme všechna dosavadní hodnocení tohoto řešení | 		# Smažeme všechna dosavadní hodnocení tohoto řešení | ||||||
| 		qs = m.Hodnoceni.objects.filter(reseni=reseni) | 		qs = Hodnoceni.objects.filter(reseni=reseni) | ||||||
| 		logger.info(f"Will delete {qs.count()} objects: {qs}") | 		logger.info(f"Will delete {qs.count()} objects: {qs}") | ||||||
| 		qs.delete() | 		qs.delete() | ||||||
| 
 | 
 | ||||||
|  | @ -311,7 +315,7 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): | ||||||
| 			del(data_for_hodnoceni["body_celkem"]) | 			del(data_for_hodnoceni["body_celkem"]) | ||||||
| 			del(data_for_hodnoceni["body_neprepocitane"]) | 			del(data_for_hodnoceni["body_neprepocitane"]) | ||||||
| 			del(data_for_hodnoceni["body_neprepocitane_celkem"]) | 			del(data_for_hodnoceni["body_neprepocitane_celkem"]) | ||||||
| 			hodnoceni = m.Hodnoceni( | 			hodnoceni = Hodnoceni( | ||||||
| 					reseni=reseni, | 					reseni=reseni, | ||||||
| 					**form.cleaned_data, | 					**form.cleaned_data, | ||||||
| 					) | 					) | ||||||
|  | @ -332,14 +336,14 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PrehledOdevzdanychReseni(ListView): | class PrehledOdevzdanychReseni(ListView): | ||||||
| 	model = m.Hodnoceni | 	model = Hodnoceni | ||||||
| 	template_name = 'odevzdavatko/prehled_reseni.html' | 	template_name = 'odevzdavatko/prehled_reseni.html' | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		if not self.request.user.is_authenticated: | 		if not self.request.user.is_authenticated: | ||||||
| 			raise RuntimeError("Uživatel měl být přihlášený!") | 			raise RuntimeError("Uživatel měl být přihlášený!") | ||||||
| 		# get_or_none, aby neexistence řešitele (např. u orgů) neházela chybu | 		# get_or_none, aby neexistence řešitele (např. u orgů) neházela chybu | ||||||
| 		resitel = m.Resitel.objects.filter(osoba__user=self.request.user).first() | 		resitel = Resitel.objects.filter(osoba__user=self.request.user).first() | ||||||
| 		qs = super().get_queryset() | 		qs = super().get_queryset() | ||||||
| 		qs = qs.filter(reseni__resitele__in=[resitel]) | 		qs = qs.filter(reseni__resitele__in=[resitel]) | ||||||
| 		# Setřídíme podle času doručení řešení, aby se netřídily podle okamžiku vyrobení Hodnocení | 		# Setřídíme podle času doručení řešení, aby se netřídily podle okamžiku vyrobení Hodnocení | ||||||
|  | @ -360,13 +364,13 @@ class PrehledOdevzdanychReseni(ListView): | ||||||
| # Přehled všech řešení kvůli debugování | # Přehled všech řešení kvůli debugování | ||||||
| 
 | 
 | ||||||
| class SeznamReseniView(ListView): | class SeznamReseniView(ListView): | ||||||
| 	model = m.Reseni | 	model = Reseni | ||||||
| 	template_name = 'odevzdavatko/seznam.html' | 	template_name = 'odevzdavatko/seznam.html' | ||||||
| 
 | 
 | ||||||
| class SeznamAktualnichReseniView(SeznamReseniView): | class SeznamAktualnichReseniView(SeznamReseniView): | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		qs = super().get_queryset() | 		qs = super().get_queryset() | ||||||
| 		akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik	# .get_solo() vrátí tu jedinou instanci, asi... | 		akt_rocnik = Nastaveni.get_solo().aktualni_rocnik	# .get_solo() vrátí tu jedinou instanci, asi... | ||||||
| 		resitele = resi_v_rocniku(akt_rocnik) | 		resitele = resi_v_rocniku(akt_rocnik) | ||||||
| 		qs = qs.filter(resitele__in=resitele)	# FIXME: Najde řešení i ze starých ročníků, která odevzdal alespoň jeden aktuální řešitel | 		qs = qs.filter(resitele__in=resitele)	# FIXME: Najde řešení i ze starých ročníků, která odevzdal alespoň jeden aktuální řešitel | ||||||
| 		return qs | 		return qs | ||||||
|  | @ -378,7 +382,7 @@ class VlozReseniView(LoginRequiredMixin, FormView): | ||||||
| 
 | 
 | ||||||
| 	def form_valid(self, form): | 	def form_valid(self, form): | ||||||
| 		data = form.cleaned_data | 		data = form.cleaned_data | ||||||
| 		nove_reseni = m.Reseni.objects.create( | 		nove_reseni = Reseni.objects.create( | ||||||
| 			cas_doruceni=data['cas_doruceni'], | 			cas_doruceni=data['cas_doruceni'], | ||||||
| 			forma=data['forma'], | 			forma=data['forma'], | ||||||
| 			poznamka=data['poznamka'], | 			poznamka=data['poznamka'], | ||||||
|  | @ -405,35 +409,35 @@ class VlozReseniView(LoginRequiredMixin, FormView): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class NahrajReseniRozcestnikTematekView(LoginRequiredMixin, ListView): | class NahrajReseniRozcestnikTematekView(LoginRequiredMixin, ListView): | ||||||
| 	model = m.Problem | 	model = Problem | ||||||
| 	template_name = 'odevzdavatko/nahraj_reseni_nadproblem.html' | 	template_name = 'odevzdavatko/nahraj_reseni_nadproblem.html' | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		return super().get_queryset().filter(stav=m.Problem.STAV_ZADANY, nadproblem__isnull=True) | 		return super().get_queryset().filter(stav=Problem.STAV_ZADANY, nadproblem__isnull=True) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class NahrajReseniView(LoginRequiredMixin, CreateView): | class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 	model = m.Reseni | 	model = Reseni | ||||||
| 	template_name = 'odevzdavatko/nahraj_reseni.html' | 	template_name = 'odevzdavatko/nahraj_reseni.html' | ||||||
| 	form_class = f.NahrajReseniForm | 	form_class = f.NahrajReseniForm | ||||||
| 	nadproblem: m.Problem | 	nadproblem: Problem | ||||||
| 
 | 
 | ||||||
| 	def setup(self, request, *args, **kwargs): | 	def setup(self, request, *args, **kwargs): | ||||||
| 		super().setup(request, *args, **kwargs) | 		super().setup(request, *args, **kwargs) | ||||||
| 		nadproblem_id = self.kwargs["nadproblem_id"] | 		nadproblem_id = self.kwargs["nadproblem_id"] | ||||||
| 		self.nadproblem = get_object_or_404(m.Problem, id=nadproblem_id) | 		self.nadproblem = get_object_or_404(Problem, id=nadproblem_id) | ||||||
| 
 | 
 | ||||||
| 	def get(self, request, *args, **kwargs): | 	def get(self, request, *args, **kwargs): | ||||||
| 		# Zaříznutí nezadaných problémů | 		# Zaříznutí nezadaných problémů | ||||||
| 		if self.nadproblem.stav != m.Problem.STAV_ZADANY: | 		if self.nadproblem.stav != Problem.STAV_ZADANY: | ||||||
| 			raise PermissionDenied() | 			raise PermissionDenied() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		# Zaříznutí starých řešitelů: | 		# Zaříznutí starých řešitelů: | ||||||
| 		# FIXME: Je to tady dost naprasené, mělo by to asi být jinde… | 		# FIXME: Je to tady dost naprasené, mělo by to asi být jinde… | ||||||
| 		osoba = m.Osoba.objects.get(user=self.request.user) | 		osoba = Osoba.objects.get(user=self.request.user) | ||||||
| 		resitel = osoba.resitel | 		resitel = osoba.resitel | ||||||
| 		if resitel.rok_maturity <= m.Nastaveni.get_solo().aktualni_rocnik.prvni_rok: | 		if resitel.rok_maturity <= Nastaveni.get_solo().aktualni_rocnik.prvni_rok: | ||||||
| 			return render(request, 'universal.html', { | 			return render(request, 'universal.html', { | ||||||
| 				'title': 'Nelze odevzdat', | 				'title': 'Nelze odevzdat', | ||||||
| 				'error': 'Zdá se, že jsi již odmaturoval/a, a tedy nemůžeš odevzdat do našeho semináře řešení.', | 				'error': 'Zdá se, že jsi již odmaturoval/a, a tedy nemůžeš odevzdat do našeho semináře řešení.', | ||||||
|  | @ -445,7 +449,7 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 		nadproblem_id = self.nadproblem.id | 		nadproblem_id = self.nadproblem.id | ||||||
| 		return { | 		return { | ||||||
| 			"nadproblem_id": nadproblem_id, | 			"nadproblem_id": nadproblem_id, | ||||||
| 			"problem": [] if self.nadproblem.podproblem.filter(stav=m.Problem.STAV_ZADANY).exists() else nadproblem_id | 			"problem": [] if self.nadproblem.podproblem.filter(stav=Problem.STAV_ZADANY).exists() else nadproblem_id | ||||||
| 
 | 
 | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -457,7 +461,7 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 			data['prilohy'] = f.ReseniSPrilohamiFormSet() | 			data['prilohy'] = f.ReseniSPrilohamiFormSet() | ||||||
| 
 | 
 | ||||||
| 		data["nadproblem_id"] = self.nadproblem.id | 		data["nadproblem_id"] = self.nadproblem.id | ||||||
| 		data["nadproblem"] = get_object_or_404(m.Problem, id=self.nadproblem.id) | 		data["nadproblem"] = get_object_or_404(Problem, id=self.nadproblem.id) | ||||||
| 		return data | 		return data | ||||||
| 
 | 
 | ||||||
| 	# FIXME prepsat tak, aby form_valid se volalo jen tehdy, kdyz je form i formset validni | 	# FIXME prepsat tak, aby form_valid se volalo jen tehdy, kdyz je form i formset validni | ||||||
|  | @ -469,17 +473,17 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 			return super().form_invalid(form) | 			return super().form_invalid(form) | ||||||
| 		with transaction.atomic(): | 		with transaction.atomic(): | ||||||
| 			self.object = form.save() | 			self.object = form.save() | ||||||
| 			self.object.resitele.add(m.Resitel.objects.get(osoba__user = self.request.user)) | 			self.object.resitele.add(Resitel.objects.get(osoba__user = self.request.user)) | ||||||
| 			self.object.resitele.add(*form.cleaned_data["resitele"]) | 			self.object.resitele.add(*form.cleaned_data["resitele"]) | ||||||
| 			self.object.cas_doruceni = timezone.now() | 			self.object.cas_doruceni = timezone.now() | ||||||
| 			self.object.forma = m.Reseni.FORMA_UPLOAD | 			self.object.forma = Reseni.FORMA_UPLOAD | ||||||
| 			self.object.save() | 			self.object.save() | ||||||
| 
 | 
 | ||||||
| 			prilohy.instance = self.object | 			prilohy.instance = self.object | ||||||
| 			prilohy.save() | 			prilohy.save() | ||||||
| 
 | 
 | ||||||
| 		for hodnoceni in self.object.hodnoceni_set.all(): | 		for hodnoceni in self.object.hodnoceni_set.all(): | ||||||
| 			hodnoceni.deadline_body = m.Deadline.objects.filter(deadline__gte=self.object.cas_doruceni).first() | 			hodnoceni.deadline_body = Deadline.objects.filter(deadline__gte=self.object.cas_doruceni).first() | ||||||
| 			hodnoceni.save() | 			hodnoceni.save() | ||||||
| 
 | 
 | ||||||
| 		# Pošleme mail opravovatelům a garantovi | 		# Pošleme mail opravovatelům a garantovi | ||||||
|  | @ -497,7 +501,7 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 		# FIXME: Víc informativní obsah mailů, možná vč. příloh? | 		# FIXME: Víc informativní obsah mailů, možná vč. příloh? | ||||||
| 		prijemci = map(lambda it: it.osoba.email, prijemci) | 		prijemci = map(lambda it: it.osoba.email, prijemci) | ||||||
| 
 | 
 | ||||||
| 		resitel = m.Osoba.objects.get(user = self.request.user) | 		resitel = Osoba.objects.get(user = self.request.user) | ||||||
| 
 | 
 | ||||||
| 		seznam = "problému " + str(problemy[0]) if len(problemy) == 1 else 'následujícím problémům:\n' + ', \n'.join(map(str, problemy)) | 		seznam = "problému " + str(problemy[0]) if len(problemy) == 1 else 'následujícím problémům:\n' + ', \n'.join(map(str, problemy)) | ||||||
| 		seznam_do_subjectu = "problému " + str(problemy[0]) + ("" if len(problemy) == 1 else f" (a dalším { len(problemy) - 1 })") | 		seznam_do_subjectu = "problému " + str(problemy[0]) + ("" if len(problemy) == 1 else f" (a dalším { len(problemy) - 1 })") | ||||||
|  |  | ||||||
|  | @ -16,10 +16,12 @@ from django.db import transaction | ||||||
| from django.http import HttpResponse | from django.http import HttpResponse | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| 
 | 
 | ||||||
| import seminar.models as s | 
 | ||||||
| import personalni.models as m | import personalni.models as m | ||||||
| from soustredeni.models import Soustredeni | from soustredeni.models import Soustredeni | ||||||
| from odevzdavatko.models import Hodnoceni | from odevzdavatko.models import Hodnoceni | ||||||
|  | from tvorba.models import Clanek, Uloha, Tema | ||||||
|  | from various.models import Nastaveni | ||||||
| from .forms import PrihlaskaForm, ProfileEditForm, PoMaturiteProfileEditForm | from .forms import PrihlaskaForm, ProfileEditForm, PoMaturiteProfileEditForm | ||||||
| 
 | 
 | ||||||
| from datetime import date | from datetime import date | ||||||
|  | @ -94,7 +96,7 @@ class OrgoRozcestnikView(TemplateView): | ||||||
| 	def get_context_data(self, **kwargs): | 	def get_context_data(self, **kwargs): | ||||||
| 		context = super().get_context_data(**kwargs) | 		context = super().get_context_data(**kwargs) | ||||||
| 		context['posledni_soustredeni'] = Soustredeni.objects.order_by('-datum_konce').first() | 		context['posledni_soustredeni'] = Soustredeni.objects.order_by('-datum_konce').first() | ||||||
| 		nastaveni = s.Nastaveni.objects.first() | 		nastaveni = Nastaveni.objects.first() | ||||||
| 		aktualni_rocnik = nastaveni.aktualni_rocnik | 		aktualni_rocnik = nastaveni.aktualni_rocnik | ||||||
| 		context['posledni_cislo_url'] = nastaveni.aktualni_cislo.verejne_url() | 		context['posledni_cislo_url'] = nastaveni.aktualni_cislo.verejne_url() | ||||||
| 		# TODO možná chceme odkazovat na právě rozpracované číslo, a ne to poslední vydané | 		# TODO možná chceme odkazovat na právě rozpracované číslo, a ne to poslední vydané | ||||||
|  | @ -118,11 +120,11 @@ class OrgoRozcestnikView(TemplateView): | ||||||
| 		context["pocty_neopravenych_reseni"] = [(it['problem__nazev'], it['cas'].date) for it in pocty_neopravenych_reseni.all()] | 		context["pocty_neopravenych_reseni"] = [(it['problem__nazev'], it['cas'].date) for it in pocty_neopravenych_reseni.all()] | ||||||
| 
 | 
 | ||||||
| 		#FIXME: přidat stav='STAV_ZADANY' | 		#FIXME: přidat stav='STAV_ZADANY' | ||||||
| 		temata = s.Tema.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | 		temata = Tema.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | ||||||
| 			rocnik=aktualni_rocnik).distinct() | 			rocnik=aktualni_rocnik).distinct() | ||||||
| 		ulohy = s.Uloha.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | 		ulohy = Uloha.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | ||||||
| 			cislo_zadani__rocnik=aktualni_rocnik).distinct() | 			cislo_zadani__rocnik=aktualni_rocnik).distinct() | ||||||
| 		clanky = s.Clanek.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | 		clanky = Clanek.objects.filter(Q(garant=organizator) | Q(autor=organizator) | Q(opravovatele__in=[organizator]), | ||||||
| 			cislo__rocnik=aktualni_rocnik).distinct() | 			cislo__rocnik=aktualni_rocnik).distinct() | ||||||
| 
 | 
 | ||||||
| 		context['temata'] = temata | 		context['temata'] = temata | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ from django.conf import settings | ||||||
| from personalni.models import Resitel, Organizator | from personalni.models import Resitel, Organizator | ||||||
| 
 | 
 | ||||||
| from seminar.models.base import SeminarModelBase | from seminar.models.base import SeminarModelBase | ||||||
| import tvorba.models as am | from tvorba.models import Rocnik, Problem, aux_generate_filename | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
|  | @ -27,7 +27,7 @@ class Soustredeni(SeminarModelBase): | ||||||
| 	# Interní ID | 	# Interní ID | ||||||
| 	id = models.AutoField(primary_key = True) | 	id = models.AutoField(primary_key = True) | ||||||
| 
 | 
 | ||||||
| 	rocnik = models.ForeignKey(am.Rocnik, verbose_name='ročník', related_name='soustredeni', | 	rocnik = models.ForeignKey(Rocnik, verbose_name='ročník', related_name='soustredeni', | ||||||
| 		on_delete=models.PROTECT) | 		on_delete=models.PROTECT) | ||||||
| 
 | 
 | ||||||
| 	datum_zacatku = models.DateField('datum začátku', blank=True, null=True, | 	datum_zacatku = models.DateField('datum začátku', blank=True, null=True, | ||||||
|  | @ -143,13 +143,13 @@ class Soustredeni_Organizatori(SeminarModelBase): | ||||||
| def generate_filename_konfera(self, filename): | def generate_filename_konfera(self, filename): | ||||||
| 	return os.path.join( | 	return os.path.join( | ||||||
| 		settings.SEMINAR_KONFERY_DIR, | 		settings.SEMINAR_KONFERY_DIR, | ||||||
| 		am.aux_generate_filename(self, filename) | 		aux_generate_filename(self, filename) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| ## | ## | ||||||
| 
 | 
 | ||||||
| @reversion.register(ignore_duplicates=True) | @reversion.register(ignore_duplicates=True) | ||||||
| class Konfera(am.Problem): | class Konfera(Problem): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		db_table = 'seminar_konfera' | 		db_table = 'seminar_konfera' | ||||||
| 		verbose_name = 'Konfera' | 		verbose_name = 'Konfera' | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ from typing import Sequence | ||||||
| import lorem | import lorem | ||||||
| 
 | 
 | ||||||
| from .models import Soustredeni, Konfera | from .models import Soustredeni, Konfera | ||||||
| import seminar.models as am # tvorba | from tvorba.models import Rocnik | ||||||
| import personalni.models as pm | import personalni.models as pm | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
|  | @ -25,7 +25,7 @@ def gen_soustredeni( | ||||||
| 	for _ in range(1, 10):  # FIXME Tu range si změňte jak chcete, nevím, co přesně znamená size (asi Anet?) | 	for _ in range(1, 10):  # FIXME Tu range si změňte jak chcete, nevím, co přesně znamená size (asi Anet?) | ||||||
| 		datum_zacatku = datetime.date(rnd.randint(2000, 2020), rnd.randint(1, 12), rnd.randint(1, 28)) | 		datum_zacatku = datetime.date(rnd.randint(2000, 2020), rnd.randint(1, 12), rnd.randint(1, 28)) | ||||||
| 		working_sous = Soustredeni.objects.create( | 		working_sous = Soustredeni.objects.create( | ||||||
| 			rocnik=am.Rocnik.objects.order_by('?').first(), | 			rocnik=Rocnik.objects.order_by('?').first(), | ||||||
| 			verejne_db=rnd.choice([True, False]), | 			verejne_db=rnd.choice([True, False]), | ||||||
| 			misto=rnd.choice(['Kremrolovice', 'Indiánov', 'U zmzliny', 'Vafláreň', 'Větrník', 'Horní Rakvička', 'Dolní cheesecake']), | 			misto=rnd.choice(['Kremrolovice', 'Indiánov', 'U zmzliny', 'Vafláreň', 'Větrník', 'Horní Rakvička', 'Dolní cheesecake']), | ||||||
| 			typ=rnd.choice(['jarni', 'podzimni', 'vikend']), | 			typ=rnd.choice(['jarni', 'podzimni', 'vikend']), | ||||||
|  |  | ||||||
|  | @ -1,30 +1,30 @@ | ||||||
| from django import template | from django import template | ||||||
| from django.utils.safestring import mark_safe | from django.utils.safestring import mark_safe | ||||||
| register = template.Library() | register = template.Library() | ||||||
| import seminar.models as m | from tvorba.models import Deadline | ||||||
| 
 | 
 | ||||||
| @register.filter(name='deadline_kratseji') | @register.filter(name='deadline_kratseji') | ||||||
| def deadline_kratsi_text(deadline: m.Deadline): | def deadline_kratsi_text(deadline: Deadline): | ||||||
| 	if deadline is None: | 	if deadline is None: | ||||||
| 		return 'NONE' | 		return 'NONE' | ||||||
| 	strings = { | 	strings = { | ||||||
| 		m.Deadline.TYP_PRVNI: f"{deadline.cislo} ⭯", | 		Deadline.TYP_PRVNI: f"{deadline.cislo} ⭯", | ||||||
| 		m.Deadline.TYP_SOUS: f"{deadline.cislo} Ⓢ", | 		Deadline.TYP_SOUS: f"{deadline.cislo} Ⓢ", | ||||||
| 		m.Deadline.TYP_PRVNI_A_SOUS: f"{deadline.cislo} ⭯Ⓢ", | 		Deadline.TYP_PRVNI_A_SOUS: f"{deadline.cislo} ⭯Ⓢ", | ||||||
| 		m.Deadline.TYP_CISLA: f"{deadline.cislo} ✓", | 		Deadline.TYP_CISLA: f"{deadline.cislo} ✓", | ||||||
| 		} | 		} | ||||||
| 	return strings[deadline.typ] | 	return strings[deadline.typ] | ||||||
| 
 | 
 | ||||||
| @register.filter(name='deadline_html') | @register.filter(name='deadline_html') | ||||||
| def deadline_html(deadline: m.Deadline): | def deadline_html(deadline: Deadline): | ||||||
| 	if deadline is None: | 	if deadline is None: | ||||||
| 		return 'Neznámý deadline' | 		return 'Neznámý deadline' | ||||||
| 	text = deadline_kratsi_text(deadline) | 	text = deadline_kratsi_text(deadline) | ||||||
| 	classes = { | 	classes = { | ||||||
| 		m.Deadline.TYP_PRVNI: 'preddeadline', | 		Deadline.TYP_PRVNI: 'preddeadline', | ||||||
| 		m.Deadline.TYP_SOUS: 'sous_deadline', | 		Deadline.TYP_SOUS: 'sous_deadline', | ||||||
| 		m.Deadline.TYP_PRVNI_A_SOUS: 'sous_deadline', | 		Deadline.TYP_PRVNI_A_SOUS: 'sous_deadline', | ||||||
| 		m.Deadline.TYP_CISLA: 'final_deadline', | 		Deadline.TYP_CISLA: 'final_deadline', | ||||||
| 		} | 		} | ||||||
| 	return mark_safe(f'<span class="{classes[deadline.typ]}" title="{deadline}">{text}</span>') | 	return mark_safe(f'<span class="{classes[deadline.typ]}" title="{deadline}">{text}</span>') | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,9 @@ import lorem | ||||||
| import django.contrib.auth | import django.contrib.auth | ||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| from seminar.models import Rocnik, Cislo, Deadline, Problem, Tema, Uloha, TextNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, Text, UlohaZadaniNode | from .models import Rocnik, Cislo, Deadline, Problem, Tema, Uloha | ||||||
|  | 
 | ||||||
|  | from odevzdavatko.models import Reseni, Hodnoceni | ||||||
| import seminar.models as m | import seminar.models as m | ||||||
| 
 | 
 | ||||||
| from treenode.treelib import all_children, insert_last_child, all_children_of_type, create_node_after | from treenode.treelib import all_children, insert_last_child, all_children_of_type, create_node_after | ||||||
|  | @ -54,12 +56,12 @@ def gen_zadani_ulohy(rnd, cisla, organizatori, pocet_oboru, poradi_cisla, poradi | ||||||
| 		rnd.choice(jmeno), | 		rnd.choice(jmeno), | ||||||
| 		rnd.choice(kde)] | 		rnd.choice(kde)] | ||||||
| 		) | 		) | ||||||
| 	text_zadani = Text.objects.create( | 	text_zadani = m.Text.objects.create( | ||||||
| 		na_web = text, | 		na_web = text, | ||||||
| 		do_cisla = text, | 		do_cisla = text, | ||||||
| 	) | 	) | ||||||
| 	zad = TextNode.objects.create(text = text_zadani, root = p.cislo_zadani.rocnik.rocniknode) | 	zad = m.TextNode.objects.create(text = text_zadani, root = p.cislo_zadani.rocnik.rocniknode) | ||||||
| 	uloha_zadani = UlohaZadaniNode.objects.create(uloha = p, first_child = zad, root = p.cislo_zadani.rocnik.rocniknode) | 	uloha_zadani = m.UlohaZadaniNode.objects.create(uloha = p, first_child = zad, root = p.cislo_zadani.rocnik.rocniknode) | ||||||
| 	p.ulohazadaninode = uloha_zadani | 	p.ulohazadaninode = uloha_zadani | ||||||
| 	otec_syn(cisla[poradi_cisla-2-1].cislonode, uloha_zadani) | 	otec_syn(cisla[poradi_cisla-2-1].cislonode, uloha_zadani) | ||||||
| 
 | 
 | ||||||
|  | @ -76,12 +78,12 @@ def gen_vzoroveho_reseni_ulohy(rnd, organizatori, uloha, pocet_opravovatelu): | ||||||
| 
 | 
 | ||||||
| 	# Generování vzorového řešení. | 	# Generování vzorového řešení. | ||||||
| 	obsah = rnd.choice(reseni) | 	obsah = rnd.choice(reseni) | ||||||
| 	text_vzoraku = Text.objects.create( | 	text_vzoraku = m.Text.objects.create( | ||||||
| 		na_web = obsah, | 		na_web = obsah, | ||||||
| 		do_cisla = obsah | 		do_cisla = obsah | ||||||
| 	) | 	) | ||||||
| 	vzorak = TextNode.objects.create(text = text_vzoraku, root = uloha.cislo_zadani.rocnik.rocniknode) | 	vzorak = m.TextNode.objects.create(text = text_vzoraku, root = uloha.cislo_zadani.rocnik.rocniknode) | ||||||
| 	uloha_vzorak = UlohaVzorakNode.objects.create(uloha = uloha, first_child = vzorak, root = uloha.cislo_zadani.rocnik.rocniknode) | 	uloha_vzorak = m.UlohaVzorakNode.objects.create(uloha = uloha, first_child = vzorak, root = uloha.cislo_zadani.rocnik.rocniknode) | ||||||
| 	uloha.ulohavzoraknode = uloha_vzorak | 	uloha.ulohavzoraknode = uloha_vzorak | ||||||
| 
 | 
 | ||||||
| 	uloha.opravovatele.set(rnd.sample(organizatori, pocet_opravovatelu)) | 	uloha.opravovatele.set(rnd.sample(organizatori, pocet_opravovatelu)) | ||||||
|  | @ -132,7 +134,7 @@ def gen_rocniky(last_rocnik, size): | ||||||
| 	node = None | 	node = None | ||||||
| 	for ri in range(min(last_rocnik - size, 1), last_rocnik + 1): | 	for ri in range(min(last_rocnik - size, 1), last_rocnik + 1): | ||||||
| 		rocnik = Rocnik.objects.create(prvni_rok = 1993 + ri, rocnik = ri) | 		rocnik = Rocnik.objects.create(prvni_rok = 1993 + ri, rocnik = ri) | ||||||
| 		node2 = RocnikNode.objects.create(rocnik = rocnik, succ = node) | 		node2 = m.RocnikNode.objects.create(rocnik = rocnik, succ = node) | ||||||
| 		rocnik.save() | 		rocnik.save() | ||||||
| 		node = node2 | 		node = node2 | ||||||
| 		rocniky.append(rocnik) | 		rocniky.append(rocnik) | ||||||
|  | @ -167,7 +169,7 @@ def gen_cisla(rnd, rocniky): | ||||||
| 				datum_vydani=vydano, | 				datum_vydani=vydano, | ||||||
| 				verejne_db=True, | 				verejne_db=True, | ||||||
| 			) | 			) | ||||||
| 			node2 = CisloNode.objects.get(cislo = cislo) | 			node2 = m.CisloNode.objects.get(cislo = cislo) | ||||||
| 			node2.succ = node | 			node2.succ = node | ||||||
| 			node2.root = rocnik.rocniknode | 			node2.root = rocnik.rocniknode | ||||||
| 			cislo.save() | 			cislo.save() | ||||||
|  | @ -195,7 +197,7 @@ def add_first_child(node, child): | ||||||
| 
 | 
 | ||||||
| def get_text(): | def get_text(): | ||||||
| 	odstavec = lorem.paragraph() | 	odstavec = lorem.paragraph() | ||||||
| 	return Text.objects.create(na_web = odstavec, do_cisla = odstavec)	 | 	return m.Text.objects.create(na_web = odstavec, do_cisla = odstavec) | ||||||
| 
 | 
 | ||||||
| def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | ||||||
| 	tema = Tema.objects.create( | 	tema = Tema.objects.create( | ||||||
|  | @ -215,32 +217,32 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | ||||||
| 	for cislo in cisla: | 	for cislo in cisla: | ||||||
| 		# Přidáme TemaVCisleNode do daného čísla | 		# Přidáme TemaVCisleNode do daného čísla | ||||||
| 		cislo_node = cislo.cislonode	 | 		cislo_node = cislo.cislonode	 | ||||||
| 		tema_cislo_node = TemaVCisleNode.objects.create(tema = tema, root = cislo_node.root) | 		tema_cislo_node = m.TemaVCisleNode.objects.create(tema = tema, root = cislo_node.root) | ||||||
| 		insert_last_child(cislo_node, tema_cislo_node) | 		insert_last_child(cislo_node, tema_cislo_node) | ||||||
| 		 | 		 | ||||||
| 		# Přidávání obsahu do čísla | 		# Přidávání obsahu do čísla | ||||||
| 		cast_node = m.CastNode.objects.create(nadpis = "Příspěvek k číslu {}".format(cislo.kod), root=cislo_node.root) | 		cast_node = m.CastNode.objects.create(nadpis = "Příspěvek k číslu {}".format(cislo.kod), root=cislo_node.root) | ||||||
| 		add_first_child(tema_cislo_node, cast_node) | 		add_first_child(tema_cislo_node, cast_node) | ||||||
| 	 | 	 | ||||||
| 		text_node = TextNode.objects.create(text = get_text(), root=cislo_node.root) | 		text_node = m.TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||||
| 		add_first_child(cast_node, text_node) | 		add_first_child(cast_node, text_node) | ||||||
| 
 | 
 | ||||||
| 		cast_node2 = m.CastNode.objects.create(nadpis = "První podproblém", root=cislo_node.root) | 		cast_node2 = m.CastNode.objects.create(nadpis = "První podproblém", root=cislo_node.root) | ||||||
| 		add_first_child(text_node, cast_node2) | 		add_first_child(text_node, cast_node2) | ||||||
| 		 | 		 | ||||||
| 		text_node2 = TextNode.objects.create(text = get_text(), root=cislo_node.root) | 		text_node2 = m.TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||||
| 		add_first_child(cast_node2, text_node2) | 		add_first_child(cast_node2, text_node2) | ||||||
| 		 | 		 | ||||||
| 		cast_node3 = m.CastNode.objects.create(nadpis = "Druhý podproblém", root=cislo_node.root) | 		cast_node3 = m.CastNode.objects.create(nadpis = "Druhý podproblém", root=cislo_node.root) | ||||||
| 		add_first_child(text_node2, cast_node3) | 		add_first_child(text_node2, cast_node3) | ||||||
| 
 | 
 | ||||||
| 		text_node3 = TextNode.objects.create(text = get_text(), root=cislo_node.root) | 		text_node3 = m.TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||||
| 		add_first_child(cast_node3, text_node3) | 		add_first_child(cast_node3, text_node3) | ||||||
| 
 | 
 | ||||||
| 		cast_node4 = m.CastNode.objects.create(nadpis = "Třetí podproblém", root=cislo_node.root) | 		cast_node4 = m.CastNode.objects.create(nadpis = "Třetí podproblém", root=cislo_node.root) | ||||||
| 		add_first_child(text_node3, cast_node4)	 | 		add_first_child(text_node3, cast_node4)	 | ||||||
| 
 | 
 | ||||||
| 		text_node4 = TextNode.objects.create(text = get_text(), root=cislo_node.root) | 		text_node4 = m.TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||||
| 		add_first_child(cast_node3, text_node4) | 		add_first_child(cast_node3, text_node4) | ||||||
| 		 | 		 | ||||||
| 		cast_node3a = m.CastNode.objects.create(nadpis = "Podproblém paralelní s " | 		cast_node3a = m.CastNode.objects.create(nadpis = "Podproblém paralelní s " | ||||||
|  | @ -248,7 +250,7 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | ||||||
| 		cast_node3.succ = cast_node3a | 		cast_node3.succ = cast_node3a | ||||||
| 		cast_node3.save() | 		cast_node3.save() | ||||||
| 
 | 
 | ||||||
| 		text_node3a = TextNode.objects.create(text = get_text(), root=cislo_node.root) | 		text_node3a = m.TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||||
| 		add_first_child(cast_node3a, text_node3a) | 		add_first_child(cast_node3a, text_node3a) | ||||||
| 
 | 
 | ||||||
| 		# Občas přidáme mezičíslo | 		# Občas přidáme mezičíslo | ||||||
|  | @ -261,8 +263,8 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | ||||||
| 			add_first_child(mezicislo_node, cast_node_mezicislo) | 			add_first_child(mezicislo_node, cast_node_mezicislo) | ||||||
| 
 | 
 | ||||||
| 			odstavec = lorem.paragraph() | 			odstavec = lorem.paragraph() | ||||||
| 			text_mezicislo = Text.objects.create(na_web = odstavec, do_cisla = odstavec) | 			text_mezicislo = m.Text.objects.create(na_web = odstavec, do_cisla = odstavec) | ||||||
| 			text_node_mezicislo = TextNode.objects.create(text = text_mezicislo, root=cislo_node.root) | 			text_node_mezicislo = m.TextNode.objects.create(text = text_mezicislo, root=cislo_node.root) | ||||||
| 			add_first_child(cast_node_mezicislo, text_node_mezicislo) | 			add_first_child(cast_node_mezicislo, text_node_mezicislo) | ||||||
| 
 | 
 | ||||||
| 	return tema | 	return tema | ||||||
|  | @ -306,7 +308,7 @@ def gen_temata(rnd, rocniky, rocnik_cisla, organizatori): | ||||||
| 
 | 
 | ||||||
| 			# Vyrobíme TemaVCisleNody pro obsah | 			# Vyrobíme TemaVCisleNody pro obsah | ||||||
| 			for i in range(zacatek_tematu, konec_tematu+1): | 			for i in range(zacatek_tematu, konec_tematu+1): | ||||||
| 				node = TemaVCisleNode.objects.create(tema = t,root=rocnik.rocniknode) | 				node = m.TemaVCisleNode.objects.create(tema = t,root=rocnik.rocniknode) | ||||||
| 				# FIXME: Není to off-by-one? | 				# FIXME: Není to off-by-one? | ||||||
| 				otec = cisla[i-1].cislonode | 				otec = cisla[i-1].cislonode | ||||||
| 				otec_syn(otec, node) | 				otec_syn(otec, node) | ||||||
|  | @ -359,12 +361,12 @@ def gen_ulohy_tematu(rnd, organizatori, resitele, tema, kod, cislo, cislo_se_vzo | ||||||
| 		rnd.choice(jmeno),  | 		rnd.choice(jmeno),  | ||||||
| 		rnd.choice(kde)] | 		rnd.choice(kde)] | ||||||
| 		) | 		) | ||||||
| 	text_zadani = Text.objects.create( | 	text_zadani = m.Text.objects.create( | ||||||
| 		na_web = obsah, | 		na_web = obsah, | ||||||
| 		do_cisla = obsah, | 		do_cisla = obsah, | ||||||
| 		) | 		) | ||||||
| 	zad = TextNode.objects.create(text = text_zadani, root=tema.temavcislenode_set.first().root) | 	zad = m.TextNode.objects.create(text = text_zadani, root=tema.temavcislenode_set.first().root) | ||||||
| 	uloha_zadani = UlohaZadaniNode.objects.create(uloha=uloha, first_child = zad, root=tema.temavcislenode_set.first().root) | 	uloha_zadani = m.UlohaZadaniNode.objects.create(uloha=uloha, first_child = zad, root=tema.temavcislenode_set.first().root) | ||||||
| 	uloha.ulohazadaninode = uloha_zadani | 	uloha.ulohazadaninode = uloha_zadani | ||||||
| 
 | 
 | ||||||
| 	# Generování řešení a hodnocení k úloze | 	# Generování řešení a hodnocení k úloze | ||||||
|  | @ -396,7 +398,7 @@ def gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori, | ||||||
| 			else: | 			else: | ||||||
| 				cislo_se_vzorakem = cislo_se_vzorakem.first() | 				cislo_se_vzorakem = cislo_se_vzorakem.first() | ||||||
| 
 | 
 | ||||||
| 			for tema_node in all_children_of_type(cislo.cislonode, TemaVCisleNode): | 			for tema_node in all_children_of_type(cislo.cislonode, m.TemaVCisleNode): | ||||||
| 				tema = tema_node.tema | 				tema = tema_node.tema | ||||||
| 					 | 					 | ||||||
| 				# Pokud už témátko skončilo, žádné úložky negenerujeme | 				# Pokud už témátko skončilo, žádné úložky negenerujeme | ||||||
|  | @ -419,7 +421,7 @@ def gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori, | ||||||
| 					# Najdeme správný TemaVCisleNode pro vložení vzoráku | 					# Najdeme správný TemaVCisleNode pro vložení vzoráku | ||||||
| 					res_tema_node = None; | 					res_tema_node = None; | ||||||
| 					for node in all_children(cislo_se_vzorakem.cislonode): | 					for node in all_children(cislo_se_vzorakem.cislonode): | ||||||
| 						if isinstance(node, TemaVCisleNode):  | 						if isinstance(node, m.TemaVCisleNode): | ||||||
| 							if node.tema == tema: | 							if node.tema == tema: | ||||||
| 								res_tema_node = node | 								res_tema_node = node | ||||||
| 					if res_tema_node is None: | 					if res_tema_node is None: | ||||||
|  | @ -448,16 +450,16 @@ def gen_clanek(rnd, organizatori, resitele): | ||||||
| 		) | 		) | ||||||
| 	clanek.save() | 	clanek.save() | ||||||
| 
 | 
 | ||||||
| 	reseni = m.Reseni.objects.create( | 	reseni = Reseni.objects.create( | ||||||
| 		zverejneno=True, | 		zverejneno=True, | ||||||
| 		) | 		) | ||||||
| 	reseni.resitele.add(rnd.choice(resitele)) | 	reseni.resitele.add(rnd.choice(resitele)) | ||||||
| 	reseni.save() | 	reseni.save() | ||||||
| 
 | 
 | ||||||
| 	cislo = m.Cislo.objects.get(rocnik__rocnik=22, poradi=2) | 	cislo = Cislo.objects.get(rocnik__rocnik=22, poradi=2) | ||||||
| 	cislonode = cislo.cislonode | 	cislonode = cislo.cislonode | ||||||
| 
 | 
 | ||||||
| 	hodnoceni = m.Hodnoceni.objects.create( | 	hodnoceni = Hodnoceni.objects.create( | ||||||
| 		body=15.0, | 		body=15.0, | ||||||
| 		cislo_body=cislo, | 		cislo_body=cislo, | ||||||
| 		reseni=reseni, | 		reseni=reseni, | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ from django.core.exceptions import ObjectDoesNotExist | ||||||
| 
 | 
 | ||||||
| import personalni.models | import personalni.models | ||||||
| 
 | 
 | ||||||
| import seminar.models as m | import tvorba.models as m | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def resi_v_rocniku(rocnik, cislo=None): | def resi_v_rocniku(rocnik, cislo=None): | ||||||
|  |  | ||||||
|  | @ -14,12 +14,11 @@ from django.db.models import Q, Sum, Count | ||||||
| from django.views.generic.base import RedirectView | from django.views.generic.base import RedirectView | ||||||
| from django.core.exceptions import PermissionDenied | from django.core.exceptions import PermissionDenied | ||||||
| 
 | 
 | ||||||
| import seminar.models as s |  | ||||||
| import seminar.models as m | import seminar.models as m | ||||||
| from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, \ | from personalni.models import Resitel | ||||||
| 	Resitel, Novinky, Tema, Clanek, \ | from soustredeni.models import Konfera | ||||||
| 	Deadline  # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | from tvorba.models import Problem, Cislo, Rocnik, Tema, Clanek, Deadline, Uloha | ||||||
| #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | from various.models import Nastaveni | ||||||
| from treenode import treelib | from treenode import treelib | ||||||
| import treenode.templatetags as tnltt | import treenode.templatetags as tnltt | ||||||
| import treenode.serializers as vr | import treenode.serializers as vr | ||||||
|  | @ -58,7 +57,7 @@ def get_problemy_k_tematu(tema): | ||||||
| 
 | 
 | ||||||
| # FIXME: Pozor, níž je ještě jeden ProblemView! | # FIXME: Pozor, níž je ještě jeden ProblemView! | ||||||
| #class ProblemView(generic.DetailView): | #class ProblemView(generic.DetailView): | ||||||
| #	model = s.Problem | #	model = Problem | ||||||
| #	# Zkopírujeme template_name od TreeNodeView, protože jsme prakticky jen trošku upravený TreeNodeView | #	# Zkopírujeme template_name od TreeNodeView, protože jsme prakticky jen trošku upravený TreeNodeView | ||||||
| #	template_name = TreeNodeView.template_name | #	template_name = TreeNodeView.template_name | ||||||
| # | # | ||||||
|  | @ -70,17 +69,17 @@ def get_problemy_k_tematu(tema): | ||||||
| #		if False: | #		if False: | ||||||
| #			# Hezčí formátování zbytku :-P | #			# Hezčí formátování zbytku :-P | ||||||
| #			pass | #			pass | ||||||
| #		elif isinstance(self.object, s.Clanek) or  isinstance(self.object, s.Konfera): | #		elif isinstance(self.object, Clanek) or  isinstance(self.object, Konfera): | ||||||
| #			# Tyhle Problémy mají ŘešeníNode | #			# Tyhle Problémy mají ŘešeníNode | ||||||
| #			context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user) | #			context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user) | ||||||
| #		elif isinstance(self.object, s.Uloha): | #		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 | #			# 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_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user) | ||||||
| #			tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user) | #			tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user) | ||||||
| #			context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak]) | #			context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak]) | ||||||
| #		elif isinstance(self.object, s.Tema): | #		elif isinstance(self.object, Tema): | ||||||
| #			rocniknode = self.object.rocnik.rocniknode | #			rocniknode = self.object.rocnik.rocniknode | ||||||
| #			context['tnldata'] = TNLData.filter_treenode(rocniknode, lambda x: isinstance(x, s.TemaVCisleNode)) | #			context['tnldata'] = TNLData.filter_treenode(rocniknode, lambda x: isinstance(x, m.TemaVCisleNode)) | ||||||
| #		else: | #		else: | ||||||
| #			raise ValueError("Obecný problém nejde zobrazit.") | #			raise ValueError("Obecný problém nejde zobrazit.") | ||||||
| #		return context | #		return context | ||||||
|  | @ -115,7 +114,7 @@ def ZadaniTemataView(request): | ||||||
| 	nastaveni = get_object_or_404(Nastaveni) | 	nastaveni = get_object_or_404(Nastaveni) | ||||||
| 	verejne = nastaveni.aktualni_cislo.verejne() | 	verejne = nastaveni.aktualni_cislo.verejne() | ||||||
| 	akt_rocnik = nastaveni.aktualni_cislo.rocnik | 	akt_rocnik = nastaveni.aktualni_cislo.rocnik | ||||||
| 	temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') | 	temata = Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') | ||||||
| 	return render(request, 'tvorba/tematka/rozcestnik.html', | 	return render(request, 'tvorba/tematka/rozcestnik.html', | ||||||
| 				  { | 				  { | ||||||
| 					  'tematka': temata, | 					  'tematka': temata, | ||||||
|  | @ -140,14 +139,14 @@ def ZadaniTemataView(request): | ||||||
| # | # | ||||||
| # | # | ||||||
| #def TematkoView(request, rocnik, tematko): | #def TematkoView(request, rocnik, tematko): | ||||||
| #	nastaveni = s.Nastaveni.objects.first() | #	nastaveni = Nastaveni.objects.first() | ||||||
| #	rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik) | #	rocnik_object = Rocnik.objects.filter(rocnik=rocnik) | ||||||
| #	tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) | #	tematko_object = Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) | ||||||
| #	seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode) | #	seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode) | ||||||
| #	for node, depth in seznam: | #	for node, depth in seznam: | ||||||
| #		if node.isinstance(node, s.KonferaNode): | #		if node.isinstance(node, m.KonferaNode): | ||||||
| #			raise Exception("Not implemented yet") | #			raise Exception("Not implemented yet") | ||||||
| #		if node.isinstance(node, s.PohadkaNode): # Mohu ignorovat, má pod sebou | #		if node.isinstance(node, m.PohadkaNode): # Mohu ignorovat, má pod sebou | ||||||
| #			pass | #			pass | ||||||
| # | # | ||||||
| #	return render(request, 'tvorba/tematka/toaletak.html', {}) | #	return render(request, 'tvorba/tematka/toaletak.html', {}) | ||||||
|  | @ -155,8 +154,8 @@ def ZadaniTemataView(request): | ||||||
| # | # | ||||||
| #def TemataRozcestnikView(request): | #def TemataRozcestnikView(request): | ||||||
| #	print("=============================================") | #	print("=============================================") | ||||||
| #	nastaveni = s.Nastaveni.objects.first() | #	nastaveni = Nastaveni.objects.first() | ||||||
| #	tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) | #	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 | #	tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku | ||||||
| #	for tematko_object in tematka_objects: | #	for tematko_object in tematka_objects: | ||||||
| #		print("AKTUALNI TEMATKO") | #		print("AKTUALNI TEMATKO") | ||||||
|  | @ -278,7 +277,7 @@ def resiteleRocnikuCsvExportView(request, rocnik): | ||||||
| 	assert request.method in ('GET', 'HEAD') | 	assert request.method in ('GET', 'HEAD') | ||||||
| 	return dataResiteluCsvResponse( | 	return dataResiteluCsvResponse( | ||||||
| 		utils.resi_v_rocniku( | 		utils.resi_v_rocniku( | ||||||
| 			get_object_or_404(m.Rocnik, rocnik=rocnik) | 			get_object_or_404(Rocnik, rocnik=rocnik) | ||||||
| 		) | 		) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
|  | @ -291,10 +290,10 @@ def resiteleRocnikuCsvExportView(request, rocnik): | ||||||
| #	def get_template_names(self, **kwargs): | #	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. | #		# 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 = { | #		spravne_templaty = { | ||||||
| #				s.Uloha: "uloha", | #				Uloha: "uloha", | ||||||
| #				s.Tema: "tema", | #				Tema: "tema", | ||||||
| #				s.Konfera: "konfera", | #				Konfera: "konfera", | ||||||
| #				s.Clanek: "clanek", | #				Clanek: "clanek", | ||||||
| #				} | #				} | ||||||
| #		context = super().get_context_data(**kwargs) | #		context = super().get_context_data(**kwargs) | ||||||
| #		return ['tvorba/archiv/problem_' + spravne_templaty[context['object'].__class__]  + '.html'] | #		return ['tvorba/archiv/problem_' + spravne_templaty[context['object'].__class__]  + '.html'] | ||||||
|  | @ -340,10 +339,10 @@ class CisloView(generic.DetailView): | ||||||
| 		deadliny_s_vysledkovkami = [] | 		deadliny_s_vysledkovkami = [] | ||||||
| 
 | 
 | ||||||
| 		nadpisy = { | 		nadpisy = { | ||||||
| 			m.Deadline.TYP_CISLA: "Výsledkovka", | 			Deadline.TYP_CISLA: "Výsledkovka", | ||||||
| 			m.Deadline.TYP_PRVNI: "Výsledkovka do prvního deadlinu", | 			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í", | 			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í", | 			Deadline.TYP_SOUS: "Výsledkovka do deadlinu pro účast na soustředění", | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for deadline in deadliny: | 		for deadline in deadliny: | ||||||
|  | @ -580,5 +579,5 @@ class AktualniRocnikRedirectView(RedirectView): | ||||||
| 	pattern_name = 'seminar_rocnik' | 	pattern_name = 'seminar_rocnik' | ||||||
| 
 | 
 | ||||||
| 	def get_redirect_url(self, *args, **kwargs): | 	def get_redirect_url(self, *args, **kwargs): | ||||||
| 		aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik.rocnik | 		aktualni_rocnik = Nastaveni.get_solo().aktualni_rocnik.rocnik | ||||||
| 		return super().get_redirect_url(rocnik=aktualni_rocnik, *args, **kwargs) | 		return super().get_redirect_url(rocnik=aktualni_rocnik, *args, **kwargs) | ||||||
|  |  | ||||||
|  | @ -5,13 +5,13 @@ from django.db import transaction | ||||||
| from django.forms import Form, CharField, IntegerField | from django.forms import Form, CharField, IntegerField | ||||||
| from django.views.generic import FormView | from django.views.generic import FormView | ||||||
| 
 | 
 | ||||||
| import seminar.models as m | from tvorba.models import Cislo, Problem, Uloha, Tema | ||||||
| from django.shortcuts import render, get_object_or_404 | from django.shortcuts import render, get_object_or_404 | ||||||
| 
 | 
 | ||||||
| def problemView(request, pk): | def problemView(request, pk): | ||||||
| 	# Pokud problém neexistuje, hodíme obyčejnou 404 | 	# Pokud problém neexistuje, hodíme obyčejnou 404 | ||||||
| 	# Taktéž v případě, že takový problém nemá být vidět | 	# Taktéž v případě, že takový problém nemá být vidět | ||||||
| 	problem = get_object_or_404(m.Problem, id=pk, stav__in=[m.Problem.STAV_ZADANY, m.Problem.STAV_VYRESENY]) | 	problem = get_object_or_404(Problem, id=pk, stav__in=[Problem.STAV_ZADANY, Problem.STAV_VYRESENY]) | ||||||
| 	# Problém existuje, neumíme ho zobrazit, renderujeme nějakou haluz | 	# Problém existuje, neumíme ho zobrazit, renderujeme nějakou haluz | ||||||
| 	template = 'universal.html' | 	template = 'universal.html' | ||||||
| 	ctx = { | 	ctx = { | ||||||
|  | @ -32,7 +32,7 @@ class HromadnePridaniForm(Form): | ||||||
| 
 | 
 | ||||||
| 	def clean_tema(self): | 	def clean_tema(self): | ||||||
| 		""" Kontrola, že `tema` je název právě jednoho tématu """ | 		""" Kontrola, že `tema` je název právě jednoho tématu """ | ||||||
| 		if m.Tema.objects.filter( | 		if Tema.objects.filter( | ||||||
| 				nazev__exact=self.cleaned_data['tema'], | 				nazev__exact=self.cleaned_data['tema'], | ||||||
| 				nadproblem=None).count() != 1: | 				nadproblem=None).count() != 1: | ||||||
| 			raise ValidationError("Špatný nebo nepřesně zadaný název témátka") | 			raise ValidationError("Špatný nebo nepřesně zadaný název témátka") | ||||||
|  | @ -67,20 +67,20 @@ class HromadnePridaniView(FormView): | ||||||
| 		dil = cd["dil"] | 		dil = cd["dil"] | ||||||
| 		body = list(map(int, cd["body"].split(","))) | 		body = list(map(int, cd["body"].split(","))) | ||||||
| 
 | 
 | ||||||
| 		t = m.Problem.objects.get(nazev__exact=tema, nadproblem=None) | 		t = Problem.objects.get(nazev__exact=tema, nadproblem=None) | ||||||
| 		with transaction.atomic(): | 		with transaction.atomic(): | ||||||
| 			pfx = f"{t.nazev}, díl {dil}, " | 			pfx = f"{t.nazev}, díl {dil}, " | ||||||
| 
 | 
 | ||||||
| 			for k, b in enumerate(body, 1): | 			for k, b in enumerate(body, 1): | ||||||
| 				u = m.Uloha.objects.create( | 				u = Uloha.objects.create( | ||||||
| 					nadproblem=t, | 					nadproblem=t, | ||||||
| 					nazev=pfx + f"{'úloha' if b > 0 else 'problém'} {k}", | 					nazev=pfx + f"{'úloha' if b > 0 else 'problém'} {k}", | ||||||
| 					autor=t.autor, | 					autor=t.autor, | ||||||
| 					garant=t.garant, | 					garant=t.garant, | ||||||
| 					max_body=b, | 					max_body=b, | ||||||
| 					cislo_zadani=m.Cislo.get(t.rocnik.rocnik, dil), | 					cislo_zadani=Cislo.get(t.rocnik.rocnik, dil), | ||||||
| 					kod=k, | 					kod=k, | ||||||
| 					stav=m.Problem.STAV_ZADANY, | 					stav=Problem.STAV_ZADANY, | ||||||
| 				) | 				) | ||||||
| 				u.opravovatele.set(t.opravovatele.all()) | 				u.opravovatele.set(t.opravovatele.all()) | ||||||
| 		return super().form_valid(form) | 		return super().form_valid(form) | ||||||
|  |  | ||||||
|  | @ -55,5 +55,4 @@ class PasswordResetCompleteView(auth_views.PasswordResetCompleteView): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PasswordChangeView(auth_views.PasswordChangeView): | class PasswordChangeView(auth_views.PasswordChangeView): | ||||||
| 	# template_name = 'seminar/password_change.html' |  | ||||||
| 	success_url = reverse_lazy('titulni_strana') | 	success_url = reverse_lazy('titulni_strana') | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| from django.core.management.base import BaseCommand | from django.core.management.base import BaseCommand | ||||||
| 
 | 
 | ||||||
| from seminar.models import Cislo | from tvorba.models import Cislo | ||||||
| 
 | 
 | ||||||
| from subprocess import CalledProcessError | from subprocess import CalledProcessError | ||||||
| import logging | import logging | ||||||
|  |  | ||||||
|  | @ -1,11 +1,11 @@ | ||||||
| from django.core.management.base import BaseCommand | from django.core.management.base import BaseCommand | ||||||
| import seminar.models as m | from tvorba.models import Deadline | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Command(BaseCommand): | class Command(BaseCommand): | ||||||
| 	help = "Všem deadlinům se zveřejněnou výsledkovkou vygeneruj výsledkovku" | 	help = "Všem deadlinům se zveřejněnou výsledkovkou vygeneruj výsledkovku" | ||||||
| 
 | 
 | ||||||
| 	def handle(self, *args, **options): | 	def handle(self, *args, **options): | ||||||
| 		for deadline in m.Deadline.objects.filter(verejna_vysledkovka=True): | 		for deadline in Deadline.objects.filter(verejna_vysledkovka=True): | ||||||
| 			deadline.vygeneruj_vysledkovku() | 			deadline.vygeneruj_vysledkovku() | ||||||
| 		 | 		 | ||||||
|  |  | ||||||
|  | @ -4,7 +4,9 @@ from django.core.management.base import BaseCommand | ||||||
| from django.core.management import call_command | from django.core.management import call_command | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| 
 | 
 | ||||||
| from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni | from odevzdavatko.models import Reseni | ||||||
|  | from personalni.models import Skola, Resitel | ||||||
|  | from tvorba.models import Rocnik, Cislo, Problem | ||||||
| from various.testutils import create_test_data | from various.testutils import create_test_data | ||||||
| import django.contrib.auth | import django.contrib.auth | ||||||
| User = django.contrib.auth.get_user_model() | User = django.contrib.auth.get_user_model() | ||||||
|  |  | ||||||
|  | @ -7,7 +7,9 @@ from django.contrib.flatpages.models import FlatPage | ||||||
| from django.contrib.sites.models import Site | from django.contrib.sites.models import Site | ||||||
| from django.db import transaction | from django.db import transaction | ||||||
| 
 | 
 | ||||||
| from seminar.models import Rocnik, Cislo, Nastaveni, Osoba, Organizator | from personalni.models import Osoba, Organizator | ||||||
|  | from tvorba.models import Rocnik, Cislo | ||||||
|  | from various.models import Nastaveni | ||||||
| 
 | 
 | ||||||
| from korektury.testutils import create_test_pdf | from korektury.testutils import create_test_pdf | ||||||
| from novinky.testutils import gen_novinky | from novinky.testutils import gen_novinky | ||||||
|  |  | ||||||
|  | @ -14,8 +14,9 @@ from django.views import generic | ||||||
| import novinky.views | import novinky.views | ||||||
| import treenode.treelib as t | import treenode.treelib as t | ||||||
| import tvorba.views | import tvorba.views | ||||||
| from personalni.models import Resitel | import seminar.models as m | ||||||
| from seminar import models as m | from personalni.models import Resitel, Osoba | ||||||
|  | from tvorba.models import Clanek, Deadline | ||||||
| 
 | 
 | ||||||
| from ..models import Nastaveni | from ..models import Nastaveni | ||||||
| 
 | 
 | ||||||
|  | @ -30,7 +31,7 @@ class TitulniStranaView(generic.ListView): | ||||||
| 		context = super(TitulniStranaView, self).get_context_data(**kwargs) | 		context = super(TitulniStranaView, self).get_context_data(**kwargs) | ||||||
| 		nastaveni = get_object_or_404(Nastaveni) | 		nastaveni = get_object_or_404(Nastaveni) | ||||||
| 
 | 
 | ||||||
| 		deadline = m.Deadline.objects.filter( | 		deadline = Deadline.objects.filter( | ||||||
| 			deadline__gte=timezone.now()).order_by("deadline").first() | 			deadline__gte=timezone.now()).order_by("deadline").first() | ||||||
| 		context['nejblizsi_deadline'] = deadline | 		context['nejblizsi_deadline'] = deadline | ||||||
| 
 | 
 | ||||||
|  | @ -93,31 +94,31 @@ def seznam_problemu(): | ||||||
| 
 | 
 | ||||||
| 	# Duplicita jmen | 	# Duplicita jmen | ||||||
| 	jmena = {} | 	jmena = {} | ||||||
| 	for r in m.Resitel.objects.all(): | 	for r in Resitel.objects.all(): | ||||||
| 		j = r.osoba.plne_jmeno() | 		j = r.osoba.plne_jmeno() | ||||||
| 		if j not in jmena: | 		if j not in jmena: | ||||||
| 			jmena[j] = [] | 			jmena[j] = [] | ||||||
| 		jmena[j].append(r) | 		jmena[j].append(r) | ||||||
| 	for j in jmena: | 	for j in jmena: | ||||||
| 		if len(jmena[j]) > 1: | 		if len(jmena[j]) > 1: | ||||||
| 			prb(m.Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j]) | 			prb(Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j]) | ||||||
| 
 | 
 | ||||||
| 	# Data maturity a narození | 	# Data maturity a narození | ||||||
| 	for r in m.Resitel.objects.all(): | 	for r in Resitel.objects.all(): | ||||||
| 		if not r.rok_maturity: | 		if not r.rok_maturity: | ||||||
| 			prb(m.Resitel, 'Neznámý rok maturity', [r]) | 			prb(Resitel, 'Neznámý rok maturity', [r]) | ||||||
| 		if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): | 		if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): | ||||||
| 			prb(m.Resitel, 'Podezřelé datum maturity', [r]) | 			prb(Resitel, 'Podezřelé datum maturity', [r]) | ||||||
| 		if r.osoba.datum_narozeni and ( | 		if r.osoba.datum_narozeni and ( | ||||||
| 				r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12): | 				r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12): | ||||||
| 			prb(m.Resitel, 'Podezřelé datum narození', [r]) | 			prb(Resitel, 'Podezřelé datum narození', [r]) | ||||||
| 	#		if not r.email: | 	#		if not r.email: | ||||||
| 	#			prb(Resitel, u'Neznámý email', [r]) | 	#			prb(Resitel, u'Neznámý email', [r]) | ||||||
| 
 | 
 | ||||||
| 	## Kontroly konzistence databáze a TreeNodů | 	## Kontroly konzistence databáze a TreeNodů | ||||||
| 
 | 
 | ||||||
| 	# Články | 	# Články | ||||||
| 	for clanek in m.Clanek.objects.all(): | 	for clanek in Clanek.objects.all(): | ||||||
| 		# získáme řešení svázané se článkem a z něj node ve stromě | 		# získáme řešení svázané se článkem a z něj node ve stromě | ||||||
| 		reseni = clanek.reseni_set | 		reseni = clanek.reseni_set | ||||||
| 		if (reseni.count() != 1): | 		if (reseni.count() != 1): | ||||||
|  | @ -136,7 +137,7 @@ def seznam_problemu(): | ||||||
| 				# .cislonode je opačná vazba k treenode_ptr, abychom z TreeNode dostali | 				# .cislonode je opačná vazba k treenode_ptr, abychom z TreeNode dostali | ||||||
| 				# CisloNode | 				# CisloNode | ||||||
| 				if clanek.cislo != node.cislonode.cislo: | 				if clanek.cislo != node.cislonode.cislo: | ||||||
| 					prb(m.Clanek, "Číslo otištění uložené u článku nesedí s " | 					prb(Clanek, "Číslo otištění uložené u článku nesedí s " | ||||||
| 								  "číslem otištění podle struktury treenodů.", [clanek]) | 								  "číslem otištění podle struktury treenodů.", [clanek]) | ||||||
| 				break | 				break | ||||||
| 			node = t.get_parent(node) | 			node = t.get_parent(node) | ||||||
|  | @ -146,8 +147,8 @@ def seznam_problemu(): | ||||||
| def StavDatabazeView(request): | def StavDatabazeView(request): | ||||||
| 	# nastaveni = Nastaveni.objects.get() | 	# nastaveni = Nastaveni.objects.get() | ||||||
| 	problemy = seznam_problemu() | 	problemy = seznam_problemu() | ||||||
| 	muzi = Resitel.objects.filter(osoba__osloveni=m.Osoba.OSLOVENI_MUZSKE) | 	muzi = Resitel.objects.filter(osoba__osloveni=Osoba.OSLOVENI_MUZSKE) | ||||||
| 	zeny = Resitel.objects.filter(osoba__osloveni=m.Osoba.OSLOVENI_ZENSKE) | 	zeny = Resitel.objects.filter(osoba__osloveni=Osoba.OSLOVENI_ZENSKE) | ||||||
| 	return render(request, 'various/stav_databaze.html', { | 	return render(request, 'various/stav_databaze.html', { | ||||||
| 		# 'nastaveni': nastaveni, | 		# 'nastaveni': nastaveni, | ||||||
| 		'problemy': problemy, | 		'problemy': problemy, | ||||||
|  |  | ||||||
|  | @ -2,7 +2,10 @@ import abc | ||||||
| from functools import cached_property | from functools import cached_property | ||||||
| from typing import Union, Iterable  # TODO: s pythonem 3.10 přepsat na '|' | from typing import Union, Iterable  # TODO: s pythonem 3.10 přepsat na '|' | ||||||
| 
 | 
 | ||||||
| import seminar.models as m | from odevzdavatko.models import Hodnoceni | ||||||
|  | from personalni.models import Resitel | ||||||
|  | from soustredeni.models import Konfera | ||||||
|  | from tvorba.models import Cislo, Rocnik, Deadline, Problem, Clanek | ||||||
| from django.db.models import Q, Sum | from django.db.models import Q, Sum | ||||||
| from tvorba.utils import resi_v_rocniku | from tvorba.utils import resi_v_rocniku | ||||||
| 
 | 
 | ||||||
|  | @ -18,11 +21,11 @@ class FixedIterator: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def body_resitelu( | def body_resitelu( | ||||||
| 		za: Union[m.Cislo, m.Rocnik, None] = None, | 		za: Union[Cislo, Rocnik, None] = None, | ||||||
| 		do: m.Deadline = None, | 		do: Deadline = None, | ||||||
| 		od: m.Deadline = None, | 		od: Deadline = None, | ||||||
| 		jen_verejne: bool = True, | 		jen_verejne: bool = True, | ||||||
| 		resitele: Iterable[m.Resitel] = None, | 		resitele: Iterable[Resitel] = None, | ||||||
| 		null=0 # Výchozí hodnota, pokud pro daného řešitele nejsou body | 		null=0 # Výchozí hodnota, pokud pro daného řešitele nejsou body | ||||||
| ) -> dict[int, int]: | ) -> dict[int, int]: | ||||||
| 	filtr = Q() | 	filtr = Q() | ||||||
|  | @ -31,9 +34,9 @@ def body_resitelu( | ||||||
| 		filtr &= Q(reseni__hodnoceni__deadline_body__verejna_vysledkovka=True) | 		filtr &= Q(reseni__hodnoceni__deadline_body__verejna_vysledkovka=True) | ||||||
| 
 | 
 | ||||||
| 	# Zjistíme, typ objektu v parametru "za" | 	# Zjistíme, typ objektu v parametru "za" | ||||||
| 	if isinstance(za, m.Rocnik): | 	if isinstance(za, Rocnik): | ||||||
| 		filtr &= Q(reseni__hodnoceni__deadline_body__cislo__rocnik=za) | 		filtr &= Q(reseni__hodnoceni__deadline_body__cislo__rocnik=za) | ||||||
| 	elif isinstance(za, m.Cislo): | 	elif isinstance(za, Cislo): | ||||||
| 		filtr &= Q(reseni__hodnoceni__deadline_body__cislo=za) | 		filtr &= Q(reseni__hodnoceni__deadline_body__cislo=za) | ||||||
| 
 | 
 | ||||||
| 	if do: | 	if do: | ||||||
|  | @ -42,7 +45,7 @@ def body_resitelu( | ||||||
| 	if od: | 	if od: | ||||||
| 		filtr &= Q(reseni__hodnoceni__deadline_body__deadline__gte=od.deadline) | 		filtr &= Q(reseni__hodnoceni__deadline_body__deadline__gte=od.deadline) | ||||||
| 
 | 
 | ||||||
| 	resiteleQuery = m.Resitel.objects.all() | 	resiteleQuery = Resitel.objects.all() | ||||||
| 
 | 
 | ||||||
| 	if resitele is not None: | 	if resitele is not None: | ||||||
| 		resitele_id = [r.id for r in resitele] | 		resitele_id = [r.id for r in resitele] | ||||||
|  | @ -63,12 +66,12 @@ def body_resitelu( | ||||||
| 
 | 
 | ||||||
| class Vysledkovka(abc.ABC): | class Vysledkovka(abc.ABC): | ||||||
| 	jen_verejne: bool | 	jen_verejne: bool | ||||||
| 	rocnik: m.Rocnik | 	rocnik: Rocnik | ||||||
| 	do_deadlinu: m.Deadline | 	do_deadlinu: Deadline | ||||||
| 
 | 
 | ||||||
| 	@property | 	@property | ||||||
| 	@abc.abstractmethod | 	@abc.abstractmethod | ||||||
| 	def aktivni_resitele(self) -> list[m.Resitel]: | 	def aktivni_resitele(self) -> list[Resitel]: | ||||||
| 		... | 		... | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
|  | @ -143,20 +146,20 @@ class Vysledkovka(abc.ABC): | ||||||
| 
 | 
 | ||||||
| class VysledkovkaRocniku(Vysledkovka): | class VysledkovkaRocniku(Vysledkovka): | ||||||
| 
 | 
 | ||||||
| 	def __init__(self, rocnik: m.Rocnik, jen_verejne: bool = True): | 	def __init__(self, rocnik: Rocnik, jen_verejne: bool = True): | ||||||
| 		self.rocnik = rocnik | 		self.rocnik = rocnik | ||||||
| 		self.jen_verejne = jen_verejne | 		self.jen_verejne = jen_verejne | ||||||
| 		deadliny = m.Deadline.objects.filter(cislo__rocnik=rocnik) | 		deadliny = Deadline.objects.filter(cislo__rocnik=rocnik) | ||||||
| 		if jen_verejne: | 		if jen_verejne: | ||||||
| 			deadliny = deadliny.filter(verejna_vysledkovka=True) | 			deadliny = deadliny.filter(verejna_vysledkovka=True) | ||||||
| 		self.do_deadlinu = deadliny.order_by("deadline").last() | 		self.do_deadlinu = deadliny.order_by("deadline").last() | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def aktivni_resitele(self) -> list[m.Resitel]: | 	def aktivni_resitele(self) -> list[Resitel]: | ||||||
| 		return list(resi_v_rocniku(self.rocnik)) | 		return list(resi_v_rocniku(self.rocnik)) | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def cisla_rocniku(self) -> list[m.Cislo]: | 	def cisla_rocniku(self) -> list[Cislo]: | ||||||
| 		""" Vrátí všechna čísla daného ročníku. """ | 		""" Vrátí všechna čísla daného ročníku. """ | ||||||
| 		if self.jen_verejne: | 		if self.jen_verejne: | ||||||
| 			return self.rocnik.verejne_vysledkovky_cisla() | 			return self.rocnik.verejne_vysledkovky_cisla() | ||||||
|  | @ -164,7 +167,7 @@ class VysledkovkaRocniku(Vysledkovka): | ||||||
| 			return self.rocnik.cisla.all().order_by('poradi') | 			return self.rocnik.cisla.all().order_by('poradi') | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def body_za_cisla_slovnik(self) -> dict[int, dict[int, int]]: # Výstup: m.Cislo.id → ( m.Resitel.id → body ) | 	def body_za_cisla_slovnik(self) -> dict[int, dict[int, int]]: # Výstup: Cislo.id → ( Resitel.id → body ) | ||||||
| 		# TODO: Body jsou decimal! | 		# TODO: Body jsou decimal! | ||||||
| 		body_cisla_slovnik = dict() | 		body_cisla_slovnik = dict() | ||||||
| 		for cislo in self.cisla_rocniku: | 		for cislo in self.cisla_rocniku: | ||||||
|  | @ -197,7 +200,7 @@ class VysledkovkaRocniku(Vysledkovka): | ||||||
| 		radky_vysledkovky = [] | 		radky_vysledkovky = [] | ||||||
| 
 | 
 | ||||||
| 		setrizeni_resitele_dict = dict() | 		setrizeni_resitele_dict = dict() | ||||||
| 		for r in m.Resitel.objects.filter( | 		for r in Resitel.objects.filter( | ||||||
| 				id__in=self.setrizeni_resitele_id | 				id__in=self.setrizeni_resitele_id | ||||||
| 		).select_related('osoba'): | 		).select_related('osoba'): | ||||||
| 			setrizeni_resitele_dict[r.id] = r | 			setrizeni_resitele_dict[r.id] = r | ||||||
|  | @ -227,31 +230,31 @@ class VysledkovkaRocniku(Vysledkovka): | ||||||
| class VysledkovkaCisla(Vysledkovka): | class VysledkovkaCisla(Vysledkovka): | ||||||
| 	def __init__( | 	def __init__( | ||||||
| 			self, | 			self, | ||||||
| 			cislo: m.Cislo, | 			cislo: Cislo, | ||||||
| 			jen_verejne: bool = True, | 			jen_verejne: bool = True, | ||||||
| 			do_deadlinu: m.Deadline = None | 			do_deadlinu: Deadline = None | ||||||
| 	): | 	): | ||||||
| 		self.cislo = cislo | 		self.cislo = cislo | ||||||
| 		self.rocnik = cislo.rocnik | 		self.rocnik = cislo.rocnik | ||||||
| 		self.jen_verejne = jen_verejne | 		self.jen_verejne = jen_verejne | ||||||
| 		if do_deadlinu is None: | 		if do_deadlinu is None: | ||||||
| 			do_deadlinu = m.Deadline.objects.filter(cislo=cislo).last() | 			do_deadlinu = Deadline.objects.filter(cislo=cislo).last() | ||||||
| 		self.do_deadlinu = do_deadlinu | 		self.do_deadlinu = do_deadlinu | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def aktivni_resitele(self) -> list[m.Resitel]: | 	def aktivni_resitele(self) -> list[Resitel]: | ||||||
| 		# TODO možná chytřeji vybírat aktivní řešitele | 		# TODO možná chytřeji vybírat aktivní řešitele | ||||||
| 		return list(resi_v_rocniku(self.rocnik)) | 		return list(resi_v_rocniku(self.rocnik)) | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def problemy(self) -> list[m.Problem]: | 	def problemy(self) -> list[Problem]: | ||||||
| 		""" Vrátí seznam všech problémů s body v daném čísle. """ | 		""" Vrátí seznam všech problémů s body v daném čísle. """ | ||||||
| 		return m.Problem.objects.filter( | 		return Problem.objects.filter( | ||||||
| 			hodnoceni__in=m.Hodnoceni.objects.filter(deadline_body__cislo=self.cislo) | 			hodnoceni__in=Hodnoceni.objects.filter(deadline_body__cislo=self.cislo) | ||||||
| 		).distinct().non_polymorphic().select_related('nadproblem').select_related('nadproblem__nadproblem') | 		).distinct().non_polymorphic().select_related('nadproblem').select_related('nadproblem__nadproblem') | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def hlavni_problemy(self) -> list[m.Problem]: | 	def hlavni_problemy(self) -> list[Problem]: | ||||||
| 		""" Vrátí seznam všech problémů, které již nemají nadproblém. """ | 		""" Vrátí seznam všech problémů, které již nemají nadproblém. """ | ||||||
| 		# hlavní problémy čísla | 		# hlavní problémy čísla | ||||||
| 		# (mají vlastní sloupeček ve výsledkovce, nemají nadproblém) | 		# (mají vlastní sloupeček ve výsledkovce, nemají nadproblém) | ||||||
|  | @ -269,7 +272,7 @@ class VysledkovkaCisla(Vysledkovka): | ||||||
| 	# Není cached, protože si myslím, že queryset lze použít ve for jen jednou. | 	# Není cached, protože si myslím, že queryset lze použít ve for jen jednou. | ||||||
| 	@property | 	@property | ||||||
| 	def hodnoceni_do_cisla(self): | 	def hodnoceni_do_cisla(self): | ||||||
| 		hodnoceni = m.Hodnoceni.objects.prefetch_related('reseni__resitele').select_related('problem', 'reseni') | 		hodnoceni = Hodnoceni.objects.prefetch_related('reseni__resitele').select_related('problem', 'reseni') | ||||||
| 		if self.jen_verejne: | 		if self.jen_verejne: | ||||||
| 			hodnoceni = hodnoceni.filter(deadline_body__verejna_vysledkovka=True) | 			hodnoceni = hodnoceni.filter(deadline_body__verejna_vysledkovka=True) | ||||||
| 		return hodnoceni.filter( | 		return hodnoceni.filter( | ||||||
|  | @ -347,7 +350,7 @@ class VysledkovkaCisla(Vysledkovka): | ||||||
| 		return self.sectene_body[2] | 		return self.sectene_body[2] | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def temata_a_spol(self) -> list[m.Problem]: | 	def temata_a_spol(self) -> list[Problem]: | ||||||
| 		if self.rocnik.rocnik < ROCNIK_ZRUSENI_TEMAT: | 		if self.rocnik.rocnik < ROCNIK_ZRUSENI_TEMAT: | ||||||
| 			return self.hlavni_problemy | 			return self.hlavni_problemy | ||||||
| 		else: | 		else: | ||||||
|  | @ -358,7 +361,7 @@ class VysledkovkaCisla(Vysledkovka): | ||||||
| 		return len(self.hlavni_problemy) - len(self.temata_a_spol) > 0 | 		return len(self.hlavni_problemy) - len(self.temata_a_spol) > 0 | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def podproblemy(self) -> dict[int, list[m.Problem]]: | 	def podproblemy(self) -> dict[int, list[Problem]]: | ||||||
| 		podproblemy = {hp.id: [] for hp in self.temata_a_spol} | 		podproblemy = {hp.id: [] for hp in self.temata_a_spol} | ||||||
| 		temata_a_spol = set(self.temata_a_spol) | 		temata_a_spol = set(self.temata_a_spol) | ||||||
| 		podproblemy[-1] = [] | 		podproblemy[-1] = [] | ||||||
|  | @ -375,7 +378,7 @@ class VysledkovkaCisla(Vysledkovka): | ||||||
| 		return podproblemy | 		return podproblemy | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def podproblemy_seznam(self) -> list[list[m.Problem]]: | 	def podproblemy_seznam(self) -> list[list[Problem]]: | ||||||
| 		return [self.podproblemy[it.id] for it in self.temata_a_spol] + [self.podproblemy[-1]] | 		return [self.podproblemy[it.id] for it in self.temata_a_spol] + [self.podproblemy[-1]] | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
|  | @ -405,7 +408,7 @@ class VysledkovkaCisla(Vysledkovka): | ||||||
| 		radky_vysledkovky = [] | 		radky_vysledkovky = [] | ||||||
| 
 | 
 | ||||||
| 		setrizeni_resitele_slovnik = {} | 		setrizeni_resitele_slovnik = {} | ||||||
| 		setrizeni_resitele = m.Resitel.objects.filter(id__in=self.setrizeni_resitele_id).select_related('osoba') | 		setrizeni_resitele = Resitel.objects.filter(id__in=self.setrizeni_resitele_id).select_related('osoba') | ||||||
| 
 | 
 | ||||||
| 		for r in setrizeni_resitele: | 		for r in setrizeni_resitele: | ||||||
| 			setrizeni_resitele_slovnik[r.id] = r | 			setrizeni_resitele_slovnik[r.id] = r | ||||||
|  | @ -456,29 +459,29 @@ class VysledkovkaCisla(Vysledkovka): | ||||||
| 	@staticmethod | 	@staticmethod | ||||||
| 	def ne_clanek_ne_konfera(problem): | 	def ne_clanek_ne_konfera(problem): | ||||||
| 		inst = problem.get_real_instance() | 		inst = problem.get_real_instance() | ||||||
| 		return not (isinstance(inst, m.Clanek) or isinstance(inst, m.Konfera)) | 		return not (isinstance(inst, Clanek) or isinstance(inst, Konfera)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class VysledkovkaDoTeXu(VysledkovkaCisla): | class VysledkovkaDoTeXu(VysledkovkaCisla): | ||||||
| 	def __init__( | 	def __init__( | ||||||
| 			self, | 			self, | ||||||
| 			nejake_cislo: m.Cislo, | 			nejake_cislo: Cislo, | ||||||
| 			od_vyjma: m.Deadline, | 			od_vyjma: Deadline, | ||||||
| 			do_vcetne: m.Deadline | 			do_vcetne: Deadline | ||||||
| 	): | 	): | ||||||
| 		super().__init__(nejake_cislo, False, do_vcetne) | 		super().__init__(nejake_cislo, False, do_vcetne) | ||||||
| 		self.od_deadlinu = od_vyjma | 		self.od_deadlinu = od_vyjma | ||||||
| 
 | 
 | ||||||
| 	@cached_property | 	@cached_property | ||||||
| 	def problemy(self) -> list[m.Problem]: | 	def problemy(self) -> list[Problem]: | ||||||
| 		return m.Problem.objects.filter(hodnoceni__in=m.Hodnoceni.objects.filter( | 		return Problem.objects.filter(hodnoceni__in=Hodnoceni.objects.filter( | ||||||
| 				deadline_body__deadline__gt=self.od_deadlinu.deadline, | 				deadline_body__deadline__gt=self.od_deadlinu.deadline, | ||||||
| 				deadline_body__deadline__lte=self.do_deadlinu.deadline, | 				deadline_body__deadline__lte=self.do_deadlinu.deadline, | ||||||
| 			)).distinct().non_polymorphic().select_related('nadproblem').select_related('nadproblem__nadproblem') | 			)).distinct().non_polymorphic().select_related('nadproblem').select_related('nadproblem__nadproblem') | ||||||
| 
 | 
 | ||||||
| 	@property | 	@property | ||||||
| 	def hodnoceni_do_cisla(self): | 	def hodnoceni_do_cisla(self): | ||||||
| 		hodnoceni = m.Hodnoceni.objects.prefetch_related( | 		hodnoceni = Hodnoceni.objects.prefetch_related( | ||||||
| 			'problem', 'reseni', 'reseni__resitele') | 			'problem', 'reseni', 'reseni__resitele') | ||||||
| 		if self.jen_verejne: | 		if self.jen_verejne: | ||||||
| 			hodnoceni = hodnoceni.filter(deadline_body__verejna_vysledkovka=True) | 			hodnoceni = hodnoceni.filter(deadline_body__verejna_vysledkovka=True) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue