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( | ||||
| 		'aesop-export/mam-rocnik-<int:prvni_rok>.csv', | ||||
| 		views.ExportRocnikView.as_view(), | ||||
| 		name='seminar_export_rocnik' | ||||
| 		name='aesop_export_rocnik' | ||||
| 	), | ||||
| 	path( | ||||
| 		'aesop-export/mam-sous-<str:datum_zacatku>.csv', | ||||
| 		views.ExportSousView.as_view(), | ||||
| 		name='seminar_export_sous' | ||||
| 		name='aesop_export_sous' | ||||
| 	), | ||||
| 	path( | ||||
| 		'aesop-export/index.csv', | ||||
| 		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 .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 tvorba.utils import aktivniResitele | ||||
| 
 | ||||
|  | @ -14,10 +15,10 @@ class ExportIndexView(generic.View): | |||
| 	def get(self, request): | ||||
| 		ls = [] | ||||
| 		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]) | ||||
| 		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]) | ||||
| 
 | ||||
| 		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.urls import reverse | ||||
| import seminar.models as m | ||||
| from personalni.models import Skola | ||||
| from personalni.utils import sync_skoly | ||||
| 
 | ||||
| @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""" | ||||
| 		for pfx, id in self.spravna_data: | ||||
| 			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í | ||||
| 				resp = self.client.get(reverse('autocomplete_skola')+'?q='+pfx).json() | ||||
| 				ids = [int(x['id']) for x in resp['results']] | ||||
|  |  | |||
|  | @ -17,5 +17,5 @@ urlpatterns = [ | |||
| 	# Ceka na autocomplete v3 | ||||
| 	# path('autocomplete/organizatori/', | ||||
| 	# 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.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 | ||||
| 
 | ||||
| # 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. """ | ||||
| 	def get_queryset(self): | ||||
| 		# Don't forget to filter out results depending on the visitor ! | ||||
| 		qs = m.Skola.objects.all() | ||||
| 		qs = Skola.objects.all() | ||||
| 		if self.q: | ||||
| 			words = self.q.split(' ') #TODO re split podle bileho znaku | ||||
| 			partq = Q() | ||||
|  | @ -31,7 +33,7 @@ class SkolaAutocomplete(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. """ | ||||
| 	def get_queryset(self): | ||||
| 		qs = m.Resitel.objects.all() | ||||
| 		qs = Resitel.objects.all() | ||||
| 		if self.q: | ||||
| 			parts = self.q.split() | ||||
| 			query = Q() | ||||
|  | @ -51,8 +53,8 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer | |||
| 		především v odevzdávátku. | ||||
| 	""" | ||||
| 	def get_queryset(self): | ||||
| 		letos = m.Nastaveni.get_solo().aktualni_rocnik | ||||
| 		qs = m.Resitel.objects.filter( | ||||
| 		letos = Nastaveni.get_solo().aktualni_rocnik | ||||
| 		qs = Resitel.objects.filter( | ||||
| 			rok_maturity__gte=letos.druhy_rok() | ||||
| 		).filter( | ||||
| 			prezdivka_resitele__isnull=False | ||||
|  | @ -70,7 +72,7 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer | |||
| class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView): | ||||
| 	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """ | ||||
| 	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: | ||||
| 			qs = qs.filter( | ||||
| 					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. """ | ||||
| 	def get_queryset(self): | ||||
| 		# FIXME i starší úlohy | ||||
| 		nastaveni = get_object_or_404(m.Nastaveni) | ||||
| 		nastaveni = get_object_or_404(Nastaveni) | ||||
| 		rocnik = nastaveni.aktualni_rocnik | ||||
| 		temaQ = Q(Tema___rocnik = rocnik) | ||||
| 		ulohaQ = Q(Uloha___cislo_zadani__rocnik=rocnik) | ||||
| 		clanekQ = Q(Clanek___cislo__rocnik=rocnik) | ||||
| 		qs = m.Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev") | ||||
| 		qs = Problem.objects.filter(temaQ | ulohaQ | clanekQ).order_by("-stav", "nazev") | ||||
| 		if self.q: | ||||
| 			qs = qs.filter( | ||||
| 					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.http import HttpResponse | ||||
| def exportSkolView(request): | ||||
|  |  | |||
|  | @ -73,7 +73,7 @@ | |||
| 			"sort_order": 3, | ||||
| 			"title": "Aktuální<br/> ročník", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_aktualni_zadani", | ||||
| 			"url": "tvorba_aktualni_zadani", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -121,7 +121,7 @@ | |||
| 			"sort_order": 5, | ||||
| 			"title": "Archiv", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_archiv_rocniky", | ||||
| 			"url": "tvorba_archiv_rocniky", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -289,7 +289,7 @@ | |||
| 			"sort_order": 43, | ||||
| 			"title": "Výsledková listina", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_aktualni_vysledky", | ||||
| 			"url": "tvorba_aktualni_vysledky", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -361,7 +361,7 @@ | |||
| 			"sort_order": 20, | ||||
| 			"title": "Proběhlo", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_seznam_soustredeni", | ||||
| 			"url": "soustredeni_seznam", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -409,7 +409,7 @@ | |||
| 			"sort_order": 23, | ||||
| 			"title": "Osobní údaje", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_resitel_edit", | ||||
| 			"url": "personalni_resitel_edit", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -439,7 +439,7 @@ | |||
| 			"sort_order": 36, | ||||
| 			"title": "Nahrát řešení", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_nahraj_reseni", | ||||
| 			"url": "odevzdavatko_nahraj_reseni", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -463,7 +463,7 @@ | |||
| 			"sort_order": 35, | ||||
| 			"title": "Témata", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_archiv_temata", | ||||
| 			"url": "tvorba_archiv_temata", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -589,7 +589,7 @@ | |||
| 			"sort_order": 15, | ||||
| 			"title": "Aktuální číslo", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_aktualni_zadani", | ||||
| 			"url": "tvorba_aktualni_zadani", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -613,7 +613,7 @@ | |||
| 			"sort_order": 24, | ||||
| 			"title": "Čísla", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_archiv_rocniky", | ||||
| 			"url": "tvorba_archiv_rocniky", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -721,7 +721,7 @@ | |||
| 			"sort_order": 36, | ||||
| 			"title": "Vložit řešení", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_vloz_reseni", | ||||
| 			"url": "odevzdavatko_vloz_reseni", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -804,7 +804,7 @@ | |||
| 			"sort_order": 37, | ||||
| 			"title": "Moje řešení", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_resitel_odevzdana_reseni", | ||||
| 			"url": "odevzdavatko_resitel_odevzdana_reseni", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -828,7 +828,7 @@ | |||
| 			"sort_order": 33, | ||||
| 			"title": "Aktuální ročník", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_aktualni_rocnik", | ||||
| 			"url": "tvorba_aktualni_rocnik", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -900,7 +900,7 @@ | |||
| 			"sort_order": 46, | ||||
| 			"title": "Ročník {{rocnik.rocnik}}", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_rocnik rocnik.rocnik", | ||||
| 			"url": "tvorba_rocnik rocnik.rocnik", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -924,7 +924,7 @@ | |||
| 			"sort_order": 47, | ||||
| 			"title": "Číslo {{ cislo.rocnik.rocnik }}.{{ cislo.poradi }}", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_cislo cislo.rocnik.rocnik cislo.poradi", | ||||
| 			"url": "tvorba_cislo cislo.rocnik.rocnik cislo.poradi", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -1061,7 +1061,7 @@ | |||
| 			"sort_order": 52, | ||||
| 			"title": "Nahrát řešení k nadproblému {{nadproblem_id}}", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_nahraj_reseni nadproblem_id", | ||||
| 			"url": "odevzdavatko_nahraj_reseni nadproblem_id", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  | @ -1109,7 +1109,7 @@ | |||
| 			"sort_order": 54, | ||||
| 			"title": "Export do abstraktů sousu {{ soustredeni.id }}", | ||||
| 			"tree": 1, | ||||
| 			"url": "seminar_soustredeni_abstrakty soustredeni.id", | ||||
| 			"url": "soustredeni_abstrakty soustredeni.id", | ||||
| 			"urlaspattern": true | ||||
| 		}, | ||||
| 		"model": "sitetree.treeitem", | ||||
|  |  | |||
|  | @ -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. | ||||
| 
 | ||||
| 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 | ||||
| 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. | ||||
| tu aplikaci, která tomu odpovídá, respektive se k ní dostat přes url). | ||||
| 
 | ||||
| **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, | ||||
| 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 | ||||
|  | @ -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 | ||||
| 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 | ||||
| -------------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ Aktuálně: Jakýsi coding style zhruba existuje, není popsaný, šíří se li | |||
| - Nesmí být striktně vynucovaný | ||||
| - Musel by být hodně nastavitelný | ||||
|     - 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 ☺) | ||||
| - __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? | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ from django.template import RequestContext | |||
| from datetime import datetime | ||||
| 
 | ||||
| from galerie.models import Obrazek, Galerie | ||||
| from seminar.models import Soustredeni | ||||
| from soustredeni.models import Soustredeni | ||||
| from galerie.forms import KomentarForm, NewGalerieForm | ||||
| 
 | ||||
| def zobrazit(galerie, request): | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ set -exuo pipefail | |||
| . make/lib.sh | ||||
| 
 | ||||
| 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" " | ||||
| 	set -euxo pipefail | ||||
| 	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) | ||||
| 	aplikace_nahore = [ | ||||
| 		'seminar', | ||||
| 		'tvorba', | ||||
| 		'personalni', | ||||
| 		'novinky', | ||||
| 		'korektury', | ||||
|  | @ -57,7 +57,7 @@ def get_app_list(self, request, app_label=None): | |||
| 
 | ||||
| 	# Sort the models alphabetically within each app. | ||||
| 	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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -279,11 +279,11 @@ LOGGING = { | |||
| 				'filters': ['Http404AsInfo'], | ||||
| 				}, | ||||
| 
 | ||||
| 			'seminar.prihlaska.form':{ | ||||
| 			'personalni.prihlaska.form':{ | ||||
| 		'handlers': ['console','registration_logfile'], | ||||
| 		'level': 'INFO' | ||||
| 		}, | ||||
| 			'seminar.prihlaska.problem':{ | ||||
| 			'personalni.prihlaska.problem':{ | ||||
| 		'handlers': ['console','mail_registration','registration_error_log'], | ||||
| 		'level': 'INFO' | ||||
| 		}, | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
|   {% if not novinka.zverejneno and user.je_org %} | ||||
|   <div class="mam-org-only"> | ||||
|     <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> | ||||
|   {% endif %} | ||||
|   {% if novinka.zverejneno or user.je_org %} | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| from django.contrib import admin | ||||
| from django_reverse_admin import ReverseModelAdmin | ||||
| import seminar.models as m | ||||
| import odevzdavatko.models as m | ||||
| 
 | ||||
| 
 | ||||
| class PrilohaReseniInline(admin.TabularInline): | ||||
|  |  | |||
|  | @ -4,8 +4,11 @@ from django.forms import formset_factory | |||
| from django.forms.models import inlineformset_factory | ||||
| from django.utils import timezone | ||||
| 
 | ||||
| from seminar.models import Resitel | ||||
| import seminar.models as m | ||||
| from personalni.models import Resitel | ||||
| from tvorba.models import Problem, Deadline | ||||
| from various.models import Nastaveni | ||||
| 
 | ||||
| from odevzdavatko.models import Reseni, PrilohaReseni, Hodnoceni | ||||
| 
 | ||||
| import logging | ||||
| 
 | ||||
|  | @ -22,7 +25,7 @@ class DateInput(forms.DateInput): | |||
| 
 | ||||
| class PosliReseniForm(forms.Form): | ||||
| 	problem = forms.ModelMultipleChoiceField( | ||||
| 		queryset=m.Problem.objects.all(), | ||||
| 		queryset=Problem.objects.all(), | ||||
| 		label="Problémy", | ||||
| 		widget=autocomplete.ModelSelect2Multiple( | ||||
| 			url='autocomplete_problem', | ||||
|  | @ -58,7 +61,7 @@ class PosliReseniForm(forms.Form): | |||
| 
 | ||||
| 	#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, | ||||
| 	#	 default=FORMA_EMAIL) | ||||
| 
 | ||||
|  | @ -69,7 +72,7 @@ class PosliReseniForm(forms.Form): | |||
| 
 | ||||
| class NahrajReseniForm(forms.ModelForm): | ||||
| 	class Meta: | ||||
| 		model = m.Reseni | ||||
| 		model = Reseni | ||||
| 		fields = ('problem', 'resitele') | ||||
| 		help_texts = {'problem':''} # Nezobrazovat help text ve formuláři | ||||
| 		 | ||||
|  | @ -109,11 +112,11 @@ class NahrajReseniForm(forms.ModelForm): | |||
| 	def clean_problem(self): | ||||
| 		problem = self.cleaned_data.get('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!") | ||||
| 		return problem | ||||
| 
 | ||||
| ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni,  | ||||
| ReseniSPrilohamiFormSet = inlineformset_factory(Reseni, PrilohaReseni, | ||||
| 		form = NahrajReseniForm, | ||||
| 		fields = ('soubor','res_poznamka'), | ||||
| 		widgets = {'res_poznamka':forms.TextInput()}, | ||||
|  | @ -125,7 +128,7 @@ ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni, | |||
| 
 | ||||
| class JednoHodnoceniForm(forms.ModelForm): | ||||
| 	class Meta: | ||||
| 		model = m.Hodnoceni | ||||
| 		model = Hodnoceni | ||||
| 		fields = ('problem', 'body', 'deadline_body', 'feedback',) | ||||
| 		widgets = { | ||||
| 			'problem': autocomplete.ModelSelect2( | ||||
|  | @ -158,7 +161,7 @@ OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm, | |||
| 
 | ||||
| class PoznamkaReseniForm(forms.ModelForm): | ||||
| 	class Meta: | ||||
| 		model = m.Reseni | ||||
| 		model = Reseni | ||||
| 		fields = ('poznamka',) | ||||
| 
 | ||||
| # 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 | ||||
| 		try: | ||||
| 			aktualni_rocnik = m.Nastaveni.get_solo().aktualni_rocnik | ||||
| 			aktualni_rocnik = Nastaveni.get_solo().aktualni_rocnik | ||||
| 		except OperationalError: | ||||
| 			# 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 | ||||
|  | @ -214,7 +217,7 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form): | |||
| 
 | ||||
| 		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(), | ||||
| 				cislo__rocnik=aktualni_rocnik | ||||
| 				).order_by("deadline"): | ||||
|  |  | |||
|  | @ -9,14 +9,14 @@ from django.urls import reverse_lazy | |||
| from django.utils import timezone | ||||
| from django.conf import settings | ||||
| 
 | ||||
| import tvorba.models as am | ||||
| from seminar.models import base as bm | ||||
| from tvorba.models import Problem, Deadline, Cislo, Uloha, aux_generate_filename | ||||
| from various.models import SeminarModelBase | ||||
| 
 | ||||
| from odevzdavatko.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet | ||||
| from personalni.models import Resitel | ||||
| 
 | ||||
| @reversion.register(ignore_duplicates=True) | ||||
| class Reseni(bm.SeminarModelBase): | ||||
| class Reseni(SeminarModelBase): | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_reseni' | ||||
|  | @ -29,7 +29,7 @@ class Reseni(bm.SeminarModelBase): | |||
| 	id = models.AutoField(primary_key = True) | ||||
| 
 | ||||
| 	# 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') | ||||
| 
 | ||||
| 	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) | ||||
| 
 | ||||
| 	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: | ||||
| #	def save(self, *args, **kwargs): | ||||
|  | @ -88,7 +88,7 @@ class Reseni(bm.SeminarModelBase): | |||
| #			self.cislo_body = self.problem.cislo_reseni | ||||
| #		super(Reseni, self).save(*args, **kwargs) | ||||
| 
 | ||||
| class Hodnoceni(bm.SeminarModelBase): | ||||
| class Hodnoceni(SeminarModelBase): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_hodnoceni' | ||||
| 		verbose_name = 'Hodnocení' | ||||
|  | @ -101,16 +101,16 @@ class Hodnoceni(bm.SeminarModelBase): | |||
| 	body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='body', | ||||
| 							   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) | ||||
| 
 | ||||
| 	# 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) | ||||
| 
 | ||||
| 	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) | ||||
| 
 | ||||
| 	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 | ||||
| 	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 self.problem.uloha.max_body | ||||
| 
 | ||||
|  | @ -176,12 +176,12 @@ class Hodnoceni(bm.SeminarModelBase): | |||
| def generate_filename(self, filename): | ||||
| 	return os.path.join( | ||||
| 		settings.SEMINAR_RESENI_DIR, | ||||
| 		am.aux_generate_filename(self, filename) | ||||
| 		aux_generate_filename(self, filename) | ||||
| 	) | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicates=True) | ||||
| class PrilohaReseni(bm.SeminarModelBase): | ||||
| class PrilohaReseni(SeminarModelBase): | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_priloha_reseni' | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ | |||
|   {% endblock %} | ||||
| </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 %} | ||||
|   <table class='form'> | ||||
|     <tr> | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| 
 | ||||
| <ul> | ||||
|   {% 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 %} | ||||
|     <li>Nelze nic odevzdávat.</li> | ||||
|   {% endfor %} | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
|     Vložit řešení | ||||
|   {% endblock %} | ||||
| </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 %} | ||||
| {{form.as_p}} | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,11 +2,11 @@ from django import template | |||
| register = template.Library() | ||||
| 
 | ||||
| from functools import cache | ||||
| import seminar.models as m | ||||
| from odevzdavatko.models import Reseni | ||||
| 
 | ||||
| @register.filter | ||||
| @cache | ||||
| def barva_reseni(r: m.Reseni): | ||||
| def barva_reseni(r: Reseni): | ||||
| 	"""Vrátí nějakou barvu pro daný problém, ve tvaru '#RRGGBB' | ||||
| 
 | ||||
| 	Efektivně hešujeme do barev.""" | ||||
|  |  | |||
|  | @ -2,8 +2,8 @@ from django import template | |||
| register = template.Library() | ||||
| 
 | ||||
| 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 | ||||
| def jmeno_jako_prefix(o: m.Osoba): | ||||
| def jmeno_jako_prefix(o: Osoba): | ||||
| 	return normalizuj_jmeno(o).replace(' ', '_') | ||||
|  |  | |||
|  | @ -5,10 +5,10 @@ from various.views.generic import viewMethodSwitch | |||
| from . import views | ||||
| 
 | ||||
| urlpatterns = [ | ||||
| 	path('org/add_solution', org_required(views.VlozReseniView.as_view()), name='seminar_vloz_reseni'), | ||||
| 	path('resitel/nahraj_reseni', resitel_required(views.NahrajReseniRozcestnikTematekView.as_view()), name='seminar_nahraj_reseni'), | ||||
| 	path('resitel/nahraj_reseni/<int:nadproblem_id>/', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'), | ||||
| 	path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='seminar_resitel_odevzdana_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='odevzdavatko_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='odevzdavatko_resitel_odevzdana_reseni'), | ||||
| 
 | ||||
| 	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'), | ||||
|  |  | |||
|  | @ -17,10 +17,14 @@ from decimal import Decimal | |||
| from itertools import groupby | ||||
| import logging | ||||
| 
 | ||||
| import seminar.models as m | ||||
| from . import forms as f | ||||
| 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 various.models import Nastaveni | ||||
| from various.views.pomocne import formularOKView | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
|  | @ -40,20 +44,20 @@ logger = logging.getLogger(__name__) | |||
| 
 | ||||
| class TabulkaOdevzdanychReseniView(ListView): | ||||
| 	template_name = 'odevzdavatko/tabulka.html' | ||||
| 	model = m.Hodnoceni | ||||
| 	model = Hodnoceni | ||||
| 
 | ||||
| 	def inicializuj_osy_tabulky(self): | ||||
| 		"""Vyrobí prvotní querysety pro sloupce a řádky, tj. seznam všech řešitelů a problémů""" | ||||
| 		# 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 | ||||
| 		# TODO: Prefetches, Select related, ... | ||||
| 		self.resitele = m.Resitel.objects.all() | ||||
| 		self.problemy = m.Problem.objects.all() | ||||
| 		self.reseni = m.Reseni.objects.all() | ||||
| 		self.resitele = Resitel.objects.all() | ||||
| 		self.problemy = Problem.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: | ||||
| 			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) | ||||
| 		if form.is_valid(): | ||||
|  | @ -86,14 +90,14 @@ class TabulkaOdevzdanychReseniView(ListView): | |||
| 			self.resitele = self.resitele.filter(rok_maturity__gt=self.aktualni_rocnik.prvni_rok) | ||||
| 
 | ||||
| 		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( | ||||
| 					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: | ||||
| 			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.... | ||||
| 		# 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['problemy'] = self.problemy | ||||
| 		ctx['resitele'] = self.resitele | ||||
| 		tabulka: dict[m.Problem, dict[m.Resitel, list[tuple[m.Reseni, m.Hodnoceni]]]] = dict() | ||||
| 		soucty: dict[m.Problem, dict[m.Resitel, Decimal]] = dict() | ||||
| 		tabulka: dict[Problem, dict[Resitel, list[tuple[Reseni, Hodnoceni]]]] = dict() | ||||
| 		soucty: dict[Problem, dict[Resitel, Decimal]] = dict() | ||||
| 
 | ||||
| 		def pridej_reseni(resitel, hodnoceni): | ||||
| 			problem = hodnoceni.problem | ||||
|  | @ -143,11 +147,11 @@ class TabulkaOdevzdanychReseniView(ListView): | |||
| 			for resitel in hodnoceni.reseni.resitele.all(): | ||||
| 				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. | ||||
| 		resitele_do_tabulky: list[m.Resitel] = [] | ||||
| 		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[Resitel] = [] | ||||
| 		for resitel in self.resitele: | ||||
| 			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: | ||||
| 				if problem in tabulka and resitel in tabulka[problem]: | ||||
| 					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: | ||||
| 		ctx['form'] = ctx['filtr'] | ||||
| 		# 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 | ||||
| 		if 'rocnik' in self.kwargs: | ||||
| 			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 :-) | ||||
| 
 | ||||
| 	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' | ||||
| 	 | ||||
| 	def get_queryset(self): | ||||
|  | @ -190,8 +194,8 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi | |||
| 		if problem_id is None: | ||||
| 			raise ValueError("Nemám problém! (To je problém!)") | ||||
| 		 | ||||
| 		resitel = m.Resitel.objects.get(id=resitel_id) | ||||
| 		problem = m.Problem.objects.get(id=problem_id) | ||||
| 		resitel = Resitel.objects.get(id=resitel_id) | ||||
| 		problem = Problem.objects.get(id=problem_id) | ||||
| 		qs = qs.filter( | ||||
| 			problem__in=[problem], | ||||
| 			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 | ||||
| class DetailReseniView(DetailView): | ||||
| 	""" Náhled na řešení. Editace je v :py:class:`EditReseniView`. """ | ||||
| 	model = m.Reseni | ||||
| 	model = Reseni | ||||
| 	template_name = 'odevzdavatko/detail.html' | ||||
| 	 | ||||
| 	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 | ||||
| 		for hodn in m.Hodnoceni.objects.filter(reseni=self.reseni): | ||||
| 		for hodn in Hodnoceni.objects.filter(reseni=self.reseni): | ||||
| 			seznam_atributu = [ | ||||
| 				"problem", | ||||
| 				"body", | ||||
|  | @ -284,7 +288,7 @@ class EditReseniView(DetailReseniView): | |||
| 
 | ||||
| 
 | ||||
| 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}) | ||||
| 
 | ||||
| 	# 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() | ||||
| 
 | ||||
| 		# 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}") | ||||
| 		qs.delete() | ||||
| 
 | ||||
|  | @ -311,7 +315,7 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): | |||
| 			del(data_for_hodnoceni["body_celkem"]) | ||||
| 			del(data_for_hodnoceni["body_neprepocitane"]) | ||||
| 			del(data_for_hodnoceni["body_neprepocitane_celkem"]) | ||||
| 			hodnoceni = m.Hodnoceni( | ||||
| 			hodnoceni = Hodnoceni( | ||||
| 					reseni=reseni, | ||||
| 					**form.cleaned_data, | ||||
| 					) | ||||
|  | @ -332,14 +336,14 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): | |||
| 
 | ||||
| 
 | ||||
| class PrehledOdevzdanychReseni(ListView): | ||||
| 	model = m.Hodnoceni | ||||
| 	model = Hodnoceni | ||||
| 	template_name = 'odevzdavatko/prehled_reseni.html' | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		if not self.request.user.is_authenticated: | ||||
| 			raise RuntimeError("Uživatel měl být přihlášený!") | ||||
| 		# 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 = qs.filter(reseni__resitele__in=[resitel]) | ||||
| 		# 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í | ||||
| 
 | ||||
| class SeznamReseniView(ListView): | ||||
| 	model = m.Reseni | ||||
| 	model = Reseni | ||||
| 	template_name = 'odevzdavatko/seznam.html' | ||||
| 
 | ||||
| class SeznamAktualnichReseniView(SeznamReseniView): | ||||
| 	def get_queryset(self): | ||||
| 		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) | ||||
| 		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 | ||||
|  | @ -378,7 +382,7 @@ class VlozReseniView(LoginRequiredMixin, FormView): | |||
| 
 | ||||
| 	def form_valid(self, form): | ||||
| 		data = form.cleaned_data | ||||
| 		nove_reseni = m.Reseni.objects.create( | ||||
| 		nove_reseni = Reseni.objects.create( | ||||
| 			cas_doruceni=data['cas_doruceni'], | ||||
| 			forma=data['forma'], | ||||
| 			poznamka=data['poznamka'], | ||||
|  | @ -405,35 +409,35 @@ class VlozReseniView(LoginRequiredMixin, FormView): | |||
| 
 | ||||
| 
 | ||||
| class NahrajReseniRozcestnikTematekView(LoginRequiredMixin, ListView): | ||||
| 	model = m.Problem | ||||
| 	model = Problem | ||||
| 	template_name = 'odevzdavatko/nahraj_reseni_nadproblem.html' | ||||
| 
 | ||||
| 	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): | ||||
| 	model = m.Reseni | ||||
| 	model = Reseni | ||||
| 	template_name = 'odevzdavatko/nahraj_reseni.html' | ||||
| 	form_class = f.NahrajReseniForm | ||||
| 	nadproblem: m.Problem | ||||
| 	nadproblem: Problem | ||||
| 
 | ||||
| 	def setup(self, request, *args, **kwargs): | ||||
| 		super().setup(request, *args, **kwargs) | ||||
| 		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): | ||||
| 		# Zaříznutí nezadaných problémů | ||||
| 		if self.nadproblem.stav != m.Problem.STAV_ZADANY: | ||||
| 		if self.nadproblem.stav != Problem.STAV_ZADANY: | ||||
| 			raise PermissionDenied() | ||||
| 
 | ||||
| 
 | ||||
| 		# Zaříznutí starých řešitelů: | ||||
| 		# 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 | ||||
| 		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', { | ||||
| 				'title': 'Nelze odevzdat', | ||||
| 				'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 | ||||
| 		return { | ||||
| 			"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["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 | ||||
| 
 | ||||
| 	# 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) | ||||
| 		with transaction.atomic(): | ||||
| 			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.cas_doruceni = timezone.now() | ||||
| 			self.object.forma = m.Reseni.FORMA_UPLOAD | ||||
| 			self.object.forma = Reseni.FORMA_UPLOAD | ||||
| 			self.object.save() | ||||
| 
 | ||||
| 			prilohy.instance = self.object | ||||
| 			prilohy.save() | ||||
| 
 | ||||
| 		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() | ||||
| 
 | ||||
| 		# 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? | ||||
| 		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_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( | ||||
| 			self.request, | ||||
| 			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_reverse_admin import ReverseModelAdmin | ||||
| from django.contrib.messages import WARNING, ERROR, SUCCESS | ||||
| import seminar.models as m | ||||
| import personalni.models as m | ||||
| from datetime import datetime | ||||
| 
 | ||||
| @admin.action(description="Sjednoť telefony") | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ from django.contrib.auth.forms import PasswordResetForm | |||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| 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 | ||||
| import logging | ||||
|  | @ -27,7 +27,7 @@ class TelInput(forms.TextInput): | |||
| 
 | ||||
| class UdajeForm(forms.Form): | ||||
| 	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) | ||||
| 	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): | ||||
| 	err_logger = logging.getLogger('seminar.edit.problem') | ||||
| 	err_logger = logging.getLogger('personalni.prihlaska.problem.edit') | ||||
| 	username = forms.CharField( | ||||
| 		label='Přihlašovací jméno', | ||||
| 		max_length=256, | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ from django_countries.fields import CountryField | |||
| 
 | ||||
| from reversion import revisions as reversion | ||||
| 
 | ||||
| from seminar.models.base import SeminarModelBase | ||||
| from various.models import SeminarModelBase | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ | |||
| 		<li>hlasování o přednáškách</li> | ||||
| 	</ul> | ||||
| 	</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> | ||||
| 		<li>vytvoření galerie</li> | ||||
| 		<li>stažení seznamu účastníků</li> | ||||
|  |  | |||
|  | @ -10,9 +10,9 @@ | |||
| </h1> | ||||
| 
 | ||||
| <a href="{% url 'logout' %}">Odhlásit se</a><br> | ||||
| <a href="{% url 'seminar_resitel_edit' %}">Upravit údaje</a><br> | ||||
| <a href="{% url 'seminar_nahraj_reseni' %}">Nahrát řešení</a><br> | ||||
| <a href="{% url 'seminar_resitel_odevzdana_reseni' %}">Již odevzdaná řešení</a><br> | ||||
| <a href="{% url 'personalni_resitel_edit' %}">Upravit údaje</a><br> | ||||
| <a href="{% url 'odevzdavatko_nahraj_reseni' %}">Nahrát řešení</a><br> | ||||
| <a href="{% url 'odevzdavatko_resitel_odevzdana_reseni' %}">Již odevzdaná řešení</a><br> | ||||
| 
 | ||||
| 
 | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ | |||
| <hr> | ||||
| <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"%} | ||||
|   <input type="submit" value="Změnit"> | ||||
| </form> | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
| 
 | ||||
| <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" %} | ||||
|   <h4> | ||||
|     GDPR | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ from django.contrib.auth.models import User, Group | |||
| from django.contrib.admin.sites import AdminSite | ||||
| 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? :-) | ||||
| import seminar.models as m | ||||
| import personalni.models as m | ||||
| 
 | ||||
| import logging | ||||
| logger = logging.getLogger(__name__) | ||||
|  |  | |||
|  | @ -7,15 +7,15 @@ urlpatterns = [ | |||
| 	path( | ||||
| 		'org/rozcestnik/', | ||||
| 		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( | ||||
| 		'resitel/osobni-udaje/', | ||||
| 		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 | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| import seminar.models as m | ||||
| from various.utils import bez_diakritiky_translate | ||||
| 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.db import transaction | ||||
| 
 | ||||
| import seminar.models as m | ||||
| import soustredeni.models | ||||
| 
 | ||||
| from odevzdavatko.models import Reseni_Resitele | ||||
| 
 | ||||
| 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 | ||||
| 	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) | ||||
| 	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í') | ||||
| 	ct = soustredeni.models.Konfery_Ucastnici.objects.filter(resitel=zdrojovy).update(resitel=cilovy) | ||||
| 	print(f' Přepojeno {ct} konfer') | ||||
|  |  | |||
|  | @ -16,8 +16,12 @@ from django.db import transaction | |||
| from django.http import HttpResponse | ||||
| 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 datetime import date | ||||
|  | @ -91,22 +95,22 @@ class OrgoRozcestnikView(TemplateView): | |||
| 
 | ||||
| 	def get_context_data(self, **kwargs): | ||||
| 		context = super().get_context_data(**kwargs) | ||||
| 		context['posledni_soustredeni'] = s.Soustredeni.objects.order_by('-datum_konce').first() | ||||
| 		nastaveni = s.Nastaveni.objects.first() | ||||
| 		context['posledni_soustredeni'] = Soustredeni.objects.order_by('-datum_konce').first() | ||||
| 		nastaveni = Nastaveni.objects.first() | ||||
| 		aktualni_rocnik = nastaveni.aktualni_rocnik | ||||
| 		context['posledni_cislo_url'] = nastaveni.aktualni_cislo.verejne_url() | ||||
| 		# 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 | ||||
| 		# přes treenody (a dát si přitom pozor na MezicisloNode) | ||||
| 
 | ||||
| 		neobodovana_reseni = s.Hodnoceni.objects.filter(body__isnull=True) | ||||
| 		reseni_mimo_cislo = s.Hodnoceni.objects.filter(deadline_body__isnull=True) | ||||
| 		neobodovana_reseni = Hodnoceni.objects.filter(body__isnull=True) | ||||
| 		reseni_mimo_cislo = Hodnoceni.objects.filter(deadline_body__isnull=True) | ||||
| 		context['pocet_neobodovanych_reseni'] = neobodovana_reseni.count() | ||||
| 		context['pocet_reseni_mimo_cislo'] = reseni_mimo_cislo.count() | ||||
| 
 | ||||
| 		u = self.request.user | ||||
| 		os = s.Osoba.objects.get(user=u) | ||||
| 		organizator = s.Organizator.objects.get(osoba=os) | ||||
| 		os = m.Osoba.objects.get(user=u) | ||||
| 		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_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()] | ||||
| 
 | ||||
| 		#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() | ||||
| 		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() | ||||
| 		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() | ||||
| 
 | ||||
| 		context['temata'] = temata | ||||
|  | @ -134,12 +138,12 @@ class OrgoRozcestnikView(TemplateView): | |||
| 
 | ||||
| 
 | ||||
| class ResitelView(LoginRequiredMixin,generic.DetailView): | ||||
| 	model = s.Resitel | ||||
| 	model = m.Resitel | ||||
| 	template_name = 'personalni/profil/resitel.html' | ||||
| 
 | ||||
| 	def get_object(self, queryset=None): | ||||
| 		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 | ||||
| 
 | ||||
|  | @ -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') | ||||
| 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 | ||||
| 	u = request.user | ||||
| 	osoba_edit = s.Osoba.objects.get(user=u) | ||||
| 	osoba_edit = m.Osoba.objects.get(user=u) | ||||
| 	if hasattr(osoba_edit,'resitel'): | ||||
| 		resitel_edit = osoba_edit.resitel | ||||
| 	else: | ||||
|  | @ -195,7 +199,7 @@ def resitelEditView(request): | |||
| 			## Změny v osobě | ||||
| 			fcd = form.cleaned_data | ||||
| 			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 | ||||
| 			osoba_edit.jmeno = fcd['jmeno'] | ||||
| 			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') | ||||
| def prihlaskaView(request): | ||||
| 	generic_logger = logging.getLogger('seminar.prihlaska') | ||||
| 	err_logger = logging.getLogger('seminar.prihlaska.problem') | ||||
| 	form_logger = logging.getLogger('seminar.prihlaska.form') | ||||
| 	generic_logger = logging.getLogger('personalni.prihlaska') | ||||
| 	err_logger = logging.getLogger('personalni.prihlaska.problem') | ||||
| 	form_logger = logging.getLogger('personalni.prihlaska.form') | ||||
| 	if request.method == 'POST': | ||||
| 		form = PrihlaskaForm(request.POST) | ||||
| 		# 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() | ||||
| 				u.groups.add(resitel_grp) | ||||
| 
 | ||||
| 				o = s.Osoba( | ||||
| 				o = m.Osoba( | ||||
| 					jmeno = fcd['jmeno'], | ||||
| 					prijmeni = fcd['prijmeni'], | ||||
| 					osloveni = fcd['osloveni'], | ||||
|  | @ -328,7 +332,7 @@ def prihlaskaView(request): | |||
| 				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]}') | ||||
| 
 | ||||
| 				r = s.Resitel( | ||||
| 				r = m.Resitel( | ||||
| 					prezdivka_resitele=fcd['prezdivka_resitele'] if fcd['prezdivka_resitele'] != "" else None, | ||||
| 					rok_maturity = fcd['rok_maturity'], | ||||
| 					zasilat = fcd['zasilat'], | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ from django.utils.safestring import mark_safe | |||
| from django.utils.html import escape | ||||
| 
 | ||||
| from .models import Prednaska, Seznam, STAV_NAVRH | ||||
| from seminar.models import Soustredeni | ||||
| from soustredeni.models import Soustredeni | ||||
| 
 | ||||
| 
 | ||||
| class Seznam_PrednaskaInline(admin.TabularInline): | ||||
|  |  | |||
|  | @ -6,7 +6,8 @@ from django.db.models import Sum | |||
| from django.forms import Form | ||||
| 
 | ||||
| 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): | ||||
| 	# 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, | ||||
| přehled orgů, aktuální (k aktuálnímu číslu) věci, titulka a jak řešit. | ||||
| 
 | ||||
| Také je tu generování testovacích (lokálních) dat. | ||||
| Zde bývalo vše. Teď tu zbývají migrace. | ||||
| A kód pro `import seminar.models as m` pro ./manage.py shell. | ||||
| """ | ||||
|  | @ -2,10 +2,11 @@ from __future__ import unicode_literals | |||
| 
 | ||||
| from django.db import models, migrations | ||||
| import django_countries.fields | ||||
| import seminar.models | ||||
| import django.utils.timezone | ||||
| from django.conf import settings | ||||
| 
 | ||||
| from odevzdavatko.models import generate_filename | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|  | @ -75,7 +76,7 @@ class Migration(migrations.Migration): | |||
|             fields=[ | ||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||
|                 ('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)), | ||||
|             ], | ||||
|             options={ | ||||
|  |  | |||
|  | @ -7,9 +7,12 @@ import django.db.models.deletion | |||
| import django.utils.timezone | ||||
| import django_countries.fields | ||||
| import imagekit.models.fields | ||||
| import seminar.models | ||||
| 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 django.db.models import Q | ||||
| from treenode.treelib import get_parent | ||||
|  | @ -962,7 +965,7 @@ class Migration(migrations.Migration): | |||
|             fields=[ | ||||
|                 ('id', models.AutoField(primary_key=True, serialize=False)), | ||||
|                 ('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')), | ||||
|                 ('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( | ||||
|             model_name='cislo', | ||||
|             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( | ||||
|             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')), | ||||
|                 ('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')), | ||||
|                 ('prezentace', models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=seminar.models.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')), | ||||
|                 ('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=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')), | ||||
|                 ('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( | ||||
|             model_name='konfera', | ||||
|             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( | ||||
|             model_name='konfera', | ||||
|             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( | ||||
|             model_name='konfera', | ||||
|  | @ -2648,12 +2651,12 @@ class Migration(migrations.Migration): | |||
|         migrations.AlterField( | ||||
|             model_name='cislo', | ||||
|             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( | ||||
|             model_name='cislo', | ||||
|             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( | ||||
|             model_name='treenode', | ||||
|  |  | |||
|  | @ -1,10 +1,6 @@ | |||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import django_countries.fields | ||||
| import seminar.models | ||||
| import django.utils.timezone | ||||
| from django.conf import settings | ||||
| from django.db import migrations | ||||
| 
 | ||||
| CREATE_VIEWS=""" | ||||
| create view seminar_body_za_cislo as | ||||
|  |  | |||
|  | @ -1,10 +1,6 @@ | |||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import django_countries.fields | ||||
| import seminar.models | ||||
| import django.utils.timezone | ||||
| from django.conf import settings | ||||
| from django.db import migrations | ||||
| 
 | ||||
| CREATE_VIEWS=""" | ||||
| drop view seminar_body_k_cislu; | ||||
|  |  | |||
|  | @ -1,10 +1,6 @@ | |||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import django_countries.fields | ||||
| import seminar.models | ||||
| import django.utils.timezone | ||||
| from django.conf import settings | ||||
| from django.db import migrations | ||||
| 
 | ||||
| CREATE_VIEWS=""" | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| import seminar.models | ||||
| from tvorba.models import cislo_pdf_filename | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|  | @ -14,7 +14,7 @@ class Migration(migrations.Migration): | |||
|         migrations.AddField( | ||||
|             model_name='cislo', | ||||
|             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, | ||||
|         ), | ||||
|     ] | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ from __future__ import unicode_literals | |||
| 
 | ||||
| from django.db import models, migrations | ||||
| import django_countries.fields | ||||
| import seminar.models | ||||
| 
 | ||||
| from tvorba.models import cislo_pdf_filename | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|  | @ -25,7 +26,7 @@ class Migration(migrations.Migration): | |||
|         migrations.AlterField( | ||||
|             model_name='cislo', | ||||
|             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, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ from __future__ import unicode_literals | |||
| 
 | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| import seminar.models | ||||
| 
 | ||||
| from soustredeni.models import generate_filename_konfera | ||||
| 
 | ||||
| 
 | ||||
| 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)), | ||||
|                 ('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)')])), | ||||
|                 ('prezentace', models.FileField(help_text='Prezentace nebo fotka posteru', upload_to=seminar.models.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')), | ||||
|                 ('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=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)), | ||||
|             ], | ||||
|             options={ | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ from __future__ import unicode_literals | |||
| 
 | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| import seminar.models | ||||
| from soustredeni.models import generate_filename_konfera | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|  | @ -15,12 +15,12 @@ class Migration(migrations.Migration): | |||
|         migrations.AlterField( | ||||
|             model_name='konfera', | ||||
|             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( | ||||
|             model_name='konfera', | ||||
|             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( | ||||
|             model_name='konfera', | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| # Generated by Django 2.2.9 on 2020-04-08 20:21 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| import seminar.models | ||||
| 
 | ||||
| from tvorba.models import cislo_pdf_filename | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|  | @ -19,6 +20,6 @@ class Migration(migrations.Migration): | |||
|         migrations.AlterField( | ||||
|             model_name='cislo', | ||||
|             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 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| import seminar.models | ||||
| from tvorba.models import cislo_png_filename | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|  | @ -14,6 +14,6 @@ class Migration(migrations.Migration): | |||
|         migrations.AlterField( | ||||
|             model_name='cislo', | ||||
|             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 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| import seminar.models.tvorba | ||||
| import various.models | ||||
| from tvorba.models import cislo_pdf_filename | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|  | @ -14,6 +15,6 @@ class Migration(migrations.Migration): | |||
|         migrations.AlterField( | ||||
|             model_name='cislo', | ||||
|             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 | ||||
| from django.utils import timezone | ||||
| 
 | ||||
| import seminar.models as m | ||||
| from tvorba.models import Deadline as mDeadline | ||||
| 
 | ||||
| 
 | ||||
| def vytvor_deadliny(apps, schema_editor): | ||||
|  | @ -16,7 +16,7 @@ def vytvor_deadliny(apps, schema_editor): | |||
|         if cislo.rocnik.rocnik < 26: | ||||
|             Deadline.objects.create( | ||||
|                 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)), | ||||
|                 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: | ||||
|             vytvor_deadline( | ||||
|                 date=cislo.datum_deadline_soustredeni, | ||||
|                 typ=m.Deadline.TYP_PRVNI_A_SOUS | ||||
|                 typ=mDeadline.TYP_PRVNI_A_SOUS | ||||
|             ) | ||||
|         else: | ||||
|             if cislo.datum_deadline_soustredeni: | ||||
|                 vytvor_deadline( | ||||
|                     date=cislo.datum_deadline_soustredeni, | ||||
|                     typ=m.Deadline.TYP_SOUS | ||||
|                     typ=mDeadline.TYP_SOUS | ||||
|                 ) | ||||
|             if cislo.datum_preddeadline: | ||||
|                 vytvor_deadline( | ||||
|                     date=cislo.datum_preddeadline, | ||||
|                     typ=m.Deadline.TYP_PRVNI | ||||
|                     typ=mDeadline.TYP_PRVNI | ||||
|                 ) | ||||
| 
 | ||||
|         if cislo.datum_deadline: | ||||
|             vytvor_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 | ||||
| 
 | ||||
| from django.db import migrations | ||||
| from seminar.models import Deadline | ||||
| from tvorba.models import Deadline | ||||
| 
 | ||||
| 
 | ||||
| def vrat_deadliny(apps, schema_editor): | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| # Generated by Django 3.2.15 on 2022-10-09 11:04 | ||||
| 
 | ||||
| from django.db import migrations | ||||
| from seminar.models import Deadline | ||||
| from tvorba.models import Deadline | ||||
| 
 | ||||
| 
 | ||||
| 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 seminar.models.base import SeminarModelBase | ||||
| import tvorba.models as am | ||||
| from various.models import SeminarModelBase | ||||
| from tvorba.models import Rocnik, Problem, aux_generate_filename | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
|  | @ -27,7 +27,7 @@ class Soustredeni(SeminarModelBase): | |||
| 	# Interní ID | ||||
| 	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) | ||||
| 
 | ||||
| 	datum_zacatku = models.DateField('datum začátku', blank=True, null=True, | ||||
|  | @ -75,7 +75,7 @@ class Soustredeni(SeminarModelBase): | |||
| 
 | ||||
| 	def verejne_url(self): | ||||
| 		#return reverse('seminar_soustredeni', kwargs={'pk': self.id}) | ||||
| 		return reverse('seminar_seznam_soustredeni') | ||||
| 		return reverse('soustredeni_seznam') | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicates=True) | ||||
|  | @ -143,13 +143,13 @@ class Soustredeni_Organizatori(SeminarModelBase): | |||
| def generate_filename_konfera(self, filename): | ||||
| 	return os.path.join( | ||||
| 		settings.SEMINAR_KONFERY_DIR, | ||||
| 		am.aux_generate_filename(self, filename) | ||||
| 		aux_generate_filename(self, filename) | ||||
| 	) | ||||
| 
 | ||||
| ## | ||||
| 
 | ||||
| @reversion.register(ignore_duplicates=True) | ||||
| class Konfera(am.Problem): | ||||
| class Konfera(Problem): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_konfera' | ||||
| 		verbose_name = 'Konfera' | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ | |||
|         <div class="mam-org-only"> | ||||
|           <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={%  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ů -  | ||||
|           <a href="../{{soustredeni.pk}}/seznam_ucastniku">HTML tabulka pro tisk</a>, | ||||
|           <a href="../{{soustredeni.pk}}/export_ucastniku">CSV</a>, | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ from typing import Sequence | |||
| import lorem | ||||
| 
 | ||||
| from .models import Soustredeni, Konfera | ||||
| import seminar.models as am # tvorba | ||||
| from tvorba.models import Rocnik | ||||
| import personalni.models as pm | ||||
| 
 | ||||
| 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?) | ||||
| 		datum_zacatku = datetime.date(rnd.randint(2000, 2020), rnd.randint(1, 12), rnd.randint(1, 28)) | ||||
| 		working_sous = Soustredeni.objects.create( | ||||
| 			rocnik=am.Rocnik.objects.order_by('?').first(), | ||||
| 			rocnik=Rocnik.objects.order_by('?').first(), | ||||
| 			verejne_db=rnd.choice([True, False]), | ||||
| 			misto=rnd.choice(['Kremrolovice', 'Indiánov', 'U zmzliny', 'Vafláreň', 'Větrník', 'Horní Rakvička', 'Dolní cheesecake']), | ||||
| 			typ=rnd.choice(['jarni', 'podzimni', 'vikend']), | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ urlpatterns = [ | |||
| 	path( | ||||
| 		'probehlo/', | ||||
| 		views.SoustredeniListView.as_view(), | ||||
| 		name='seminar_seznam_soustredeni' | ||||
| 		name='soustredeni_seznam' | ||||
| 	), | ||||
| 	path( | ||||
| 		'<int:soustredeni>/', | ||||
|  | @ -37,12 +37,12 @@ urlpatterns = [ | |||
| 				path( | ||||
| 					'obalky.pdf', | ||||
| 					org_required(views.soustredeniObalkyView), | ||||
| 					name='seminar_soustredeni_obalky' | ||||
| 					name='soustredeni_obalky' | ||||
| 				), | ||||
| 				path( | ||||
| 					'abstrakty', | ||||
| 					org_required(views.SoustredeniAbstraktyView.as_view()), | ||||
| 					name='seminar_soustredeni_abstrakty' | ||||
| 					name='soustredeni_abstrakty' | ||||
| 				), | ||||
| 				path( | ||||
| 					'fotogalerie/', | ||||
|  |  | |||
|  | @ -4,25 +4,27 @@ from django.forms import widgets | |||
| 
 | ||||
| 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 | ||||
| # TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html | ||||
| 
 | ||||
| @admin.register(m.TreeNode) | ||||
| @admin.register(TreeNode) | ||||
| class TreeNodeAdmin(PolymorphicParentModelAdmin): | ||||
| 	base_model = m.TreeNode | ||||
| 	base_model = TreeNode | ||||
| 	child_models = [ | ||||
| 		m.RocnikNode, | ||||
| 		m.CisloNode, | ||||
| 		m.MezicisloNode, | ||||
| 		m.TemaVCisleNode, | ||||
| 		m.UlohaZadaniNode, | ||||
| 		m.PohadkaNode, | ||||
| 		m.UlohaVzorakNode, | ||||
| 		m.TextNode, | ||||
| 		m.CastNode, | ||||
| 		m.OrgTextNode, | ||||
| 		RocnikNode, | ||||
| 		CisloNode, | ||||
| 		MezicisloNode, | ||||
| 		TemaVCisleNode, | ||||
| 		UlohaZadaniNode, | ||||
| 		PohadkaNode, | ||||
| 		UlohaVzorakNode, | ||||
| 		TextNode, | ||||
| 		CastNode, | ||||
| 		OrgTextNode, | ||||
| 		ReseniNode, | ||||
| 	] | ||||
| 
 | ||||
| 	actions = ['aktualizuj_nazvy'] | ||||
|  | @ -36,64 +38,68 @@ class TreeNodeAdmin(PolymorphicParentModelAdmin): | |||
| 		self.message_user(request, "Názvy aktualizovány.") | ||||
| 	aktualizuj_nazvy.short_description = "Aktualizuj vybraným TreeNodům názvy" | ||||
| 
 | ||||
| @admin.register(m.RocnikNode) | ||||
| @admin.register(RocnikNode) | ||||
| class RocnikNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.RocnikNode | ||||
| 	base_model = RocnikNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.CisloNode) | ||||
| @admin.register(CisloNode) | ||||
| class CisloNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.CisloNode | ||||
| 	base_model = CisloNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.MezicisloNode) | ||||
| @admin.register(MezicisloNode) | ||||
| class MezicisloNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.MezicisloNode | ||||
| 	base_model = MezicisloNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.TemaVCisleNode) | ||||
| @admin.register(TemaVCisleNode) | ||||
| class TemaVCisleNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.TemaVCisleNode | ||||
| 	base_model = TemaVCisleNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.UlohaZadaniNode) | ||||
| @admin.register(UlohaZadaniNode) | ||||
| class UlohaZadaniNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.UlohaZadaniNode | ||||
| 	base_model = UlohaZadaniNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.PohadkaNode) | ||||
| @admin.register(PohadkaNode) | ||||
| class PohadkaNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.PohadkaNode | ||||
| 	base_model = PohadkaNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.UlohaVzorakNode) | ||||
| @admin.register(UlohaVzorakNode) | ||||
| class UlohaVzorakNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.UlohaVzorakNode | ||||
| 	base_model = UlohaVzorakNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.TextNode) | ||||
| @admin.register(TextNode) | ||||
| class TextNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.TextNode | ||||
| 	base_model = TextNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(m.CastNode) | ||||
| @admin.register(CastNode) | ||||
| class TextNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.CastNode | ||||
| 	base_model = CastNode | ||||
| 	show_in_index = True | ||||
| 	fields = ('nadpis',) | ||||
| 
 | ||||
| @admin.register(m.OrgTextNode) | ||||
| @admin.register(OrgTextNode) | ||||
| class TextNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.OrgTextNode | ||||
| 	base_model = OrgTextNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| @admin.register(ReseniNode) | ||||
| class ReseniNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = ReseniNode | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| class TextAdminInline(admin.TabularInline): | ||||
| 	model = m.Text | ||||
| 	model = Text | ||||
| 	formfield_overrides = { | ||||
| 		models.TextField: {'widget': widgets.TextInput} | ||||
| 	} | ||||
| 	exclude = ['text_zkraceny_set', 'text_zkraceny'] | ||||
| 
 | ||||
| admin.site.register(m.Text) | ||||
| admin.site.register(m.Obrazek) | ||||
| admin.site.register(Text) | ||||
| admin.site.register(Obrazek) | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| 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 | ||||
| # - mít v modelu tu položku, kterou chci upravovat | ||||
|  | @ -10,5 +10,5 @@ import seminar.models as m | |||
| 
 | ||||
| class NahrajObrazekKTreeNoduForm(forms.ModelForm): | ||||
| 	class Meta: | ||||
| 		model = m.Obrazek | ||||
| 		model = Obrazek | ||||
| 		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 seminar.models import SeminarModelBase | ||||
| from various.models import SeminarModelBase | ||||
| 
 | ||||
| from personalni.models import Organizator | ||||
| from odevzdavatko.models import Reseni | ||||
|  | @ -347,4 +347,3 @@ class Obrazek(SeminarModelBase): | |||
| 
 | ||||
| 	# TODO placement hint - chci ho tady / pred textem / za textem | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,11 @@ | |||
| from rest_framework import serializers | ||||
| 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 | ||||
| 
 | ||||
| DEFAULT_NODE_DEPTH = 2 | ||||
|  | @ -9,57 +13,57 @@ DEFAULT_NODE_DEPTH = 2 | |||
| 
 | ||||
| class TextSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.Text | ||||
| 		model = Text | ||||
| 		fields = '__all__' | ||||
| 
 | ||||
| class ProblemSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.Problem | ||||
| 		model = Problem | ||||
| 		fields = '__all__' | ||||
| 
 | ||||
| class UlohaSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.Uloha | ||||
| 		model = Uloha | ||||
| 		fields = '__all__' | ||||
| 
 | ||||
| class ReseniSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.Reseni | ||||
| 		model = Reseni | ||||
| 		fields = '__all__' | ||||
| 	 | ||||
| class RocnikNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.RocnikNode | ||||
| 		model = RocnikNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class CisloNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.CisloNode | ||||
| 		model = CisloNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class MezicisloNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.MezicisloNode | ||||
| 		model = MezicisloNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class TemaVCisleNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.TemaVCisleNode | ||||
| 		model = TemaVCisleNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class OrgTextNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.OrgTextNode | ||||
| 		model = OrgTextNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class PohadkaNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.PohadkaNode | ||||
| 		model = PohadkaNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -67,7 +71,7 @@ class TextNodeSerializer(serializers.ModelSerializer): | |||
| 	text = TextSerializer() | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.TextNode | ||||
| 		model = TextNode | ||||
| 		fields = ('id','text','polymorphic_ctype') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -80,7 +84,7 @@ class TextNodeWriteSerializer(serializers.ModelSerializer): | |||
| 		return node | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.TextNode | ||||
| 		model = TextNode | ||||
| 		fields = ('id','text') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -93,26 +97,26 @@ class TextNodeCreateSerializer(serializers.ModelSerializer): | |||
| 		temp_text = validated_data.pop('text') | ||||
| 		where = validated_data.pop('where') | ||||
| 		refnode_id = validated_data.pop('refnode') | ||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | ||||
| 		text = m.Text.objects.create(**temp_text) | ||||
| 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||
| 		text = Text.objects.create(**temp_text) | ||||
| 		if where == 'syn': | ||||
| 			node = treelib.create_child(refnode,m.TextNode,text=text) | ||||
| 			node = treelib.create_child(refnode,TextNode,text=text) | ||||
| 		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': | ||||
| 			node = treelib.create_node_before(refnode,m.TextNode,text=text) | ||||
| 			node = treelib.create_node_before(refnode,TextNode,text=text) | ||||
| 		node.where = None | ||||
| 		node.refnode = None | ||||
| 		return node | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.TextNode | ||||
| 		model = TextNode | ||||
| 		fields = ('text','where','refnode') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class CastNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.CastNode | ||||
| 		model = CastNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -124,25 +128,25 @@ class CastNodeCreateSerializer(serializers.ModelSerializer): | |||
| 		temp_nadpis = validated_data.pop('nadpis') | ||||
| 		where = validated_data.pop('where') | ||||
| 		refnode_id = validated_data.pop('refnode') | ||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | ||||
| 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||
| 		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': | ||||
| 			node = treelib.create_node_after(refnode,m.CastNode,nadpis=temp_nadpis) | ||||
| 			node = treelib.create_node_after(refnode,CastNode,nadpis=temp_nadpis) | ||||
| 		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.refnode = None | ||||
| 		return node | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.CastNode | ||||
| 		model = CastNode | ||||
| 		fields = ('nadpis','where','refnode') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class UlohaZadaniNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.UlohaZadaniNode | ||||
| 		model = UlohaZadaniNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -157,7 +161,7 @@ class UlohaZadaniNodeWriteSerializer(serializers.ModelSerializer): | |||
| 		return node | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.TextNode | ||||
| 		model = TextNode | ||||
| 		fields = ('id','uloha') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -171,28 +175,28 @@ class UlohaZadaniNodeCreateSerializer(serializers.ModelSerializer): | |||
| 		temp_uloha = validated_data.pop('uloha') | ||||
| 		where = validated_data.pop('where') | ||||
| 		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 | ||||
| 		cislo = None | ||||
| 		tema = None | ||||
| 		travelnode = refnode | ||||
| 		while travelnode is not None: | ||||
| 			if isinstance(travelnode, m.TemaVCisleNode): | ||||
| 			if isinstance(travelnode, TemaVCisleNode): | ||||
| 				tema = travelnode.tema | ||||
| 			if isinstance(travelnode, m.CisloNode): | ||||
| 			if isinstance(travelnode, CisloNode): | ||||
| 				cislo = travelnode.cislo | ||||
| 			travelnode = treelib.get_parent(travelnode) | ||||
| 		# 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 | ||||
| 		if where == 'syn': | ||||
| 			node = treelib.create_child(refnode,m.UlohaZadaniNode,uloha = uloha) | ||||
| 			node = treelib.create_child(refnode,UlohaZadaniNode,uloha = uloha) | ||||
| 		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': | ||||
| 			node = treelib.create_node_before(refnode,m.UlohaZadaniNode,uloha = uloha) | ||||
| 			node = treelib.create_node_before(refnode,UlohaZadaniNode,uloha = uloha) | ||||
| 		node.where = None | ||||
| 		node.refnode = None | ||||
| 		node.max_body = None | ||||
|  | @ -200,21 +204,21 @@ class UlohaZadaniNodeCreateSerializer(serializers.ModelSerializer): | |||
| 		return node | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.UlohaZadaniNode | ||||
| 		model = UlohaZadaniNode | ||||
| 		fields = ('uloha','where','refnode') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| class UlohaVzorakNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.UlohaVzorakNode | ||||
| 		model = UlohaVzorakNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 	 | ||||
| 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: | ||||
| 		model = m.UlohaVzorakNode | ||||
| 		model = UlohaVzorakNode | ||||
| 		fields = ('id','uloha') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 	 | ||||
|  | @ -226,17 +230,17 @@ class UlohaVzorakNodeCreateSerializer(serializers.ModelSerializer): | |||
| 
 | ||||
| 	def create(self, validated_data): | ||||
| 		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') | ||||
| 		refnode_id = validated_data.pop('refnode') | ||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | ||||
| 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||
| 
 | ||||
| 		if where == 'syn': | ||||
| 			node = treelib.create_child(refnode,m.UlohaVzorakNode,uloha = uloha) | ||||
| 			node = treelib.create_child(refnode,UlohaVzorakNode,uloha = uloha) | ||||
| 		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': | ||||
| 			node = treelib.create_node_before(refnode,m.UlohaVzorakNode,uloha = uloha) | ||||
| 			node = treelib.create_node_before(refnode,UlohaVzorakNode,uloha = uloha) | ||||
| 		node.refnode = None | ||||
| 		node.where = None | ||||
| 		node.uloha_id = None | ||||
|  | @ -244,7 +248,7 @@ class UlohaVzorakNodeCreateSerializer(serializers.ModelSerializer): | |||
| 		return node | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.UlohaVzorakNode | ||||
| 		model = UlohaVzorakNode | ||||
| 		fields = ('refnode', 'uloha_id', 'where') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -253,15 +257,15 @@ class UlohaVzorakNodeCreateSerializer(serializers.ModelSerializer): | |||
| 
 | ||||
| class ReseniNodeSerializer(serializers.ModelSerializer): | ||||
| 	class Meta: | ||||
| 		model = m.ReseniNode | ||||
| 		model = ReseniNode | ||||
| 		fields = '__all__' | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| 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: | ||||
| 		model = m.ReseniNode | ||||
| 		model = ReseniNode | ||||
| 		fields = ('id','reseni') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
|  | @ -273,41 +277,41 @@ class ReseniNodeCreateSerializer(serializers.ModelSerializer): | |||
| 	def create(self,validated_data): | ||||
| 		# text_zadani = validated_data.pop('text_zadani') | ||||
| 		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') | ||||
| 		refnode_id = validated_data.pop('refnode') | ||||
| 		refnode = m.TreeNode.objects.get(pk=refnode_id) | ||||
| 		refnode = TreeNode.objects.get(pk=refnode_id) | ||||
| 		 | ||||
| 		# A vyrobime UlohaZadaniNode | ||||
| 		if where == 'syn': | ||||
| 			node = treelib.create_child(refnode,m.ReseniNode,reseni = reseni) | ||||
| 			node = treelib.create_child(refnode,ReseniNode,reseni = reseni) | ||||
| 		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': | ||||
| 			node = treelib.create_node_before(refnode,m.ReseniNode,reseni = reseni) | ||||
| 			node = treelib.create_node_before(refnode,ReseniNode,reseni = reseni) | ||||
| 		node.where = None | ||||
| 		node.refnode = None | ||||
| 		node.reseni_id = None | ||||
| 		return node | ||||
| 
 | ||||
| 	class Meta: | ||||
| 		model = m.ReseniNode | ||||
| 		model = ReseniNode | ||||
| 		fields = ('reseni_id','where','refnode') | ||||
| 		depth = DEFAULT_NODE_DEPTH | ||||
| 
 | ||||
| 
 | ||||
| class TreeNodeSerializer(PolymorphicSerializer): | ||||
| 	model_serializer_mapping = { | ||||
| 		m.RocnikNode: RocnikNodeSerializer, | ||||
| 		m.CisloNode: CisloNodeSerializer, | ||||
| 		m.MezicisloNode: MezicisloNodeSerializer, | ||||
| 		m.TemaVCisleNode: TemaVCisleNodeSerializer, | ||||
| 		m.OrgTextNode: OrgTextNodeSerializer, | ||||
| 		m.UlohaZadaniNode: UlohaZadaniNodeSerializer, | ||||
| 		m.UlohaVzorakNode: UlohaVzorakNodeSerializer, | ||||
| 		m.PohadkaNode: PohadkaNodeSerializer, | ||||
| 		m.TextNode: TextNodeSerializer, | ||||
| 		m.CastNode: CastNodeSerializer, | ||||
| 		m.ReseniNode: ReseniNodeSerializer, | ||||
| 		RocnikNode: RocnikNodeSerializer, | ||||
| 		CisloNode: CisloNodeSerializer, | ||||
| 		MezicisloNode: MezicisloNodeSerializer, | ||||
| 		TemaVCisleNode: TemaVCisleNodeSerializer, | ||||
| 		OrgTextNode: OrgTextNodeSerializer, | ||||
| 		UlohaZadaniNode: UlohaZadaniNodeSerializer, | ||||
| 		UlohaVzorakNode: UlohaVzorakNodeSerializer, | ||||
| 		PohadkaNode: PohadkaNodeSerializer, | ||||
| 		TextNode: TextNodeSerializer, | ||||
| 		CastNode: CastNodeSerializer, | ||||
| 		ReseniNode: ReseniNodeSerializer, | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,20 +25,20 @@ | |||
| 		<button>Zvyš úroveň nadpisu</button> - nejsou testovací data | ||||
| 	</div> | ||||
| {% endif %} | ||||
| {% include "seminar/treenode_name.html" %} | ||||
| {% include "treenode/treenode_name.html" %} | ||||
| {%if obj.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 %} | ||||
| 		 | ||||
| 			{# ----------- 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 -------- #} | ||||
| 			{% 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 %} | ||||
| 				{% 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 %} | ||||
| 			{# ----------- Prohazujeme sousedy ----------#} | ||||
| 			<div class="pink"> | ||||
|  | @ -50,6 +50,6 @@ | |||
| 	</div> | ||||
| {% else %} | ||||
| 	{# ----------- 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%} | ||||
| </div> | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| from django import template | ||||
| from enum import Enum | ||||
| import seminar.models as m | ||||
| from .models import RocnikNode, CisloNode, CastNode, TextNode, TemaVCisleNode, UlohaVzorakNode, UlohaZadaniNode, PohadkaNode | ||||
| 
 | ||||
| register = template.Library() | ||||
| 
 | ||||
|  | @ -11,8 +11,8 @@ def nodeType(value): | |||
| 	if isinstance(value,CastNode): return "Část" | ||||
| 	if isinstance(value,TextNode): return "Text" | ||||
| 	if isinstance(value,TemaVCisleNode): return "Téma v čísle" | ||||
| 	if isinstance(value,KonferaNode): return "Konfera" | ||||
| 	if isinstance(value,ClanekNode): return "Článek" | ||||
| 	# if isinstance(value,KonferaNode): return "Konfera" # FIXME neexistuje | ||||
| 	# if isinstance(value,ClanekNode): return "Článek" # FIXME neexistuje | ||||
| 	if isinstance(value,UlohaVzorakNode): return "Vzorák" | ||||
| 	if isinstance(value,UlohaZadaniNode): return "Zadání úlohy" | ||||
| 	if isinstance(value,PohadkaNode): return "Pohádka" | ||||
|  | @ -22,53 +22,57 @@ def nodeType(value): | |||
| 
 | ||||
| @register.filter | ||||
| def isRocnik(value): | ||||
| 	return isinstance(value, m.RocnikNode) | ||||
| 	return isinstance(value, RocnikNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isCislo(value): | ||||
| 	return isinstance(value, m.CisloNode) | ||||
| 	return isinstance(value, CisloNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isCast(value): | ||||
| 	return isinstance(value, m.CastNode) | ||||
| 	return isinstance(value, CastNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isText(value): | ||||
| 	return isinstance(value, m.TextNode) | ||||
| 	return isinstance(value, TextNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isTemaVCisle(value): | ||||
| 	return isinstance(value, m.TemaVCisleNode) | ||||
| 	return isinstance(value, TemaVCisleNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isKonfera(value): | ||||
| 	return isinstance(value, m.KonferaNode) | ||||
| 	# FIXME neexistuje | ||||
| 	# return isinstance(value, KonferaNode) | ||||
| 	return False | ||||
| 
 | ||||
| @register.filter | ||||
| def isClanek(value): | ||||
| 	return isinstance(value, m.ClanekNode) | ||||
| 	# FIXME neexistuje | ||||
| 	# return isinstance(value, ClanekNode) | ||||
| 	return False | ||||
| 
 | ||||
| @register.filter | ||||
| def isUlohaVzorak(value): | ||||
| 	return isinstance(value, m.UlohaVzorakNode) | ||||
| 	return isinstance(value, UlohaVzorakNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isUlohaZadani(value): | ||||
| 	return isinstance(value, m.UlohaZadaniNode) | ||||
| 	return isinstance(value, UlohaZadaniNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isPohadka(value): | ||||
| 	return isinstance(value, m.PohadkaNode) | ||||
| 	return isinstance(value, PohadkaNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isReseni(value): | ||||
| 	return False | ||||
| #	return isinstance(value, m.OtisteneReseniNode) | ||||
| #	return isinstance(value, OtisteneReseniNode) | ||||
| 
 | ||||
| @register.filter | ||||
| def isOrgText(value): | ||||
| 	return False | ||||
| #	return isinstance(value, m.OrgTextNode) | ||||
| #	return isinstance(value, OrgTextNode) | ||||
| 
 | ||||
| 
 | ||||
| ###  | ||||
|  |  | |||
|  | @ -1,16 +1,16 @@ | |||
| from django.test import TestCase | ||||
| import treenode.treelib as tl | ||||
| import seminar.models as m | ||||
| from .models import CastNode | ||||
| 
 | ||||
| class SimpleTreeLibTests(TestCase): | ||||
| 	def setUp(self): | ||||
| 		# 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.some_node = m.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.some_orphan = m.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.some_node = CastNode(root=self.root, first_child=None, succ=None, nadpis="Přetržené") | ||||
| 		self.other_node = CastNode(root=self.root, first_child=None, succ=None, nadpis="Dítě") | ||||
| 		self.some_orphan = CastNode(root=None, first_child=None, succ=None, nadpis="Ošklivé") | ||||
| 		self.other_orphan = CastNode(root=None, first_child=None, succ=None, nadpis="Káčátko") | ||||
| 		 | ||||
| 		# Trochu je pospojujeme | ||||
| 		self.root.first_child = self.some_node | ||||
|  |  | |||
|  | @ -238,7 +238,7 @@ class TreeLibError(RuntimeError): | |||
| 
 | ||||
| # Editace stromu: | ||||
| def create_node_after(predecessor, type, **kwargs): | ||||
| 	from seminar.models import TreeNode | ||||
| 	from .models import TreeNode | ||||
| 	if predecessor is None: | ||||
| 		raise TreeLibError("Nelze vyrábět sirotky! (predecessor=None)") | ||||
| 	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) | ||||
| def create_child(parent, type, **kwargs): | ||||
| 	from seminar.models import TreeNode | ||||
| 	from .models import TreeNode | ||||
| 	if parent is None: | ||||
| 		raise TreeLibError("Nelze vyrábět sirotky! (parent=None)") | ||||
| 	if not issubclass(type, TreeNode): | ||||
|  | @ -293,7 +293,7 @@ def insert_last_child(parent, node): | |||
| 		last.save() | ||||
| 
 | ||||
| def create_node_before(successor, type, **kwargs): | ||||
| 	from seminar.models import TreeNode | ||||
| 	from .models import TreeNode | ||||
| 	if successor is None: | ||||
| 		raise TreeLibError("Nelze vyrábět sirotky! (successor=None)") | ||||
| 	if not issubclass(type, TreeNode): | ||||
|  |  | |||
|  | @ -2,16 +2,16 @@ from django.urls import path, re_path | |||
| from . import views | ||||
| 
 | ||||
| urlpatterns = [ | ||||
| 	#path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='seminar_treenode'), | ||||
| 	#path('treenode/<int:pk>/json/', views.TreeNodeJSONView.as_view(), name='seminar_treenode_json'), | ||||
| 	#path('treenode/text/<int:pk>/', views.TextWebView.as_view(), name='seminar_textnode_web'), | ||||
| 	#path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='treenode'), | ||||
| 	#path('treenode/<int:pk>/json/', views.TreeNodeJSONView.as_view(), name='treenode_json'), | ||||
| 	#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/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/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/sirotcinec/', views.SirotcinecView.as_view(), name='seminar_treenode_sirotcinec'), | ||||
| 	#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), | ||||
| 	#path('treenode/sirotcinec/', views.SirotcinecView.as_view(), name='treenode_sirotcinec'), | ||||
| 	#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'), | ||||
| 	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.core.exceptions import PermissionDenied | ||||
| 
 | ||||
| import seminar.models as s | ||||
| import seminar.models as m | ||||
| from .models import TemaVCisleNode, RocnikNode, CisloNode, UlohaVzorakNode, UlohaZadaniNode, TreeNode, CastNode, TextNode, ReseniNode, PohadkaNode, OrgTextNode | ||||
| from .models import Text, Obrazek | ||||
| from treenode import treelib | ||||
| import treenode.forms as f | ||||
| import treenode.templatetags as tnltt | ||||
|  | @ -29,7 +29,7 @@ class TNLData(object): | |||
| 
 | ||||
| 		if parent: | ||||
| 			self.tema_in_path = parent.tema_in_path | ||||
| 		if isinstance(anode, m.TemaVCisleNode): | ||||
| 		if isinstance(anode, TemaVCisleNode): | ||||
| 			self.tema_in_path = True | ||||
| 
 | ||||
| 	def add_edit_options(self): | ||||
|  | @ -51,11 +51,11 @@ class TNLData(object): | |||
| 		(All of them have method verejne.)""" | ||||
| 		parent = anode # chceme začít už od konkrétního node včetně | ||||
| 		while True: | ||||
| 			rocnik = isinstance(parent, s.RocnikNode) | ||||
| 			cislo = isinstance(parent, s.CisloNode) | ||||
| 			uloha = (isinstance(parent, s.UlohaVzorakNode) or | ||||
| 				isinstance(parent, s.UlohaZadaniNode)) | ||||
| 			tema = isinstance(parent, s.TemaVCisleNode) | ||||
| 			rocnik = isinstance(parent, RocnikNode) | ||||
| 			cislo = isinstance(parent, CisloNode) | ||||
| 			uloha = (isinstance(parent, UlohaVzorakNode) or | ||||
| 				isinstance(parent, UlohaZadaniNode)) | ||||
| 			tema = isinstance(parent, TemaVCisleNode) | ||||
| 
 | ||||
| 			if (rocnik or cislo or uloha or tema) or parent==None: | ||||
| 				break | ||||
|  | @ -158,7 +158,7 @@ class TNLData(object): | |||
| 
 | ||||
| 
 | ||||
| class TreeNodeView(generic.DetailView): | ||||
| 	model = s.TreeNode | ||||
| 	model = TreeNode | ||||
| 	template_name = 'treenode/treenode.html' | ||||
| 
 | ||||
| 	def get_context_data(self,**kwargs): | ||||
|  | @ -168,7 +168,7 @@ class TreeNodeView(generic.DetailView): | |||
| 
 | ||||
| 
 | ||||
| class TreeNodeJSONView(generic.DetailView): | ||||
| 	model = s.TreeNode | ||||
| 	model = TreeNode | ||||
| 
 | ||||
| 	def get(self,request,*args, **kwargs): | ||||
| 		self.object = self.get_object() | ||||
|  | @ -178,21 +178,21 @@ class TreeNodeJSONView(generic.DetailView): | |||
| 
 | ||||
| class TreeNodePridatView(generic.View): | ||||
| 	type_from_str = { | ||||
| 		'rocnikNode': m.RocnikNode, | ||||
| 		'cisloNode': m.CisloNode, | ||||
| 		'castNode': m.CastNode, | ||||
| 		'textNode': m.TextNode, | ||||
| 		'temaVCisleNode': m.TemaVCisleNode, | ||||
| 		'reseniNode': m.ReseniNode, | ||||
| 		'ulohaZadaniNode': m.UlohaZadaniNode, | ||||
| 		'ulohaVzorakNode': m.UlohaVzorakNode, | ||||
| 		'pohadkaNode': m.PohadkaNode, | ||||
| 		'orgText': m.OrgTextNode, | ||||
| 		'rocnikNode': RocnikNode, | ||||
| 		'cisloNode': CisloNode, | ||||
| 		'castNode': CastNode, | ||||
| 		'textNode': TextNode, | ||||
| 		'temaVCisleNode': TemaVCisleNode, | ||||
| 		'reseniNode': ReseniNode, | ||||
| 		'ulohaZadaniNode': UlohaZadaniNode, | ||||
| 		'ulohaVzorakNode': UlohaVzorakNode, | ||||
| 		'pohadkaNode': PohadkaNode, | ||||
| 		'orgText': OrgTextNode, | ||||
| 		} | ||||
| 
 | ||||
| 	def post(self, request, *args, **kwargs): | ||||
| 		######## 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'] | ||||
| 		co = self.kwargs['co'] | ||||
| 		typ = self.type_from_str[co] | ||||
|  | @ -202,19 +202,19 @@ class TreeNodePridatView(generic.View): | |||
| 		if kam not in ('pred','syn','za'): | ||||
| 			raise ValidationError('Přidat lze pouze před nebo za node nebo jako syna') | ||||
| 
 | ||||
| 		if co == m.TextNode: | ||||
| 			new_obj = m.Text() | ||||
| 		if co == TextNode: | ||||
| 			new_obj = Text() | ||||
| 			new_obj.save() | ||||
| 		elif co == m.CastNode: | ||||
| 			new_obj = m.CastNode() | ||||
| 		elif co == CastNode: | ||||
| 			new_obj = CastNode() | ||||
| 			new_obj.nadpis = request.POST.get('pridat-castNode-{}-{}'.format(node.id,kam)) | ||||
| 			new_obj.save() | ||||
| 		elif co == m.ReseniNode: | ||||
| 		elif co == ReseniNode: | ||||
| 			new_obj = m | ||||
| 			pass | ||||
| 		elif co == m.UlohaZadaniNode: | ||||
| 		elif co == UlohaZadaniNode: | ||||
| 			pass | ||||
| 		elif co == m.UlohaReseniNode: | ||||
| 		elif co == UlohaReseniNode: | ||||
| 			pass | ||||
| 		else: | ||||
| 			new_obj = None | ||||
|  | @ -225,15 +225,15 @@ class TreeNodePridatView(generic.View): | |||
| 
 | ||||
| 
 | ||||
| 		if kam == 'syn': | ||||
| 			if typ == m.TextNode: | ||||
| 				text_obj = m.Text() | ||||
| 			if typ == TextNode: | ||||
| 				text_obj = Text() | ||||
| 				text_obj.save() | ||||
| 				node = treelib.create_child(node, typ, text=text_obj) | ||||
| 			else: | ||||
| 				node = treelib.create_child(node, typ) | ||||
| 		if kam == 'za': | ||||
| 			if typ == m.TextNode: | ||||
| 				text_obj = m.Text() | ||||
| 			if typ == TextNode: | ||||
| 				text_obj = Text() | ||||
| 				text_obj.save() | ||||
| 				node = treelib.create_node_after(node, typ, text=text_obj) | ||||
| 			else: | ||||
|  | @ -244,7 +244,7 @@ class TreeNodePridatView(generic.View): | |||
| 
 | ||||
| class TreeNodeSmazatView(generic.base.View): | ||||
| 	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: | ||||
| 			raise NotImplementedError('Mazání TreeNode se syny není zatím podporováno!') | ||||
| 		treelib.disconnect_node(node) | ||||
|  | @ -254,7 +254,7 @@ class TreeNodeSmazatView(generic.base.View): | |||
| 
 | ||||
| class TreeNodeOdvesitPrycView(generic.base.View): | ||||
| 	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) | ||||
| 		node.root = None | ||||
| 		node.save() | ||||
|  | @ -263,7 +263,7 @@ class TreeNodeOdvesitPrycView(generic.base.View): | |||
| 
 | ||||
| class TreeNodePodvesitView(generic.base.View): | ||||
| 	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'] | ||||
| 		if kam == 'pred': | ||||
| 			treelib.lower_node(node) | ||||
|  | @ -274,21 +274,21 @@ class TreeNodePodvesitView(generic.base.View): | |||
| 
 | ||||
| class TreeNodeProhoditView(generic.base.View): | ||||
| 	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) | ||||
| 		return redirect(request.headers.get('referer')) | ||||
| 		#FIXME ve formulari predat puvodni url a vratit redirect na ni | ||||
| 
 | ||||
| class SirotcinecView(generic.ListView): | ||||
| 	model = s.TreeNode | ||||
| 	model = TreeNode | ||||
| 	template_name = 'treenode/orphanage.html' | ||||
| 
 | ||||
| 	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 | ||||
| class TextWebView(generic.DetailView): | ||||
| 	model = s.Text | ||||
| 	model = Text | ||||
| 
 | ||||
| 	def get(self,request,*args, **kwargs): | ||||
| 		self.object = self.get_object() | ||||
|  | @ -300,7 +300,7 @@ class VueTestView(generic.TemplateView): | |||
| 
 | ||||
| 
 | ||||
| class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView): | ||||
| 	model = s.Obrazek | ||||
| 	model = Obrazek | ||||
| 	form_class = f.NahrajObrazekKTreeNoduForm | ||||
| 
 | ||||
| 	def get_initial(self): | ||||
|  | @ -316,7 +316,7 @@ class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView): | |||
| 		print(form) | ||||
| 		self.object = form.save(commit=False) | ||||
| 		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() | ||||
| 
 | ||||
| 		return JsonResponse({"url":self.object.na_web.url}) | ||||
|  |  | |||
|  | @ -3,7 +3,12 @@ from rest_framework import status | |||
| from rest_framework.response import Response | ||||
| from django.core.exceptions import PermissionDenied | ||||
| 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 | ||||
| 
 | ||||
| from treenode.permissions import AllowWrite | ||||
|  | @ -66,17 +71,17 @@ class ReadWriteSerializerMixin(object): | |||
| 		return self.create_serializer_class | ||||
| 
 | ||||
| class TextViewSet(PermissionMixin, viewsets.ModelViewSet): | ||||
| 	queryset = m.Text.objects.all() | ||||
| 	queryset = Text.objects.all() | ||||
| 	serializer_class = views.TextSerializer | ||||
| 
 | ||||
| class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | ||||
| 	queryset = m.TextNode.objects.all() | ||||
| 	queryset = TextNode.objects.all() | ||||
| 	read_serializer_class = views.TextNodeSerializer | ||||
| 	write_serializer_class = views.TextNodeWriteSerializer | ||||
| 	create_serializer_class = views.TextNodeCreateSerializer | ||||
| 
 | ||||
| class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | ||||
| 	queryset = m.CastNode.objects.all() | ||||
| 	queryset = CastNode.objects.all() | ||||
| 	read_serializer_class = views.CastNodeSerializer | ||||
| 	write_serializer_class = views.CastNodeSerializer | ||||
| 	create_serializer_class = views.CastNodeCreateSerializer | ||||
|  | @ -95,7 +100,7 @@ class UlohaVzorakNodeViewSet(PermissionMixin, ReadWriteSerializerMixin, viewsets | |||
| 	create_serializer_class = views.UlohaVzorakNodeCreateSerializer | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		queryset = m.UlohaVzorakNode.objects.all() | ||||
| 		queryset = UlohaVzorakNode.objects.all() | ||||
| 		nazev = self.request.query_params.get('nazev',None) | ||||
| 		if nazev is not None: | ||||
| 			queryset = queryset.filter(nazev__contains=nazev) | ||||
|  | @ -114,7 +119,7 @@ class ReseniViewSet(viewsets.ModelViewSet): | |||
| 	serializer_class = views.ReseniSerializer | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		queryset = m.Reseni.objects.all() | ||||
| 		queryset = Reseni.objects.all() | ||||
| 		#FIXME upravit nazvy dle skutecnych polozek reseni | ||||
| 		nazev = self.request.query_params.get('nazev',None) | ||||
| 		if nazev is not None: | ||||
|  | @ -128,7 +133,7 @@ class UlohaViewSet(viewsets.ModelViewSet): | |||
| 	serializer_class = views.UlohaSerializer | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		queryset = m.Uloha.objects.all() | ||||
| 		queryset = Uloha.objects.all() | ||||
| 		nazev = self.request.query_params.get('nazev',None) | ||||
| 		if nazev is not None: | ||||
| 			queryset = queryset.filter(nazev__contains=nazev) | ||||
|  | @ -138,13 +143,13 @@ class UlohaViewSet(viewsets.ModelViewSet): | |||
| 		return queryset | ||||
| 
 | ||||
| class UlohaZadaniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet): | ||||
| 	queryset = m.UlohaZadaniNode.objects.all() | ||||
| 	queryset = UlohaZadaniNode.objects.all() | ||||
| 	read_serializer_class = views.UlohaZadaniNodeSerializer | ||||
| 	write_serializer_class = views.UlohaZadaniNodeWriteSerializer | ||||
| 	create_serializer_class = views.UlohaZadaniNodeCreateSerializer | ||||
| 
 | ||||
| class ReseniNodeViewSet(ReadWriteSerializerMixin, viewsets.ModelViewSet): | ||||
| 	queryset = m.ReseniNode.objects.all() | ||||
| 	queryset = ReseniNode.objects.all() | ||||
| 	read_serializer_class = views.ReseniNodeSerializer | ||||
| 	write_serializer_class = views.ReseniNodeWriteSerializer | ||||
| 	create_serializer_class = views.ReseniNodeCreateSerializer | ||||
|  | @ -155,7 +160,7 @@ class ProblemViewSet(viewsets.ModelViewSet): | |||
| 	serializer_class = views.ProblemSerializer | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		queryset = m.Problem.objects.all() | ||||
| 		queryset = Problem.objects.all() | ||||
| 		ucel = self.request.query_params.get('ucel',None) | ||||
| 		rocnik = self.request.query_params.get('rocnik',None) | ||||
| 		tema = self.request.query_params.get('tema',None) | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import datetime | |||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| import django.utils.timezone | ||||
| import seminar.models.tvorba | ||||
| import various.models | ||||
| import tvorba.models | ||||
| 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í')), | ||||
|                 ('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')), | ||||
|                 ('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')), | ||||
|                 ('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 seminar.models.base import SeminarModelBase | ||||
| from seminar.models.tvorba import OverwriteStorage | ||||
| from various.models import SeminarModelBase, OverwriteStorage | ||||
| from personalni.models import Prijemce, Organizator | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
|  | @ -96,7 +95,7 @@ class Rocnik(SeminarModelBase): | |||
| 		return self.prvni_rok + 1 | ||||
| 
 | ||||
| 	def verejne_url(self): | ||||
| 		return reverse('seminar_rocnik', kwargs={'rocnik': self.rocnik}) | ||||
| 		return reverse('tvorba_rocnik', kwargs={'rocnik': self.rocnik}) | ||||
| 
 | ||||
| 	@classmethod | ||||
| 	def cached_rocnik(cls, r_id): | ||||
|  | @ -171,7 +170,7 @@ class Cislo(SeminarModelBase): | |||
| 	verejne.boolean = True | ||||
| 
 | ||||
| 	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): | ||||
| 		return "https://" + str(get_current_site(None)) + self.verejne_url() | ||||
|  | @ -508,7 +507,7 @@ class Problem(SeminarModelBase,PolymorphicModel): | |||
| #	verejne.boolean = True | ||||
| 
 | ||||
| 	def verejne_url(self): | ||||
| 		return reverse('seminar_problem', kwargs={'pk': self.id}) | ||||
| 		return reverse('tvorba_problem', kwargs={'pk': self.id}) | ||||
| 
 | ||||
| 	def admin_url(self): | ||||
| 			return reverse('admin:tvorba_problem_change', args=(self.id, )) | ||||
|  |  | |||
|  | @ -35,12 +35,12 @@ | |||
|       <div class="mam-org-only"> | ||||
|         <h2> Orgovské odkazy </h2> | ||||
|         <ul> | ||||
|           <li><a href="obalky.pdf">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="vysledkovka.tex" 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><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 "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_cislo_obalky" rocnik=cislo.rocnik.rocnik cislo=cislo.poradi %}">Obálky (PDF)</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="{% 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>{% 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 "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 "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> | ||||
|       </div> | ||||
|   {% endif %} | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| {% extends "seminar/archiv/problem.html" %} | ||||
| {% extends "tvorba/archiv/problem.html" %} | ||||
| 
 | ||||
| {% block problem %} | ||||
|   {% if problem.cislo_zadani %} | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| {% extends "seminar/archiv/problem.html" %} | ||||
| {% extends "tvorba/archiv/problem.html" %} | ||||
| 
 | ||||
| {% block problem %} | ||||
|     <h1> | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| {% extends "seminar/archiv/problem.html" %} | ||||
| {% extends "tvorba/archiv/problem.html" %} | ||||
| 
 | ||||
| {% block problem %} | ||||
|     <h1> | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| {% extends "seminar/archiv/problem.html" %} | ||||
| {% extends "tvorba/archiv/problem.html" %} | ||||
| 
 | ||||
| {% block problem %} | ||||
|     <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="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šší… #} | ||||
|     <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> | ||||
|         {% include "vysledkovky/vysledkovka_rocnik.html" with vysledkovka=vysledkovka_neverejna %} | ||||
|     </div> | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| {% extends 'seminar/clanky/resitelske_clanky.html' %} | ||||
| {% extends 'tvorba/clanky/resitelske_clanky.html' %} | ||||
| 
 | ||||
| {% block nadpis1a %} | ||||
| Organizátorské články  | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ | |||
| 
 | ||||
|   <p> | ||||
|     Staré výsledkové listiny najdete | ||||
|     v <a href="{% url 'seminar_archiv_rocniky' %}">archivu</a>. | ||||
|     v <a href="{% url 'tvorba_archiv_rocniky' %}">archivu</a>. | ||||
|   </p> | ||||
| 
 | ||||
|   {% if user.je_org and vysledkovka_s_neverejnymi %} | ||||
|  |  | |||
|  | @ -1,30 +1,30 @@ | |||
| from django import template | ||||
| from django.utils.safestring import mark_safe | ||||
| register = template.Library() | ||||
| import seminar.models as m | ||||
| from tvorba.models import Deadline | ||||
| 
 | ||||
| @register.filter(name='deadline_kratseji') | ||||
| def deadline_kratsi_text(deadline: m.Deadline): | ||||
| def deadline_kratsi_text(deadline: Deadline): | ||||
| 	if deadline is None: | ||||
| 		return 'NONE' | ||||
| 	strings = { | ||||
| 		m.Deadline.TYP_PRVNI: f"{deadline.cislo} ⭯", | ||||
| 		m.Deadline.TYP_SOUS: f"{deadline.cislo} Ⓢ", | ||||
| 		m.Deadline.TYP_PRVNI_A_SOUS: f"{deadline.cislo} ⭯Ⓢ", | ||||
| 		m.Deadline.TYP_CISLA: f"{deadline.cislo} ✓", | ||||
| 		Deadline.TYP_PRVNI: f"{deadline.cislo} ⭯", | ||||
| 		Deadline.TYP_SOUS: f"{deadline.cislo} Ⓢ", | ||||
| 		Deadline.TYP_PRVNI_A_SOUS: f"{deadline.cislo} ⭯Ⓢ", | ||||
| 		Deadline.TYP_CISLA: f"{deadline.cislo} ✓", | ||||
| 		} | ||||
| 	return strings[deadline.typ] | ||||
| 
 | ||||
| @register.filter(name='deadline_html') | ||||
| def deadline_html(deadline: m.Deadline): | ||||
| def deadline_html(deadline: Deadline): | ||||
| 	if deadline is None: | ||||
| 		return 'Neznámý deadline' | ||||
| 	text = deadline_kratsi_text(deadline) | ||||
| 	classes = { | ||||
| 		m.Deadline.TYP_PRVNI: 'preddeadline', | ||||
| 		m.Deadline.TYP_SOUS: 'sous_deadline', | ||||
| 		m.Deadline.TYP_PRVNI_A_SOUS: 'sous_deadline', | ||||
| 		m.Deadline.TYP_CISLA: 'final_deadline', | ||||
| 		Deadline.TYP_PRVNI: 'preddeadline', | ||||
| 		Deadline.TYP_SOUS: 'sous_deadline', | ||||
| 		Deadline.TYP_PRVNI_A_SOUS: 'sous_deadline', | ||||
| 		Deadline.TYP_CISLA: 'final_deadline', | ||||
| 		} | ||||
| 	return mark_safe(f'<span class="{classes[deadline.typ]}" title="{deadline}">{text}</span>') | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,8 +6,12 @@ import lorem | |||
| import django.contrib.auth | ||||
| import logging | ||||
| 
 | ||||
| from seminar.models import Rocnik, Cislo, Deadline, Problem, Tema, Uloha, TextNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, Text, UlohaZadaniNode | ||||
| import seminar.models as m | ||||
| from .models import Rocnik, Cislo, Deadline, Problem, Tema, Uloha, Clanek | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
|  | @ -219,31 +223,31 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | |||
| 		insert_last_child(cislo_node, tema_cislo_node) | ||||
| 		 | ||||
| 		# 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) | ||||
| 	 | ||||
| 		text_node = TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||
| 		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) | ||||
| 		 | ||||
| 		text_node2 = TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||
| 		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) | ||||
| 
 | ||||
| 		text_node3 = TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||
| 		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)	 | ||||
| 
 | ||||
| 		text_node4 = TextNode.objects.create(text = get_text(), root=cislo_node.root) | ||||
| 		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) | ||||
| 		cast_node3.succ = cast_node3a | ||||
| 		cast_node3.save() | ||||
|  | @ -253,10 +257,10 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): | |||
| 
 | ||||
| 		# Občas přidáme mezičíslo | ||||
| 		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 | ||||
| 	 | ||||
| 			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) | ||||
| 			add_first_child(mezicislo_node, cast_node_mezicislo) | ||||
| 
 | ||||
|  | @ -438,7 +442,7 @@ def otec_syn(otec, syn): | |||
| 
 | ||||
| def gen_clanek(rnd, organizatori, resitele): | ||||
| 	logger.info("Generuji článek do čísla 22.2") | ||||
| 	clanek = m.Clanek.objects.create( | ||||
| 	clanek = Clanek.objects.create( | ||||
| 		nazev="Článek o Lorem ipsum", | ||||
| 		nadproblem=None, | ||||
| 		stav='vyreseny', | ||||
|  | @ -448,16 +452,16 @@ def gen_clanek(rnd, organizatori, resitele): | |||
| 		) | ||||
| 	clanek.save() | ||||
| 
 | ||||
| 	reseni = m.Reseni.objects.create( | ||||
| 	reseni = Reseni.objects.create( | ||||
| 		zverejneno=True, | ||||
| 		) | ||||
| 	reseni.resitele.add(rnd.choice(resitele)) | ||||
| 	reseni.save() | ||||
| 
 | ||||
| 	cislo = m.Cislo.objects.get(rocnik__rocnik=22, poradi=2) | ||||
| 	cislo = Cislo.objects.get(rocnik__rocnik=22, poradi=2) | ||||
| 	cislonode = cislo.cislonode | ||||
| 
 | ||||
| 	hodnoceni = m.Hodnoceni.objects.create( | ||||
| 	hodnoceni = Hodnoceni.objects.create( | ||||
| 		body=15.0, | ||||
| 		cislo_body=cislo, | ||||
| 		reseni=reseni, | ||||
|  | @ -465,7 +469,7 @@ def gen_clanek(rnd, organizatori, resitele): | |||
| 		) | ||||
| 	hodnoceni.save() | ||||
| 
 | ||||
| 	reseninode = m.ReseniNode.objects.create( | ||||
| 	reseninode = ReseniNode.objects.create( | ||||
| 		reseni=reseni | ||||
| 		) | ||||
| 	reseninode.save() | ||||
|  | @ -481,26 +485,26 @@ def gen_clanek(rnd, organizatori, resitele): | |||
| 	# 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 | ||||
| 	# (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í... | ||||
| 	castnode = reseninode.first_child | ||||
| 	 | ||||
| 	# Úvodní odstaveček | ||||
| 	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, | ||||
| 		do_cisla=obsah, | ||||
| 		) | ||||
| 	text.save() | ||||
| 	create_child(reseninode, m.TextNode, text=text) | ||||
| 	create_child(reseninode, TextNode, text=text) | ||||
| 
 | ||||
| 	# Několik odstavců lorem ipsum | ||||
| 	for _ in range(rnd.randint(3, 7)): | ||||
| 		lipsum = lorem.paragraph() | ||||
| 		text = m.Text.objects.create( | ||||
| 		text = Text.objects.create( | ||||
| 			na_web=lipsum, | ||||
| 			do_cisla=lipsum, | ||||
| 			) | ||||
| 		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})") | ||||
|  |  | |||
|  | @ -7,19 +7,19 @@ urlpatterns = [ | |||
| #	path('<int:rocnik>/t<int:tematko>/', views.TematkoView), | ||||
| 
 | ||||
| 	# Archiv | ||||
| 	path('archiv/rocniky/', views.ArchivView.as_view(), name="seminar_archiv_rocniky"), | ||||
| 	path('archiv/temata/', views.ArchivTemataView.as_view(), name="seminar_archiv_temata"), | ||||
| 	path('archiv/rocniky/', views.ArchivView.as_view(), name="tvorba_archiv_rocniky"), | ||||
| 	path('archiv/temata/', views.ArchivTemataView.as_view(), name="tvorba_archiv_temata"), | ||||
| 
 | ||||
| 	path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'), | ||||
| 	path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'), | ||||
| 	path('problem/<int:pk>/', views.problemView, name='seminar_problem'), | ||||
| 	path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='tvorba_rocnik'), | ||||
| 	path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='tvorba_cislo'), | ||||
| 	path('problem/<int:pk>/', views.problemView, name='tvorba_problem'), | ||||
| 
 | ||||
| 	# Zadani | ||||
| #	path('aktualni/zadani/', views.AktualniZadaniView.as_view(), name='seminar_aktualni_zadani'), # Dočasně ad-hoc jednoduchá věc. | ||||
| 	path('aktualni/zadani/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), | ||||
| 	#path('aktualni/temata/', views.ZadaniTemataView, name='seminar_temata'), | ||||
| 	path('aktualni/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_aktualni_vysledky'), | ||||
| 	path('aktualni/rocnik/', views.AktualniRocnikRedirectView.as_view(), name='seminar_aktualni_rocnik'), | ||||
| #	path('aktualni/zadani/', views.AktualniZadaniView.as_view(), name='tvorba_aktualni_zadani'), # Dočasně ad-hoc jednoduchá věc. | ||||
| 	path('aktualni/zadani/', views.AktualniZadaniView, name='tvorba_aktualni_zadani'), | ||||
| 	#path('aktualni/temata/', views.ZadaniTemataView, name='tvorba_temata'), | ||||
| 	path('aktualni/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='tvorba_aktualni_vysledky'), | ||||
| 	path('aktualni/rocnik/', views.AktualniRocnikRedirectView.as_view(), name='tvorba_aktualni_rocnik'), | ||||
| 
 | ||||
| 	# Clanky | ||||
| 	path('archiv/clanky/', views.ClankyResitelView.as_view(), name='clanky_resitel'), | ||||
|  | @ -29,42 +29,42 @@ urlpatterns = [ | |||
| 	path( | ||||
| 		'rocnik/<int:rocnik>/vysledkovka.tex', | ||||
| 		org_required(views.RocnikVysledkovkaView.as_view()), | ||||
| 		name='seminar_rocnik_vysledkovka' | ||||
| 		name='tvorba_rocnik_vysledkovka' | ||||
| 	), | ||||
| 	path( | ||||
| 		'rocnik/<int:rocnik>/resitele.csv', | ||||
| 		org_required(views.resiteleRocnikuCsvExportView), | ||||
| 		name='seminar_rocnik_resitele_csv' | ||||
| 		name='tvorba_rocnik_resitele_csv' | ||||
| 	), | ||||
| 	path( | ||||
| 		'rocnik/<int:rocnik>/tituly.tex', | ||||
| 		org_required(views.TitulyViewRocnik), | ||||
| 		name='seminar_rocnik_titul' | ||||
| 		name='tvorba_rocnik_titul' | ||||
| 	), | ||||
| 	path( | ||||
| 		'rocnik/<int:rocnik>/posledni_vysledkovka.tex', | ||||
| 		org_required(views.PosledniCisloVysledkovkaView.as_view()), | ||||
| 		name='seminar_rocnik_posledni_vysledkovka' | ||||
| 		name='tvorba_rocnik_posledni_vysledkovka' | ||||
| 	), | ||||
| 	path( | ||||
| 		'cislo/<int:rocnik>.<str:cislo>/vysledkovka.tex', | ||||
| 		org_required(views.CisloVysledkovkaView.as_view()), | ||||
| 		name='seminar_cislo_vysledkovka' | ||||
| 		name='tvorba_cislo_vysledkovka' | ||||
| 	), | ||||
| 	path( | ||||
| 		'cislo/<int:rocnik>.<str:cislo>/obalky.pdf', | ||||
| 		org_required(views.cisloObalkyView), | ||||
| 		name='seminar_cislo_obalky' | ||||
| 		name='tvorba_cislo_obalky' | ||||
| 	), | ||||
| 	path( | ||||
| 		'cislo/<int:rocnik>.<str:cislo>/tituly.tex', | ||||
| 		org_required(views.TitulyView), | ||||
| 		name='seminar_cislo_titul' | ||||
| 		name='tvorba_cislo_titul' | ||||
| 	), | ||||
| 	path( | ||||
| 		'cislo/<int:trocnik>.<str:tcislo>/odmeny/<int:frocnik>.<str:fcislo>/', | ||||
| 		org_required(views.OdmenyView.as_view()), | ||||
| 		name="seminar_archiv_odmeny"), | ||||
| 		name="tvorba_archiv_odmeny"), | ||||
| 
 | ||||
| 	# Dočasné & neodladěné: | ||||
| 	path( | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ from django.core.exceptions import ObjectDoesNotExist | |||
| 
 | ||||
| import personalni.models | ||||
| 
 | ||||
| import seminar.models as m | ||||
| import tvorba.models as m | ||||
| 
 | ||||
| 
 | ||||
| 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.core.exceptions import PermissionDenied | ||||
| 
 | ||||
| import seminar.models as s | ||||
| import seminar.models as m | ||||
| from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, \ | ||||
| 	Resitel, Novinky, Tema, Clanek, \ | ||||
| 	Deadline  # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | ||||
| #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | ||||
| from personalni.models import Resitel | ||||
| from soustredeni.models import Konfera | ||||
| from tvorba.models import Problem, Cislo, Rocnik, Tema, Clanek, Deadline, Uloha | ||||
| from treenode.models import TemaVCisleNode, PohadkaNode | ||||
| from various.models import Nastaveni | ||||
| from treenode import treelib | ||||
| import treenode.templatetags as tnltt | ||||
| import treenode.serializers as vr | ||||
|  | @ -58,7 +57,7 @@ def get_problemy_k_tematu(tema): | |||
| 
 | ||||
| # FIXME: Pozor, níž je ještě jeden ProblemView! | ||||
| #class ProblemView(generic.DetailView): | ||||
| #	model = s.Problem | ||||
| #	model = Problem | ||||
| #	# Zkopírujeme template_name od TreeNodeView, protože jsme prakticky jen trošku upravený TreeNodeView | ||||
| #	template_name = TreeNodeView.template_name | ||||
| # | ||||
|  | @ -70,17 +69,17 @@ def get_problemy_k_tematu(tema): | |||
| #		if False: | ||||
| #			# Hezčí formátování zbytku :-P | ||||
| #			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 | ||||
| #			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 | ||||
| #			tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user) | ||||
| #			tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user) | ||||
| #			context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak]) | ||||
| #		elif isinstance(self.object, s.Tema): | ||||
| #		elif isinstance(self.object, Tema): | ||||
| #			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: | ||||
| #			raise ValueError("Obecný problém nejde zobrazit.") | ||||
| #		return context | ||||
|  | @ -115,7 +114,7 @@ def ZadaniTemataView(request): | |||
| 	nastaveni = get_object_or_404(Nastaveni) | ||||
| 	verejne = nastaveni.aktualni_cislo.verejne() | ||||
| 	akt_rocnik = nastaveni.aktualni_cislo.rocnik | ||||
| 	temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') | ||||
| 	temata = Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') | ||||
| 	return render(request, 'tvorba/tematka/rozcestnik.html', | ||||
| 				  { | ||||
| 					  'tematka': temata, | ||||
|  | @ -140,14 +139,14 @@ def ZadaniTemataView(request): | |||
| # | ||||
| # | ||||
| #def TematkoView(request, rocnik, tematko): | ||||
| #	nastaveni = s.Nastaveni.objects.first() | ||||
| #	rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik) | ||||
| #	tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) | ||||
| #	nastaveni = Nastaveni.objects.first() | ||||
| #	rocnik_object = Rocnik.objects.filter(rocnik=rocnik) | ||||
| #	tematko_object = Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) | ||||
| #	seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode) | ||||
| #	for node, depth in seznam: | ||||
| #		if node.isinstance(node, s.KonferaNode): | ||||
| #		if node.isinstance(node, KonferaNode): # FIXME neexistuje | ||||
| #			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 | ||||
| # | ||||
| #	return render(request, 'tvorba/tematka/toaletak.html', {}) | ||||
|  | @ -155,8 +154,8 @@ def ZadaniTemataView(request): | |||
| # | ||||
| #def TemataRozcestnikView(request): | ||||
| #	print("=============================================") | ||||
| #	nastaveni = s.Nastaveni.objects.first() | ||||
| #	tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) | ||||
| #	nastaveni = Nastaveni.objects.first() | ||||
| #	tematka_objects = Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) | ||||
| #	tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku | ||||
| #	for tematko_object in tematka_objects: | ||||
| #		print("AKTUALNI TEMATKO") | ||||
|  | @ -278,7 +277,7 @@ def resiteleRocnikuCsvExportView(request, rocnik): | |||
| 	assert request.method in ('GET', 'HEAD') | ||||
| 	return dataResiteluCsvResponse( | ||||
| 		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): | ||||
| #		# FIXME: Switch podle typu není hezký, ale nechtělo se mi to přepisovat celé. Správně by se tohle mělo řešit polymorfismem. | ||||
| #		spravne_templaty = { | ||||
| #				s.Uloha: "uloha", | ||||
| #				s.Tema: "tema", | ||||
| #				s.Konfera: "konfera", | ||||
| #				s.Clanek: "clanek", | ||||
| #				Uloha: "uloha", | ||||
| #				Tema: "tema", | ||||
| #				Konfera: "konfera", | ||||
| #				Clanek: "clanek", | ||||
| #				} | ||||
| #		context = super().get_context_data(**kwargs) | ||||
| #		return ['tvorba/archiv/problem_' + spravne_templaty[context['object'].__class__]  + '.html'] | ||||
|  | @ -340,10 +339,10 @@ class CisloView(generic.DetailView): | |||
| 		deadliny_s_vysledkovkami = [] | ||||
| 
 | ||||
| 		nadpisy = { | ||||
| 			m.Deadline.TYP_CISLA: "Výsledkovka", | ||||
| 			m.Deadline.TYP_PRVNI: "Výsledkovka do prvního deadlinu", | ||||
| 			m.Deadline.TYP_PRVNI_A_SOUS: "Výsledkovka do prvního deadlinu a deadlinu pro účast na soustředění", | ||||
| 			m.Deadline.TYP_SOUS: "Výsledkovka do deadlinu pro účast na soustředění", | ||||
| 			Deadline.TYP_CISLA: "Výsledkovka", | ||||
| 			Deadline.TYP_PRVNI: "Výsledkovka do prvního deadlinu", | ||||
| 			Deadline.TYP_PRVNI_A_SOUS: "Výsledkovka do prvního deadlinu a deadlinu pro účast na soustředění", | ||||
| 			Deadline.TYP_SOUS: "Výsledkovka do deadlinu pro účast na soustředění", | ||||
| 		} | ||||
| 
 | ||||
| 		for deadline in deadliny: | ||||
|  | @ -577,8 +576,8 @@ class ClankyResitelView(generic.ListView): | |||
| 
 | ||||
| class AktualniRocnikRedirectView(RedirectView): | ||||
| 	permanent=False | ||||
| 	pattern_name = 'seminar_rocnik' | ||||
| 	pattern_name = 'tvorba_rocnik' | ||||
| 
 | ||||
| 	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) | ||||
|  |  | |||
|  | @ -5,13 +5,13 @@ from django.db import transaction | |||
| from django.forms import Form, CharField, IntegerField | ||||
| 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 | ||||
| 
 | ||||
| def problemView(request, pk): | ||||
| 	# Pokud problém neexistuje, hodíme obyčejnou 404 | ||||
| 	# 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 | ||||
| 	template = 'universal.html' | ||||
| 	ctx = { | ||||
|  | @ -32,7 +32,7 @@ class HromadnePridaniForm(Form): | |||
| 
 | ||||
| 	def clean_tema(self): | ||||
| 		""" 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'], | ||||
| 				nadproblem=None).count() != 1: | ||||
| 			raise ValidationError("Špatný nebo nepřesně zadaný název témátka") | ||||
|  | @ -67,20 +67,20 @@ class HromadnePridaniView(FormView): | |||
| 		dil = cd["dil"] | ||||
| 		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(): | ||||
| 			pfx = f"{t.nazev}, díl {dil}, " | ||||
| 
 | ||||
| 			for k, b in enumerate(body, 1): | ||||
| 				u = m.Uloha.objects.create( | ||||
| 				u = Uloha.objects.create( | ||||
| 					nadproblem=t, | ||||
| 					nazev=pfx + f"{'úloha' if b > 0 else 'problém'} {k}", | ||||
| 					autor=t.autor, | ||||
| 					garant=t.garant, | ||||
| 					max_body=b, | ||||
| 					cislo_zadani=m.Cislo.get(t.rocnik.rocnik, dil), | ||||
| 					cislo_zadani=Cislo.get(t.rocnik.rocnik, dil), | ||||
| 					kod=k, | ||||
| 					stav=m.Problem.STAV_ZADANY, | ||||
| 					stav=Problem.STAV_ZADANY, | ||||
| 				) | ||||
| 				u.opravovatele.set(t.opravovatele.all()) | ||||
| 		return super().form_valid(form) | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ | |||
|     Ješte nejsi zaregistrován? | ||||
| </h2> | ||||
| 
 | ||||
| <form action="{% url 'seminar_prihlaska' %}"> | ||||
| <form action="{% url 'personalni_prihlaska' %}"> | ||||
|     <input type="submit" value="Registrovat" /> | ||||
| </form> | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,5 +55,4 @@ class PasswordResetCompleteView(auth_views.PasswordResetCompleteView): | |||
| 
 | ||||
| 
 | ||||
| class PasswordChangeView(auth_views.PasswordChangeView): | ||||
| 	# template_name = 'seminar/password_change.html' | ||||
| 	success_url = reverse_lazy('titulni_strana') | ||||
|  |  | |||
|  | @ -12,8 +12,8 @@ class StripSensitiveFormDataFilter(Filter): | |||
| 		if hasattr(record, 'request') and record.request.path in [ | ||||
| 				reverse('login'), | ||||
| 				reverse('logout'), | ||||
| 				reverse('seminar_prihlaska'), | ||||
| 				reverse('seminar_resitel_edit'), | ||||
| 				reverse('personalni_prihlaska'), | ||||
| 				reverse('personalni_resitel_edit'), | ||||
| 				reverse('reset_password'), | ||||
| 				reverse('reset_password_done'), | ||||
| 				# FIXME | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| from django.core.management.base import BaseCommand | ||||
| 
 | ||||
| from seminar.models import Cislo | ||||
| from tvorba.models import Cislo | ||||
| 
 | ||||
| from subprocess import CalledProcessError | ||||
| import logging | ||||
|  |  | |||
|  | @ -1,11 +1,11 @@ | |||
| from django.core.management.base import BaseCommand | ||||
| import seminar.models as m | ||||
| from tvorba.models import Deadline | ||||
| 
 | ||||
| 
 | ||||
| class Command(BaseCommand): | ||||
| 	help = "Všem deadlinům se zveřejněnou výsledkovkou vygeneruj výsledkovku" | ||||
| 
 | ||||
| 	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() | ||||
| 		 | ||||
|  |  | |||
|  | @ -4,7 +4,9 @@ from django.core.management.base import BaseCommand | |||
| from django.core.management import call_command | ||||
| 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 | ||||
| import django.contrib.auth | ||||
| User = django.contrib.auth.get_user_model() | ||||
|  |  | |||
|  | @ -1,11 +1,12 @@ | |||
| import os | ||||
| 
 | ||||
| from django.db import models | ||||
| from django.core.files.storage import FileSystemStorage | ||||
| from django.urls import reverse | ||||
| 
 | ||||
| from reversion import revisions as reversion | ||||
| from solo.models import SingletonModel | ||||
| 
 | ||||
| from tvorba.models import Cislo | ||||
| 
 | ||||
| from django.urls import reverse | ||||
| 
 | ||||
| @reversion.register(ignore_duplicates=True) | ||||
| class Nastaveni(SingletonModel): | ||||
|  | @ -14,10 +15,10 @@ class Nastaveni(SingletonModel): | |||
| 		db_table = 'seminar_nastaveni' | ||||
| 		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) | ||||
| 
 | ||||
| 	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, | ||||
| 		) | ||||
| 
 | ||||
|  | @ -37,3 +38,28 @@ class Nastaveni(SingletonModel): | |||
| 	 | ||||
| 	def verejne(self): | ||||
| 		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. | ||||
|     Za dočasnou nedostupnost se omlouváme. | ||||
|     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> | ||||
|   <img src="{% static '404.png' %}"> | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -7,7 +7,9 @@ from django.contrib.flatpages.models import FlatPage | |||
| from django.contrib.sites.models import Site | ||||
| 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 novinky.testutils import gen_novinky | ||||
|  |  | |||
|  | @ -14,8 +14,10 @@ from django.views import generic | |||
| import novinky.views | ||||
| import treenode.treelib as t | ||||
| 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 | ||||
| 
 | ||||
|  | @ -30,7 +32,7 @@ class TitulniStranaView(generic.ListView): | |||
| 		context = super(TitulniStranaView, self).get_context_data(**kwargs) | ||||
| 		nastaveni = get_object_or_404(Nastaveni) | ||||
| 
 | ||||
| 		deadline = m.Deadline.objects.filter( | ||||
| 		deadline = Deadline.objects.filter( | ||||
| 			deadline__gte=timezone.now()).order_by("deadline").first() | ||||
| 		context['nejblizsi_deadline'] = deadline | ||||
| 
 | ||||
|  | @ -93,31 +95,31 @@ def seznam_problemu(): | |||
| 
 | ||||
| 	# Duplicita jmen | ||||
| 	jmena = {} | ||||
| 	for r in m.Resitel.objects.all(): | ||||
| 	for r in Resitel.objects.all(): | ||||
| 		j = r.osoba.plne_jmeno() | ||||
| 		if j not in jmena: | ||||
| 			jmena[j] = [] | ||||
| 		jmena[j].append(r) | ||||
| 	for j in jmena: | ||||
| 		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í | ||||
| 	for r in m.Resitel.objects.all(): | ||||
| 	for r in Resitel.objects.all(): | ||||
| 		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): | ||||
| 			prb(m.Resitel, 'Podezřelé datum maturity', [r]) | ||||
| 			prb(Resitel, 'Podezřelé datum maturity', [r]) | ||||
| 		if r.osoba.datum_narozeni and ( | ||||
| 				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: | ||||
| 	#			prb(Resitel, u'Neznámý email', [r]) | ||||
| 
 | ||||
| 	## Kontroly konzistence databáze a TreeNodů | ||||
| 
 | ||||
| 	# Č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ě | ||||
| 		reseni = clanek.reseni_set | ||||
| 		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 | ||||
| 		# protože isinstance vrátí vždy jen TreeNode | ||||
| 		# 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 | ||||
| 		while node is not None: | ||||
| 			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 | ||||
| 				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]) | ||||
| 				break | ||||
| 			node = t.get_parent(node) | ||||
|  | @ -146,8 +148,8 @@ def seznam_problemu(): | |||
| def StavDatabazeView(request): | ||||
| 	# nastaveni = Nastaveni.objects.get() | ||||
| 	problemy = seznam_problemu() | ||||
| 	muzi = Resitel.objects.filter(osoba__osloveni=m.Osoba.OSLOVENI_MUZSKE) | ||||
| 	zeny = Resitel.objects.filter(osoba__osloveni=m.Osoba.OSLOVENI_ZENSKE) | ||||
| 	muzi = Resitel.objects.filter(osoba__osloveni=Osoba.OSLOVENI_MUZSKE) | ||||
| 	zeny = Resitel.objects.filter(osoba__osloveni=Osoba.OSLOVENI_ZENSKE) | ||||
| 	return render(request, 'various/stav_databaze.html', { | ||||
| 		# 'nastaveni': nastaveni, | ||||
| 		'problemy': problemy, | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ def formularOKView(request, text='', dalsi_odkazy: Sequence[tuple[str, str]] = ( | |||
| 	odkazy = list(dalsi_odkazy) + [ | ||||
| 		# (Text, odkaz) | ||||
| 		('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 = { | ||||
| 		'odkazy': odkazy, | ||||
|  |  | |||
|  | @ -17,9 +17,9 @@ module.exports = { | |||
|     filenameHashing: false, | ||||
|     productionSourceMap: true, | ||||
|     publicPath: process.env.NODE_ENV === 'production' | ||||
|         ? '/static/seminar/vue/' | ||||
|         ? '/static/treenode/vue/' | ||||
|         : 'http://localhost:8080/', | ||||
|     outputDir: '../seminar/static/seminar/vue/', | ||||
|     outputDir: '../treenode/static/treenode/vue/', | ||||
| 
 | ||||
|     chainWebpack: config => { | ||||
| 
 | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue