WIP: Nástroj pro plošné vyrábění problémů #17
					 34 changed files with 231 additions and 260 deletions
				
			
		
							
								
								
									
										24
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| # Univerzální popis našich konvencí pro nastavení editorů. | ||||
| # Vizte https://editorconfig.org pro detaily | ||||
| 
 | ||||
| root = true | ||||
| 
 | ||||
| [*] | ||||
| charset = utf-8 | ||||
| # Unixové řádky | ||||
| end_of_line = lf | ||||
| insert_final_newline = true | ||||
| 
 | ||||
| [*.{py,css}] | ||||
| indent_style = tab | ||||
| # Nenařizujeme konkrétní šířku tabulátoru | ||||
| indent_size = unset | ||||
| 
 | ||||
| # Automaticky generované migrace dodržují PEP-8, nemá smysl s tím moc bojovat. | ||||
| [*/migrations/*.py] | ||||
| indent_style = space | ||||
| indent_size = 4 | ||||
| 
 | ||||
| [*.html] | ||||
| indent_style = space | ||||
| indent_size = 2 | ||||
|  | @ -23,6 +23,7 @@ urlpatterns = [ | |||
| 	path('api/autocomplete/skola/', views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), | ||||
| 	path('api/autocomplete/resitel/', org_required(views.ResitelAutocomplete.as_view()), name='autocomplete_resitel'), | ||||
| 	path('api/autocomplete/problem/odevzdatelny', views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), | ||||
| 	path('api/autocomplete/problem/vsechny', views.ProblemAutocomplete.as_view(), name='autocomplete_problem'), | ||||
| 
 | ||||
| 	# Ceka na autocomplete v3 | ||||
| 	# path('autocomplete/organizatori/', | ||||
|  |  | |||
|  | @ -66,6 +66,21 @@ class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView): | |||
| 					Q(nazev__icontains=self.q)) | ||||
| 		return qs | ||||
| 
 | ||||
| class ProblemAutocomplete(autocomplete.Select2QuerySetView): | ||||
| 	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """ | ||||
| 	def get_queryset(self): | ||||
| 		# FIXME i starší úlohy | ||||
| 		nastaveni = get_object_or_404(m.Nastaveni) | ||||
| 		rocnik = nastaveni.aktualni_rocnik | ||||
| 		temaQ = Q(Tema___rocnik = rocnik) | ||||
| 		ulohaQ = Q(Uloha___cislo_zadani__rocnik=rocnik) | ||||
| 		clanekQ = Q(Clanek___cislo__rocnik=rocnik) | ||||
| 		qs = m.Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev") | ||||
| 		if self.q: | ||||
| 			qs = qs.filter( | ||||
| 					Q(nazev__icontains=self.q)) | ||||
| 		return qs | ||||
| 
 | ||||
| # Ceka na autocomplete v3 | ||||
| # class OrganizatorAutocomplete(autocomplete.Select2QuerySetView): | ||||
| # 	def get_queryset(self): | ||||
|  |  | |||
|  | @ -160,6 +160,9 @@ INSTALLED_APPS = ( | |||
| #    'admin_tools.menu', | ||||
| #    'admin_tools.dashboard', | ||||
|     'django.contrib.admin', | ||||
| 
 | ||||
|     # Nechat na konci (INSTALLED_APPS je uspořádané): | ||||
|     'django_cleanup.apps.CleanupConfig',  # Uklízí media/ | ||||
| ) | ||||
| 
 | ||||
| DEBUG_TOOLBAR_CONFIG = { | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ TEMPLATES[0]['OPTIONS']['debug'] = True | |||
| from ipaddress import ip_network | ||||
| ALLOWED_HOSTS = [str(ip) for ip in ip_network('192.168.0.0/16')] | ||||
| ALLOWED_HOSTS.append('127.0.0.1') | ||||
| ALLOWED_HOSTS.append('localhost') | ||||
| 
 | ||||
| # Database | ||||
| # https://docs.djangoproject.com/en/1.7/ref/settings/#databases | ||||
|  |  | |||
|  | @ -421,6 +421,10 @@ input { | |||
| 	margin: 5px; | ||||
| } | ||||
| 
 | ||||
| textarea.feedback { | ||||
| 	margin: 5px; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* titulni stranka */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,5 +10,5 @@ | |||
| {% block bodyclass %}{{ LOCAL_TEST_PROD }}web{% endblock %} | ||||
| 
 | ||||
| {% block branding %} | ||||
| <h1 id="site-name"><a href="/"> M&M GWP web </a></h1> | ||||
| <h1 id="site-name"><a href="/"> M&M web </a></h1> | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -3,11 +3,9 @@ | |||
| {% autoescape off %} | ||||
| <ul class="menu_mobile"> | ||||
|     {% for item in sitetree_items %} | ||||
|         <li class="{% if item.has_children %}dropdown{% endif %} {% if item.is_current or item.in_current_branch %}active{% endif %}" | ||||
|             style="{% if item.title == "HIDDEN" %}display:none{% endif %}" | ||||
|         > | ||||
|         <li class="{% if item.has_children %}dropdown{% endif %} {% if item.is_current or item.in_current_branch %}active{% endif %}"> | ||||
|             <a href="{% if item.has_children %}#{% else %}{% sitetree_url for item %}{% endif %}" {% if item.has_children %}class="dropdown-toggle" data-toggle="dropdown"{% endif %}> | ||||
|                 {{ item.title_resolved }} | ||||
|                 {% if item.title == "HIDDEN" %}Korektury{% else %}{{ item.title_resolved }}{% endif %} | ||||
|             </a> | ||||
|             <div class="submenu_mobile {% if item.is_current or item.in_current_branch %}active{% endif %}"> | ||||
|             {% if item.has_children %} | ||||
|  |  | |||
|  | @ -88,11 +88,12 @@ ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni, | |||
| class JednoHodnoceniForm(forms.ModelForm): | ||||
| 	class Meta: | ||||
| 		model = m.Hodnoceni | ||||
| 		fields = ('problem', 'body', 'deadline_body') | ||||
| 		fields = ('problem', 'body', 'deadline_body', 'feedback',) | ||||
| 		widgets = { | ||||
| 			'problem': autocomplete.ModelSelect2( | ||||
| 				url='autocomplete_problem_odevzdatelny',   # FIXME: Dovolit i starší? | ||||
| 				) | ||||
| 				url='autocomplete_problem', | ||||
| 				), | ||||
| 			'feedback': forms.Textarea(attrs={'rows': 1, 'cols': 30, 'class': 'feedback'}), | ||||
| 			} | ||||
| 
 | ||||
| OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm, | ||||
|  | @ -155,10 +156,7 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form): | |||
| 
 | ||||
| 		result = [] | ||||
| 
 | ||||
| 		date_str = strftime(DATE_FORMAT, datetime.date.min.timetuple()) | ||||
| 		if date_str[0] == '1':  # Někde očividně vrací strftime rok bez nul. | ||||
| 			date_str = "000" + date_str | ||||
| 		result.append((date_str, f"Odjakživa")) | ||||
| 		result.append(("0001-01-01", f"Odjakživa")) | ||||
| 
 | ||||
| 		for deadline in m.Deadline.objects.filter( | ||||
| 				deadline__lte=timezone.now(), | ||||
|  |  | |||
|  | @ -91,7 +91,7 @@ $(document).ready(function(){ | |||
| 
 | ||||
| <form method=post onsubmit="return zkontroluj_hodnoceni();"> | ||||
| {# Poznámka #} | ||||
| <h3>Poznámka:</h3> | ||||
| <h3>Neveřejná poznámka:</h3> | ||||
| <p>{{ poznamka_form.poznamka }}</p> | ||||
| 
 | ||||
| {# Hodnocení: #} | ||||
|  | @ -101,13 +101,14 @@ $(document).ready(function(){ | |||
| {{ form.management_form }} | ||||
| </table> | ||||
| <table id="form_set"> | ||||
| <tr><th>Problém</th><th>Body</th><th>Deadline pro body</th></tr> | ||||
| <tr><th>Problém</th><th>Body</th><th>Deadline pro body</th><th>Zpětná vazba pro řešitele</th></tr> | ||||
| {% for subform in form %} | ||||
|     <tbody> | ||||
| 	<tr class="hodnoceni"> | ||||
| 		<td>{{ subform.problem }}</td> | ||||
| 		<td>{{ subform.body }}</td> | ||||
| 		<td>{{ subform.deadline_body }}</td> | ||||
| 		<td>{{ subform.feedback }}</td> | ||||
| 		<td><a href="#" class="smazat_hodnoceni" id="id_{{subform.prefix}}-jsremove"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td> | ||||
| 	</tr> | ||||
|     </tbody> | ||||
|  | @ -123,6 +124,7 @@ $(document).ready(function(){ | |||
| 		<td>{{ form.empty_form.problem }}</td> | ||||
| 		<td>{{ form.empty_form.body }}</td> | ||||
| 		<td>{{ form.empty_form.deadline_body }}</td> | ||||
| 		<td>{{ form.empty_form.feedback }}</td> | ||||
| 		<td><a href="#" class="smazat_hodnoceni" id="id_{{form.empty_form.prefix}}-jsremove"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td> | ||||
| 	</tr> | ||||
| </table> | ||||
|  |  | |||
|  | @ -37,11 +37,12 @@ | |||
| {# Hodnocení: #} | ||||
| <h3>Hodnocení:</h3> | ||||
| <table id="form_set" class="dosla_reseni"> | ||||
| <tr><th>Problém</th><th>Body</th>{# <th>Deadline pro body</th> #}</tr> | ||||
| <tr><th>Problém</th><th>Body</th><th>Zpětná vazba od opravovatele</th>{# <th>Deadline pro body</th> #}</tr> | ||||
| {% for h in hodnoceni %} | ||||
| 	<tr class="hodnoceni"> | ||||
| 		<td>{{ h.problem }}</td> | ||||
| 		<td>{{ h.body }}</td> | ||||
| 		<td>{{ h.feedback }}</td> | ||||
| {#		<td>{{ h.deadline_body }}</td>#} | ||||
| 	</tr> | ||||
| {% endfor %} | ||||
|  |  | |||
|  | @ -218,10 +218,11 @@ class DetailReseniView(DetailView): | |||
| 		self.reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk']) | ||||
| 		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): | ||||
| 			result.append( | ||||
| 				{"problem": hodn.problem,  | ||||
| 			result.append({ | ||||
| 				"problem": hodn.problem, | ||||
| 				"body": hodn.body, | ||||
| 				"deadline_body": hodn.deadline_body, | ||||
| 				"feedback": hodn.feedback, | ||||
| 				}) | ||||
| 		return result | ||||
| 
 | ||||
|  | @ -245,30 +246,26 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): | |||
| 	formset = f.OhodnoceniReseniFormSet(request.POST) | ||||
| 	poznamka_form = f.PoznamkaReseniForm(request.POST, instance=reseni) | ||||
| 	# TODO: Napsat validaci formuláře a formsetu | ||||
| 	# TODO: Implementovat větev, kdy formulář validní není. | ||||
| 	if formset.is_valid() and poznamka_form.is_valid(): | ||||
| 		with transaction.atomic(): | ||||
| 			# Poznámka je jednoduchá na zpracování: | ||||
| 			poznamka_form.save() | ||||
| 	if not (formset.is_valid() and poznamka_form.is_valid()): | ||||
| 		raise ValueError(formset.errors, poznamka_form.errors) | ||||
| 
 | ||||
| 			# Smažeme všechna dosavadní hodnocení tohoto řešení | ||||
| 			qs = m.Hodnoceni.objects.filter(reseni=reseni) | ||||
| 			logger.info(f"Will delete {qs.count()} objects: {qs}") | ||||
| 			qs.delete() | ||||
| 	with transaction.atomic(): | ||||
| 		# Poznámka je jednoduchá na zpracování: | ||||
| 		poznamka_form.save() | ||||
| 
 | ||||
| 			# Vyrobíme nová podle formsetu | ||||
| 			for form in formset: | ||||
| 				problem = form.cleaned_data['problem'] | ||||
| 				body = form.cleaned_data['body'] | ||||
| 				deadline_body = form.cleaned_data['deadline_body'] | ||||
| 				hodnoceni = m.Hodnoceni( | ||||
| 					problem=problem, | ||||
| 					body=body, | ||||
| 					deadline_body=deadline_body, | ||||
| 		# Smažeme všechna dosavadní hodnocení tohoto řešení | ||||
| 		qs = m.Hodnoceni.objects.filter(reseni=reseni) | ||||
| 		logger.info(f"Will delete {qs.count()} objects: {qs}") | ||||
| 		qs.delete() | ||||
| 
 | ||||
| 		# Vyrobíme nová podle formsetu | ||||
| 		for form in formset: | ||||
| 			hodnoceni = m.Hodnoceni( | ||||
| 					reseni=reseni, | ||||
| 					**form.cleaned_data, | ||||
| 					) | ||||
| 				logger.info(f"Creating Hodnoceni: {hodnoceni}") | ||||
| 				hodnoceni.save() | ||||
| 			logger.info(f"Creating Hodnoceni: {hodnoceni}") | ||||
| 			hodnoceni.save() | ||||
| 
 | ||||
| 	return redirect(success_url) | ||||
| 
 | ||||
|  | @ -285,6 +282,7 @@ class ResitelReseniView(DetailView): | |||
| 				{ | ||||
| 					"problem": hodn.problem, | ||||
| 					"body": hodn.body, | ||||
| 					"feedback": hodn.feedback, | ||||
| 					# "deadline_body": hodn.deadline_body, | ||||
| 				} | ||||
| 			) | ||||
|  |  | |||
|  | @ -8,13 +8,13 @@ Soubor sloužící jako „router“, tj. zde se definují url adresy a na co uk | |||
| - ``prednasky/seznam_prednasek/<int:seznam>/`` (seznam-list) :class:`~prednasky.views.SeznamListView` | ||||
| """ | ||||
| from django.urls import path | ||||
| from seminar.utils import org_required, resitel_required | ||||
| from seminar.utils import org_required, resitel_or_org_required | ||||
| from . import views | ||||
| 
 | ||||
| urlpatterns = [ | ||||
| 	path( | ||||
| 		'prednasky/', | ||||
| 		resitel_required(views.newPrednaska) | ||||
| 		resitel_or_org_required(views.newPrednaska) | ||||
| 	), | ||||
| 	path('prednasky/hotovo', views.Prednaska_hotovo), | ||||
| 	path( | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ django-sekizai | |||
| django-countries | ||||
| django-solo | ||||
| django-ckeditor | ||||
| django-cleanup  # Uklízí media/ od smazaných „databázových“ souborů | ||||
| django-flat-theme | ||||
| django-taggit | ||||
| django-autocomplete-light>=3.9.0rc1 | ||||
|  | @ -62,3 +63,4 @@ lorem | |||
| 
 | ||||
| sphinx | ||||
| sphinx_rtd_theme | ||||
| myst_parser | ||||
|  |  | |||
							
								
								
									
										18
									
								
								seminar/migrations/0108_nastaveni_cena_sous.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								seminar/migrations/0108_nastaveni_cena_sous.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| # Generated by Django 3.2.16 on 2022-11-14 20:51 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0107_zmrazenavysledkovka'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='nastaveni', | ||||
|             name='cena_sous', | ||||
|             field=models.IntegerField(default=1000, verbose_name='Účastnický poplatek za soustředění'), | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										18
									
								
								seminar/migrations/0109_hodnoceni_feedback.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								seminar/migrations/0109_hodnoceni_feedback.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| # Generated by Django 3.2.16 on 2022-11-14 19:30 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0108_nastaveni_cena_sous'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='hodnoceni', | ||||
|             name='feedback', | ||||
|             field=models.TextField(blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)', verbose_name='zpětná vazba'), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -113,6 +113,8 @@ class Hodnoceni(bm.SeminarModelBase): | |||
|     problem = models.ForeignKey(am.Problem, verbose_name='problém', | ||||
|                                 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)') | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "{}, {}, {}".format(self.problem, self.reseni, self.body) | ||||
| 
 | ||||
|  |  | |||
|  | @ -718,6 +718,10 @@ class Nastaveni(SingletonModel): | |||
| 	aktualni_cislo = models.ForeignKey(Cislo, verbose_name='Aktuální číslo',  | ||||
| 		null=False, on_delete=models.PROTECT) | ||||
| 
 | ||||
| 	cena_sous = models.IntegerField(null=False, | ||||
| 									verbose_name="Účastnický poplatek za soustředění", | ||||
| 									default=1000) | ||||
| 
 | ||||
| 	@property | ||||
| 	def aktualni_rocnik(self): | ||||
| 		return self.aktualni_cislo.rocnik | ||||
|  |  | |||
|  | @ -1,25 +0,0 @@ | |||
| \input opmac | ||||
| \chyph | ||||
| \nopagenumbers | ||||
| \parindent=0pt | ||||
| 
 | ||||
| \def\castka{1000} | ||||
| 
 | ||||
| \newread\data | ||||
| \openin\data=/dev/stdin | ||||
| \read\data to\termin | ||||
| \read\data to\misto | ||||
| 
 | ||||
| \loop | ||||
| 	\read\data to\ucastnik | ||||
| 	\unless\ifeof\data | ||||
| 		\vbox{\picw=2cm\inspic logomm.pdf \smallskip\hrule\medskip | ||||
| 		Potvrzujeme, že \ucastnik se zúčastnil(a) soustředění Korespondenčního semináře M\&M konaného % \ucastnik má na konci mezeru | ||||
| 		v~termínu \termin a že zaplatil(a) účastnický poplatek ve výši $\sim$\castka Kč$\sim$. % \termin též | ||||
| 		\bigskip | ||||
| 		\the\day.~\the\month.~\the\year, \misto\hfill Přijal(a): \hbox to 4cm{\hrulefill} | ||||
| 		\bigskip | ||||
| 		} | ||||
| \repeat | ||||
| 
 | ||||
| \bye | ||||
|  | @ -40,8 +40,7 @@ | |||
|           <li><a href="obalky.pdf">Obálky (PDF)</a></li> | ||||
|           <li><a href="tituly.tex" download>Tituly (TeX)</a></li> | ||||
|           <li><a href="vysledkovka.tex" download>Výsledkovka (TeX)</a></li> | ||||
|           <li><a href="obalkovani">Obálkování</a></li> | ||||
| 	  <li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li> | ||||
|           <li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li> | ||||
|         </ul> | ||||
|       </div> | ||||
|   {% endif %} | ||||
|  |  | |||
|  | @ -1,33 +0,0 @@ | |||
| {% extends "base.html" %} | ||||
| 
 | ||||
| {% block content %} | ||||
|   <h1> | ||||
|     {% block nadpis1a %} | ||||
|       Obálkování {{ cislo }} | ||||
|     {% endblock %} | ||||
|   </h1> | ||||
| 
 | ||||
|   Obálkovat se budou tyto problémy: | ||||
|   <ul> | ||||
|     {% for p in problemy %} | ||||
| 
 | ||||
|       <li> {{ p.kod_v_rocniku }} {{ p }} | ||||
|     {% endfor %} | ||||
|   </ul> | ||||
| 
 | ||||
|   {% for r in reseni %} | ||||
|     {% ifchanged r.resitel %} | ||||
|       {% if not forloop.first %} | ||||
|         </ul> | ||||
|       {% endif %} | ||||
|       <h4>{{ r.resitel }}</h4> | ||||
|         <ul> | ||||
|     {% endifchanged %} | ||||
| 
 | ||||
|     <li> | ||||
|       {{ r.problem.kod_v_rocniku }} {{ r.problem.nazev }} ({{ r.body }}) | ||||
| 
 | ||||
|   {% endfor %} | ||||
|   </ul> | ||||
| 
 | ||||
| {% endblock content %} | ||||
|  | @ -7,23 +7,11 @@ | |||
|     {% endblock %} | ||||
|   </h1> | ||||
| 
 | ||||
|   <h2>Od prvního deadlinu {{ from_cislo }} do prvního deadlinu {{ to_cislo }}</h2> | ||||
|   <h2>Od čísla {{ from_cislo }} do čísla {{ to_cislo }}</h2> | ||||
|     (Od „{{ from_deadline }}“ (vyjma) do „{{ to_deadline }}“ (včetně)) <br/> | ||||
|     <div class="field-error"><b>Posílat použe po opravení všeho v čísle {{ to_cislo }}!</b></div> | ||||
|   <ul> | ||||
| 	  {% for z in zmeny_prvni_prvni %} | ||||
| 	  <li> {{z.jmeno}}: {{z.ftitul}} → {{z.ttitul}}</li> | ||||
| 	  {% endfor %} | ||||
|   </ul> | ||||
| 
 | ||||
|   <h2>Od {{ from_cislo }} do prvního deadlinu {{ to_cislo }} (pro první číslo)</h2> | ||||
|   <ul> | ||||
| 	  {% for z in zmeny_posledni_prvni %} | ||||
| 	  <li> {{z.jmeno}}: {{z.ftitul}} → {{z.ttitul}}</li> | ||||
| 	  {% endfor %} | ||||
|   </ul> | ||||
| 
 | ||||
|   <h2>Od prvního deadlinu {{ from_cislo }} do {{ to_cislo }} (pro poslední číslo)</h2> | ||||
|   <ul> | ||||
| 	  {% for z in zmeny_prvni_posledni %} | ||||
| 	  {% for z in zmeny %} | ||||
| 	  <li> {{z.jmeno}}: {{z.ftitul}} → {{z.ttitul}}</li> | ||||
| 	  {% endfor %} | ||||
|   </ul> | ||||
|  |  | |||
|  | @ -1,30 +0,0 @@ | |||
| {% extends "base.html" %} | ||||
| 
 | ||||
| {% block content %} | ||||
|   <h1> | ||||
|     {% block nadpis1a %} | ||||
|       Obálkování {{ cislo }} | ||||
|     {% endblock %} | ||||
|   </h1> | ||||
|   <ul> | ||||
|   {% for reseni in object_list %} | ||||
| 	{% ifchanged reseni.resitele %} | ||||
| 		{% if not forloop.first %} | ||||
| 		 </ul> | ||||
| 		{% endif %} | ||||
| 		<h4>{% for resitel in reseni.resitele.all %}{{resitel.osoba}},{% endfor %}</h4> | ||||
| 	<ul> | ||||
| 	{% endifchanged %} | ||||
| 
 | ||||
|   <li>Celkem {{reseni.hodnoceni__body__sum}} bodů z {{reseni.hodnoceni__count}} hodnocení | ||||
| 	<ul> | ||||
| 		{% for h in reseni.hodnoceni_set.all %} | ||||
| 		<li> {{ h.problem }}: {{ h.body }}b </li> | ||||
| 		{% endfor %} | ||||
| 	</ul> | ||||
|   </li> | ||||
|   {% endfor %} | ||||
|   </ul> | ||||
| 
 | ||||
| 
 | ||||
| {% endblock content %} | ||||
|  | @ -4,7 +4,8 @@ | |||
| 
 | ||||
|   <h1> | ||||
|     {% block nadpis1a %} | ||||
|       Průběžné výsledky {{ rocnik.rocnik }}. ročníku | ||||
|       Výsledky {{ rocnik.rocnik }}. ročníku | ||||
|         {% if vysledkovka.do_deadlinu %}k datu {{ vysledkovka.do_deadlinu.deadline.date }}{% endif %} | ||||
|     {% endblock %} | ||||
|   </h1> | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ import unidecode | |||
| import logging | ||||
| 
 | ||||
| from korektury.testutils import create_test_pdf | ||||
| from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Osoba, Organizator, Prijemce, Tema, Uloha, Konfera, TextNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, Text, Hodnoceni, UlohaZadaniNode, Novinky, TreeNode | ||||
| from seminar.models import Skola, Resitel, Rocnik, Cislo, Deadline, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Osoba, Organizator, Prijemce, Tema, Uloha, Konfera, TextNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, Text, Hodnoceni, UlohaZadaniNode, Novinky, TreeNode | ||||
| import seminar.models as m | ||||
| 
 | ||||
| from django.contrib.flatpages.models import FlatPage | ||||
|  | @ -299,7 +299,7 @@ def gen_reseni_ulohy(rnd, cisla, uloha, pocet_resitelu, poradi_cisla, resitele_c | |||
| 		# Vytvoření řešení. | ||||
| 		if uloha.cislo_zadani.zlomovy_deadline_pro_papirove_cislo() is not None: | ||||
| 			# combine, abychom dostali plný čas a ne jen datum | ||||
| 			cas_doruceni = datetime.datetime.combine(uloha.cislo_zadani.datum_deadline, datetime.datetime.min.time()) - datetime.timedelta(days=random.randint(0, 40)) - datetime.timedelta(minutes=random.randint(0, 60*24)) | ||||
| 			cas_doruceni = uloha.cislo_zadani.deadline_v_cisle.first().deadline - datetime.timedelta(days=random.randint(0, 40)) - datetime.timedelta(minutes=random.randint(0, 60*24)) | ||||
| 			# astimezone, protože jinak vyhazuje warning o nenastavené TZ | ||||
| 			res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0], cas_doruceni=cas_doruceni.astimezone(datetime.timezone.utc)) | ||||
| 		else: | ||||
|  | @ -436,22 +436,23 @@ def gen_cisla(rnd, rocniky): | |||
| 				(mesic_vydani + 1) % 12 + 1, | ||||
| 				rnd.randint(1, 28)) | ||||
| 
 | ||||
| 			# posledni 2 cisla v rocniku nemaji deadline | ||||
| 			if (ci + 2 > cisel): | ||||
| 				deadline = None | ||||
| 
 | ||||
| 			cislo = Cislo.objects.create( | ||||
| 				rocnik = rocnik, | ||||
| 				poradi = str(ci),  | ||||
| 				datum_vydani=vydano, | ||||
| 				datum_deadline=deadline, | ||||
| 				verejne_db=True, | ||||
| 				verejna_vysledkovka=True | ||||
| 			) | ||||
| 			node2 = CisloNode.objects.get(cislo = cislo) | ||||
| 			node2.succ = node | ||||
| 			node2.root = rocnik.rocniknode | ||||
| 			cislo.save() | ||||
| 			deadline = Deadline.objects.create( | ||||
| 				cislo=cislo, | ||||
| 				deadline=deadline, | ||||
| 				typ=Deadline.TYP_CISLA, | ||||
| 				verejna_vysledkovka=True, | ||||
| 			) | ||||
| 			deadline.save() | ||||
| 			node = node2 | ||||
| 			if otec: | ||||
| 				otec = False | ||||
|  |  | |||
|  | @ -23,7 +23,6 @@ Soubor sloužící jako „router“, tj. zde se definují url adresy a na co uk | |||
| 	- ``cislo/<int:rocnik>.<str:cislo>/obalky.pdf`` (seminar_cislo_obalky) :func:`~seminar.views.views_all.cisloObalkyView` | ||||
| 	- ``cislo/<int:rocnik>.<str:cislo>/tituly.tex`` (seminar_cislo_titul) :func:`~seminar.views.views_all.TitulyView` | ||||
| 	- ``stav`` (stav_databaze) :func:`~seminar.views.views_all.StavDatabazeView` | ||||
| 	- ``cislo/<int:rocnik>.<str:cislo>/obalkovani`` (seminar_cislo_resitel_obalkovani) :class:`~seminar.views.views_all.ObalkovaniView` | ||||
| 	- ``cislo/<int:trocnik>.<str:tcislo>/odmeny/<int:frocnik>.<str:fcislo>/`` (seminar_archiv_odmeny) :class:`~seminar.views.views_all.OdmenyView` | ||||
| - Další | ||||
| 	- `` `` (titulni_strana) :class:`~seminar.views.views_all.TitulniStranaView` | ||||
|  | @ -102,11 +101,6 @@ urlpatterns = [ | |||
| 		org_required(views.StavDatabazeView), | ||||
| 		name='stav_databaze' | ||||
| 	), | ||||
| 	path( | ||||
| 		'cislo/<int:rocnik>.<str:cislo>/obalkovani', | ||||
| 		org_required(views.ObalkovaniView.as_view()), | ||||
| 		name='seminar_cislo_resitel_obalkovani' | ||||
| 	), | ||||
| 	path( | ||||
| 		'cislo/<int:trocnik>.<str:tcislo>/odmeny/<int:frocnik>.<str:fcislo>/', | ||||
| 		org_required(views.OdmenyView.as_view()), | ||||
|  |  | |||
|  | @ -53,23 +53,6 @@ logger = logging.getLogger(__name__) | |||
| def get_problemy_k_tematu(tema): | ||||
| 	return Problem.objects.filter(nadproblem = tema) | ||||
| 
 | ||||
| class ObalkovaniView(generic.ListView): | ||||
| 	template_name = 'seminar/org/obalkovani.html' | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		rocnik = get_object_or_404(Rocnik,rocnik=self.kwargs['rocnik']) | ||||
| 		cislo = get_object_or_404(Cislo,rocnik=rocnik,poradi=self.kwargs['cislo']) | ||||
| 		self.cislo = cislo | ||||
| 		self.hodnoceni = s.Hodnoceni.objects.filter(cislo_body=cislo) | ||||
| 		self.reseni = Reseni.objects.filter(hodnoceni__in = self.hodnoceni).annotate(Sum('hodnoceni__body')).annotate(Count('hodnoceni')).order_by('resitele__osoba') | ||||
| 		return self.reseni | ||||
| 
 | ||||
| 	def get_context_data(self, **kwargs): | ||||
| 		context = super(ObalkovaniView, self).get_context_data(**kwargs) | ||||
| 		print(self.cislo) | ||||
| 		context['cislo'] = self.cislo | ||||
| 		return context | ||||
| 
 | ||||
| 
 | ||||
| # FIXME: Pozor, níž je ještě jeden ProblemView! | ||||
| #class ProblemView(generic.DetailView): | ||||
|  | @ -484,18 +467,11 @@ class OdmenyView(generic.TemplateView): | |||
| 
 | ||||
| 		context["from_cislo"] = fromcislo | ||||
| 		context["to_cislo"] = tocislo | ||||
| 		context["zmeny_prvni_prvni"] = get_diff( | ||||
| 			fromcislo.zlomovy_deadline_pro_papirove_cislo(), | ||||
| 			tocislo.zlomovy_deadline_pro_papirove_cislo() | ||||
| 		) | ||||
| 		context["zmeny_prvni_posledni"] = get_diff( | ||||
| 			fromcislo.zlomovy_deadline_pro_papirove_cislo(), | ||||
| 			posledni_deadline_oprava(tocislo) | ||||
| 		) | ||||
| 		context["zmeny_posledni_prvni"] = get_diff( | ||||
| 			posledni_deadline_oprava(fromcislo), | ||||
| 			tocislo.zlomovy_deadline_pro_papirove_cislo() | ||||
| 		) | ||||
| 		from_deadline = posledni_deadline_oprava(fromcislo) | ||||
| 		to_deadline = posledni_deadline_oprava(tocislo) | ||||
| 		context["from_deadline"] = from_deadline | ||||
| 		context["to_deadline"] = to_deadline | ||||
| 		context["zmeny"] = get_diff(from_deadline, to_deadline) | ||||
| 
 | ||||
| 		return context | ||||
| 
 | ||||
|  | @ -597,28 +573,6 @@ def obalkyView(request, resitele): | |||
| 	return response | ||||
| 
 | ||||
| 
 | ||||
| def oldObalkovaniView(request, rocnik, cislo): | ||||
| 	rocnik = Rocnik.objects.get(rocnik=rocnik) | ||||
| 	cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo) | ||||
| 
 | ||||
| 	reseni = ( | ||||
| 		Reseni.objects.filter(cislo_body=cislo) | ||||
| 		.order_by( | ||||
| 			'resitel__prijmeni', | ||||
| 			'resitel__jmeno', | ||||
| 			'problem__typ', | ||||
| 			'problem__kod' | ||||
| 		) | ||||
| 	) | ||||
| 
 | ||||
| 	problemy = sorted(set(r.problem for r in reseni), key=lambda p: (p.typ, p.kod)) | ||||
| 	return render( | ||||
| 		request, | ||||
| 		'seminar/archiv/cislo_obalkovani.html', | ||||
| 		{'cislo': cislo, 'problemy': problemy, 'reseni': reseni} | ||||
| 	) | ||||
| 
 | ||||
| 
 | ||||
| ### Tituly | ||||
| def TitulyViewRocnik(request, rocnik): | ||||
| 	return TitulyView(request, rocnik, None) | ||||
|  |  | |||
							
								
								
									
										37
									
								
								soustredeni/templates/soustredeni/stvrzenky.tex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								soustredeni/templates/soustredeni/stvrzenky.tex
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| {% autoescape off %} | ||||
| {% load static %} | ||||
| {% load tex %} | ||||
| \documentclass[11pt,a4paper]{article} | ||||
| \usepackage[left=0.75in, right=0.75in,top=0.5in,bottom=0.5in]{geometry} | ||||
| \usepackage[T1]{fontenc} | ||||
| \usepackage[utf8]{inputenc} | ||||
| \usepackage[czech]{babel} | ||||
| \usepackage{graphicx} | ||||
| \begin{document} | ||||
| \pagenumbering{gobble} | ||||
| \parindent=0pt | ||||
| 
 | ||||
| \def\stvrzenka#1#2{ | ||||
|   \vbox{% | ||||
|     \includegraphics[width=2cm]{logomm.pdf} | ||||
|     \smallskip\hrule\medskip | ||||
| 	{% with soustredeni as s %} | ||||
| 		Potvrzujeme, že #1 #2 se zúčastnil(a) soustředění Korespondenčního semináře M\&M konaného | ||||
| 		v~termínu {{s.datum_zacatku|date:"j.~n.~Y"|sloz}} -- | ||||
|     {{s.datum_konce|date:"j.~n.~Y"|sloz}} a~že zaplatil(a) účastnický poplatek ve | ||||
|     výši $\sim${{castka|sloz}}Kč$\sim$. | ||||
| 
 | ||||
| 		\bigskip | ||||
| 		{{s.datum_zacatku|date:"j.~n.~Y"|sloz}}, {{s.misto|sloz}} \hfill Přijal(a): \hbox to 4cm{\hrulefill} | ||||
| 		\bigskip | ||||
| 		} | ||||
| 	{% endwith %} | ||||
| } | ||||
| 
 | ||||
| {% for u in ucastnici %} | ||||
| 	{% with o=u.osoba %} | ||||
| 	\stvrzenka{{o.jmeno|sloz}}{{o.prijmeni|sloz}} | ||||
| 	{% endwith %} | ||||
| {% endfor %} | ||||
| \end{document} | ||||
| {% endautoescape %} | ||||
|  | @ -1,5 +0,0 @@ | |||
| {% load tex %} | ||||
| \newcommand{\datum}{{datum|date:"j. n. Y"|sloz}} | ||||
| {% for u in ucastnici %} | ||||
| \stvrzenka{{u.cislo_stvrzenky|sloz}}{{u.jmeno|sloz}}{{u.prijmeni|sloz}}{{u.ulice|sloz}}{{u.psc|sloz}}{{u.mesto|sloz}} | ||||
| {% endfor %} | ||||
|  | @ -1,8 +1,9 @@ | |||
| from django.shortcuts import get_object_or_404 | ||||
| from django.shortcuts import get_object_or_404, render | ||||
| from django.http import HttpResponse | ||||
| from django.views import generic | ||||
| from django.conf import settings | ||||
| from seminar.models import Soustredeni, Resitel, Soustredeni_Ucastnici # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | ||||
| from django.contrib.staticfiles.finders import find | ||||
| from seminar.models import Soustredeni, Resitel, Soustredeni_Ucastnici, Nastaveni # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | ||||
| import csv | ||||
| import tempfile | ||||
| import shutil | ||||
|  | @ -62,20 +63,17 @@ def soustredeniUcastniciExportView(request, soustredeni): | |||
| def soustredeniStvrzenkyView(request, soustredeni): | ||||
| 	soustredeni = get_object_or_404(Soustredeni, id=soustredeni) | ||||
| 	ucastnici = Resitel.objects.filter(soustredeni=soustredeni) | ||||
| 	castka = Nastaveni.get_solo().cena_sous | ||||
| 	tex = render(request, 'soustredeni/stvrzenky.tex', {'ucastnici': ucastnici, 'soustredeni': soustredeni, 'castka': castka}).content | ||||
| 
 | ||||
| 	static = Path(settings.STATIC_ROOT) | ||||
| 	tempdir = Path(tempfile.mkdtemp()) | ||||
| 	shutil.copy(static / 'images/logomm.pdf', tempdir) | ||||
| 	shutil.copy(static / 'seminar/stvrzenky.tex', tempdir) | ||||
| 	subprocess.run( | ||||
| 			['pdfcsplain', 'stvrzenky.tex'], | ||||
| 			cwd=tempdir, | ||||
| 			encoding='utf-8', | ||||
| 			input=f'{soustredeni.datum_zacatku.strftime("%-d.~%-m.~%Y")} -- {soustredeni.datum_konce.strftime("%-d.~%-m.~%Y")}\n{soustredeni.misto}\n' | ||||
| 			+ '\n'.join([f'{u.osoba.jmeno} {u.osoba.prijmeni}' for u in ucastnici]) | ||||
| 			) | ||||
| 	with open(tempdir / "stvrzenky.tex", "w") as texfile: | ||||
| 		texfile.write(tex.decode()) | ||||
| 
 | ||||
| 	with open(tempdir / 'stvrzenky.pdf', 'rb') as pdffile: | ||||
| 	shutil.copy(find('images/logomm.pdf'), tempdir) | ||||
| 	subprocess.call(["pdflatex", "stvrzenky.tex"], cwd = tempdir, stdout=subprocess.DEVNULL) | ||||
| 
 | ||||
| 	with open(tempdir / "stvrzenky.pdf", "rb") as pdffile: | ||||
| 		response = HttpResponse(pdffile.read(), content_type='application/pdf') | ||||
| 	shutil.rmtree(tempdir) | ||||
| 	return response | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| 
 | ||||
| <br> | ||||
| <p><a href="{% url 'reset_password' %}"> | ||||
|     Zapomněl jsem heslo | ||||
|     Zapomněl jsem heslo nebo uživatelské jméno | ||||
| </a></p> | ||||
| 
 | ||||
| <hr> | ||||
|  |  | |||
|  | @ -1,49 +1,49 @@ | |||
| <div style="overflow-x: auto;"> | ||||
| <table class='vysledkovka'> | ||||
|     <tr class='border-b'> | ||||
|         <th class='border-r'># | ||||
|         <th class='border-r'>Jméno | ||||
|         <th class='border-r'>#</th> | ||||
|         <th class='border-r'>Jméno</th> | ||||
|             {% for p in vysledkovka.temata_a_spol%} | ||||
|                 <th class='border-r' id="problem{{ oznaceni_vysledkovky }}_{{ forloop.counter0 }}">{# <a href="{{ p.verejne_url }}"> #}{{ p.kod_v_rocniku }}{# </a> #} | ||||
|                 <th class='border-r' id="problem{{ oznaceni_vysledkovky }}_{{ forloop.counter0 }}">{# <a href="{{ p.verejne_url }}"> #}{{ p.kod_v_rocniku }}{# </a> #}</th> | ||||
| 
 | ||||
|                     {# TODELETE #} | ||||
|                     {% for podproblemy in vysledkovka.podproblemy_iter.next %} | ||||
|                         <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ forloop.parentloop.counter0 }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #} | ||||
|                         <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ forloop.parentloop.counter0 }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}</th> | ||||
|                     {% endfor %} | ||||
|                 {# TODELETE #} | ||||
| 
 | ||||
|             {% endfor %} | ||||
|         {% if vysledkovka.je_nejake_ostatni %}<th class='border-r' id='problem{{ oznaceni_vysledkovky }}_{{ vysledkovka.temata_a_spol| length }}'>Ostatní {% endif %} | ||||
|         {% if vysledkovka.je_nejake_ostatni %}<th class='border-r' id='problem{{ oznaceni_vysledkovky }}_{{ vysledkovka.temata_a_spol| length }}'>Ostatní</th>{% endif %} | ||||
| 
 | ||||
|         {# TODELETE #} | ||||
|         {% for podproblemy in vysledkovka.podproblemy_iter.next %} | ||||
|             <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ vysledkovka.temata_a_spol| length }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #} | ||||
|             <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ vysledkovka.temata_a_spol| length }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}</th> | ||||
|         {% endfor %} | ||||
|         {# TODELETE #} | ||||
| 
 | ||||
| 
 | ||||
|         <th class='border-r'>Za číslo | ||||
|         <th class='border-r'>Za ročník | ||||
|         <th class='border-r'>Odjakživa | ||||
|         <th class='border-r'>Za číslo</th> | ||||
|         <th class='border-r'>Za ročník</th> | ||||
|         <th class='border-r'>Odjakživa</th> | ||||
|             {% for rv in vysledkovka.radky_vysledkovky %} | ||||
|                 <tr> | ||||
|                     <td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %} | ||||
|                     <td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}</td> | ||||
|                     <th class='border-r'> | ||||
|                         {% if rv.titul %} | ||||
|                             {{ rv.titul }}<sup>MM</sup> | ||||
|                         {% endif %} | ||||
|                         {{ rv.resitel.osoba.plne_jmeno }} | ||||
|                         {{ rv.resitel.osoba.plne_jmeno }}</th> | ||||
|                         {% for b in rv.body_za_temata_seznam %} | ||||
|                             <td class='border-r'>{{ b }} | ||||
|                             <td class='border-r'>{{ b }}</td> | ||||
| 
 | ||||
|                                 {% for body_podproblemu in rv.body_podproblemy_iter.next %} | ||||
|                                     <td class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ forloop.parentloop.counter0 }} podproblem'>{{ body_podproblemu }} | ||||
|                                     <td class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ forloop.parentloop.counter0 }} podproblem'>{{ body_podproblemu }}</td> | ||||
|                                 {% endfor %} | ||||
| 
 | ||||
|                         {% endfor %} | ||||
|                     <td class='border-r'>{{ rv.body_cislo }} | ||||
|                     <td class='border-r'><b>{{ rv.body_rocnik }}</b> | ||||
|                     <td class='border-r'>{{ rv.body_celkem_odjakziva }} | ||||
|                     <td class='border-r'>{{ rv.body_cislo }}</td> | ||||
|                     <td class='border-r'><b>{{ rv.body_rocnik }}</b></td> | ||||
|                     <td class='border-r'>{{ rv.body_celkem_odjakziva }}</td> | ||||
|                 </tr> | ||||
|             {% endfor %} | ||||
| </table> | ||||
|  |  | |||
|  | @ -1,29 +1,29 @@ | |||
| <table class='vysledkovka'> | ||||
|   <tr class='border-b'> | ||||
|     <th class='border-r'># | ||||
|     <th class='border-r'>Jméno | ||||
|     <th class='border-r'>R. | ||||
|     <th class='border-r'>Odjakživa | ||||
|     <th class='border-r'>#</th> | ||||
|     <th class='border-r'>Jméno</th> | ||||
|     <th class='border-r'>R.</th> | ||||
|     <th class='border-r'>Odjakživa</th> | ||||
|         {% for c in vysledkovka.cisla_rocniku %} | ||||
|     <th class='border-r'><a href="{{ c.verejne_url }}"> | ||||
|             {{c.rocnik.rocnik}}.{{ c.poradi }}</a> | ||||
|         {{c.rocnik.rocnik}}.{{ c.poradi }}</a></th> | ||||
|     {% endfor %} | ||||
|     <th class='border-r'>Celkem | ||||
|     <th class='border-r'>Celkem</th> | ||||
| 
 | ||||
| {% for rv in vysledkovka.radky_vysledkovky %} | ||||
|   <tr> | ||||
|     <td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %} | ||||
|     <td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}</td> | ||||
|     <th class='border-r'> | ||||
|       {% if rv.titul %} | ||||
|         {{ rv.titul }}<sup>MM</sup> | ||||
|       {% endif %} | ||||
|       {{ rv.resitel.osoba.plne_jmeno }} | ||||
|     <td class='border-r'>{{ rv.rocnik_resitele }} | ||||
|     <td class='border-r'>{{ rv.body_celkem_odjakziva }} | ||||
|       {{ rv.resitel.osoba.plne_jmeno }}</th> | ||||
|     <td class='border-r'>{{ rv.rocnik_resitele }}</td> | ||||
|     <td class='border-r'>{{ rv.body_celkem_odjakziva }}</td> | ||||
|     {% for b in rv.body_cisla_seznam %} | ||||
|     <td class='border-r'>{{ b }} | ||||
|         <td class='border-r'>{{ b }}</td> | ||||
|     {% endfor %} | ||||
|     <td class='border-r'><b>{{ rv.body_rocnik }}</b> | ||||
|     <td class='border-r'><b>{{ rv.body_rocnik }}</b></td> | ||||
|   </tr> | ||||
| {% endfor %} | ||||
| </table> | ||||
|  |  | |||
|  | @ -146,7 +146,10 @@ class VysledkovkaRocniku(Vysledkovka): | |||
| 	def __init__(self, rocnik: m.Rocnik, jen_verejne: bool = True): | ||||
| 		self.rocnik = rocnik | ||||
| 		self.jen_verejne = jen_verejne | ||||
| 		self.do_deadlinu = m.Deadline.objects.filter(cislo__rocnik=rocnik).last() | ||||
| 		deadliny = m.Deadline.objects.filter(cislo__rocnik=rocnik) | ||||
| 		if jen_verejne: | ||||
| 			deadliny = deadliny.filter(verejna_vysledkovka=True) | ||||
| 		self.do_deadlinu = deadliny.order_by("deadline").last() | ||||
| 
 | ||||
| 	@cached_property | ||||
| 	def aktivni_resitele(self) -> list[m.Resitel]: | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue