Reviewed-on: #65
This commit is contained in:
		
						commit
						024f8e0a80
					
				
					 102 changed files with 682 additions and 661 deletions
				
			
		|  | @ -5,16 +5,16 @@ urlpatterns = [ | ||||||
| 	path( | 	path( | ||||||
| 		'aesop-export/mam-rocnik-<int:prvni_rok>.csv', | 		'aesop-export/mam-rocnik-<int:prvni_rok>.csv', | ||||||
| 		views.ExportRocnikView.as_view(), | 		views.ExportRocnikView.as_view(), | ||||||
| 		name='seminar_export_rocnik' | 		name='aesop_export_rocnik' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'aesop-export/mam-sous-<str:datum_zacatku>.csv', | 		'aesop-export/mam-sous-<str:datum_zacatku>.csv', | ||||||
| 		views.ExportSousView.as_view(), | 		views.ExportSousView.as_view(), | ||||||
| 		name='seminar_export_sous' | 		name='aesop_export_sous' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'aesop-export/index.csv', | 		'aesop-export/index.csv', | ||||||
| 		views.ExportIndexView.as_view(), | 		views.ExportIndexView.as_view(), | ||||||
| 		name='seminar_export_index' | 		name='aesop_export_index' | ||||||
| 	), | 	), | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -6,7 +6,8 @@ from django.views import generic | ||||||
| from django.utils.encoding import force_str | from django.utils.encoding import force_str | ||||||
| 
 | 
 | ||||||
| from .utils import default_ovvpfile | from .utils import default_ovvpfile | ||||||
| from seminar.models import Rocnik, Soustredeni | from soustredeni.models import Soustredeni | ||||||
|  | from tvorba.models import Rocnik | ||||||
| from vysledkovky import utils | from vysledkovky import utils | ||||||
| from tvorba.utils import aktivniResitele | from tvorba.utils import aktivniResitele | ||||||
| 
 | 
 | ||||||
|  | @ -14,10 +15,10 @@ class ExportIndexView(generic.View): | ||||||
| 	def get(self, request): | 	def get(self, request): | ||||||
| 		ls = [] | 		ls = [] | ||||||
| 		for r in Rocnik.objects.filter(exportovat = True): | 		for r in Rocnik.objects.filter(exportovat = True): | ||||||
| 	    		url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok}) | 	    		url = reverse('aesop_export_rocnik', kwargs={'prvni_rok': r.prvni_rok}) | ||||||
| 	    		ls.append(url.split('/')[-1]) | 	    		ls.append(url.split('/')[-1]) | ||||||
| 		for s in Soustredeni.objects.filter(exportovat = True): | 		for s in Soustredeni.objects.filter(exportovat = True): | ||||||
| 			url = reverse('seminar_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()}) | 			url = reverse('aesop_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()}) | ||||||
| 			ls.append(url.split('/')[-1]) | 			ls.append(url.split('/')[-1]) | ||||||
| 
 | 
 | ||||||
| 		return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8') | 		return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8') | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| from django.test import TestCase, tag | from django.test import TestCase, tag | ||||||
| from django.urls import reverse | from django.urls import reverse | ||||||
| import seminar.models as m | from personalni.models import Skola | ||||||
| from personalni.utils import sync_skoly | from personalni.utils import sync_skoly | ||||||
| 
 | 
 | ||||||
| @tag('stejny-model-na-produkci') | @tag('stejny-model-na-produkci') | ||||||
|  | @ -48,7 +48,7 @@ class OrgSkolyAutocompleteTestCase(TestCase): | ||||||
| 		"""Testuje, že pro každého orga je jeho škola ve výsledném QuerySetu""" | 		"""Testuje, že pro každého orga je jeho škola ve výsledném QuerySetu""" | ||||||
| 		for pfx, id in self.spravna_data: | 		for pfx, id in self.spravna_data: | ||||||
| 			with self.subTest(prefix=pfx, spravne_id=id): | 			with self.subTest(prefix=pfx, spravne_id=id): | ||||||
| 				spravna_skola = m.Skola.objects.get(id=id) | 				spravna_skola = Skola.objects.get(id=id) | ||||||
| 				# Zeptáme se view, co si myslí | 				# Zeptáme se view, co si myslí | ||||||
| 				resp = self.client.get(reverse('autocomplete_skola')+'?q='+pfx).json() | 				resp = self.client.get(reverse('autocomplete_skola')+'?q='+pfx).json() | ||||||
| 				ids = [int(x['id']) for x in resp['results']] | 				ids = [int(x['id']) for x in resp['results']] | ||||||
|  |  | ||||||
|  | @ -17,5 +17,5 @@ urlpatterns = [ | ||||||
| 	# Ceka na autocomplete v3 | 	# Ceka na autocomplete v3 | ||||||
| 	# path('autocomplete/organizatori/', | 	# path('autocomplete/organizatori/', | ||||||
| 	# org_member_required(views.OrganizatorAutocomplete.as_view()), | 	# org_member_required(views.OrganizatorAutocomplete.as_view()), | ||||||
| 	# name='seminar_autocomplete_organizator') | 	# name='autocomplete_organizator') | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -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)) | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import seminar.models as m | import personalni.models as m | ||||||
| from django.core import serializers as ser | from django.core import serializers as ser | ||||||
| from django.http import HttpResponse | from django.http import HttpResponse | ||||||
| def exportSkolView(request): | def exportSkolView(request): | ||||||
|  |  | ||||||
|  | @ -73,7 +73,7 @@ | ||||||
| 			"sort_order": 3, | 			"sort_order": 3, | ||||||
| 			"title": "Aktuální<br/> ročník", | 			"title": "Aktuální<br/> ročník", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_aktualni_zadani", | 			"url": "tvorba_aktualni_zadani", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -121,7 +121,7 @@ | ||||||
| 			"sort_order": 5, | 			"sort_order": 5, | ||||||
| 			"title": "Archiv", | 			"title": "Archiv", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_archiv_rocniky", | 			"url": "tvorba_archiv_rocniky", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -289,7 +289,7 @@ | ||||||
| 			"sort_order": 43, | 			"sort_order": 43, | ||||||
| 			"title": "Výsledková listina", | 			"title": "Výsledková listina", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_aktualni_vysledky", | 			"url": "tvorba_aktualni_vysledky", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -361,7 +361,7 @@ | ||||||
| 			"sort_order": 20, | 			"sort_order": 20, | ||||||
| 			"title": "Proběhlo", | 			"title": "Proběhlo", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_seznam_soustredeni", | 			"url": "soustredeni_seznam", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -409,7 +409,7 @@ | ||||||
| 			"sort_order": 23, | 			"sort_order": 23, | ||||||
| 			"title": "Osobní údaje", | 			"title": "Osobní údaje", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_resitel_edit", | 			"url": "personalni_resitel_edit", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -439,7 +439,7 @@ | ||||||
| 			"sort_order": 36, | 			"sort_order": 36, | ||||||
| 			"title": "Nahrát řešení", | 			"title": "Nahrát řešení", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_nahraj_reseni", | 			"url": "odevzdavatko_nahraj_reseni", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -463,7 +463,7 @@ | ||||||
| 			"sort_order": 35, | 			"sort_order": 35, | ||||||
| 			"title": "Témata", | 			"title": "Témata", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_archiv_temata", | 			"url": "tvorba_archiv_temata", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -589,7 +589,7 @@ | ||||||
| 			"sort_order": 15, | 			"sort_order": 15, | ||||||
| 			"title": "Aktuální číslo", | 			"title": "Aktuální číslo", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_aktualni_zadani", | 			"url": "tvorba_aktualni_zadani", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -613,7 +613,7 @@ | ||||||
| 			"sort_order": 24, | 			"sort_order": 24, | ||||||
| 			"title": "Čísla", | 			"title": "Čísla", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_archiv_rocniky", | 			"url": "tvorba_archiv_rocniky", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -721,7 +721,7 @@ | ||||||
| 			"sort_order": 36, | 			"sort_order": 36, | ||||||
| 			"title": "Vložit řešení", | 			"title": "Vložit řešení", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_vloz_reseni", | 			"url": "odevzdavatko_vloz_reseni", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -804,7 +804,7 @@ | ||||||
| 			"sort_order": 37, | 			"sort_order": 37, | ||||||
| 			"title": "Moje řešení", | 			"title": "Moje řešení", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_resitel_odevzdana_reseni", | 			"url": "odevzdavatko_resitel_odevzdana_reseni", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -828,7 +828,7 @@ | ||||||
| 			"sort_order": 33, | 			"sort_order": 33, | ||||||
| 			"title": "Aktuální ročník", | 			"title": "Aktuální ročník", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_aktualni_rocnik", | 			"url": "tvorba_aktualni_rocnik", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -900,7 +900,7 @@ | ||||||
| 			"sort_order": 46, | 			"sort_order": 46, | ||||||
| 			"title": "Ročník {{rocnik.rocnik}}", | 			"title": "Ročník {{rocnik.rocnik}}", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_rocnik rocnik.rocnik", | 			"url": "tvorba_rocnik rocnik.rocnik", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -924,7 +924,7 @@ | ||||||
| 			"sort_order": 47, | 			"sort_order": 47, | ||||||
| 			"title": "Číslo {{ cislo.rocnik.rocnik }}.{{ cislo.poradi }}", | 			"title": "Číslo {{ cislo.rocnik.rocnik }}.{{ cislo.poradi }}", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_cislo cislo.rocnik.rocnik cislo.poradi", | 			"url": "tvorba_cislo cislo.rocnik.rocnik cislo.poradi", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -1061,7 +1061,7 @@ | ||||||
| 			"sort_order": 52, | 			"sort_order": 52, | ||||||
| 			"title": "Nahrát řešení k nadproblému {{nadproblem_id}}", | 			"title": "Nahrát řešení k nadproblému {{nadproblem_id}}", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_nahraj_reseni nadproblem_id", | 			"url": "odevzdavatko_nahraj_reseni nadproblem_id", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
|  | @ -1109,10 +1109,10 @@ | ||||||
| 			"sort_order": 54, | 			"sort_order": 54, | ||||||
| 			"title": "Export do abstraktů sousu {{ soustredeni.id }}", | 			"title": "Export do abstraktů sousu {{ soustredeni.id }}", | ||||||
| 			"tree": 1, | 			"tree": 1, | ||||||
| 			"url": "seminar_soustredeni_abstrakty soustredeni.id", | 			"url": "soustredeni_abstrakty soustredeni.id", | ||||||
| 			"urlaspattern": true | 			"urlaspattern": true | ||||||
| 		}, | 		}, | ||||||
| 		"model": "sitetree.treeitem", | 		"model": "sitetree.treeitem", | ||||||
| 		"pk": 54 | 		"pk": 54 | ||||||
| 	} | 	} | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -10,11 +10,9 @@ věci jako chybové hlášky a vzhled M&M stránek (menu, patička, atd.). Aktu | ||||||
| i veškeré csv. | i veškeré csv. | ||||||
| 
 | 
 | ||||||
| Další jsou pak jednotlivé aplikace (pokud něco hledáte, tak zřejmě chcete najít | Další jsou pak jednotlivé aplikace (pokud něco hledáte, tak zřejmě chcete najít | ||||||
| tu aplikaci, která tomu odpovídá, respektive se k ní dostat přes url), za | tu aplikaci, která tomu odpovídá, respektive se k ní dostat přes url). | ||||||
| zmínku stojí seminar, kde jsou takové ty věci, co zbyly. Plus jsou tam aktuálně |  | ||||||
| téměř všechny modely, protože je těžké je přesunout jinam. |  | ||||||
| 
 | 
 | ||||||
| **TLDR: Nevšímejte si složky data/ a souborů přímo v kořenové složce.** | **TLDR: Nevšímejte si složek data/ seminar/ a souborů přímo v kořenové složce.** | ||||||
| Kromě věcí potřebných ke gitu, :doc:`ke spuštění <vyvoj>` a fukci djanga, | Kromě věcí potřebných ke gitu, :doc:`ke spuštění <vyvoj>` a fukci djanga, | ||||||
| dalších drobností, lokální databáze a již zmíněných aplikací jsou tu ``data``, | dalších drobností, lokální databáze a již zmíněných aplikací jsou tu ``data``, | ||||||
| kde je takový ten obsah webu, co by se měl dát snadno měnit (tudíž musí být v | kde je takový ten obsah webu, co by se měl dát snadno měnit (tudíž musí být v | ||||||
|  | @ -22,6 +20,9 @@ databázi), tj. statické stránky, menu a obrázky v pozadí menu. Ten je třeb | ||||||
| měnit hlavně na produkci a sekundárně tady (může to dělat i newebař a nechcete | měnit hlavně na produkci a sekundárně tady (může to dělat i newebař a nechcete | ||||||
| přepsat jeho práci). Vše, co nejsou aplikace je popsáno :doc:`tady <dalsi_soubory>`. | přepsat jeho práci). Vše, co nejsou aplikace je popsáno :doc:`tady <dalsi_soubory>`. | ||||||
| 
 | 
 | ||||||
|  | Ještě je tu aplikace ``seminar/``, kde bylo původně skoro všechno, a tak nám | ||||||
|  | tam zbývá spoustu historických migrací (čehož se jen tak nezbavíme). | ||||||
|  | 
 | ||||||
| Základy djanga | Základy djanga | ||||||
| -------------- | -------------- | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -116,7 +116,7 @@ Aktuálně: Jakýsi coding style zhruba existuje, není popsaný, šíří se li | ||||||
| - Nesmí být striktně vynucovaný | - Nesmí být striktně vynucovaný | ||||||
| - Musel by být hodně nastavitelný | - Musel by být hodně nastavitelný | ||||||
|     - Nechceme mít kód plný `#NOQA: WTF42` |     - Nechceme mít kód plný `#NOQA: WTF42` | ||||||
| - Nejspíš vždycky bude mít false positives (`tvorba.utils.roman_numerals`) i false negatives (`seminar.models.tvorba.Cislo.posli_cislo_mailem`) | - Nejspíš vždycky bude mít false positives (`tvorba.utils.roman_numerals`) i false negatives (`tvorba.models.Cislo.posli_cislo_mailem`) | ||||||
|     - Možná dobrý sluha, ale určitě špatný pán (also: špatná zkušenost ☺) |     - Možná dobrý sluha, ale určitě špatný pán (also: špatná zkušenost ☺) | ||||||
| - __Důsledek:__ Hrozí, že těch falešných varování bude moc, čímž to ztratí smysl úplně | - __Důsledek:__ Hrozí, že těch falešných varování bude moc, čímž to ztratí smysl úplně | ||||||
|     - Potenciálně by šlo aplikovat jen lokálně na změny? |     - Potenciálně by šlo aplikovat jen lokálně na změny? | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ from django.template import RequestContext | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| 
 | 
 | ||||||
| from galerie.models import Obrazek, Galerie | from galerie.models import Obrazek, Galerie | ||||||
| from seminar.models import Soustredeni | from soustredeni.models import Soustredeni | ||||||
| from galerie.forms import KomentarForm, NewGalerieForm | from galerie.forms import KomentarForm, NewGalerieForm | ||||||
| 
 | 
 | ||||||
| def zobrazit(galerie, request): | def zobrazit(galerie, request): | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ set -exuo pipefail | ||||||
| . make/lib.sh | . make/lib.sh | ||||||
| 
 | 
 | ||||||
| scp vue_frontend/webpack-stats.json "$GIMLI_LOGIN:$TESTWEB/vue_frontend/" | scp vue_frontend/webpack-stats.json "$GIMLI_LOGIN:$TESTWEB/vue_frontend/" | ||||||
| rsync -ave ssh seminar/static/seminar/vue "$GIMLI_LOGIN:$TESTWEB/seminar/static/seminar/" | rsync -ave ssh treenode/static/treenode/vue "$GIMLI_LOGIN:$TESTWEB/treenode/static/treenode/" | ||||||
| ssh "$GIMLI_LOGIN" " | ssh "$GIMLI_LOGIN" " | ||||||
| 	set -euxo pipefail | 	set -euxo pipefail | ||||||
| 	cd $TESTWEB | 	cd $TESTWEB | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -279,11 +279,11 @@ LOGGING = { | ||||||
| 				'filters': ['Http404AsInfo'], | 				'filters': ['Http404AsInfo'], | ||||||
| 				}, | 				}, | ||||||
| 
 | 
 | ||||||
| 			'seminar.prihlaska.form':{ | 			'personalni.prihlaska.form':{ | ||||||
| 		'handlers': ['console','registration_logfile'], | 		'handlers': ['console','registration_logfile'], | ||||||
| 		'level': 'INFO' | 		'level': 'INFO' | ||||||
| 		}, | 		}, | ||||||
| 			'seminar.prihlaska.problem':{ | 			'personalni.prihlaska.problem':{ | ||||||
| 		'handlers': ['console','mail_registration','registration_error_log'], | 		'handlers': ['console','mail_registration','registration_error_log'], | ||||||
| 		'level': 'INFO' | 		'level': 'INFO' | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
|   {% if not novinka.zverejneno and user.je_org %} |   {% if not novinka.zverejneno and user.je_org %} | ||||||
|   <div class="mam-org-only"> |   <div class="mam-org-only"> | ||||||
|     <ul> |     <ul> | ||||||
|       <li><a href="/admin/seminar/novinky/{{novinka.pk}}">Upravit novinku</a> |       <li><a href="{% url 'admin:novinky_novinky_change' novinka.pk %}">Upravit novinku</a> | ||||||
|     </ul> |     </ul> | ||||||
|   {% endif %} |   {% endif %} | ||||||
|   {% if novinka.zverejneno or user.je_org %} |   {% if novinka.zverejneno or user.je_org %} | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| from django.contrib import admin | from django.contrib import admin | ||||||
| from django_reverse_admin import ReverseModelAdmin | from django_reverse_admin import ReverseModelAdmin | ||||||
| import seminar.models as m | import odevzdavatko.models as m | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PrilohaReseniInline(admin.TabularInline): | class PrilohaReseniInline(admin.TabularInline): | ||||||
|  |  | ||||||
|  | @ -4,8 +4,11 @@ from django.forms import formset_factory | ||||||
| from django.forms.models import inlineformset_factory | from django.forms.models import inlineformset_factory | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| 
 | 
 | ||||||
| from seminar.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,14 +9,14 @@ 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 various.models import SeminarModelBase | ||||||
| 
 | 
 | ||||||
| from odevzdavatko.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet | from odevzdavatko.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet | ||||||
| from personalni.models import Resitel | from personalni.models import Resitel | ||||||
| 
 | 
 | ||||||
| @reversion.register(ignore_duplicates=True) | @reversion.register(ignore_duplicates=True) | ||||||
| class Reseni(bm.SeminarModelBase): | class Reseni(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		db_table = 'seminar_reseni' | 		db_table = 'seminar_reseni' | ||||||
|  | @ -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): | ||||||
|  | @ -88,7 +88,7 @@ class Reseni(bm.SeminarModelBase): | ||||||
| #			self.cislo_body = self.problem.cislo_reseni | #			self.cislo_body = self.problem.cislo_reseni | ||||||
| #		super(Reseni, self).save(*args, **kwargs) | #		super(Reseni, self).save(*args, **kwargs) | ||||||
| 
 | 
 | ||||||
| class Hodnoceni(bm.SeminarModelBase): | class Hodnoceni(SeminarModelBase): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		db_table = 'seminar_hodnoceni' | 		db_table = 'seminar_hodnoceni' | ||||||
| 		verbose_name = 'Hodnocení' | 		verbose_name = 'Hodnocení' | ||||||
|  | @ -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,12 +176,12 @@ 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) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @reversion.register(ignore_duplicates=True) | @reversion.register(ignore_duplicates=True) | ||||||
| class PrilohaReseni(bm.SeminarModelBase): | class PrilohaReseni(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		db_table = 'seminar_priloha_reseni' | 		db_table = 'seminar_priloha_reseni' | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
|   {% endblock %} |   {% endblock %} | ||||||
| </h1> | </h1> | ||||||
| 
 | 
 | ||||||
| <form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' nadproblem_id %}" method="post" onsubmit="return zkontroluj_prilohy();"> | <form enctype="multipart/form-data" action="{% url 'odevzdavatko_nahraj_reseni' nadproblem_id %}" method="post" onsubmit="return zkontroluj_prilohy();"> | ||||||
|   {% csrf_token %} |   {% csrf_token %} | ||||||
|   <table class='form'> |   <table class='form'> | ||||||
|     <tr> |     <tr> | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ | ||||||
| 
 | 
 | ||||||
| <ul> | <ul> | ||||||
|   {% for problem in object_list %} |   {% for problem in object_list %} | ||||||
|     <li><a href="{% url 'seminar_nahraj_reseni' problem.id %}">{{ problem }}</a></li> |     <li><a href="{% url 'odevzdavatko_nahraj_reseni' problem.id %}">{{ problem }}</a></li> | ||||||
|   {% empty %} |   {% empty %} | ||||||
|     <li>Nelze nic odevzdávat.</li> |     <li>Nelze nic odevzdávat.</li> | ||||||
|   {% endfor %} |   {% endfor %} | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ | ||||||
|     Vložit řešení |     Vložit řešení | ||||||
|   {% endblock %} |   {% endblock %} | ||||||
| </h1> | </h1> | ||||||
| <form enctype="multipart/form-data" action="{% url 'seminar_vloz_reseni' %}" method="post" onsubmit="return zkontroluj_prilohy();"> | <form enctype="multipart/form-data" action="{% url 'odevzdavatko_vloz_reseni' %}" method="post" onsubmit="return zkontroluj_prilohy();"> | ||||||
|   {% csrf_token %} |   {% csrf_token %} | ||||||
| {{form.as_p}} | {{form.as_p}} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,11 +2,11 @@ from django import template | ||||||
| register = template.Library() | register = template.Library() | ||||||
| 
 | 
 | ||||||
| from functools import cache | from functools import cache | ||||||
| import seminar.models as m | from odevzdavatko.models import Reseni | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| @cache | @cache | ||||||
| def barva_reseni(r: m.Reseni): | def barva_reseni(r: Reseni): | ||||||
| 	"""Vrátí nějakou barvu pro daný problém, ve tvaru '#RRGGBB' | 	"""Vrátí nějakou barvu pro daný problém, ve tvaru '#RRGGBB' | ||||||
| 
 | 
 | ||||||
| 	Efektivně hešujeme do barev.""" | 	Efektivně hešujeme do barev.""" | ||||||
|  |  | ||||||
|  | @ -2,8 +2,8 @@ from django import template | ||||||
| register = template.Library() | register = template.Library() | ||||||
| 
 | 
 | ||||||
| from personalni.utils import normalizuj_jmeno | from personalni.utils import normalizuj_jmeno | ||||||
| import seminar.models as m # jen kvůli typové anotaci… | from personalni.models import Osoba # jen kvůli typové anotaci… | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def jmeno_jako_prefix(o: m.Osoba): | def jmeno_jako_prefix(o: Osoba): | ||||||
| 	return normalizuj_jmeno(o).replace(' ', '_') | 	return normalizuj_jmeno(o).replace(' ', '_') | ||||||
|  |  | ||||||
|  | @ -5,10 +5,10 @@ from various.views.generic import viewMethodSwitch | ||||||
| from . import views | from . import views | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
| 	path('org/add_solution', org_required(views.VlozReseniView.as_view()), name='seminar_vloz_reseni'), | 	path('org/add_solution', org_required(views.VlozReseniView.as_view()), name='odevzdavatko_vloz_reseni'), | ||||||
| 	path('resitel/nahraj_reseni', resitel_required(views.NahrajReseniRozcestnikTematekView.as_view()), name='seminar_nahraj_reseni'), | 	path('resitel/nahraj_reseni', resitel_required(views.NahrajReseniRozcestnikTematekView.as_view()), name='odevzdavatko_nahraj_reseni'), | ||||||
| 	path('resitel/nahraj_reseni/<int:nadproblem_id>/', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'), | 	path('resitel/nahraj_reseni/<int:nadproblem_id>/', resitel_required(views.NahrajReseniView.as_view()), name='odevzdavatko_nahraj_reseni'), | ||||||
| 	path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='seminar_resitel_odevzdana_reseni'), | 	path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='odevzdavatko_resitel_odevzdana_reseni'), | ||||||
| 
 | 
 | ||||||
| 	path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), | 	path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), | ||||||
| 	path('org/reseni/rocnik/<int:rocnik>/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), | 	path('org/reseni/rocnik/<int:rocnik>/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), | ||||||
|  |  | ||||||
|  | @ -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 })") | ||||||
|  | @ -512,5 +516,5 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): | ||||||
| 		return formularOKView( | 		return formularOKView( | ||||||
| 			self.request, | 			self.request, | ||||||
| 			text='Řešení úspěšně odevzdáno', | 			text='Řešení úspěšně odevzdáno', | ||||||
| 			dalsi_odkazy=[("Odevzdat další řešení", reverse("seminar_nahraj_reseni"))], | 			dalsi_odkazy=[("Odevzdat další řešení", reverse("odevzdavatko_nahraj_reseni"))], | ||||||
| 		) | 		) | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ from django.contrib import admin | ||||||
| from django.contrib.auth.models import Group | from django.contrib.auth.models import Group | ||||||
| from django_reverse_admin import ReverseModelAdmin | from django_reverse_admin import ReverseModelAdmin | ||||||
| from django.contrib.messages import WARNING, ERROR, SUCCESS | from django.contrib.messages import WARNING, ERROR, SUCCESS | ||||||
| import seminar.models as m | import personalni.models as m | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| 
 | 
 | ||||||
| @admin.action(description="Sjednoť telefony") | @admin.action(description="Sjednoť telefony") | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ from django.contrib.auth.forms import PasswordResetForm | ||||||
| from django.core.exceptions import ObjectDoesNotExist | from django.core.exceptions import ObjectDoesNotExist | ||||||
| from django.contrib.auth.models import User | from django.contrib.auth.models import User | ||||||
| 
 | 
 | ||||||
| from seminar.models import Skola, Resitel, Osoba | from personalni.models import Skola, Resitel, Osoba | ||||||
| 
 | 
 | ||||||
| from datetime import date | from datetime import date | ||||||
| import logging | import logging | ||||||
|  | @ -27,7 +27,7 @@ class TelInput(forms.TextInput): | ||||||
| 
 | 
 | ||||||
| class UdajeForm(forms.Form): | class UdajeForm(forms.Form): | ||||||
| 	username = None | 	username = None | ||||||
| 	err_logger = logging.getLogger('seminar.prihlaska.problem') | 	err_logger = logging.getLogger('personalni.prihlaska.problem') | ||||||
| 
 | 
 | ||||||
| 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) | 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) | ||||||
| 	prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) | 	prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) | ||||||
|  | @ -147,7 +147,7 @@ class PrihlaskaForm(PasswordResetForm, UdajeForm): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ProfileEditForm(UdajeForm): | class ProfileEditForm(UdajeForm): | ||||||
| 	err_logger = logging.getLogger('seminar.edit.problem') | 	err_logger = logging.getLogger('personalni.prihlaska.problem.edit') | ||||||
| 	username = forms.CharField( | 	username = forms.CharField( | ||||||
| 		label='Přihlašovací jméno', | 		label='Přihlašovací jméno', | ||||||
| 		max_length=256, | 		max_length=256, | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ from django_countries.fields import CountryField | ||||||
| 
 | 
 | ||||||
| from reversion import revisions as reversion | from reversion import revisions as reversion | ||||||
| 
 | 
 | ||||||
| from seminar.models.base import SeminarModelBase | from various.models import SeminarModelBase | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -78,7 +78,7 @@ | ||||||
| 		<li>hlasování o přednáškách</li> | 		<li>hlasování o přednáškách</li> | ||||||
| 	</ul> | 	</ul> | ||||||
| 	</li> | 	</li> | ||||||
| 	<li><a href="{% url 'seminar_seznam_soustredeni' %}">proběhlá soustředění</a> | 	<li><a href="{% url 'soustredeni_seznam' %}">proběhlá soustředění</a> | ||||||
| 	<ul> | 	<ul> | ||||||
| 		<li>vytvoření galerie</li> | 		<li>vytvoření galerie</li> | ||||||
| 		<li>stažení seznamu účastníků</li> | 		<li>stažení seznamu účastníků</li> | ||||||
|  |  | ||||||
|  | @ -10,9 +10,9 @@ | ||||||
| </h1> | </h1> | ||||||
| 
 | 
 | ||||||
| <a href="{% url 'logout' %}">Odhlásit se</a><br> | <a href="{% url 'logout' %}">Odhlásit se</a><br> | ||||||
| <a href="{% url 'seminar_resitel_edit' %}">Upravit údaje</a><br> | <a href="{% url 'personalni_resitel_edit' %}">Upravit údaje</a><br> | ||||||
| <a href="{% url 'seminar_nahraj_reseni' %}">Nahrát řešení</a><br> | <a href="{% url 'odevzdavatko_nahraj_reseni' %}">Nahrát řešení</a><br> | ||||||
| <a href="{% url 'seminar_resitel_odevzdana_reseni' %}">Již odevzdaná řešení</a><br> | <a href="{% url 'odevzdavatko_resitel_odevzdana_reseni' %}">Již odevzdaná řešení</a><br> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
| <hr> | <hr> | ||||||
| <p><a href="{% url 'reset_password' %}">Změnit heslo</a></p> | <p><a href="{% url 'reset_password' %}">Změnit heslo</a></p> | ||||||
| 
 | 
 | ||||||
| <form action="{% url 'seminar_resitel_edit' %}" method="post"> | <form action="{% url 'personalni_resitel_edit' %}" method="post"> | ||||||
|   {% include "personalni/udaje/udaje.html"%} |   {% include "personalni/udaje/udaje.html"%} | ||||||
|   <input type="submit" value="Změnit"> |   <input type="submit" value="Změnit"> | ||||||
| </form> | </form> | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ | ||||||
| 
 | 
 | ||||||
| <p><b>Tučně</b> popsaná pole jsou povinná.</p> | <p><b>Tučně</b> popsaná pole jsou povinná.</p> | ||||||
| 
 | 
 | ||||||
| <form action="{% url 'seminar_prihlaska' %}" method="post"> | <form action="{% url 'personalni_prihlaska' %}" method="post"> | ||||||
|   {% include "personalni/udaje/udaje.html" %} |   {% include "personalni/udaje/udaje.html" %} | ||||||
|   <h4> |   <h4> | ||||||
|     GDPR |     GDPR | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ from django.contrib.auth.models import User, Group | ||||||
| from django.contrib.admin.sites import AdminSite | from django.contrib.admin.sites import AdminSite | ||||||
| from personalni.admin import OsobaAdmin, udelej_orgem | from personalni.admin import OsobaAdmin, udelej_orgem | ||||||
| # Tohle bude peklo, až jednou ty modely fakt rozstřelíme… Možná vyrobit various.all_models, které půjdou importovat jako m? :-) | # Tohle bude peklo, až jednou ty modely fakt rozstřelíme… Možná vyrobit various.all_models, které půjdou importovat jako m? :-) | ||||||
| import seminar.models as m | import personalni.models as m | ||||||
| 
 | 
 | ||||||
| import logging | import logging | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  | @ -7,15 +7,15 @@ urlpatterns = [ | ||||||
| 	path( | 	path( | ||||||
| 		'org/rozcestnik/', | 		'org/rozcestnik/', | ||||||
| 		org_required(views.OrgoRozcestnikView.as_view()), | 		org_required(views.OrgoRozcestnikView.as_view()), | ||||||
| 		name='seminar_org_rozcestnik' | 		name='personalni_org_rozcestnik' | ||||||
| 	), | 	), | ||||||
| 
 | 
 | ||||||
| 	path('prihlaska/', views.prihlaskaView, name='seminar_prihlaska'), | 	path('prihlaska/', views.prihlaskaView, name='personalni_prihlaska'), | ||||||
| 
 | 
 | ||||||
| 	path( | 	path( | ||||||
| 		'resitel/osobni-udaje/', | 		'resitel/osobni-udaje/', | ||||||
| 		login_required(views.resitelEditView), | 		login_required(views.resitelEditView), | ||||||
| 		name='seminar_resitel_edit' | 		name='personalni_resitel_edit' | ||||||
| 	), | 	), | ||||||
| 
 | 
 | ||||||
| 	# Obecný view na profil -- orgům dá rozcestník, řešitelům jejich stránku | 	# Obecný view na profil -- orgům dá rozcestník, řešitelům jejich stránku | ||||||
|  |  | ||||||
|  | @ -1,4 +1,3 @@ | ||||||
| import seminar.models as m |  | ||||||
| from various.utils import bez_diakritiky_translate | from various.utils import bez_diakritiky_translate | ||||||
| import re | import re | ||||||
| 
 | 
 | ||||||
|  | @ -7,9 +6,10 @@ from django.contrib.auth.decorators import permission_required, user_passes_test | ||||||
| from django.contrib.auth.models import AnonymousUser | from django.contrib.auth.models import AnonymousUser | ||||||
| from django.db import transaction | from django.db import transaction | ||||||
| 
 | 
 | ||||||
| import seminar.models as m |  | ||||||
| import soustredeni.models | import soustredeni.models | ||||||
| 
 | 
 | ||||||
|  | from odevzdavatko.models import Reseni_Resitele | ||||||
|  | 
 | ||||||
| from .models import Osoba, Organizator, Skola, Resitel, Prijemce | from .models import Osoba, Organizator, Skola, Resitel, Prijemce | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -97,7 +97,7 @@ def merge_resitele(cilovy, zdrojovy): | ||||||
| 	# Přepojit všechny vazby ze zdrojového na cílového | 	# Přepojit všechny vazby ze zdrojového na cílového | ||||||
| 	print('Přepojuji vazby') | 	print('Přepojuji vazby') | ||||||
| 	# Vazby: Škola (hotovo), Řešení_Řešitelé, Konfery_Účastníci, Soustředění_Účastníci, Osoba (vyřeší se později, nejde přepojit) | 	# Vazby: Škola (hotovo), Řešení_Řešitelé, Konfery_Účastníci, Soustředění_Účastníci, Osoba (vyřeší se později, nejde přepojit) | ||||||
| 	ct = m.Reseni_Resitele.objects.filter(resitele=zdrojovy).update(resitele=cilovy) | 	ct = Reseni_Resitele.objects.filter(resitele=zdrojovy).update(resitele=cilovy) | ||||||
| 	print(f' Přepojeno {ct} řešení') | 	print(f' Přepojeno {ct} řešení') | ||||||
| 	ct = soustredeni.models.Konfery_Ucastnici.objects.filter(resitel=zdrojovy).update(resitel=cilovy) | 	ct = soustredeni.models.Konfery_Ucastnici.objects.filter(resitel=zdrojovy).update(resitel=cilovy) | ||||||
| 	print(f' Přepojeno {ct} konfer') | 	print(f' Přepojeno {ct} konfer') | ||||||
|  |  | ||||||
|  | @ -16,8 +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 seminar.models as m | import personalni.models as m | ||||||
|  | from soustredeni.models import Soustredeni | ||||||
|  | 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 | ||||||
|  | @ -91,22 +95,22 @@ 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'] = s.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é | ||||||
| 		# pokud nechceme haluzit kód (= poradi) dalšího čísla, bude asi potřeba jít | 		# pokud nechceme haluzit kód (= poradi) dalšího čísla, bude asi potřeba jít | ||||||
| 		# přes treenody (a dát si přitom pozor na MezicisloNode) | 		# přes treenody (a dát si přitom pozor na MezicisloNode) | ||||||
| 
 | 
 | ||||||
| 		neobodovana_reseni = s.Hodnoceni.objects.filter(body__isnull=True) | 		neobodovana_reseni = Hodnoceni.objects.filter(body__isnull=True) | ||||||
| 		reseni_mimo_cislo = s.Hodnoceni.objects.filter(deadline_body__isnull=True) | 		reseni_mimo_cislo = Hodnoceni.objects.filter(deadline_body__isnull=True) | ||||||
| 		context['pocet_neobodovanych_reseni'] = neobodovana_reseni.count() | 		context['pocet_neobodovanych_reseni'] = neobodovana_reseni.count() | ||||||
| 		context['pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.count() | 		context['pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.count() | ||||||
| 
 | 
 | ||||||
| 		u = self.request.user | 		u = self.request.user | ||||||
| 		os = s.Osoba.objects.get(user=u) | 		os = m.Osoba.objects.get(user=u) | ||||||
| 		organizator = s.Organizator.objects.get(osoba=os) | 		organizator = m.Organizator.objects.get(osoba=os) | ||||||
| 
 | 
 | ||||||
| 		context['muj_pocet_neobodovanych_reseni'] = neobodovana_reseni.filter(Q(problem__garant=organizator) | Q(problem__autor=organizator) | Q(problem__opravovatele__in=[organizator])).distinct().count() | 		context['muj_pocet_neobodovanych_reseni'] = neobodovana_reseni.filter(Q(problem__garant=organizator) | Q(problem__autor=organizator) | Q(problem__opravovatele__in=[organizator])).distinct().count() | ||||||
| 		context['muj_pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.filter(Q(problem__garant=organizator) | Q(problem__autor=organizator) | Q(problem__opravovatele__in=[organizator])).count() | 		context['muj_pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.filter(Q(problem__garant=organizator) | Q(problem__autor=organizator) | Q(problem__opravovatele__in=[organizator])).count() | ||||||
|  | @ -116,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 | ||||||
|  | @ -134,12 +138,12 @@ class OrgoRozcestnikView(TemplateView): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ResitelView(LoginRequiredMixin,generic.DetailView): | class ResitelView(LoginRequiredMixin,generic.DetailView): | ||||||
| 	model = s.Resitel | 	model = m.Resitel | ||||||
| 	template_name = 'personalni/profil/resitel.html' | 	template_name = 'personalni/profil/resitel.html' | ||||||
| 
 | 
 | ||||||
| 	def get_object(self, queryset=None): | 	def get_object(self, queryset=None): | ||||||
| 		print(self.request.user) | 		print(self.request.user) | ||||||
| 		return s.Resitel.objects.get(osoba__user=self.request.user) | 		return m.Resitel.objects.get(osoba__user=self.request.user) | ||||||
| 
 | 
 | ||||||
| ### Formulare | ### Formulare | ||||||
| 
 | 
 | ||||||
|  | @ -157,10 +161,10 @@ def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data): | ||||||
| 
 | 
 | ||||||
| @sensitive_post_parameters('jmeno', 'prijmeni', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'skola') | @sensitive_post_parameters('jmeno', 'prijmeni', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'skola') | ||||||
| def resitelEditView(request): | def resitelEditView(request): | ||||||
| 	err_logger = logging.getLogger('seminar.prihlaska.problem') | 	err_logger = logging.getLogger('personalni.prihlaska.problem') | ||||||
| 	## Načtení objektů Osoba a Resitel patřících k aktuálně přihlášenému uživateli | 	## Načtení objektů Osoba a Resitel patřících k aktuálně přihlášenému uživateli | ||||||
| 	u = request.user | 	u = request.user | ||||||
| 	osoba_edit = s.Osoba.objects.get(user=u) | 	osoba_edit = m.Osoba.objects.get(user=u) | ||||||
| 	if hasattr(osoba_edit,'resitel'): | 	if hasattr(osoba_edit,'resitel'): | ||||||
| 		resitel_edit = osoba_edit.resitel | 		resitel_edit = osoba_edit.resitel | ||||||
| 	else: | 	else: | ||||||
|  | @ -195,7 +199,7 @@ def resitelEditView(request): | ||||||
| 			## Změny v osobě | 			## Změny v osobě | ||||||
| 			fcd = form.cleaned_data | 			fcd = form.cleaned_data | ||||||
| 			form_hash = hash(frozenset(fcd.items())) | 			form_hash = hash(frozenset(fcd.items())) | ||||||
| 			form_logger = logging.getLogger('seminar.prihlaska.form') | 			form_logger = logging.getLogger('personalni.prihlaska.form') | ||||||
| 			form_logger.info("EDIT:" + str(fcd) + str(form_hash))  # TODO možná logovat jinak | 			form_logger.info("EDIT:" + str(fcd) + str(form_hash))  # TODO možná logovat jinak | ||||||
| 			osoba_edit.jmeno = fcd['jmeno'] | 			osoba_edit.jmeno = fcd['jmeno'] | ||||||
| 			osoba_edit.prijmeni = fcd['prijmeni'] | 			osoba_edit.prijmeni = fcd['prijmeni'] | ||||||
|  | @ -244,9 +248,9 @@ def resitelEditView(request): | ||||||
| 
 | 
 | ||||||
| @sensitive_post_parameters('jmeno', 'prijmeni', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'skola', 'jak_se_dozvedeli') | @sensitive_post_parameters('jmeno', 'prijmeni', 'email', 'telefon', 'datum_narozeni', 'ulice', 'mesto', 'psc', 'skola', 'jak_se_dozvedeli') | ||||||
| def prihlaskaView(request): | def prihlaskaView(request): | ||||||
| 	generic_logger = logging.getLogger('seminar.prihlaska') | 	generic_logger = logging.getLogger('personalni.prihlaska') | ||||||
| 	err_logger = logging.getLogger('seminar.prihlaska.problem') | 	err_logger = logging.getLogger('personalni.prihlaska.problem') | ||||||
| 	form_logger = logging.getLogger('seminar.prihlaska.form') | 	form_logger = logging.getLogger('personalni.prihlaska.form') | ||||||
| 	if request.method == 'POST': | 	if request.method == 'POST': | ||||||
| 		form = PrihlaskaForm(request.POST) | 		form = PrihlaskaForm(request.POST) | ||||||
| 		# TODO vyresit, co se bude v jakych situacich zobrazovat | 		# TODO vyresit, co se bude v jakych situacich zobrazovat | ||||||
|  | @ -266,7 +270,7 @@ def prihlaskaView(request): | ||||||
| 				resitel_grp = Group.objects.filter(name__exact='resitel').first() | 				resitel_grp = Group.objects.filter(name__exact='resitel').first() | ||||||
| 				u.groups.add(resitel_grp) | 				u.groups.add(resitel_grp) | ||||||
| 
 | 
 | ||||||
| 				o = s.Osoba( | 				o = m.Osoba( | ||||||
| 					jmeno = fcd['jmeno'], | 					jmeno = fcd['jmeno'], | ||||||
| 					prijmeni = fcd['prijmeni'], | 					prijmeni = fcd['prijmeni'], | ||||||
| 					osloveni = fcd['osloveni'], | 					osloveni = fcd['osloveni'], | ||||||
|  | @ -328,7 +332,7 @@ def prihlaskaView(request): | ||||||
| 				if kolize.count() > 1:	# Jednu z nich jsme právě uložili | 				if kolize.count() > 1:	# Jednu z nich jsme právě uložili | ||||||
| 					err_logger.warning(f'Zaregistrovala se osoba s kolizním jménem. ID osob: {[o.id for o in kolize]}') | 					err_logger.warning(f'Zaregistrovala se osoba s kolizním jménem. ID osob: {[o.id for o in kolize]}') | ||||||
| 
 | 
 | ||||||
| 				r = s.Resitel( | 				r = m.Resitel( | ||||||
| 					prezdivka_resitele=fcd['prezdivka_resitele'] if fcd['prezdivka_resitele'] != "" else None, | 					prezdivka_resitele=fcd['prezdivka_resitele'] if fcd['prezdivka_resitele'] != "" else None, | ||||||
| 					rok_maturity = fcd['rok_maturity'], | 					rok_maturity = fcd['rok_maturity'], | ||||||
| 					zasilat = fcd['zasilat'], | 					zasilat = fcd['zasilat'], | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ from django.utils.safestring import mark_safe | ||||||
| from django.utils.html import escape | from django.utils.html import escape | ||||||
| 
 | 
 | ||||||
| from .models import Prednaska, Seznam, STAV_NAVRH | from .models import Prednaska, Seznam, STAV_NAVRH | ||||||
| from seminar.models import Soustredeni | from soustredeni.models import Soustredeni | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Seznam_PrednaskaInline(admin.TabularInline): | class Seznam_PrednaskaInline(admin.TabularInline): | ||||||
|  |  | ||||||
|  | @ -6,7 +6,8 @@ from django.db.models import Sum | ||||||
| from django.forms import Form | from django.forms import Form | ||||||
| 
 | 
 | ||||||
| from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH | from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH | ||||||
| from seminar.models import Soustredeni, Osoba | from soustredeni.models import Soustredeni | ||||||
|  | from personalni.models import Osoba | ||||||
| 
 | 
 | ||||||
| def newPrednaska(request): | def newPrednaska(request): | ||||||
| 	# hlasovani se vztahuje k nejnovejsimu soustredeni | 	# hlasovani se vztahuje k nejnovejsimu soustredeni | ||||||
|  |  | ||||||
|  | @ -1,6 +1,4 @@ | ||||||
| """ | """ | ||||||
| Zde bývalo vše. Teď tu zbývají všechny modely a části webu jako archiv, | Zde bývalo vše. Teď tu zbývají migrace. | ||||||
| přehled orgů, aktuální (k aktuálnímu číslu) věci, titulka a jak řešit. | A kód pro `import seminar.models as m` pro ./manage.py shell. | ||||||
| 
 | """ | ||||||
| Také je tu generování testovacích (lokálních) dat. |  | ||||||
| """ |  | ||||||
|  |  | ||||||
|  | @ -2,10 +2,11 @@ from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import models, migrations | from django.db import models, migrations | ||||||
| import django_countries.fields | import django_countries.fields | ||||||
| import seminar.models |  | ||||||
| import django.utils.timezone | import django.utils.timezone | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| 
 | 
 | ||||||
|  | from odevzdavatko.models import generate_filename | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
| 
 | 
 | ||||||
|  | @ -75,7 +76,7 @@ class Migration(migrations.Migration): | ||||||
|             fields=[ |             fields=[ | ||||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), |                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||||
|                 ('timestamp', models.DateTimeField(auto_now=True, verbose_name='vytvo\u0159eno')), |                 ('timestamp', models.DateTimeField(auto_now=True, verbose_name='vytvo\u0159eno')), | ||||||
|                 ('soubor', models.FileField(upload_to=seminar.models.generate_filename, verbose_name='soubor')), |                 ('soubor', models.FileField(upload_to=generate_filename, verbose_name='soubor')), | ||||||
|                 ('poznamka', models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka k p\u0159\xedloze \u0159e\u0161en\xed (plain text), nap\u0159. o p\u016fvodu', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True)), |                 ('poznamka', models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka k p\u0159\xedloze \u0159e\u0161en\xed (plain text), nap\u0159. o p\u016fvodu', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True)), | ||||||
|             ], |             ], | ||||||
|             options={ |             options={ | ||||||
|  |  | ||||||
|  | @ -7,9 +7,12 @@ import django.db.models.deletion | ||||||
| import django.utils.timezone | import django.utils.timezone | ||||||
| import django_countries.fields | import django_countries.fields | ||||||
| import imagekit.models.fields | import imagekit.models.fields | ||||||
| import seminar.models |  | ||||||
| import taggit.managers | import taggit.managers | ||||||
| 
 | 
 | ||||||
|  | from soustredeni.models import generate_filename_konfera | ||||||
|  | from odevzdavatko.models import generate_filename | ||||||
|  | from tvorba.models import cislo_pdf_filename, cislo_png_filename | ||||||
|  | 
 | ||||||
| from datetime import date | from datetime import date | ||||||
| from django.db.models import Q | from django.db.models import Q | ||||||
| from treenode.treelib import get_parent | from treenode.treelib import get_parent | ||||||
|  | @ -962,7 +965,7 @@ class Migration(migrations.Migration): | ||||||
|             fields=[ |             fields=[ | ||||||
|                 ('id', models.AutoField(primary_key=True, serialize=False)), |                 ('id', models.AutoField(primary_key=True, serialize=False)), | ||||||
|                 ('timestamp', models.DateTimeField(auto_now=True, verbose_name='vytvořeno')), |                 ('timestamp', models.DateTimeField(auto_now=True, verbose_name='vytvořeno')), | ||||||
|                 ('soubor', models.FileField(upload_to=seminar.models.generate_filename, verbose_name='soubor')), |                 ('soubor', models.FileField(upload_to=generate_filename, verbose_name='soubor')), | ||||||
|                 ('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k příloze řešení (plain text), např. o původu', verbose_name='neveřejná poznámka')), |                 ('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k příloze řešení (plain text), např. o původu', verbose_name='neveřejná poznámka')), | ||||||
|                 ('reseni', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='prilohy', to='seminar.Reseni', verbose_name='řešení')), |                 ('reseni', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='prilohy', to='seminar.Reseni', verbose_name='řešení')), | ||||||
|             ], |             ], | ||||||
|  | @ -1284,7 +1287,7 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AddField( |         migrations.AddField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='pdf', |             name='pdf', | ||||||
|             field=models.FileField(blank=True, help_text='Pdf čísla, které si mohou řešitelé stáhnout', null=True, upload_to=seminar.models.cislo_pdf_filename, verbose_name='pdf'), |             field=models.FileField(blank=True, help_text='Pdf čísla, které si mohou řešitelé stáhnout', null=True, upload_to=cislo_pdf_filename, verbose_name='pdf'), | ||||||
|         ), |         ), | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='problem', |             model_name='problem', | ||||||
|  | @ -1361,8 +1364,8 @@ class Migration(migrations.Migration): | ||||||
|                 ('abstrakt', models.TextField(blank=True, help_text='Abstrakt konfery tak, jak byl uveden ve sborníku', verbose_name='abstrakt')), |                 ('abstrakt', models.TextField(blank=True, help_text='Abstrakt konfery tak, jak byl uveden ve sborníku', verbose_name='abstrakt')), | ||||||
|                 ('org_poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka ke konfeře(plain text)', verbose_name='neveřejná poznámka')), |                 ('org_poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka ke konfeře(plain text)', verbose_name='neveřejná poznámka')), | ||||||
|                 ('typ_prezentace', models.CharField(choices=[(b'veletrh', 'Veletrh (postery)'), (b'prezentace', 'Prezentace (přednáška)')], default=b'veletrh', max_length=16, verbose_name='typ prezentace')), |                 ('typ_prezentace', models.CharField(choices=[(b'veletrh', 'Veletrh (postery)'), (b'prezentace', 'Prezentace (přednáška)')], default=b'veletrh', max_length=16, verbose_name='typ prezentace')), | ||||||
|                 ('prezentace', models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=seminar.models.generate_filename_konfera, verbose_name='prezentace')), |                 ('prezentace', models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=generate_filename_konfera, verbose_name='prezentace')), | ||||||
|                 ('materialy', models.FileField(help_text='Další materiály ke konfeře zabalené do jednoho souboru', upload_to=seminar.models.generate_filename_konfera, verbose_name='materialy')), |                 ('materialy', models.FileField(help_text='Další materiály ke konfeře zabalené do jednoho souboru', upload_to=generate_filename_konfera, verbose_name='materialy')), | ||||||
|                 ('organizator', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='konfery', to='seminar.Organizator', verbose_name='organizátor')), |                 ('organizator', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='konfery', to='seminar.Organizator', verbose_name='organizátor')), | ||||||
|                 ('soustredeni', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='konfery', to='seminar.Soustredeni', verbose_name='soustředění')), |                 ('soustredeni', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='konfery', to='seminar.Soustredeni', verbose_name='soustředění')), | ||||||
|             ], |             ], | ||||||
|  | @ -1400,12 +1403,12 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='konfera', |             model_name='konfera', | ||||||
|             name='materialy', |             name='materialy', | ||||||
|             field=models.FileField(blank=True, help_text='Další materiály ke konfeře zabalené do jednoho souboru', upload_to=seminar.models.generate_filename_konfera, verbose_name='materialy'), |             field=models.FileField(blank=True, help_text='Další materiály ke konfeře zabalené do jednoho souboru', upload_to=generate_filename_konfera, verbose_name='materialy'), | ||||||
|         ), |         ), | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='konfera', |             model_name='konfera', | ||||||
|             name='prezentace', |             name='prezentace', | ||||||
|             field=models.FileField(blank=True, help_text='Prezentace nebo fotka posteru', upload_to=seminar.models.generate_filename_konfera, verbose_name='prezentace'), |             field=models.FileField(blank=True, help_text='Prezentace nebo fotka posteru', upload_to=generate_filename_konfera, verbose_name='prezentace'), | ||||||
|         ), |         ), | ||||||
|         migrations.AddField( |         migrations.AddField( | ||||||
|             model_name='konfera', |             model_name='konfera', | ||||||
|  | @ -2648,12 +2651,12 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='pdf', |             name='pdf', | ||||||
|             field=models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, upload_to=seminar.models.cislo_pdf_filename, verbose_name='pdf'), |             field=models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, upload_to=cislo_pdf_filename, verbose_name='pdf'), | ||||||
|         ), |         ), | ||||||
|         migrations.AddField( |         migrations.AddField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='titulka_nahled', |             name='titulka_nahled', | ||||||
|             field=models.ImageField(blank=True, help_text='Obrázek titulní strany, generuje se automaticky', null=True, upload_to=seminar.models.cislo_png_filename, verbose_name='Obrázek titulní strany'), |             field=models.ImageField(blank=True, help_text='Obrázek titulní strany, generuje se automaticky', null=True, upload_to=cislo_png_filename, verbose_name='Obrázek titulní strany'), | ||||||
|         ), |         ), | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='treenode', |             model_name='treenode', | ||||||
|  |  | ||||||
|  | @ -1,10 +1,6 @@ | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import models, migrations | from django.db import migrations | ||||||
| import django_countries.fields |  | ||||||
| import seminar.models |  | ||||||
| import django.utils.timezone |  | ||||||
| from django.conf import settings |  | ||||||
| 
 | 
 | ||||||
| CREATE_VIEWS=""" | CREATE_VIEWS=""" | ||||||
| create view seminar_body_za_cislo as | create view seminar_body_za_cislo as | ||||||
|  |  | ||||||
|  | @ -1,10 +1,6 @@ | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import models, migrations | from django.db import migrations | ||||||
| import django_countries.fields |  | ||||||
| import seminar.models |  | ||||||
| import django.utils.timezone |  | ||||||
| from django.conf import settings |  | ||||||
| 
 | 
 | ||||||
| CREATE_VIEWS=""" | CREATE_VIEWS=""" | ||||||
| drop view seminar_body_k_cislu; | drop view seminar_body_k_cislu; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,6 @@ | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import models, migrations | from django.db import migrations | ||||||
| import django_countries.fields |  | ||||||
| import seminar.models |  | ||||||
| import django.utils.timezone |  | ||||||
| from django.conf import settings |  | ||||||
| 
 | 
 | ||||||
| CREATE_VIEWS=""" | CREATE_VIEWS=""" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import models, migrations | from django.db import models, migrations | ||||||
| import seminar.models | from tvorba.models import cislo_pdf_filename | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
|  | @ -14,7 +14,7 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AddField( |         migrations.AddField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='pdf', |             name='pdf', | ||||||
|             field=models.FileField(help_text='Pdf \u010d\xedsla, kter\xe9 si mohou \u0159e\u0161itel\xe9 st\xe1hnout', upload_to=seminar.models.cislo_pdf_filename, null=True, verbose_name='pdf'), |             field=models.FileField(help_text='Pdf \u010d\xedsla, kter\xe9 si mohou \u0159e\u0161itel\xe9 st\xe1hnout', upload_to=cislo_pdf_filename, null=True, verbose_name='pdf'), | ||||||
|             preserve_default=True, |             preserve_default=True, | ||||||
|         ), |         ), | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|  | @ -2,7 +2,8 @@ from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import models, migrations | from django.db import models, migrations | ||||||
| import django_countries.fields | import django_countries.fields | ||||||
| import seminar.models | 
 | ||||||
|  | from tvorba.models import cislo_pdf_filename | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
|  | @ -25,7 +26,7 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='pdf', |             name='pdf', | ||||||
|             field=models.FileField(help_text='Pdf \u010d\xedsla, kter\xe9 si mohou \u0159e\u0161itel\xe9 st\xe1hnout', upload_to=seminar.models.cislo_pdf_filename, null=True, verbose_name='pdf', blank=True), |             field=models.FileField(help_text='Pdf \u010d\xedsla, kter\xe9 si mohou \u0159e\u0161itel\xe9 st\xe1hnout', upload_to=cislo_pdf_filename, null=True, verbose_name='pdf', blank=True), | ||||||
|             preserve_default=True, |             preserve_default=True, | ||||||
|         ), |         ), | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|  |  | ||||||
|  | @ -2,7 +2,8 @@ from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import migrations, models | from django.db import migrations, models | ||||||
| import django.db.models.deletion | import django.db.models.deletion | ||||||
| import seminar.models | 
 | ||||||
|  | from soustredeni.models import generate_filename_konfera | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
|  | @ -21,8 +22,8 @@ class Migration(migrations.Migration): | ||||||
|                 ('abstrakt', models.TextField(help_text='Abstrakt konfery tak, jak byl uveden ve sborn\xedku', verbose_name='abstrakt', blank=True)), |                 ('abstrakt', models.TextField(help_text='Abstrakt konfery tak, jak byl uveden ve sborn\xedku', verbose_name='abstrakt', blank=True)), | ||||||
|                 ('org_poznamka', models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka ke konfe\u0159e(plain text)', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True)), |                 ('org_poznamka', models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka ke konfe\u0159e(plain text)', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True)), | ||||||
|                 ('typ_prezentace', models.CharField(default=b'veletrh', max_length=16, verbose_name='typ prezentace', choices=[(b'veletrh', 'Veletrh (postery)'), (b'prezentace', 'Prezentace (p\u0159edn\xe1\u0161ka)')])), |                 ('typ_prezentace', models.CharField(default=b'veletrh', max_length=16, verbose_name='typ prezentace', choices=[(b'veletrh', 'Veletrh (postery)'), (b'prezentace', 'Prezentace (p\u0159edn\xe1\u0161ka)')])), | ||||||
|                 ('prezentace', models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=seminar.models.generate_filename_konfera, verbose_name='prezentace')), |                 ('prezentace', models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=generate_filename_konfera, verbose_name='prezentace')), | ||||||
|                 ('materialy', models.FileField(help_text='Dal\u0161\xed materi\xe1ly ke konfe\u0159e zabalen\xe9 do jednoho souboru', upload_to=seminar.models.generate_filename_konfera, verbose_name='materialy')), |                 ('materialy', models.FileField(help_text='Dal\u0161\xed materi\xe1ly ke konfe\u0159e zabalen\xe9 do jednoho souboru', upload_to=generate_filename_konfera, verbose_name='materialy')), | ||||||
|                 ('organizator', models.ForeignKey(related_name='konfery', on_delete=django.db.models.deletion.SET_NULL, verbose_name='organiz\xe1tor', to='seminar.Organizator', null=True)), |                 ('organizator', models.ForeignKey(related_name='konfery', on_delete=django.db.models.deletion.SET_NULL, verbose_name='organiz\xe1tor', to='seminar.Organizator', null=True)), | ||||||
|             ], |             ], | ||||||
|             options={ |             options={ | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from django.db import migrations, models | from django.db import migrations, models | ||||||
| import django.db.models.deletion | import django.db.models.deletion | ||||||
| import seminar.models | from soustredeni.models import generate_filename_konfera | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
|  | @ -15,12 +15,12 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='konfera', |             model_name='konfera', | ||||||
|             name='materialy', |             name='materialy', | ||||||
|             field=models.FileField(help_text='Dal\u0161\xed materi\xe1ly ke konfe\u0159e zabalen\xe9 do jednoho souboru', upload_to=seminar.models.generate_filename_konfera, verbose_name='materialy', blank=True), |             field=models.FileField(help_text='Dal\u0161\xed materi\xe1ly ke konfe\u0159e zabalen\xe9 do jednoho souboru', upload_to=generate_filename_konfera, verbose_name='materialy', blank=True), | ||||||
|         ), |         ), | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='konfera', |             model_name='konfera', | ||||||
|             name='prezentace', |             name='prezentace', | ||||||
|             field=models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=seminar.models.generate_filename_konfera, verbose_name='prezentace', blank=True), |             field=models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=generate_filename_konfera, verbose_name='prezentace', blank=True), | ||||||
|         ), |         ), | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='konfera', |             model_name='konfera', | ||||||
|  |  | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| # Generated by Django 2.2.9 on 2020-04-08 20:21 | # Generated by Django 2.2.9 on 2020-04-08 20:21 | ||||||
| 
 | 
 | ||||||
| from django.db import migrations, models | from django.db import migrations, models | ||||||
| import seminar.models | 
 | ||||||
|  | from tvorba.models import cislo_pdf_filename | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
|  | @ -19,6 +20,6 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='pdf', |             name='pdf', | ||||||
|             field=models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, upload_to=seminar.models.cislo_pdf_filename, verbose_name='pdf'), |             field=models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, upload_to=cislo_pdf_filename, verbose_name='pdf'), | ||||||
|         ), |         ), | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| # Generated by Django 2.2.12 on 2020-05-06 17:51 | # Generated by Django 2.2.12 on 2020-05-06 17:51 | ||||||
| 
 | 
 | ||||||
| from django.db import migrations, models | from django.db import migrations, models | ||||||
| import seminar.models | from tvorba.models import cislo_png_filename | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
|  | @ -14,6 +14,6 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='titulka_nahled', |             name='titulka_nahled', | ||||||
|             field=models.ImageField(blank=True, help_text='Obrázek titulní strany, generuje se automaticky', null=True, upload_to=seminar.models.cislo_png_filename, verbose_name='Obrázek titulní strany'), |             field=models.ImageField(blank=True, help_text='Obrázek titulní strany, generuje se automaticky', null=True, upload_to=cislo_png_filename, verbose_name='Obrázek titulní strany'), | ||||||
|         ), |         ), | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| # Generated by Django 2.2.24 on 2021-11-29 22:54 | # Generated by Django 2.2.24 on 2021-11-29 22:54 | ||||||
| 
 | 
 | ||||||
| from django.db import migrations, models | from django.db import migrations, models | ||||||
| import seminar.models.tvorba | import various.models | ||||||
|  | from tvorba.models import cislo_pdf_filename | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||||
|  | @ -14,6 +15,6 @@ class Migration(migrations.Migration): | ||||||
|         migrations.AlterField( |         migrations.AlterField( | ||||||
|             model_name='cislo', |             model_name='cislo', | ||||||
|             name='pdf', |             name='pdf', | ||||||
|             field=models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, storage=seminar.models.tvorba.OverwriteStorage(), upload_to=seminar.models.tvorba.cislo_pdf_filename, verbose_name='pdf'), |             field=models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, storage=various.models.OverwriteStorage(), upload_to=cislo_pdf_filename, verbose_name='pdf'), | ||||||
|         ), |         ), | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ from django.db import migrations, models | ||||||
| import django.db.models.deletion | import django.db.models.deletion | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| 
 | 
 | ||||||
| import seminar.models as m | from tvorba.models import Deadline as mDeadline | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def vytvor_deadliny(apps, schema_editor): | def vytvor_deadliny(apps, schema_editor): | ||||||
|  | @ -16,7 +16,7 @@ def vytvor_deadliny(apps, schema_editor): | ||||||
|         if cislo.rocnik.rocnik < 26: |         if cislo.rocnik.rocnik < 26: | ||||||
|             Deadline.objects.create( |             Deadline.objects.create( | ||||||
|                 cislo=cislo, |                 cislo=cislo, | ||||||
|                 typ=m.Deadline.TYP_CISLA, |                 typ=mDeadline.TYP_CISLA, | ||||||
|                 deadline=timezone.make_aware(datetime.datetime.combine(datetime.date(1994 + cislo.rocnik.rocnik, 6, int(cislo.poradi[0])), datetime.time.min)), |                 deadline=timezone.make_aware(datetime.datetime.combine(datetime.date(1994 + cislo.rocnik.rocnik, 6, int(cislo.poradi[0])), datetime.time.min)), | ||||||
|                 verejna_vysledkovka=cislo.verejna_vysledkovka, |                 verejna_vysledkovka=cislo.verejna_vysledkovka, | ||||||
|             ) |             ) | ||||||
|  | @ -33,24 +33,24 @@ def vytvor_deadliny(apps, schema_editor): | ||||||
|         if cislo.datum_deadline_soustredeni and cislo.datum_deadline_soustredeni == cislo.datum_preddeadline: |         if cislo.datum_deadline_soustredeni and cislo.datum_deadline_soustredeni == cislo.datum_preddeadline: | ||||||
|             vytvor_deadline( |             vytvor_deadline( | ||||||
|                 date=cislo.datum_deadline_soustredeni, |                 date=cislo.datum_deadline_soustredeni, | ||||||
|                 typ=m.Deadline.TYP_PRVNI_A_SOUS |                 typ=mDeadline.TYP_PRVNI_A_SOUS | ||||||
|             ) |             ) | ||||||
|         else: |         else: | ||||||
|             if cislo.datum_deadline_soustredeni: |             if cislo.datum_deadline_soustredeni: | ||||||
|                 vytvor_deadline( |                 vytvor_deadline( | ||||||
|                     date=cislo.datum_deadline_soustredeni, |                     date=cislo.datum_deadline_soustredeni, | ||||||
|                     typ=m.Deadline.TYP_SOUS |                     typ=mDeadline.TYP_SOUS | ||||||
|                 ) |                 ) | ||||||
|             if cislo.datum_preddeadline: |             if cislo.datum_preddeadline: | ||||||
|                 vytvor_deadline( |                 vytvor_deadline( | ||||||
|                     date=cislo.datum_preddeadline, |                     date=cislo.datum_preddeadline, | ||||||
|                     typ=m.Deadline.TYP_PRVNI |                     typ=mDeadline.TYP_PRVNI | ||||||
|                 ) |                 ) | ||||||
| 
 | 
 | ||||||
|         if cislo.datum_deadline: |         if cislo.datum_deadline: | ||||||
|             vytvor_deadline( |             vytvor_deadline( | ||||||
|                 date=cislo.datum_deadline, |                 date=cislo.datum_deadline, | ||||||
|                 typ=m.Deadline.TYP_CISLA |                 typ=mDeadline.TYP_CISLA | ||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| # Generated by Django 3.2.15 on 2022-10-09 10:14 | # Generated by Django 3.2.15 on 2022-10-09 10:14 | ||||||
| 
 | 
 | ||||||
| from django.db import migrations | from django.db import migrations | ||||||
| from seminar.models import Deadline | from tvorba.models import Deadline | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def vrat_deadliny(apps, schema_editor): | def vrat_deadliny(apps, schema_editor): | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| # Generated by Django 3.2.15 on 2022-10-09 11:04 | # Generated by Django 3.2.15 on 2022-10-09 11:04 | ||||||
| 
 | 
 | ||||||
| from django.db import migrations | from django.db import migrations | ||||||
| from seminar.models import Deadline | from tvorba.models import Deadline | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def vrat_verejnost(apps, schema_editor): | def vrat_verejnost(apps, schema_editor): | ||||||
|  |  | ||||||
							
								
								
									
										15
									
								
								seminar/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								seminar/models.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | # Tento soubor slouží pouze pro shell a podobné. Nikde neimportovat v kódu! | ||||||
|  | 
 | ||||||
|  | print("Naimportoval jsi `seminar.models`. Pevně věřím, že to nebylo nikde v kódu. Díky.") | ||||||
|  | 
 | ||||||
|  | from galerie.models import * | ||||||
|  | from header_fotky.models import * | ||||||
|  | from korektury.models import * | ||||||
|  | from novinky.models import * | ||||||
|  | from odevzdavatko.models import * | ||||||
|  | from personalni.models import * | ||||||
|  | from prednasky.models import * | ||||||
|  | from soustredeni.models import * | ||||||
|  | from treenode.models import * | ||||||
|  | from tvorba.models import * | ||||||
|  | from various.models import * | ||||||
|  | @ -1,21 +0,0 @@ | ||||||
| from .tvorba import * |  | ||||||
| from .base import * |  | ||||||
| 
 |  | ||||||
| from various.models import Nastaveni |  | ||||||
| from personalni.models import Organizator, Resitel, Skola, Prijemce, Osoba |  | ||||||
| from soustredeni.models import Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Konfera, Konfery_Ucastnici |  | ||||||
| from novinky.models import Novinky |  | ||||||
| from odevzdavatko.models import Reseni, PrilohaReseni, Reseni_Resitele, Hodnoceni |  | ||||||
| from tvorba.models import ZmrazenaVysledkovka, Deadline, Cislo, Rocnik, Pohadka, Tema, Problem, Problemy_Opravovatele, Uloha, Clanek |  | ||||||
| from treenode.models import UlohaVzorakNode, UlohaZadaniNode, CisloNode, TemaVCisleNode, OrgTextNode, Obrazek, RocnikNode, PohadkaNode, TextNode, MezicisloNode, ReseniNode, CastNode, Text, TreeNode |  | ||||||
| 
 |  | ||||||
| # Kvůli migr. 0041 |  | ||||||
| from soustredeni.models import generate_filename_konfera |  | ||||||
| # migr. 0001 |  | ||||||
| from odevzdavatko.models import generate_filename |  | ||||||
| # migr. 0031, 0032, 0081 |  | ||||||
| from tvorba.models import cislo_pdf_filename |  | ||||||
| # migr. 0082 |  | ||||||
| from tvorba.models import cislo_png_filename |  | ||||||
| # migr 0100 (hack) |  | ||||||
| import tvorba.models as tvorba |  | ||||||
|  | @ -1,23 +0,0 @@ | ||||||
| from django.urls import reverse |  | ||||||
| from django.db import models |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class SeminarModelBase(models.Model): |  | ||||||
| 
 |  | ||||||
| 	class Meta: |  | ||||||
| 		abstract = True |  | ||||||
| 
 |  | ||||||
| 	def verejne(self): |  | ||||||
| 		return False |  | ||||||
| 
 |  | ||||||
| 	# def get_absolute_url(self): |  | ||||||
| 	# 	return "https://" + str(get_current_site(None)) + self.verejne_url() |  | ||||||
| 
 |  | ||||||
| 	def admin_url(self): |  | ||||||
| 		app_name = self._meta.app_label |  | ||||||
| 		model_name = self._meta.model_name |  | ||||||
| 		return reverse('admin:{}_{}_change'.format(app_name, model_name), args=(self.id, )) |  | ||||||
| 
 |  | ||||||
| # def verejne_url(self): |  | ||||||
| # 	return None |  | ||||||
| 
 |  | ||||||
|  | @ -1,14 +0,0 @@ | ||||||
| import os |  | ||||||
| import logging |  | ||||||
| 
 |  | ||||||
| from django.core.files.storage import FileSystemStorage |  | ||||||
| 
 |  | ||||||
| logger = logging.getLogger(__name__) |  | ||||||
| 
 |  | ||||||
| class OverwriteStorage(FileSystemStorage): |  | ||||||
| 	""" Varianta FileSystemStorage, která v případě, že soubor cílového |  | ||||||
| 	jména již existuje, ho smaže a místo něj uloží soubor nový""" |  | ||||||
| 	def get_available_name(self,name, max_length=None): |  | ||||||
| 		if self.exists(name): |  | ||||||
| 			os.remove(os.path.join(self.location,name)) |  | ||||||
| 		return super().get_available_name(name,max_length) |  | ||||||
|  | @ -9,8 +9,8 @@ from django.conf import settings | ||||||
| 
 | 
 | ||||||
| from personalni.models import Resitel, Organizator | from personalni.models import Resitel, Organizator | ||||||
| 
 | 
 | ||||||
| from seminar.models.base import SeminarModelBase | from various.models 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, | ||||||
|  | @ -75,7 +75,7 @@ class Soustredeni(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 	def verejne_url(self): | 	def verejne_url(self): | ||||||
| 		#return reverse('seminar_soustredeni', kwargs={'pk': self.id}) | 		#return reverse('seminar_soustredeni', kwargs={'pk': self.id}) | ||||||
| 		return reverse('seminar_seznam_soustredeni') | 		return reverse('soustredeni_seznam') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @reversion.register(ignore_duplicates=True) | @reversion.register(ignore_duplicates=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' | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ | ||||||
|         <div class="mam-org-only"> |         <div class="mam-org-only"> | ||||||
|           <a href="../{{soustredeni.pk}}/fotogalerie/0/new/">Vytvořit novou fotogalerii</a><br> |           <a href="../{{soustredeni.pk}}/fotogalerie/0/new/">Vytvořit novou fotogalerii</a><br> | ||||||
|           <a href="../{{soustredeni.pk}}/obalky.pdf">Vygenerovat obálky pro účastníky</a><br> |           <a href="../{{soustredeni.pk}}/obalky.pdf">Vygenerovat obálky pro účastníky</a><br> | ||||||
|           <a href={%  url 'seminar_soustredeni_abstrakty' soustredeni.pk %}>Vygenerovat účastníky a vedoucí do abstraktů</a><br> |           <a href={%  url 'soustredeni_abstrakty' soustredeni.pk %}>Vygenerovat účastníky a vedoucí do abstraktů</a><br> | ||||||
| 		  Seznam účastníků -  | 		  Seznam účastníků -  | ||||||
|           <a href="../{{soustredeni.pk}}/seznam_ucastniku">HTML tabulka pro tisk</a>, |           <a href="../{{soustredeni.pk}}/seznam_ucastniku">HTML tabulka pro tisk</a>, | ||||||
|           <a href="../{{soustredeni.pk}}/export_ucastniku">CSV</a>, |           <a href="../{{soustredeni.pk}}/export_ucastniku">CSV</a>, | ||||||
|  |  | ||||||
|  | @ -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']), | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ urlpatterns = [ | ||||||
| 	path( | 	path( | ||||||
| 		'probehlo/', | 		'probehlo/', | ||||||
| 		views.SoustredeniListView.as_view(), | 		views.SoustredeniListView.as_view(), | ||||||
| 		name='seminar_seznam_soustredeni' | 		name='soustredeni_seznam' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'<int:soustredeni>/', | 		'<int:soustredeni>/', | ||||||
|  | @ -37,12 +37,12 @@ urlpatterns = [ | ||||||
| 				path( | 				path( | ||||||
| 					'obalky.pdf', | 					'obalky.pdf', | ||||||
| 					org_required(views.soustredeniObalkyView), | 					org_required(views.soustredeniObalkyView), | ||||||
| 					name='seminar_soustredeni_obalky' | 					name='soustredeni_obalky' | ||||||
| 				), | 				), | ||||||
| 				path( | 				path( | ||||||
| 					'abstrakty', | 					'abstrakty', | ||||||
| 					org_required(views.SoustredeniAbstraktyView.as_view()), | 					org_required(views.SoustredeniAbstraktyView.as_view()), | ||||||
| 					name='seminar_soustredeni_abstrakty' | 					name='soustredeni_abstrakty' | ||||||
| 				), | 				), | ||||||
| 				path( | 				path( | ||||||
| 					'fotogalerie/', | 					'fotogalerie/', | ||||||
|  |  | ||||||
|  | @ -4,25 +4,27 @@ from django.forms import widgets | ||||||
| 
 | 
 | ||||||
| from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter | from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter | ||||||
| 
 | 
 | ||||||
| import seminar.models as m | from .models import TreeNode, RocnikNode, CisloNode, MezicisloNode, TemaVCisleNode, UlohaZadaniNode, PohadkaNode, UlohaVzorakNode, TextNode, CastNode, OrgTextNode, ReseniNode | ||||||
|  | from .models import Text, Obrazek | ||||||
| 
 | 
 | ||||||
| # Polymorfismus pro stromy | # Polymorfismus pro stromy | ||||||
| # TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html | # TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html | ||||||
| 
 | 
 | ||||||
| @admin.register(m.TreeNode) | @admin.register(TreeNode) | ||||||
| class TreeNodeAdmin(PolymorphicParentModelAdmin): | class TreeNodeAdmin(PolymorphicParentModelAdmin): | ||||||
| 	base_model = m.TreeNode | 	base_model = TreeNode | ||||||
| 	child_models = [ | 	child_models = [ | ||||||
| 		m.RocnikNode, | 		RocnikNode, | ||||||
| 		m.CisloNode, | 		CisloNode, | ||||||
| 		m.MezicisloNode, | 		MezicisloNode, | ||||||
| 		m.TemaVCisleNode, | 		TemaVCisleNode, | ||||||
| 		m.UlohaZadaniNode, | 		UlohaZadaniNode, | ||||||
| 		m.PohadkaNode, | 		PohadkaNode, | ||||||
| 		m.UlohaVzorakNode, | 		UlohaVzorakNode, | ||||||
| 		m.TextNode, | 		TextNode, | ||||||
| 		m.CastNode, | 		CastNode, | ||||||
| 		m.OrgTextNode, | 		OrgTextNode, | ||||||
|  | 		ReseniNode, | ||||||
| 	] | 	] | ||||||
| 
 | 
 | ||||||
| 	actions = ['aktualizuj_nazvy'] | 	actions = ['aktualizuj_nazvy'] | ||||||
|  | @ -36,64 +38,68 @@ class TreeNodeAdmin(PolymorphicParentModelAdmin): | ||||||
| 		self.message_user(request, "Názvy aktualizovány.") | 		self.message_user(request, "Názvy aktualizovány.") | ||||||
| 	aktualizuj_nazvy.short_description = "Aktualizuj vybraným TreeNodům názvy" | 	aktualizuj_nazvy.short_description = "Aktualizuj vybraným TreeNodům názvy" | ||||||
| 
 | 
 | ||||||
| @admin.register(m.RocnikNode) | @admin.register(RocnikNode) | ||||||
| class RocnikNodeAdmin(PolymorphicChildModelAdmin): | class RocnikNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.RocnikNode | 	base_model = RocnikNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.CisloNode) | @admin.register(CisloNode) | ||||||
| class CisloNodeAdmin(PolymorphicChildModelAdmin): | class CisloNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.CisloNode | 	base_model = CisloNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.MezicisloNode) | @admin.register(MezicisloNode) | ||||||
| class MezicisloNodeAdmin(PolymorphicChildModelAdmin): | class MezicisloNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.MezicisloNode | 	base_model = MezicisloNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.TemaVCisleNode) | @admin.register(TemaVCisleNode) | ||||||
| class TemaVCisleNodeAdmin(PolymorphicChildModelAdmin): | class TemaVCisleNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.TemaVCisleNode | 	base_model = TemaVCisleNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.UlohaZadaniNode) | @admin.register(UlohaZadaniNode) | ||||||
| class UlohaZadaniNodeAdmin(PolymorphicChildModelAdmin): | class UlohaZadaniNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.UlohaZadaniNode | 	base_model = UlohaZadaniNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.PohadkaNode) | @admin.register(PohadkaNode) | ||||||
| class PohadkaNodeAdmin(PolymorphicChildModelAdmin): | class PohadkaNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.PohadkaNode | 	base_model = PohadkaNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.UlohaVzorakNode) | @admin.register(UlohaVzorakNode) | ||||||
| class UlohaVzorakNodeAdmin(PolymorphicChildModelAdmin): | class UlohaVzorakNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.UlohaVzorakNode | 	base_model = UlohaVzorakNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.TextNode) | @admin.register(TextNode) | ||||||
| class TextNodeAdmin(PolymorphicChildModelAdmin): | class TextNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.TextNode | 	base_model = TextNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| @admin.register(m.CastNode) | @admin.register(CastNode) | ||||||
| class TextNodeAdmin(PolymorphicChildModelAdmin): | class TextNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.CastNode | 	base_model = CastNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 	fields = ('nadpis',) | 	fields = ('nadpis',) | ||||||
| 
 | 
 | ||||||
| @admin.register(m.OrgTextNode) | @admin.register(OrgTextNode) | ||||||
| class TextNodeAdmin(PolymorphicChildModelAdmin): | class TextNodeAdmin(PolymorphicChildModelAdmin): | ||||||
| 	base_model = m.OrgTextNode | 	base_model = OrgTextNode | ||||||
| 	show_in_index = True | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
|  | @admin.register(ReseniNode) | ||||||
|  | class ReseniNodeAdmin(PolymorphicChildModelAdmin): | ||||||
|  | 	base_model = ReseniNode | ||||||
|  | 	show_in_index = True | ||||||
| 
 | 
 | ||||||
| class TextAdminInline(admin.TabularInline): | class TextAdminInline(admin.TabularInline): | ||||||
| 	model = m.Text | 	model = Text | ||||||
| 	formfield_overrides = { | 	formfield_overrides = { | ||||||
| 		models.TextField: {'widget': widgets.TextInput} | 		models.TextField: {'widget': widgets.TextInput} | ||||||
| 	} | 	} | ||||||
| 	exclude = ['text_zkraceny_set', 'text_zkraceny'] | 	exclude = ['text_zkraceny_set', 'text_zkraceny'] | ||||||
| 
 | 
 | ||||||
| admin.site.register(m.Text) | admin.site.register(Text) | ||||||
| admin.site.register(m.Obrazek) | admin.site.register(Obrazek) | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| from django import forms | from django import forms | ||||||
| import seminar.models as m | from .models import Obrazek | ||||||
| 
 | 
 | ||||||
| # pro přidání políčka do formuláře je potřeba | # pro přidání políčka do formuláře je potřeba | ||||||
| # - mít v modelu tu položku, kterou chci upravovat | # - mít v modelu tu položku, kterou chci upravovat | ||||||
|  | @ -10,5 +10,5 @@ import seminar.models as m | ||||||
| 
 | 
 | ||||||
| class NahrajObrazekKTreeNoduForm(forms.ModelForm): | class NahrajObrazekKTreeNoduForm(forms.ModelForm): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Obrazek | 		model = Obrazek | ||||||
| 		fields = ('na_web',) | 		fields = ('na_web',) | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ from unidecode import unidecode # Používám pro získání ID odkazu (ještě | ||||||
| 
 | 
 | ||||||
| from polymorphic.models import PolymorphicModel | from polymorphic.models import PolymorphicModel | ||||||
| 
 | 
 | ||||||
| from seminar.models import SeminarModelBase | from various.models import SeminarModelBase | ||||||
| 
 | 
 | ||||||
| from personalni.models import Organizator | from personalni.models import Organizator | ||||||
| from odevzdavatko.models import Reseni | from odevzdavatko.models import Reseni | ||||||
|  | @ -347,4 +347,3 @@ class Obrazek(SeminarModelBase): | ||||||
| 
 | 
 | ||||||
| 	# TODO placement hint - chci ho tady / pred textem / za textem | 	# TODO placement hint - chci ho tady / pred textem / za textem | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -1,7 +1,11 @@ | ||||||
| from rest_framework import serializers | from rest_framework import serializers | ||||||
| from rest_polymorphic.serializers import PolymorphicSerializer | from rest_polymorphic.serializers import PolymorphicSerializer | ||||||
| 
 | 
 | ||||||
| import seminar.models as m | from odevzdavatko.models import Reseni | ||||||
|  | from tvorba.models import Problem, Uloha | ||||||
|  | 
 | ||||||
|  | from .models import RocnikNode, CisloNode, MezicisloNode, TemaVCisleNode, OrgTextNode, PohadkaNode, TextNode, TreeNode, CastNode, UlohaZadaniNode, UlohaVzorakNode, ReseniNode | ||||||
|  | from .models import Text | ||||||
| from treenode import treelib | from treenode import treelib | ||||||
| 
 | 
 | ||||||
| DEFAULT_NODE_DEPTH = 2 | DEFAULT_NODE_DEPTH = 2 | ||||||
|  | @ -9,57 +13,57 @@ DEFAULT_NODE_DEPTH = 2 | ||||||
| 
 | 
 | ||||||
| class TextSerializer(serializers.ModelSerializer): | class TextSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Text | 		model = Text | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 
 | 
 | ||||||
| class ProblemSerializer(serializers.ModelSerializer): | class ProblemSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Problem | 		model = Problem | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 
 | 
 | ||||||
| class UlohaSerializer(serializers.ModelSerializer): | class UlohaSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Uloha | 		model = Uloha | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 
 | 
 | ||||||
| class ReseniSerializer(serializers.ModelSerializer): | class ReseniSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.Reseni | 		model = Reseni | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 	 | 	 | ||||||
| class RocnikNodeSerializer(serializers.ModelSerializer): | class RocnikNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.RocnikNode | 		model = RocnikNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class CisloNodeSerializer(serializers.ModelSerializer): | class CisloNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.CisloNode | 		model = CisloNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class MezicisloNodeSerializer(serializers.ModelSerializer): | class MezicisloNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.MezicisloNode | 		model = MezicisloNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class TemaVCisleNodeSerializer(serializers.ModelSerializer): | class TemaVCisleNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.TemaVCisleNode | 		model = TemaVCisleNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class OrgTextNodeSerializer(serializers.ModelSerializer): | class OrgTextNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.OrgTextNode | 		model = OrgTextNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class PohadkaNodeSerializer(serializers.ModelSerializer): | class PohadkaNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.PohadkaNode | 		model = PohadkaNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -67,7 +71,7 @@ class TextNodeSerializer(serializers.ModelSerializer): | ||||||
| 	text = TextSerializer() | 	text = TextSerializer() | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.TextNode | 		model = TextNode | ||||||
| 		fields = ('id','text','polymorphic_ctype') | 		fields = ('id','text','polymorphic_ctype') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -80,7 +84,7 @@ class TextNodeWriteSerializer(serializers.ModelSerializer): | ||||||
| 		return node | 		return node | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.TextNode | 		model = TextNode | ||||||
| 		fields = ('id','text') | 		fields = ('id','text') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -93,26 +97,26 @@ class TextNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 		temp_text = validated_data.pop('text') | 		temp_text = validated_data.pop('text') | ||||||
| 		where = validated_data.pop('where') | 		where = validated_data.pop('where') | ||||||
| 		refnode_id = validated_data.pop('refnode') | 		refnode_id = validated_data.pop('refnode') | ||||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||||
| 		text = m.Text.objects.create(**temp_text) | 		text = Text.objects.create(**temp_text) | ||||||
| 		if where == 'syn': | 		if where == 'syn': | ||||||
| 			node = treelib.create_child(refnode,m.TextNode,text=text) | 			node = treelib.create_child(refnode,TextNode,text=text) | ||||||
| 		elif where == 'za': | 		elif where == 'za': | ||||||
| 			node = treelib.create_node_after(refnode,m.TextNode,text=text) | 			node = treelib.create_node_after(refnode,TextNode,text=text) | ||||||
| 		elif where == 'pred': | 		elif where == 'pred': | ||||||
| 			node = treelib.create_node_before(refnode,m.TextNode,text=text) | 			node = treelib.create_node_before(refnode,TextNode,text=text) | ||||||
| 		node.where = None | 		node.where = None | ||||||
| 		node.refnode = None | 		node.refnode = None | ||||||
| 		return node | 		return node | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.TextNode | 		model = TextNode | ||||||
| 		fields = ('text','where','refnode') | 		fields = ('text','where','refnode') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class CastNodeSerializer(serializers.ModelSerializer): | class CastNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.CastNode | 		model = CastNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -124,25 +128,25 @@ class CastNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 		temp_nadpis = validated_data.pop('nadpis') | 		temp_nadpis = validated_data.pop('nadpis') | ||||||
| 		where = validated_data.pop('where') | 		where = validated_data.pop('where') | ||||||
| 		refnode_id = validated_data.pop('refnode') | 		refnode_id = validated_data.pop('refnode') | ||||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||||
| 		if where == 'syn': | 		if where == 'syn': | ||||||
| 			node = treelib.create_child(refnode,m.CastNode,nadpis=temp_nadpis) | 			node = treelib.create_child(refnode,CastNode,nadpis=temp_nadpis) | ||||||
| 		elif where == 'za': | 		elif where == 'za': | ||||||
| 			node = treelib.create_node_after(refnode,m.CastNode,nadpis=temp_nadpis) | 			node = treelib.create_node_after(refnode,CastNode,nadpis=temp_nadpis) | ||||||
| 		elif where == 'pred': | 		elif where == 'pred': | ||||||
| 			node = treelib.create_node_before(refnode,m.CastNode,nadpis=temp_nadpis) | 			node = treelib.create_node_before(refnode,CastNode,nadpis=temp_nadpis) | ||||||
| 		node.where = None | 		node.where = None | ||||||
| 		node.refnode = None | 		node.refnode = None | ||||||
| 		return node | 		return node | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.CastNode | 		model = CastNode | ||||||
| 		fields = ('nadpis','where','refnode') | 		fields = ('nadpis','where','refnode') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class UlohaZadaniNodeSerializer(serializers.ModelSerializer): | class UlohaZadaniNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.UlohaZadaniNode | 		model = UlohaZadaniNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -157,7 +161,7 @@ class UlohaZadaniNodeWriteSerializer(serializers.ModelSerializer): | ||||||
| 		return node | 		return node | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.TextNode | 		model = TextNode | ||||||
| 		fields = ('id','uloha') | 		fields = ('id','uloha') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -171,28 +175,28 @@ class UlohaZadaniNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 		temp_uloha = validated_data.pop('uloha') | 		temp_uloha = validated_data.pop('uloha') | ||||||
| 		where = validated_data.pop('where') | 		where = validated_data.pop('where') | ||||||
| 		refnode_id = validated_data.pop('refnode') | 		refnode_id = validated_data.pop('refnode') | ||||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||||
| 
 | 
 | ||||||
| 		# Z cesty ke koreni stromu zjistime, v jakem jsme tematu a v jakem cisle | 		# Z cesty ke koreni stromu zjistime, v jakem jsme tematu a v jakem cisle | ||||||
| 		cislo = None | 		cislo = None | ||||||
| 		tema = None | 		tema = None | ||||||
| 		travelnode = refnode | 		travelnode = refnode | ||||||
| 		while travelnode is not None: | 		while travelnode is not None: | ||||||
| 			if isinstance(travelnode, m.TemaVCisleNode): | 			if isinstance(travelnode, TemaVCisleNode): | ||||||
| 				tema = travelnode.tema | 				tema = travelnode.tema | ||||||
| 			if isinstance(travelnode, m.CisloNode): | 			if isinstance(travelnode, CisloNode): | ||||||
| 				cislo = travelnode.cislo | 				cislo = travelnode.cislo | ||||||
| 			travelnode = treelib.get_parent(travelnode) | 			travelnode = treelib.get_parent(travelnode) | ||||||
| 		# Vyrobime ulohu | 		# Vyrobime ulohu | ||||||
| 		uloha = m.Uloha.objects.create(cislo_zadani=cislo, nadproblem = tema, **temp_uloha) | 		uloha = Uloha.objects.create(cislo_zadani=cislo, nadproblem = tema, **temp_uloha) | ||||||
| 		 | 		 | ||||||
| 		# A vyrobime UlohaZadaniNode | 		# A vyrobime UlohaZadaniNode | ||||||
| 		if where == 'syn': | 		if where == 'syn': | ||||||
| 			node = treelib.create_child(refnode,m.UlohaZadaniNode,uloha = uloha) | 			node = treelib.create_child(refnode,UlohaZadaniNode,uloha = uloha) | ||||||
| 		elif where == 'za': | 		elif where == 'za': | ||||||
| 			node = treelib.create_node_after(refnode,m.UlohaZadaniNode,uloha = uloha) | 			node = treelib.create_node_after(refnode,UlohaZadaniNode,uloha = uloha) | ||||||
| 		elif where == 'pred': | 		elif where == 'pred': | ||||||
| 			node = treelib.create_node_before(refnode,m.UlohaZadaniNode,uloha = uloha) | 			node = treelib.create_node_before(refnode,UlohaZadaniNode,uloha = uloha) | ||||||
| 		node.where = None | 		node.where = None | ||||||
| 		node.refnode = None | 		node.refnode = None | ||||||
| 		node.max_body = None | 		node.max_body = None | ||||||
|  | @ -200,21 +204,21 @@ class UlohaZadaniNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 		return node | 		return node | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.UlohaZadaniNode | 		model = UlohaZadaniNode | ||||||
| 		fields = ('uloha','where','refnode') | 		fields = ('uloha','where','refnode') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class UlohaVzorakNodeSerializer(serializers.ModelSerializer): | class UlohaVzorakNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.UlohaVzorakNode | 		model = UlohaVzorakNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 	 | 	 | ||||||
| class UlohaVzorakNodeWriteSerializer(serializers.ModelSerializer): | class UlohaVzorakNodeWriteSerializer(serializers.ModelSerializer): | ||||||
| 	uloha = serializers.PrimaryKeyRelatedField(queryset=m.Uloha.objects.all(), many=False, read_only=False) | 	uloha = serializers.PrimaryKeyRelatedField(queryset=Uloha.objects.all(), many=False, read_only=False) | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.UlohaVzorakNode | 		model = UlohaVzorakNode | ||||||
| 		fields = ('id','uloha') | 		fields = ('id','uloha') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 	 | 	 | ||||||
|  | @ -226,17 +230,17 @@ class UlohaVzorakNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 
 | 
 | ||||||
| 	def create(self, validated_data): | 	def create(self, validated_data): | ||||||
| 		uloha_id = validated_data.pop('uloha_id') | 		uloha_id = validated_data.pop('uloha_id') | ||||||
| 		uloha = m.Uloha.objects.get(pk=uloha_id) | 		uloha = Uloha.objects.get(pk=uloha_id) | ||||||
| 		where = validated_data.pop('where') | 		where = validated_data.pop('where') | ||||||
| 		refnode_id = validated_data.pop('refnode') | 		refnode_id = validated_data.pop('refnode') | ||||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||||
| 
 | 
 | ||||||
| 		if where == 'syn': | 		if where == 'syn': | ||||||
| 			node = treelib.create_child(refnode,m.UlohaVzorakNode,uloha = uloha) | 			node = treelib.create_child(refnode,UlohaVzorakNode,uloha = uloha) | ||||||
| 		elif where == 'za': | 		elif where == 'za': | ||||||
| 			node = treelib.create_node_after(refnode,m.UlohaVzorakNode,uloha = uloha) | 			node = treelib.create_node_after(refnode,UlohaVzorakNode,uloha = uloha) | ||||||
| 		elif where == 'pred': | 		elif where == 'pred': | ||||||
| 			node = treelib.create_node_before(refnode,m.UlohaVzorakNode,uloha = uloha) | 			node = treelib.create_node_before(refnode,UlohaVzorakNode,uloha = uloha) | ||||||
| 		node.refnode = None | 		node.refnode = None | ||||||
| 		node.where = None | 		node.where = None | ||||||
| 		node.uloha_id = None | 		node.uloha_id = None | ||||||
|  | @ -244,7 +248,7 @@ class UlohaVzorakNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 		return node | 		return node | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.UlohaVzorakNode | 		model = UlohaVzorakNode | ||||||
| 		fields = ('refnode', 'uloha_id', 'where') | 		fields = ('refnode', 'uloha_id', 'where') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -253,15 +257,15 @@ class UlohaVzorakNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 
 | 
 | ||||||
| class ReseniNodeSerializer(serializers.ModelSerializer): | class ReseniNodeSerializer(serializers.ModelSerializer): | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.ReseniNode | 		model = ReseniNode | ||||||
| 		fields = '__all__' | 		fields = '__all__' | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| class ReseniNodeWriteSerializer(serializers.ModelSerializer): | class ReseniNodeWriteSerializer(serializers.ModelSerializer): | ||||||
| 	reseni = serializers.PrimaryKeyRelatedField(queryset=m.Reseni.objects.all(), many=False, read_only=False) | 	reseni = serializers.PrimaryKeyRelatedField(queryset=Reseni.objects.all(), many=False, read_only=False) | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.ReseniNode | 		model = ReseniNode | ||||||
| 		fields = ('id','reseni') | 		fields = ('id','reseni') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
|  | @ -273,41 +277,41 @@ class ReseniNodeCreateSerializer(serializers.ModelSerializer): | ||||||
| 	def create(self,validated_data): | 	def create(self,validated_data): | ||||||
| 		# text_zadani = validated_data.pop('text_zadani') | 		# text_zadani = validated_data.pop('text_zadani') | ||||||
| 		reseni_id = validated_data.pop('reseni_id') | 		reseni_id = validated_data.pop('reseni_id') | ||||||
| 		reseni = m.Reseni.objects.get(pk=reseni_id) | 		reseni = Reseni.objects.get(pk=reseni_id) | ||||||
| 		where = validated_data.pop('where') | 		where = validated_data.pop('where') | ||||||
| 		refnode_id = validated_data.pop('refnode') | 		refnode_id = validated_data.pop('refnode') | ||||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||||
| 		 | 		 | ||||||
| 		# A vyrobime UlohaZadaniNode | 		# A vyrobime UlohaZadaniNode | ||||||
| 		if where == 'syn': | 		if where == 'syn': | ||||||
| 			node = treelib.create_child(refnode,m.ReseniNode,reseni = reseni) | 			node = treelib.create_child(refnode,ReseniNode,reseni = reseni) | ||||||
| 		elif where == 'za': | 		elif where == 'za': | ||||||
| 			node = treelib.create_node_after(refnode,m.ReseniNode,reseni = reseni) | 			node = treelib.create_node_after(refnode,ReseniNode,reseni = reseni) | ||||||
| 		elif where == 'pred': | 		elif where == 'pred': | ||||||
| 			node = treelib.create_node_before(refnode,m.ReseniNode,reseni = reseni) | 			node = treelib.create_node_before(refnode,ReseniNode,reseni = reseni) | ||||||
| 		node.where = None | 		node.where = None | ||||||
| 		node.refnode = None | 		node.refnode = None | ||||||
| 		node.reseni_id = None | 		node.reseni_id = None | ||||||
| 		return node | 		return node | ||||||
| 
 | 
 | ||||||
| 	class Meta: | 	class Meta: | ||||||
| 		model = m.ReseniNode | 		model = ReseniNode | ||||||
| 		fields = ('reseni_id','where','refnode') | 		fields = ('reseni_id','where','refnode') | ||||||
| 		depth = DEFAULT_NODE_DEPTH | 		depth = DEFAULT_NODE_DEPTH | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TreeNodeSerializer(PolymorphicSerializer): | class TreeNodeSerializer(PolymorphicSerializer): | ||||||
| 	model_serializer_mapping = { | 	model_serializer_mapping = { | ||||||
| 		m.RocnikNode: RocnikNodeSerializer, | 		RocnikNode: RocnikNodeSerializer, | ||||||
| 		m.CisloNode: CisloNodeSerializer, | 		CisloNode: CisloNodeSerializer, | ||||||
| 		m.MezicisloNode: MezicisloNodeSerializer, | 		MezicisloNode: MezicisloNodeSerializer, | ||||||
| 		m.TemaVCisleNode: TemaVCisleNodeSerializer, | 		TemaVCisleNode: TemaVCisleNodeSerializer, | ||||||
| 		m.OrgTextNode: OrgTextNodeSerializer, | 		OrgTextNode: OrgTextNodeSerializer, | ||||||
| 		m.UlohaZadaniNode: UlohaZadaniNodeSerializer, | 		UlohaZadaniNode: UlohaZadaniNodeSerializer, | ||||||
| 		m.UlohaVzorakNode: UlohaVzorakNodeSerializer, | 		UlohaVzorakNode: UlohaVzorakNodeSerializer, | ||||||
| 		m.PohadkaNode: PohadkaNodeSerializer, | 		PohadkaNode: PohadkaNodeSerializer, | ||||||
| 		m.TextNode: TextNodeSerializer, | 		TextNode: TextNodeSerializer, | ||||||
| 		m.CastNode: CastNodeSerializer, | 		CastNode: CastNodeSerializer, | ||||||
| 		m.ReseniNode: ReseniNodeSerializer, | 		ReseniNode: ReseniNodeSerializer, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,20 +25,20 @@ | ||||||
| 		<button>Zvyš úroveň nadpisu</button> - nejsou testovací data | 		<button>Zvyš úroveň nadpisu</button> - nejsou testovací data | ||||||
| 	</div> | 	</div> | ||||||
| {% endif %} | {% endif %} | ||||||
| {% include "seminar/treenode_name.html" %} | {% include "treenode/treenode_name.html" %} | ||||||
| {%if obj.children %} | {%if obj.children %} | ||||||
| 	<div class="borderized children"> | 	<div class="borderized children"> | ||||||
| 
 | 
 | ||||||
| 		{% with kam="před" kam_slug="syn" %} {% include "seminar/treenode_add_stub.html" %} {% endwith %} | 		{% with kam="před" kam_slug="syn" %} {% include "treenode/treenode_add_stub.html" %} {% endwith %} | ||||||
| 		{%for ch in obj.children %} | 		{%for ch in obj.children %} | ||||||
| 		 | 		 | ||||||
| 			{# ----------- Vypisujeme podstrom ----------#} | 			{# ----------- Vypisujeme podstrom ----------#} | ||||||
| 			{%with obj=ch depth=depth|add:"1" %} {%include "seminar/treenode_recursive.html" %} {%endwith%} | 			{%with obj=ch depth=depth|add:"1" %} {%include "treenode/treenode_recursive.html" %} {%endwith%} | ||||||
| 			{# ----------- Přidáváme mezi syny / za posledního -------- #} | 			{# ----------- Přidáváme mezi syny / za posledního -------- #} | ||||||
| 			{% if forloop.last %} | 			{% if forloop.last %} | ||||||
| 				{% with kam="za" kam_slug="za" obj=ch %} {% include "seminar/treenode_add_stub.html" %} {% endwith %} | 				{% with kam="za" kam_slug="za" obj=ch %} {% include "treenode/treenode_add_stub.html" %} {% endwith %} | ||||||
| 			{% else %} | 			{% else %} | ||||||
| 				{% with kam="mezi" obj=ch kam_slug="za" %} {% include "seminar/treenode_add_stub.html" %} {% endwith %} | 				{% with kam="mezi" obj=ch kam_slug="za" %} {% include "treenode/treenode_add_stub.html" %} {% endwith %} | ||||||
| 			{% endif %} | 			{% endif %} | ||||||
| 			{# ----------- Prohazujeme sousedy ----------#} | 			{# ----------- Prohazujeme sousedy ----------#} | ||||||
| 			<div class="pink"> | 			<div class="pink"> | ||||||
|  | @ -50,6 +50,6 @@ | ||||||
| 	</div> | 	</div> | ||||||
| {% else %} | {% else %} | ||||||
| 	{# ----------- Přidáváme prvního syna ----------#} | 	{# ----------- Přidáváme prvního syna ----------#} | ||||||
| 	{% with kam="jako syna" kam_slug="syn" %} {% include "seminar/treenode_add_stub.html" %} {% endwith %} | 	{% with kam="jako syna" kam_slug="syn" %} {% include "treenode/treenode_add_stub.html" %} {% endwith %} | ||||||
| {%endif%} | {%endif%} | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| from django import template | from django import template | ||||||
| from enum import Enum | from enum import Enum | ||||||
| import seminar.models as m | from .models import RocnikNode, CisloNode, CastNode, TextNode, TemaVCisleNode, UlohaVzorakNode, UlohaZadaniNode, PohadkaNode | ||||||
| 
 | 
 | ||||||
| register = template.Library() | register = template.Library() | ||||||
| 
 | 
 | ||||||
|  | @ -11,8 +11,8 @@ def nodeType(value): | ||||||
| 	if isinstance(value,CastNode): return "Část" | 	if isinstance(value,CastNode): return "Část" | ||||||
| 	if isinstance(value,TextNode): return "Text" | 	if isinstance(value,TextNode): return "Text" | ||||||
| 	if isinstance(value,TemaVCisleNode): return "Téma v čísle" | 	if isinstance(value,TemaVCisleNode): return "Téma v čísle" | ||||||
| 	if isinstance(value,KonferaNode): return "Konfera" | 	# if isinstance(value,KonferaNode): return "Konfera" # FIXME neexistuje | ||||||
| 	if isinstance(value,ClanekNode): return "Článek" | 	# if isinstance(value,ClanekNode): return "Článek" # FIXME neexistuje | ||||||
| 	if isinstance(value,UlohaVzorakNode): return "Vzorák" | 	if isinstance(value,UlohaVzorakNode): return "Vzorák" | ||||||
| 	if isinstance(value,UlohaZadaniNode): return "Zadání úlohy" | 	if isinstance(value,UlohaZadaniNode): return "Zadání úlohy" | ||||||
| 	if isinstance(value,PohadkaNode): return "Pohádka" | 	if isinstance(value,PohadkaNode): return "Pohádka" | ||||||
|  | @ -22,53 +22,57 @@ def nodeType(value): | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isRocnik(value): | def isRocnik(value): | ||||||
| 	return isinstance(value, m.RocnikNode) | 	return isinstance(value, RocnikNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isCislo(value): | def isCislo(value): | ||||||
| 	return isinstance(value, m.CisloNode) | 	return isinstance(value, CisloNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isCast(value): | def isCast(value): | ||||||
| 	return isinstance(value, m.CastNode) | 	return isinstance(value, CastNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isText(value): | def isText(value): | ||||||
| 	return isinstance(value, m.TextNode) | 	return isinstance(value, TextNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isTemaVCisle(value): | def isTemaVCisle(value): | ||||||
| 	return isinstance(value, m.TemaVCisleNode) | 	return isinstance(value, TemaVCisleNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isKonfera(value): | def isKonfera(value): | ||||||
| 	return isinstance(value, m.KonferaNode) | 	# FIXME neexistuje | ||||||
|  | 	# return isinstance(value, KonferaNode) | ||||||
|  | 	return False | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isClanek(value): | def isClanek(value): | ||||||
| 	return isinstance(value, m.ClanekNode) | 	# FIXME neexistuje | ||||||
|  | 	# return isinstance(value, ClanekNode) | ||||||
|  | 	return False | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isUlohaVzorak(value): | def isUlohaVzorak(value): | ||||||
| 	return isinstance(value, m.UlohaVzorakNode) | 	return isinstance(value, UlohaVzorakNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isUlohaZadani(value): | def isUlohaZadani(value): | ||||||
| 	return isinstance(value, m.UlohaZadaniNode) | 	return isinstance(value, UlohaZadaniNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isPohadka(value): | def isPohadka(value): | ||||||
| 	return isinstance(value, m.PohadkaNode) | 	return isinstance(value, PohadkaNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isReseni(value): | def isReseni(value): | ||||||
| 	return False | 	return False | ||||||
| #	return isinstance(value, m.OtisteneReseniNode) | #	return isinstance(value, OtisteneReseniNode) | ||||||
| 
 | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def isOrgText(value): | def isOrgText(value): | ||||||
| 	return False | 	return False | ||||||
| #	return isinstance(value, m.OrgTextNode) | #	return isinstance(value, OrgTextNode) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ###  | ###  | ||||||
|  |  | ||||||
|  | @ -1,16 +1,16 @@ | ||||||
| from django.test import TestCase | from django.test import TestCase | ||||||
| import treenode.treelib as tl | import treenode.treelib as tl | ||||||
| import seminar.models as m | from .models import CastNode | ||||||
| 
 | 
 | ||||||
| class SimpleTreeLibTests(TestCase): | class SimpleTreeLibTests(TestCase): | ||||||
| 	def setUp(self): | 	def setUp(self): | ||||||
| 		# Vyrobíme pár nějakých Nodů | 		# Vyrobíme pár nějakých Nodů | ||||||
| 		self.root = m.CastNode(root=None, first_child=None, succ=None, nadpis="Root") | 		self.root = CastNode(root=None, first_child=None, succ=None, nadpis="Root") | ||||||
| 		self.root.save() | 		self.root.save() | ||||||
| 		self.some_node = m.CastNode(root=self.root, first_child=None, succ=None, nadpis="Přetržené") | 		self.some_node = CastNode(root=self.root, first_child=None, succ=None, nadpis="Přetržené") | ||||||
| 		self.other_node = m.CastNode(root=self.root, first_child=None, succ=None, nadpis="Dítě") | 		self.other_node = CastNode(root=self.root, first_child=None, succ=None, nadpis="Dítě") | ||||||
| 		self.some_orphan = m.CastNode(root=None, first_child=None, succ=None, nadpis="Ošklivé") | 		self.some_orphan = CastNode(root=None, first_child=None, succ=None, nadpis="Ošklivé") | ||||||
| 		self.other_orphan = m.CastNode(root=None, first_child=None, succ=None, nadpis="Káčátko") | 		self.other_orphan = CastNode(root=None, first_child=None, succ=None, nadpis="Káčátko") | ||||||
| 		 | 		 | ||||||
| 		# Trochu je pospojujeme | 		# Trochu je pospojujeme | ||||||
| 		self.root.first_child = self.some_node | 		self.root.first_child = self.some_node | ||||||
|  |  | ||||||
|  | @ -238,7 +238,7 @@ class TreeLibError(RuntimeError): | ||||||
| 
 | 
 | ||||||
| # Editace stromu: | # Editace stromu: | ||||||
| def create_node_after(predecessor, type, **kwargs): | def create_node_after(predecessor, type, **kwargs): | ||||||
| 	from seminar.models import TreeNode | 	from .models import TreeNode | ||||||
| 	if predecessor is None: | 	if predecessor is None: | ||||||
| 		raise TreeLibError("Nelze vyrábět sirotky! (predecessor=None)") | 		raise TreeLibError("Nelze vyrábět sirotky! (predecessor=None)") | ||||||
| 	if not issubclass(type, TreeNode): | 	if not issubclass(type, TreeNode): | ||||||
|  | @ -255,7 +255,7 @@ def create_node_after(predecessor, type, **kwargs): | ||||||
| 
 | 
 | ||||||
| # Vyrábí prvního syna, ostatní nalepí za (existují-li) | # Vyrábí prvního syna, ostatní nalepí za (existují-li) | ||||||
| def create_child(parent, type, **kwargs): | def create_child(parent, type, **kwargs): | ||||||
| 	from seminar.models import TreeNode | 	from .models import TreeNode | ||||||
| 	if parent is None: | 	if parent is None: | ||||||
| 		raise TreeLibError("Nelze vyrábět sirotky! (parent=None)") | 		raise TreeLibError("Nelze vyrábět sirotky! (parent=None)") | ||||||
| 	if not issubclass(type, TreeNode): | 	if not issubclass(type, TreeNode): | ||||||
|  | @ -293,7 +293,7 @@ def insert_last_child(parent, node): | ||||||
| 		last.save() | 		last.save() | ||||||
| 
 | 
 | ||||||
| def create_node_before(successor, type, **kwargs): | def create_node_before(successor, type, **kwargs): | ||||||
| 	from seminar.models import TreeNode | 	from .models import TreeNode | ||||||
| 	if successor is None: | 	if successor is None: | ||||||
| 		raise TreeLibError("Nelze vyrábět sirotky! (successor=None)") | 		raise TreeLibError("Nelze vyrábět sirotky! (successor=None)") | ||||||
| 	if not issubclass(type, TreeNode): | 	if not issubclass(type, TreeNode): | ||||||
|  |  | ||||||
|  | @ -2,16 +2,16 @@ from django.urls import path, re_path | ||||||
| from . import views | from . import views | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
| 	#path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='seminar_treenode'), | 	#path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='treenode'), | ||||||
| 	#path('treenode/<int:pk>/json/', views.TreeNodeJSONView.as_view(), name='seminar_treenode_json'), | 	#path('treenode/<int:pk>/json/', views.TreeNodeJSONView.as_view(), name='treenode_json'), | ||||||
| 	#path('treenode/text/<int:pk>/', views.TextWebView.as_view(), name='seminar_textnode_web'), | 	#path('treenode/text/<int:pk>/', views.TextWebView.as_view(), name='treenode_textnode_web'), | ||||||
| 	#path('treenode/editor/pridat/<str:co>/<int:pk>/<str:kam>/', views.TreeNodePridatView.as_view(), name='treenode_pridat'), | 	#path('treenode/editor/pridat/<str:co>/<int:pk>/<str:kam>/', views.TreeNodePridatView.as_view(), name='treenode_pridat'), | ||||||
| 	#path('treenode/editor/smazat/<int:pk>/', views.TreeNodeSmazatView.as_view(), name='treenode_smazat'), | 	#path('treenode/editor/smazat/<int:pk>/', views.TreeNodeSmazatView.as_view(), name='treenode_smazat'), | ||||||
| 	#path('treenode/editor/odvesitpryc/<int:pk>/', views.TreeNodeOdvesitPrycView.as_view(), name='treenode_odvesitpryc'), | 	#path('treenode/editor/odvesitpryc/<int:pk>/', views.TreeNodeOdvesitPrycView.as_view(), name='treenode_odvesitpryc'), | ||||||
| 	#path('treenode/editor/podvesit/<int:pk>/<str:kam>/', views.TreeNodePodvesitView.as_view(), name='treenode_podvesit'), | 	#path('treenode/editor/podvesit/<int:pk>/<str:kam>/', views.TreeNodePodvesitView.as_view(), name='treenode_podvesit'), | ||||||
| 	#path('treenode/editor/prohodit/<int:pk>/', views.TreeNodeProhoditView.as_view(), name='treenode_prohodit'), | 	#path('treenode/editor/prohodit/<int:pk>/', views.TreeNodeProhoditView.as_view(), name='treenode_prohodit'), | ||||||
| 	#path('treenode/sirotcinec/', views.SirotcinecView.as_view(), name='seminar_treenode_sirotcinec'), | 	#path('treenode/sirotcinec/', views.SirotcinecView.as_view(), name='treenode_sirotcinec'), | ||||||
| 	#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), | 	#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='treenode_problem_prispevek'), | ||||||
| 
 | 
 | ||||||
| 	re_path(r'^temp/vue/.*$',views.VueTestView.as_view(),name='vue_test_view'), | 	re_path(r'^temp/vue/.*$',views.VueTestView.as_view(),name='vue_test_view'), | ||||||
| 	path('temp/image_upload/', views.NahrajObrazekKTreeNoduView.as_view()), | 	path('temp/image_upload/', views.NahrajObrazekKTreeNoduView.as_view()), | ||||||
|  |  | ||||||
|  | @ -6,8 +6,8 @@ from django.views.generic.edit import CreateView | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
| from django.core.exceptions import PermissionDenied | from django.core.exceptions import PermissionDenied | ||||||
| 
 | 
 | ||||||
| import seminar.models as s | from .models import TemaVCisleNode, RocnikNode, CisloNode, UlohaVzorakNode, UlohaZadaniNode, TreeNode, CastNode, TextNode, ReseniNode, PohadkaNode, OrgTextNode | ||||||
| import seminar.models as m | from .models import Text, Obrazek | ||||||
| from treenode import treelib | from treenode import treelib | ||||||
| import treenode.forms as f | import treenode.forms as f | ||||||
| import treenode.templatetags as tnltt | import treenode.templatetags as tnltt | ||||||
|  | @ -29,7 +29,7 @@ class TNLData(object): | ||||||
| 
 | 
 | ||||||
| 		if parent: | 		if parent: | ||||||
| 			self.tema_in_path = parent.tema_in_path | 			self.tema_in_path = parent.tema_in_path | ||||||
| 		if isinstance(anode, m.TemaVCisleNode): | 		if isinstance(anode, TemaVCisleNode): | ||||||
| 			self.tema_in_path = True | 			self.tema_in_path = True | ||||||
| 
 | 
 | ||||||
| 	def add_edit_options(self): | 	def add_edit_options(self): | ||||||
|  | @ -51,11 +51,11 @@ class TNLData(object): | ||||||
| 		(All of them have method verejne.)""" | 		(All of them have method verejne.)""" | ||||||
| 		parent = anode # chceme začít už od konkrétního node včetně | 		parent = anode # chceme začít už od konkrétního node včetně | ||||||
| 		while True: | 		while True: | ||||||
| 			rocnik = isinstance(parent, s.RocnikNode) | 			rocnik = isinstance(parent, RocnikNode) | ||||||
| 			cislo = isinstance(parent, s.CisloNode) | 			cislo = isinstance(parent, CisloNode) | ||||||
| 			uloha = (isinstance(parent, s.UlohaVzorakNode) or | 			uloha = (isinstance(parent, UlohaVzorakNode) or | ||||||
| 				isinstance(parent, s.UlohaZadaniNode)) | 				isinstance(parent, UlohaZadaniNode)) | ||||||
| 			tema = isinstance(parent, s.TemaVCisleNode) | 			tema = isinstance(parent, TemaVCisleNode) | ||||||
| 
 | 
 | ||||||
| 			if (rocnik or cislo or uloha or tema) or parent==None: | 			if (rocnik or cislo or uloha or tema) or parent==None: | ||||||
| 				break | 				break | ||||||
|  | @ -158,7 +158,7 @@ class TNLData(object): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TreeNodeView(generic.DetailView): | class TreeNodeView(generic.DetailView): | ||||||
| 	model = s.TreeNode | 	model = TreeNode | ||||||
| 	template_name = 'treenode/treenode.html' | 	template_name = 'treenode/treenode.html' | ||||||
| 
 | 
 | ||||||
| 	def get_context_data(self,**kwargs): | 	def get_context_data(self,**kwargs): | ||||||
|  | @ -168,7 +168,7 @@ class TreeNodeView(generic.DetailView): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TreeNodeJSONView(generic.DetailView): | class TreeNodeJSONView(generic.DetailView): | ||||||
| 	model = s.TreeNode | 	model = TreeNode | ||||||
| 
 | 
 | ||||||
| 	def get(self,request,*args, **kwargs): | 	def get(self,request,*args, **kwargs): | ||||||
| 		self.object = self.get_object() | 		self.object = self.get_object() | ||||||
|  | @ -178,21 +178,21 @@ class TreeNodeJSONView(generic.DetailView): | ||||||
| 
 | 
 | ||||||
| class TreeNodePridatView(generic.View): | class TreeNodePridatView(generic.View): | ||||||
| 	type_from_str = { | 	type_from_str = { | ||||||
| 		'rocnikNode': m.RocnikNode, | 		'rocnikNode': RocnikNode, | ||||||
| 		'cisloNode': m.CisloNode, | 		'cisloNode': CisloNode, | ||||||
| 		'castNode': m.CastNode, | 		'castNode': CastNode, | ||||||
| 		'textNode': m.TextNode, | 		'textNode': TextNode, | ||||||
| 		'temaVCisleNode': m.TemaVCisleNode, | 		'temaVCisleNode': TemaVCisleNode, | ||||||
| 		'reseniNode': m.ReseniNode, | 		'reseniNode': ReseniNode, | ||||||
| 		'ulohaZadaniNode': m.UlohaZadaniNode, | 		'ulohaZadaniNode': UlohaZadaniNode, | ||||||
| 		'ulohaVzorakNode': m.UlohaVzorakNode, | 		'ulohaVzorakNode': UlohaVzorakNode, | ||||||
| 		'pohadkaNode': m.PohadkaNode, | 		'pohadkaNode': PohadkaNode, | ||||||
| 		'orgText': m.OrgTextNode, | 		'orgText': OrgTextNode, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	def post(self, request, *args, **kwargs): | 	def post(self, request, *args, **kwargs): | ||||||
| 		######## FIXME: ROZEPSANE, NEFUNGUJE, DOPSAT !!!!!! ########### | 		######## FIXME: ROZEPSANE, NEFUNGUJE, DOPSAT !!!!!! ########### | ||||||
| 		node = s.TreeNode.objects.get(pk=self.kwargs['pk']) | 		node = TreeNode.objects.get(pk=self.kwargs['pk']) | ||||||
| 		kam = self.kwargs['kam'] | 		kam = self.kwargs['kam'] | ||||||
| 		co = self.kwargs['co'] | 		co = self.kwargs['co'] | ||||||
| 		typ = self.type_from_str[co] | 		typ = self.type_from_str[co] | ||||||
|  | @ -202,19 +202,19 @@ class TreeNodePridatView(generic.View): | ||||||
| 		if kam not in ('pred','syn','za'): | 		if kam not in ('pred','syn','za'): | ||||||
| 			raise ValidationError('Přidat lze pouze před nebo za node nebo jako syna') | 			raise ValidationError('Přidat lze pouze před nebo za node nebo jako syna') | ||||||
| 
 | 
 | ||||||
| 		if co == m.TextNode: | 		if co == TextNode: | ||||||
| 			new_obj = m.Text() | 			new_obj = Text() | ||||||
| 			new_obj.save() | 			new_obj.save() | ||||||
| 		elif co == m.CastNode: | 		elif co == CastNode: | ||||||
| 			new_obj = m.CastNode() | 			new_obj = CastNode() | ||||||
| 			new_obj.nadpis = request.POST.get('pridat-castNode-{}-{}'.format(node.id,kam)) | 			new_obj.nadpis = request.POST.get('pridat-castNode-{}-{}'.format(node.id,kam)) | ||||||
| 			new_obj.save() | 			new_obj.save() | ||||||
| 		elif co == m.ReseniNode: | 		elif co == ReseniNode: | ||||||
| 			new_obj = m | 			new_obj = m | ||||||
| 			pass | 			pass | ||||||
| 		elif co == m.UlohaZadaniNode: | 		elif co == UlohaZadaniNode: | ||||||
| 			pass | 			pass | ||||||
| 		elif co == m.UlohaReseniNode: | 		elif co == UlohaReseniNode: | ||||||
| 			pass | 			pass | ||||||
| 		else: | 		else: | ||||||
| 			new_obj = None | 			new_obj = None | ||||||
|  | @ -225,15 +225,15 @@ class TreeNodePridatView(generic.View): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		if kam == 'syn': | 		if kam == 'syn': | ||||||
| 			if typ == m.TextNode: | 			if typ == TextNode: | ||||||
| 				text_obj = m.Text() | 				text_obj = Text() | ||||||
| 				text_obj.save() | 				text_obj.save() | ||||||
| 				node = treelib.create_child(node, typ, text=text_obj) | 				node = treelib.create_child(node, typ, text=text_obj) | ||||||
| 			else: | 			else: | ||||||
| 				node = treelib.create_child(node, typ) | 				node = treelib.create_child(node, typ) | ||||||
| 		if kam == 'za': | 		if kam == 'za': | ||||||
| 			if typ == m.TextNode: | 			if typ == TextNode: | ||||||
| 				text_obj = m.Text() | 				text_obj = Text() | ||||||
| 				text_obj.save() | 				text_obj.save() | ||||||
| 				node = treelib.create_node_after(node, typ, text=text_obj) | 				node = treelib.create_node_after(node, typ, text=text_obj) | ||||||
| 			else: | 			else: | ||||||
|  | @ -244,7 +244,7 @@ class TreeNodePridatView(generic.View): | ||||||
| 
 | 
 | ||||||
| class TreeNodeSmazatView(generic.base.View): | class TreeNodeSmazatView(generic.base.View): | ||||||
| 	def post(self, request, *args, **kwargs): | 	def post(self, request, *args, **kwargs): | ||||||
| 		node = s.TreeNode.objects.get(pk=self.kwargs['pk']) | 		node = TreeNode.objects.get(pk=self.kwargs['pk']) | ||||||
| 		if node.first_child: | 		if node.first_child: | ||||||
| 			raise NotImplementedError('Mazání TreeNode se syny není zatím podporováno!') | 			raise NotImplementedError('Mazání TreeNode se syny není zatím podporováno!') | ||||||
| 		treelib.disconnect_node(node) | 		treelib.disconnect_node(node) | ||||||
|  | @ -254,7 +254,7 @@ class TreeNodeSmazatView(generic.base.View): | ||||||
| 
 | 
 | ||||||
| class TreeNodeOdvesitPrycView(generic.base.View): | class TreeNodeOdvesitPrycView(generic.base.View): | ||||||
| 	def post(self, request, *args, **kwargs): | 	def post(self, request, *args, **kwargs): | ||||||
| 		node = s.TreeNode.objects.get(pk=self.kwargs['pk']) | 		node = TreeNode.objects.get(pk=self.kwargs['pk']) | ||||||
| 		treelib.disconnect_node(node) | 		treelib.disconnect_node(node) | ||||||
| 		node.root = None | 		node.root = None | ||||||
| 		node.save() | 		node.save() | ||||||
|  | @ -263,7 +263,7 @@ class TreeNodeOdvesitPrycView(generic.base.View): | ||||||
| 
 | 
 | ||||||
| class TreeNodePodvesitView(generic.base.View): | class TreeNodePodvesitView(generic.base.View): | ||||||
| 	def post(self, request, *args, **kwargs): | 	def post(self, request, *args, **kwargs): | ||||||
| 		node = s.TreeNode.objects.get(pk=self.kwargs['pk']) | 		node = TreeNode.objects.get(pk=self.kwargs['pk']) | ||||||
| 		kam = self.kwargs['kam'] | 		kam = self.kwargs['kam'] | ||||||
| 		if kam == 'pred': | 		if kam == 'pred': | ||||||
| 			treelib.lower_node(node) | 			treelib.lower_node(node) | ||||||
|  | @ -274,21 +274,21 @@ class TreeNodePodvesitView(generic.base.View): | ||||||
| 
 | 
 | ||||||
| class TreeNodeProhoditView(generic.base.View): | class TreeNodeProhoditView(generic.base.View): | ||||||
| 	def post(self, request, *args, **kwargs): | 	def post(self, request, *args, **kwargs): | ||||||
| 		node = s.TreeNode.objects.get(pk=self.kwargs['pk']) | 		node = TreeNode.objects.get(pk=self.kwargs['pk']) | ||||||
| 		treelib.swap_succ(node) | 		treelib.swap_succ(node) | ||||||
| 		return redirect(request.headers.get('referer')) | 		return redirect(request.headers.get('referer')) | ||||||
| 		#FIXME ve formulari predat puvodni url a vratit redirect na ni | 		#FIXME ve formulari predat puvodni url a vratit redirect na ni | ||||||
| 
 | 
 | ||||||
| class SirotcinecView(generic.ListView): | class SirotcinecView(generic.ListView): | ||||||
| 	model = s.TreeNode | 	model = TreeNode | ||||||
| 	template_name = 'treenode/orphanage.html' | 	template_name = 'treenode/orphanage.html' | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		return s.TreeNode.objects.not_instance_of(s.RocnikNode).filter(root=None,prev=None,succ=None,father_of_first=None) | 		return TreeNode.objects.not_instance_of(RocnikNode).filter(root=None,prev=None,succ=None,father_of_first=None) | ||||||
| 
 | 
 | ||||||
| # FIXME pouzit Django REST Framework | # FIXME pouzit Django REST Framework | ||||||
| class TextWebView(generic.DetailView): | class TextWebView(generic.DetailView): | ||||||
| 	model = s.Text | 	model = Text | ||||||
| 
 | 
 | ||||||
| 	def get(self,request,*args, **kwargs): | 	def get(self,request,*args, **kwargs): | ||||||
| 		self.object = self.get_object() | 		self.object = self.get_object() | ||||||
|  | @ -300,7 +300,7 @@ class VueTestView(generic.TemplateView): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView): | class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView): | ||||||
| 	model = s.Obrazek | 	model = Obrazek | ||||||
| 	form_class = f.NahrajObrazekKTreeNoduForm | 	form_class = f.NahrajObrazekKTreeNoduForm | ||||||
| 
 | 
 | ||||||
| 	def get_initial(self): | 	def get_initial(self): | ||||||
|  | @ -316,7 +316,7 @@ class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView): | ||||||
| 		print(form) | 		print(form) | ||||||
| 		self.object = form.save(commit=False) | 		self.object = form.save(commit=False) | ||||||
| 		print(self.object.na_web) | 		print(self.object.na_web) | ||||||
| 		self.object.text = m.Text.objects.get(pk=int(self.request.headers['Textid'])) | 		self.object.text = Text.objects.get(pk=int(self.request.headers['Textid'])) | ||||||
| 		self.object.save() | 		self.object.save() | ||||||
| 
 | 
 | ||||||
| 		return JsonResponse({"url":self.object.na_web.url}) | 		return JsonResponse({"url":self.object.na_web.url}) | ||||||
|  |  | ||||||
|  | @ -3,7 +3,12 @@ from rest_framework import status | ||||||
| from rest_framework.response import Response | from rest_framework.response import Response | ||||||
| from django.core.exceptions import PermissionDenied | from django.core.exceptions import PermissionDenied | ||||||
| from rest_framework.permissions import BasePermission, AllowAny | from rest_framework.permissions import BasePermission, AllowAny | ||||||
| from seminar import models as m | 
 | ||||||
|  | from odevzdavatko.models import Reseni | ||||||
|  | from tvorba.models import Problem, Uloha | ||||||
|  | 
 | ||||||
|  | from .models import TextNode, CastNode, UlohaVzorakNode, UlohaZadaniNode, ReseniNode | ||||||
|  | from .models import Text | ||||||
| import treenode.serializers as views | import treenode.serializers as views | ||||||
| 
 | 
 | ||||||
| from treenode.permissions import AllowWrite | from treenode.permissions import AllowWrite | ||||||
|  | @ -66,17 +71,17 @@ class ReadWriteSerializerMixin(object): | ||||||
| 		return self.create_serializer_class | 		return self.create_serializer_class | ||||||
| 
 | 
 | ||||||
| class TextViewSet(PermissionMixin, viewsets.ModelViewSet): | class TextViewSet(PermissionMixin, viewsets.ModelViewSet): | ||||||
| 	queryset = m.Text.objects.all() | 	queryset = Text.objects.all() | ||||||
| 	serializer_class = views.TextSerializer | 	serializer_class = views.TextSerializer | ||||||
| 
 | 
 | ||||||
| class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | ||||||
| 	queryset = m.TextNode.objects.all() | 	queryset = TextNode.objects.all() | ||||||
| 	read_serializer_class = views.TextNodeSerializer | 	read_serializer_class = views.TextNodeSerializer | ||||||
| 	write_serializer_class = views.TextNodeWriteSerializer | 	write_serializer_class = views.TextNodeWriteSerializer | ||||||
| 	create_serializer_class = views.TextNodeCreateSerializer | 	create_serializer_class = views.TextNodeCreateSerializer | ||||||
| 
 | 
 | ||||||
| class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | ||||||
| 	queryset = m.CastNode.objects.all() | 	queryset = CastNode.objects.all() | ||||||
| 	read_serializer_class = views.CastNodeSerializer | 	read_serializer_class = views.CastNodeSerializer | ||||||
| 	write_serializer_class = views.CastNodeSerializer | 	write_serializer_class = views.CastNodeSerializer | ||||||
| 	create_serializer_class = views.CastNodeCreateSerializer | 	create_serializer_class = views.CastNodeCreateSerializer | ||||||
|  | @ -95,7 +100,7 @@ class UlohaVzorakNodeViewSet(PermissionMixin, ReadWriteSerializerMixin, viewsets | ||||||
| 	create_serializer_class = views.UlohaVzorakNodeCreateSerializer | 	create_serializer_class = views.UlohaVzorakNodeCreateSerializer | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		queryset = m.UlohaVzorakNode.objects.all() | 		queryset = UlohaVzorakNode.objects.all() | ||||||
| 		nazev = self.request.query_params.get('nazev',None) | 		nazev = self.request.query_params.get('nazev',None) | ||||||
| 		if nazev is not None: | 		if nazev is not None: | ||||||
| 			queryset = queryset.filter(nazev__contains=nazev) | 			queryset = queryset.filter(nazev__contains=nazev) | ||||||
|  | @ -114,7 +119,7 @@ class ReseniViewSet(viewsets.ModelViewSet): | ||||||
| 	serializer_class = views.ReseniSerializer | 	serializer_class = views.ReseniSerializer | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		queryset = m.Reseni.objects.all() | 		queryset = Reseni.objects.all() | ||||||
| 		#FIXME upravit nazvy dle skutecnych polozek reseni | 		#FIXME upravit nazvy dle skutecnych polozek reseni | ||||||
| 		nazev = self.request.query_params.get('nazev',None) | 		nazev = self.request.query_params.get('nazev',None) | ||||||
| 		if nazev is not None: | 		if nazev is not None: | ||||||
|  | @ -128,7 +133,7 @@ class UlohaViewSet(viewsets.ModelViewSet): | ||||||
| 	serializer_class = views.UlohaSerializer | 	serializer_class = views.UlohaSerializer | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		queryset = m.Uloha.objects.all() | 		queryset = Uloha.objects.all() | ||||||
| 		nazev = self.request.query_params.get('nazev',None) | 		nazev = self.request.query_params.get('nazev',None) | ||||||
| 		if nazev is not None: | 		if nazev is not None: | ||||||
| 			queryset = queryset.filter(nazev__contains=nazev) | 			queryset = queryset.filter(nazev__contains=nazev) | ||||||
|  | @ -138,13 +143,13 @@ class UlohaViewSet(viewsets.ModelViewSet): | ||||||
| 		return queryset | 		return queryset | ||||||
| 
 | 
 | ||||||
| class UlohaZadaniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet): | class UlohaZadaniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet): | ||||||
| 	queryset = m.UlohaZadaniNode.objects.all() | 	queryset = UlohaZadaniNode.objects.all() | ||||||
| 	read_serializer_class = views.UlohaZadaniNodeSerializer | 	read_serializer_class = views.UlohaZadaniNodeSerializer | ||||||
| 	write_serializer_class = views.UlohaZadaniNodeWriteSerializer | 	write_serializer_class = views.UlohaZadaniNodeWriteSerializer | ||||||
| 	create_serializer_class = views.UlohaZadaniNodeCreateSerializer | 	create_serializer_class = views.UlohaZadaniNodeCreateSerializer | ||||||
| 
 | 
 | ||||||
| class ReseniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet): | class ReseniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet): | ||||||
| 	queryset = m.ReseniNode.objects.all() | 	queryset = ReseniNode.objects.all() | ||||||
| 	read_serializer_class = views.ReseniNodeSerializer | 	read_serializer_class = views.ReseniNodeSerializer | ||||||
| 	write_serializer_class = views.ReseniNodeWriteSerializer | 	write_serializer_class = views.ReseniNodeWriteSerializer | ||||||
| 	create_serializer_class = views.ReseniNodeCreateSerializer | 	create_serializer_class = views.ReseniNodeCreateSerializer | ||||||
|  | @ -155,7 +160,7 @@ class ProblemViewSet(viewsets.ModelViewSet): | ||||||
| 	serializer_class = views.ProblemSerializer | 	serializer_class = views.ProblemSerializer | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
| 		queryset = m.Problem.objects.all() | 		queryset = Problem.objects.all() | ||||||
| 		ucel = self.request.query_params.get('ucel',None) | 		ucel = self.request.query_params.get('ucel',None) | ||||||
| 		rocnik = self.request.query_params.get('rocnik',None) | 		rocnik = self.request.query_params.get('rocnik',None) | ||||||
| 		tema = self.request.query_params.get('tema',None) | 		tema = self.request.query_params.get('tema',None) | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import datetime | ||||||
| from django.db import migrations, models | from django.db import migrations, models | ||||||
| import django.db.models.deletion | import django.db.models.deletion | ||||||
| import django.utils.timezone | import django.utils.timezone | ||||||
| import seminar.models.tvorba | import various.models | ||||||
| import tvorba.models | import tvorba.models | ||||||
| import taggit.managers | import taggit.managers | ||||||
| 
 | 
 | ||||||
|  | @ -35,7 +35,7 @@ class Migration(migrations.Migration): | ||||||
|                 ('datum_vydani', models.DateField(blank=True, help_text='Datum vydání finální verze', null=True, verbose_name='datum vydání')), |                 ('datum_vydani', models.DateField(blank=True, help_text='Datum vydání finální verze', null=True, verbose_name='datum vydání')), | ||||||
|                 ('verejne_db', models.BooleanField(db_column='verejne', default=False, verbose_name='číslo zveřejněno')), |                 ('verejne_db', models.BooleanField(db_column='verejne', default=False, verbose_name='číslo zveřejněno')), | ||||||
|                 ('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k číslu (plain text)', verbose_name='neveřejná poznámka')), |                 ('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k číslu (plain text)', verbose_name='neveřejná poznámka')), | ||||||
|                 ('pdf', models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, storage=seminar.models.tvorba.OverwriteStorage(), upload_to=tvorba.models.cislo_pdf_filename, verbose_name='pdf')), |                 ('pdf', models.FileField(blank=True, help_text='PDF čísla, které si mohou řešitelé stáhnout', null=True, storage=various.models.OverwriteStorage(), upload_to=tvorba.models.cislo_pdf_filename, verbose_name='pdf')), | ||||||
|                 ('titulka_nahled', models.ImageField(blank=True, help_text='Obrázek titulní strany, generuje se automaticky', null=True, upload_to=tvorba.models.cislo_png_filename, verbose_name='Obrázek titulní strany')), |                 ('titulka_nahled', models.ImageField(blank=True, help_text='Obrázek titulní strany, generuje se automaticky', null=True, upload_to=tvorba.models.cislo_png_filename, verbose_name='Obrázek titulní strany')), | ||||||
|                 ('rocnik', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='cisla', to='tvorba.rocnik', verbose_name='ročník')), |                 ('rocnik', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='cisla', to='tvorba.rocnik', verbose_name='ročník')), | ||||||
|             ], |             ], | ||||||
|  |  | ||||||
|  | @ -31,8 +31,7 @@ from polymorphic.models import PolymorphicModel | ||||||
| 
 | 
 | ||||||
| from django.core.mail import EmailMessage | from django.core.mail import EmailMessage | ||||||
| 
 | 
 | ||||||
| from seminar.models.base import SeminarModelBase | from various.models import SeminarModelBase, OverwriteStorage | ||||||
| from seminar.models.tvorba import OverwriteStorage |  | ||||||
| from personalni.models import Prijemce, Organizator | from personalni.models import Prijemce, Organizator | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
|  | @ -96,7 +95,7 @@ class Rocnik(SeminarModelBase): | ||||||
| 		return self.prvni_rok + 1 | 		return self.prvni_rok + 1 | ||||||
| 
 | 
 | ||||||
| 	def verejne_url(self): | 	def verejne_url(self): | ||||||
| 		return reverse('seminar_rocnik', kwargs={'rocnik': self.rocnik}) | 		return reverse('tvorba_rocnik', kwargs={'rocnik': self.rocnik}) | ||||||
| 
 | 
 | ||||||
| 	@classmethod | 	@classmethod | ||||||
| 	def cached_rocnik(cls, r_id): | 	def cached_rocnik(cls, r_id): | ||||||
|  | @ -171,7 +170,7 @@ class Cislo(SeminarModelBase): | ||||||
| 	verejne.boolean = True | 	verejne.boolean = True | ||||||
| 
 | 
 | ||||||
| 	def verejne_url(self): | 	def verejne_url(self): | ||||||
| 		return reverse('seminar_cislo', kwargs={'rocnik': self.rocnik.rocnik, 'cislo': self.poradi}) | 		return reverse('tvorba_cislo', kwargs={'rocnik': self.rocnik.rocnik, 'cislo': self.poradi}) | ||||||
| 
 | 
 | ||||||
| 	def absolute_url(self): | 	def absolute_url(self): | ||||||
| 		return "https://" + str(get_current_site(None)) + self.verejne_url() | 		return "https://" + str(get_current_site(None)) + self.verejne_url() | ||||||
|  | @ -508,7 +507,7 @@ class Problem(SeminarModelBase,PolymorphicModel): | ||||||
| #	verejne.boolean = True | #	verejne.boolean = True | ||||||
| 
 | 
 | ||||||
| 	def verejne_url(self): | 	def verejne_url(self): | ||||||
| 		return reverse('seminar_problem', kwargs={'pk': self.id}) | 		return reverse('tvorba_problem', kwargs={'pk': self.id}) | ||||||
| 
 | 
 | ||||||
| 	def admin_url(self): | 	def admin_url(self): | ||||||
| 			return reverse('admin:tvorba_problem_change', args=(self.id, )) | 			return reverse('admin:tvorba_problem_change', args=(self.id, )) | ||||||
|  |  | ||||||
|  | @ -35,12 +35,12 @@ | ||||||
|       <div class="mam-org-only"> |       <div class="mam-org-only"> | ||||||
|         <h2> Orgovské odkazy </h2> |         <h2> Orgovské odkazy </h2> | ||||||
|         <ul> |         <ul> | ||||||
|           <li><a href="obalky.pdf">Obálky (PDF)</a></li> |           <li><a href="{% url "tvorba_cislo_obalky" rocnik=cislo.rocnik.rocnik cislo=cislo.poradi %}">Obálky (PDF)</a></li> | ||||||
|           <li><a href="tituly.tex" download>Tituly (TeX, 2. deadline předchozího čísla a 1.deadline tohoto)</a></li> |           <li><a href="{% url "tvorba_cislo_titul" rocnik=cislo.rocnik.rocnik cislo=cislo.poradi %}" download>Tituly (TeX, 2. deadline předchozího čísla a 1.deadline tohoto)</a></li> | ||||||
|           <li><a href="vysledkovka.tex" download>Výsledkovka (TeX, 2. deadline předchozího čísla a 1.deadline tohoto)</a></li> |           <li><a href="{% url "tvorba_cislo_vysledkovka" rocnik=cislo.rocnik.rocnik cislo=cislo.poradi %}" download>Výsledkovka (TeX, 2. deadline předchozího čísla a 1.deadline tohoto)</a></li> | ||||||
|           <li><a href="odmeny/{{prevcislo.rocnik.rocnik}}.{{prevcislo.poradi}}/">Odměny</a></li> |           <li>{% if prevcislo %}<a href="{% url "tvorba_archiv_odmeny" trocnik=cislo.rocnik.rocnik tcislo=cislo.poradi frocnik=prevcislo.rocnik.rocnik fcislo=prevcislo.poradi %}">Odměny</a>{% else %}Pro toto číslo neumíme spočítat odměny.{% endif %}{# FIXME (Jediné číslo, kde toto neumíme je to úplně první.) #}</li> | ||||||
|           <li><a href="{% url "seminar_rocnik_titul" rocnik=cislo.rocnik.rocnik %}" download="posledni_tituly.tex">Tituly do závěrečného čísla (TeX, 2. deadline předchozího čísla a oba tohoto)</a></li> |           <li><a href="{% url "tvorba_rocnik_titul" rocnik=cislo.rocnik.rocnik %}" download="posledni_tituly.tex">Tituly do závěrečného čísla (TeX, 2. deadline předchozího čísla a oba tohoto)</a></li> | ||||||
|           <li><a href="{% url "seminar_rocnik_posledni_vysledkovka" rocnik=cislo.rocnik.rocnik %}" download>Výsledkovka závěrečného čísla ročníku (TeX, 2. deadline předchozího čísla a oba tohoto)</a></li> |           <li><a href="{% url "tvorba_rocnik_posledni_vysledkovka" rocnik=cislo.rocnik.rocnik %}" download>Výsledkovka závěrečného čísla ročníku (TeX, 2. deadline předchozího čísla a oba tohoto)</a></li> | ||||||
|         </ul> |         </ul> | ||||||
|       </div> |       </div> | ||||||
|   {% endif %} |   {% endif %} | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| {% extends "seminar/archiv/problem.html" %} | {% extends "tvorba/archiv/problem.html" %} | ||||||
| 
 | 
 | ||||||
| {% block problem %} | {% block problem %} | ||||||
|   {% if problem.cislo_zadani %} |   {% if problem.cislo_zadani %} | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| {% extends "seminar/archiv/problem.html" %} | {% extends "tvorba/archiv/problem.html" %} | ||||||
| 
 | 
 | ||||||
| {% block problem %} | {% block problem %} | ||||||
|     <h1> |     <h1> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| {% extends "seminar/archiv/problem.html" %} | {% extends "tvorba/archiv/problem.html" %} | ||||||
| 
 | 
 | ||||||
| {% block problem %} | {% block problem %} | ||||||
|     <h1> |     <h1> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| {% extends "seminar/archiv/problem.html" %} | {% extends "tvorba/archiv/problem.html" %} | ||||||
| 
 | 
 | ||||||
| {% block problem %} | {% block problem %} | ||||||
|     <h1> |     <h1> | ||||||
|  |  | ||||||
|  | @ -121,7 +121,7 @@ | ||||||
|     <p><a href='vysledkovka.tex' download>Výsledkovka ročníku (LaTeX, včetně neveřejných)</a></p> |     <p><a href='vysledkovka.tex' download>Výsledkovka ročníku (LaTeX, včetně neveřejných)</a></p> | ||||||
|     <p><a href="tituly.tex" download>Tituly (TeX, včetně neveřejných, všechny, nevhodné do mamtexu)</a></p> |     <p><a href="tituly.tex" download>Tituly (TeX, včetně neveřejných, všechny, nevhodné do mamtexu)</a></p> | ||||||
|     {# FIXME: Sice to sem asi nepatří sémanticky, ale bylo to nejjednodušší… #} |     {# FIXME: Sice to sem asi nepatří sémanticky, ale bylo to nejjednodušší… #} | ||||||
|     <p><a href='{% url 'seminar_rocnik_resitele_csv' rocnik=rocnik.rocnik %}' download>CSV export řešitelů</a></p> |     <p><a href='{% url 'tvorba_rocnik_resitele_csv' rocnik=rocnik.rocnik %}' download>CSV export řešitelů</a></p> | ||||||
|     <h2>Výsledková listina včetně neveřejných bodů</h2> |     <h2>Výsledková listina včetně neveřejných bodů</h2> | ||||||
|         {% include "vysledkovky/vysledkovka_rocnik.html" with vysledkovka=vysledkovka_neverejna %} |         {% include "vysledkovky/vysledkovka_rocnik.html" with vysledkovka=vysledkovka_neverejna %} | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| {% extends 'seminar/clanky/resitelske_clanky.html' %} | {% extends 'tvorba/clanky/resitelske_clanky.html' %} | ||||||
| 
 | 
 | ||||||
| {% block nadpis1a %} | {% block nadpis1a %} | ||||||
| Organizátorské články  | Organizátorské články  | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ | ||||||
| 
 | 
 | ||||||
|   <p> |   <p> | ||||||
|     Staré výsledkové listiny najdete |     Staré výsledkové listiny najdete | ||||||
|     v <a href="{% url 'seminar_archiv_rocniky' %}">archivu</a>. |     v <a href="{% url 'tvorba_archiv_rocniky' %}">archivu</a>. | ||||||
|   </p> |   </p> | ||||||
| 
 | 
 | ||||||
|   {% if user.je_org and vysledkovka_s_neverejnymi %} |   {% if user.je_org and vysledkovka_s_neverejnymi %} | ||||||
|  |  | ||||||
|  | @ -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,8 +6,12 @@ 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, Clanek | ||||||
| import seminar.models as m | 
 | ||||||
|  | from odevzdavatko.models import Reseni, Hodnoceni | ||||||
|  | # TODO zbavit se treenodů do treenode.testutils (ty pak klidně volat odtud) | ||||||
|  | from treenode.models import TextNode, UlohaZadaniNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, CastNode, MezicisloNode, ReseniNode | ||||||
|  | from treenode.models import Text | ||||||
| 
 | 
 | ||||||
| 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 | ||||||
| 
 | 
 | ||||||
|  | @ -195,7 +199,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 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( | ||||||
|  | @ -219,31 +223,31 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | ||||||
| 		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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = CastNode.objects.create(nadpis = "Podproblém paralelní s " | ||||||
| 					"druhým podproblémem", root=cislo_node.root) | 					"druhým podproblémem", root=cislo_node.root) | ||||||
| 		cast_node3.succ = cast_node3a | 		cast_node3.succ = cast_node3a | ||||||
| 		cast_node3.save() | 		cast_node3.save() | ||||||
|  | @ -253,10 +257,10 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | ||||||
| 
 | 
 | ||||||
| 		# Občas přidáme mezičíslo | 		# Občas přidáme mezičíslo | ||||||
| 		if rnd.randint(1, 3) == 1: | 		if rnd.randint(1, 3) == 1: | ||||||
| 			create_node_after(cislo_node, m.MezicisloNode, root=cislo_node.root) | 			create_node_after(cislo_node, MezicisloNode, root=cislo_node.root) | ||||||
| 			mezicislo_node = cislo_node.succ | 			mezicislo_node = cislo_node.succ | ||||||
| 	 | 	 | ||||||
| 			cast_node_mezicislo = m.CastNode.objects.create( | 			cast_node_mezicislo = CastNode.objects.create( | ||||||
| 					nadpis = "Příspěvek k mezičíslu".format(cislo.kod), root=cislo_node.root) | 					nadpis = "Příspěvek k mezičíslu".format(cislo.kod), root=cislo_node.root) | ||||||
| 			add_first_child(mezicislo_node, cast_node_mezicislo) | 			add_first_child(mezicislo_node, cast_node_mezicislo) | ||||||
| 
 | 
 | ||||||
|  | @ -419,7 +423,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, 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: | ||||||
|  | @ -438,7 +442,7 @@ def otec_syn(otec, syn): | ||||||
| 
 | 
 | ||||||
| def gen_clanek(rnd, organizatori, resitele): | def gen_clanek(rnd, organizatori, resitele): | ||||||
| 	logger.info("Generuji článek do čísla 22.2") | 	logger.info("Generuji článek do čísla 22.2") | ||||||
| 	clanek = m.Clanek.objects.create( | 	clanek = Clanek.objects.create( | ||||||
| 		nazev="Článek o Lorem ipsum", | 		nazev="Článek o Lorem ipsum", | ||||||
| 		nadproblem=None, | 		nadproblem=None, | ||||||
| 		stav='vyreseny', | 		stav='vyreseny', | ||||||
|  | @ -448,16 +452,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, | ||||||
|  | @ -465,7 +469,7 @@ def gen_clanek(rnd, organizatori, resitele): | ||||||
| 		) | 		) | ||||||
| 	hodnoceni.save() | 	hodnoceni.save() | ||||||
| 
 | 
 | ||||||
| 	reseninode = m.ReseniNode.objects.create( | 	reseninode = ReseniNode.objects.create( | ||||||
| 		reseni=reseni | 		reseni=reseni | ||||||
| 		) | 		) | ||||||
| 	reseninode.save() | 	reseninode.save() | ||||||
|  | @ -481,26 +485,26 @@ def gen_clanek(rnd, organizatori, resitele): | ||||||
| 	# FIXME: Ten, kdo vymyslel TreeLib (mj. týž, kdo psal tenhle kód), | 	# FIXME: Ten, kdo vymyslel TreeLib (mj. týž, kdo psal tenhle kód), | ||||||
| 	# nevyrobil vhodnou funkci, takže to postavíme pozpátku pomocí create_child | 	# nevyrobil vhodnou funkci, takže to postavíme pozpátku pomocí create_child | ||||||
| 	# (které vyrábí _prvního_ syna) | 	# (které vyrábí _prvního_ syna) | ||||||
| 	create_child(reseninode, m.CastNode, nadpis="Lorem ipsum") | 	create_child(reseninode, CastNode, nadpis="Lorem ipsum") | ||||||
| 	# Taky ten člověk nevyrobil vracení nových věcí... | 	# Taky ten člověk nevyrobil vracení nových věcí... | ||||||
| 	castnode = reseninode.first_child | 	castnode = reseninode.first_child | ||||||
| 	 | 	 | ||||||
| 	# Úvodní odstaveček | 	# Úvodní odstaveček | ||||||
| 	obsah = "Tohle je zamyšlení o textu lorem ipsum. Začneme a skončíme ukázkou." | 	obsah = "Tohle je zamyšlení o textu lorem ipsum. Začneme a skončíme ukázkou." | ||||||
| 	text = m.Text.objects.create( | 	text = Text.objects.create( | ||||||
| 		na_web=obsah, | 		na_web=obsah, | ||||||
| 		do_cisla=obsah, | 		do_cisla=obsah, | ||||||
| 		) | 		) | ||||||
| 	text.save() | 	text.save() | ||||||
| 	create_child(reseninode, m.TextNode, text=text) | 	create_child(reseninode, TextNode, text=text) | ||||||
| 
 | 
 | ||||||
| 	# Několik odstavců lorem ipsum | 	# Několik odstavců lorem ipsum | ||||||
| 	for _ in range(rnd.randint(3, 7)): | 	for _ in range(rnd.randint(3, 7)): | ||||||
| 		lipsum = lorem.paragraph() | 		lipsum = lorem.paragraph() | ||||||
| 		text = m.Text.objects.create( | 		text = Text.objects.create( | ||||||
| 			na_web=lipsum, | 			na_web=lipsum, | ||||||
| 			do_cisla=lipsum, | 			do_cisla=lipsum, | ||||||
| 			) | 			) | ||||||
| 		text.save() | 		text.save() | ||||||
| 		create_child(castnode, m.TextNode, text=text) | 		create_child(castnode, TextNode, text=text) | ||||||
| 	logger.info(f"Článek vygenerován (reseni={reseni.id}, treenode={reseninode.id})") | 	logger.info(f"Článek vygenerován (reseni={reseni.id}, treenode={reseninode.id})") | ||||||
|  |  | ||||||
|  | @ -7,19 +7,19 @@ urlpatterns = [ | ||||||
| #	path('<int:rocnik>/t<int:tematko>/', views.TematkoView), | #	path('<int:rocnik>/t<int:tematko>/', views.TematkoView), | ||||||
| 
 | 
 | ||||||
| 	# Archiv | 	# Archiv | ||||||
| 	path('archiv/rocniky/', views.ArchivView.as_view(), name="seminar_archiv_rocniky"), | 	path('archiv/rocniky/', views.ArchivView.as_view(), name="tvorba_archiv_rocniky"), | ||||||
| 	path('archiv/temata/', views.ArchivTemataView.as_view(), name="seminar_archiv_temata"), | 	path('archiv/temata/', views.ArchivTemataView.as_view(), name="tvorba_archiv_temata"), | ||||||
| 
 | 
 | ||||||
| 	path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'), | 	path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='tvorba_rocnik'), | ||||||
| 	path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'), | 	path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='tvorba_cislo'), | ||||||
| 	path('problem/<int:pk>/', views.problemView, name='seminar_problem'), | 	path('problem/<int:pk>/', views.problemView, name='tvorba_problem'), | ||||||
| 
 | 
 | ||||||
| 	# Zadani | 	# Zadani | ||||||
| #	path('aktualni/zadani/', views.AktualniZadaniView.as_view(), name='seminar_aktualni_zadani'), # Dočasně ad-hoc jednoduchá věc. | #	path('aktualni/zadani/', views.AktualniZadaniView.as_view(), name='tvorba_aktualni_zadani'), # Dočasně ad-hoc jednoduchá věc. | ||||||
| 	path('aktualni/zadani/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), | 	path('aktualni/zadani/', views.AktualniZadaniView, name='tvorba_aktualni_zadani'), | ||||||
| 	#path('aktualni/temata/', views.ZadaniTemataView, name='seminar_temata'), | 	#path('aktualni/temata/', views.ZadaniTemataView, name='tvorba_temata'), | ||||||
| 	path('aktualni/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_aktualni_vysledky'), | 	path('aktualni/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='tvorba_aktualni_vysledky'), | ||||||
| 	path('aktualni/rocnik/', views.AktualniRocnikRedirectView.as_view(), name='seminar_aktualni_rocnik'), | 	path('aktualni/rocnik/', views.AktualniRocnikRedirectView.as_view(), name='tvorba_aktualni_rocnik'), | ||||||
| 
 | 
 | ||||||
| 	# Clanky | 	# Clanky | ||||||
| 	path('archiv/clanky/', views.ClankyResitelView.as_view(), name='clanky_resitel'), | 	path('archiv/clanky/', views.ClankyResitelView.as_view(), name='clanky_resitel'), | ||||||
|  | @ -29,42 +29,42 @@ urlpatterns = [ | ||||||
| 	path( | 	path( | ||||||
| 		'rocnik/<int:rocnik>/vysledkovka.tex', | 		'rocnik/<int:rocnik>/vysledkovka.tex', | ||||||
| 		org_required(views.RocnikVysledkovkaView.as_view()), | 		org_required(views.RocnikVysledkovkaView.as_view()), | ||||||
| 		name='seminar_rocnik_vysledkovka' | 		name='tvorba_rocnik_vysledkovka' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'rocnik/<int:rocnik>/resitele.csv', | 		'rocnik/<int:rocnik>/resitele.csv', | ||||||
| 		org_required(views.resiteleRocnikuCsvExportView), | 		org_required(views.resiteleRocnikuCsvExportView), | ||||||
| 		name='seminar_rocnik_resitele_csv' | 		name='tvorba_rocnik_resitele_csv' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'rocnik/<int:rocnik>/tituly.tex', | 		'rocnik/<int:rocnik>/tituly.tex', | ||||||
| 		org_required(views.TitulyViewRocnik), | 		org_required(views.TitulyViewRocnik), | ||||||
| 		name='seminar_rocnik_titul' | 		name='tvorba_rocnik_titul' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'rocnik/<int:rocnik>/posledni_vysledkovka.tex', | 		'rocnik/<int:rocnik>/posledni_vysledkovka.tex', | ||||||
| 		org_required(views.PosledniCisloVysledkovkaView.as_view()), | 		org_required(views.PosledniCisloVysledkovkaView.as_view()), | ||||||
| 		name='seminar_rocnik_posledni_vysledkovka' | 		name='tvorba_rocnik_posledni_vysledkovka' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'cislo/<int:rocnik>.<str:cislo>/vysledkovka.tex', | 		'cislo/<int:rocnik>.<str:cislo>/vysledkovka.tex', | ||||||
| 		org_required(views.CisloVysledkovkaView.as_view()), | 		org_required(views.CisloVysledkovkaView.as_view()), | ||||||
| 		name='seminar_cislo_vysledkovka' | 		name='tvorba_cislo_vysledkovka' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'cislo/<int:rocnik>.<str:cislo>/obalky.pdf', | 		'cislo/<int:rocnik>.<str:cislo>/obalky.pdf', | ||||||
| 		org_required(views.cisloObalkyView), | 		org_required(views.cisloObalkyView), | ||||||
| 		name='seminar_cislo_obalky' | 		name='tvorba_cislo_obalky' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'cislo/<int:rocnik>.<str:cislo>/tituly.tex', | 		'cislo/<int:rocnik>.<str:cislo>/tituly.tex', | ||||||
| 		org_required(views.TitulyView), | 		org_required(views.TitulyView), | ||||||
| 		name='seminar_cislo_titul' | 		name='tvorba_cislo_titul' | ||||||
| 	), | 	), | ||||||
| 	path( | 	path( | ||||||
| 		'cislo/<int:trocnik>.<str:tcislo>/odmeny/<int:frocnik>.<str:fcislo>/', | 		'cislo/<int:trocnik>.<str:tcislo>/odmeny/<int:frocnik>.<str:fcislo>/', | ||||||
| 		org_required(views.OdmenyView.as_view()), | 		org_required(views.OdmenyView.as_view()), | ||||||
| 		name="seminar_archiv_odmeny"), | 		name="tvorba_archiv_odmeny"), | ||||||
| 
 | 
 | ||||||
| 	# Dočasné & neodladěné: | 	# Dočasné & neodladěné: | ||||||
| 	path( | 	path( | ||||||
|  |  | ||||||
|  | @ -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 | from personalni.models import Resitel | ||||||
| import seminar.models as m | from soustredeni.models import Konfera | ||||||
| from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, \ | from tvorba.models import Problem, Cislo, Rocnik, Tema, Clanek, Deadline, Uloha | ||||||
| 	Resitel, Novinky, Tema, Clanek, \ | from treenode.models import TemaVCisleNode, PohadkaNode | ||||||
| 	Deadline  # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | from various.models import Nastaveni | ||||||
| #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva |  | ||||||
| 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, 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, KonferaNode): # FIXME neexistuje | ||||||
| #			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, 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: | ||||||
|  | @ -577,8 +576,8 @@ class ClankyResitelView(generic.ListView): | ||||||
| 
 | 
 | ||||||
| class AktualniRocnikRedirectView(RedirectView): | class AktualniRocnikRedirectView(RedirectView): | ||||||
| 	permanent=False | 	permanent=False | ||||||
| 	pattern_name = 'seminar_rocnik' | 	pattern_name = 'tvorba_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) | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ | ||||||
|     Ješte nejsi zaregistrován? |     Ješte nejsi zaregistrován? | ||||||
| </h2> | </h2> | ||||||
| 
 | 
 | ||||||
| <form action="{% url 'seminar_prihlaska' %}"> | <form action="{% url 'personalni_prihlaska' %}"> | ||||||
|     <input type="submit" value="Registrovat" /> |     <input type="submit" value="Registrovat" /> | ||||||
| </form> | </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') | ||||||
|  |  | ||||||
|  | @ -12,8 +12,8 @@ class StripSensitiveFormDataFilter(Filter): | ||||||
| 		if hasattr(record, 'request') and record.request.path in [ | 		if hasattr(record, 'request') and record.request.path in [ | ||||||
| 				reverse('login'), | 				reverse('login'), | ||||||
| 				reverse('logout'), | 				reverse('logout'), | ||||||
| 				reverse('seminar_prihlaska'), | 				reverse('personalni_prihlaska'), | ||||||
| 				reverse('seminar_resitel_edit'), | 				reverse('personalni_resitel_edit'), | ||||||
| 				reverse('reset_password'), | 				reverse('reset_password'), | ||||||
| 				reverse('reset_password_done'), | 				reverse('reset_password_done'), | ||||||
| 				# FIXME | 				# FIXME | ||||||
|  |  | ||||||
|  | @ -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() | ||||||
|  |  | ||||||
|  | @ -1,11 +1,12 @@ | ||||||
|  | import os | ||||||
|  | 
 | ||||||
| from django.db import models | from django.db import models | ||||||
|  | from django.core.files.storage import FileSystemStorage | ||||||
|  | from django.urls import reverse | ||||||
| 
 | 
 | ||||||
| from reversion import revisions as reversion | from reversion import revisions as reversion | ||||||
| from solo.models import SingletonModel | from solo.models import SingletonModel | ||||||
| 
 | 
 | ||||||
| from tvorba.models import Cislo |  | ||||||
| 
 |  | ||||||
| from django.urls import reverse |  | ||||||
| 
 | 
 | ||||||
| @reversion.register(ignore_duplicates=True) | @reversion.register(ignore_duplicates=True) | ||||||
| class Nastaveni(SingletonModel): | class Nastaveni(SingletonModel): | ||||||
|  | @ -14,10 +15,10 @@ class Nastaveni(SingletonModel): | ||||||
| 		db_table = 'seminar_nastaveni' | 		db_table = 'seminar_nastaveni' | ||||||
| 		verbose_name = 'Nastavení semináře' | 		verbose_name = 'Nastavení semináře' | ||||||
| 
 | 
 | ||||||
| #	aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name='aktuální ročník', | #	aktualni_rocnik = models.ForeignKey("tvorba.Rocnik", verbose_name='aktuální ročník', | ||||||
| #		null=False, on_delete=models.PROTECT) | #		null=False, on_delete=models.PROTECT) | ||||||
| 
 | 
 | ||||||
| 	aktualni_cislo = models.ForeignKey(Cislo, verbose_name='Aktuální číslo',  | 	aktualni_cislo = models.ForeignKey("tvorba.Cislo", verbose_name='Aktuální číslo', | ||||||
| 		null=True, blank=False, on_delete=models.PROTECT, | 		null=True, blank=False, on_delete=models.PROTECT, | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
|  | @ -37,3 +38,28 @@ class Nastaveni(SingletonModel): | ||||||
| 	 | 	 | ||||||
| 	def verejne(self): | 	def verejne(self): | ||||||
| 		return False | 		return False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class OverwriteStorage(FileSystemStorage): | ||||||
|  | 	""" Varianta FileSystemStorage, která v případě, že soubor cílového | ||||||
|  | 	jména již existuje, ho smaže a místo něj uloží soubor nový""" | ||||||
|  | 	def get_available_name(self,name, max_length=None): | ||||||
|  | 		if self.exists(name): | ||||||
|  | 			os.remove(os.path.join(self.location,name)) | ||||||
|  | 		return super().get_available_name(name,max_length) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class SeminarModelBase(models.Model): | ||||||
|  | 	class Meta: | ||||||
|  | 		abstract = True | ||||||
|  | 
 | ||||||
|  | 	def verejne(self): | ||||||
|  | 		return False | ||||||
|  | 
 | ||||||
|  | 	# def get_absolute_url(self): | ||||||
|  | 	# 	return "https://" + str(get_current_site(None)) + self.verejne_url() | ||||||
|  | 
 | ||||||
|  | 	def admin_url(self): | ||||||
|  | 		app_name = self._meta.app_label | ||||||
|  | 		model_name = self._meta.model_name | ||||||
|  | 		return reverse('admin:{}_{}_change'.format(app_name, model_name), args=(self.id, )) | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
|     Na této stránce velmi intenzivně pracujeme. |     Na této stránce velmi intenzivně pracujeme. | ||||||
|     Za dočasnou nedostupnost se omlouváme. |     Za dočasnou nedostupnost se omlouváme. | ||||||
|     Zkuste přejít na <a href="/">titulní stránku</a> |     Zkuste přejít na <a href="/">titulní stránku</a> | ||||||
|     nebo se podívat na <a href="{% url 'seminar_aktualni_zadani' %}">aktuální zadání</a>. |     nebo se podívat na <a href="{% url 'tvorba_aktualni_zadani' %}">aktuální zadání</a>. | ||||||
|   </p> |   </p> | ||||||
|   <img src="{% static '404.png' %}"> |   <img src="{% static '404.png' %}"> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
|  | @ -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,10 @@ 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 | 
 | ||||||
| from seminar import models as m | from treenode.models import CisloNode | ||||||
|  | from personalni.models import Resitel, Osoba | ||||||
|  | from tvorba.models import Clanek, Deadline | ||||||
| 
 | 
 | ||||||
| from ..models import Nastaveni | from ..models import Nastaveni | ||||||
| 
 | 
 | ||||||
|  | @ -30,7 +32,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 +95,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): | ||||||
|  | @ -127,7 +129,7 @@ def seznam_problemu(): | ||||||
| 		# content type je věc pomáhající rozeznávat různé typy objektů v django-polymorphic | 		# content type je věc pomáhající rozeznávat různé typy objektů v django-polymorphic | ||||||
| 		# protože isinstance vrátí vždy jen TreeNode | 		# protože isinstance vrátí vždy jen TreeNode | ||||||
| 		# https://django-polymorphic.readthedocs.io/en/stable/migrating.html | 		# https://django-polymorphic.readthedocs.io/en/stable/migrating.html | ||||||
| 		cislonode_ct = ContentType.objects.get_for_model(m.CisloNode) | 		cislonode_ct = ContentType.objects.get_for_model(CisloNode) | ||||||
| 		node = clanek_node | 		node = clanek_node | ||||||
| 		while node is not None: | 		while node is not None: | ||||||
| 			node_ct = node.polymorphic_ctype | 			node_ct = node.polymorphic_ctype | ||||||
|  | @ -136,7 +138,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 +148,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, | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ def formularOKView(request, text='', dalsi_odkazy: Sequence[tuple[str, str]] = ( | ||||||
| 	odkazy = list(dalsi_odkazy) + [ | 	odkazy = list(dalsi_odkazy) + [ | ||||||
| 		# (Text, odkaz) | 		# (Text, odkaz) | ||||||
| 		('Vrátit se na titulní stránku', reverse('titulni_strana')), | 		('Vrátit se na titulní stránku', reverse('titulni_strana')), | ||||||
| 		('Zobrazit aktuální zadání', reverse('seminar_aktualni_zadani')), | 		('Zobrazit aktuální zadání', reverse('tvorba_aktualni_zadani')), | ||||||
| 	] | 	] | ||||||
| 	context = { | 	context = { | ||||||
| 		'odkazy': odkazy, | 		'odkazy': odkazy, | ||||||
|  |  | ||||||
|  | @ -17,9 +17,9 @@ module.exports = { | ||||||
|     filenameHashing: false, |     filenameHashing: false, | ||||||
|     productionSourceMap: true, |     productionSourceMap: true, | ||||||
|     publicPath: process.env.NODE_ENV === 'production' |     publicPath: process.env.NODE_ENV === 'production' | ||||||
|         ? '/static/seminar/vue/' |         ? '/static/treenode/vue/' | ||||||
|         : 'http://localhost:8080/', |         : 'http://localhost:8080/', | ||||||
|     outputDir: '../seminar/static/seminar/vue/', |     outputDir: '../treenode/static/treenode/vue/', | ||||||
| 
 | 
 | ||||||
|     chainWebpack: config => { |     chainWebpack: config => { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue