Merge branch 'data_migrations' of gimli.ms.mff.cuni.cz:/akce/mam/git/mamweb into data_migrations
This commit is contained in:
		
						commit
						0425e368ed
					
				
					 17 changed files with 705 additions and 38 deletions
				
			
		|  | @ -87,3 +87,5 @@ LOGGING = { | |||
| 
 | ||||
| # set to 'DEBUG' for EXTRA verbose output | ||||
| # LOGGING['handlers']['console']['level'] = 'INFO' | ||||
| 
 | ||||
| EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ django-crispy-forms | |||
| django-imagekit | ||||
| django-polymorphic | ||||
| django-sitetree | ||||
| django_reverse_admin | ||||
| 
 | ||||
| # Comments | ||||
| akismet==1.0.1 | ||||
|  |  | |||
|  | @ -1,20 +1,33 @@ | |||
| from django.contrib import admin | ||||
| 
 | ||||
| from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter | ||||
| from reversion.admin import VersionAdmin | ||||
| from django_reverse_admin import ReverseModelAdmin | ||||
| 
 | ||||
| # Todo: reversion | ||||
| 
 | ||||
| import seminar.models as m | ||||
| 
 | ||||
| admin.site.register(m.Osoba) | ||||
| admin.site.register(m.Skola) | ||||
| admin.site.register(m.Prijemce) | ||||
| admin.site.register(m.Resitel) | ||||
| admin.site.register(m.Rocnik) | ||||
| admin.site.register(m.Cislo) | ||||
| admin.site.register(m.Organizator) | ||||
| admin.site.register(m.Soustredeni) | ||||
| 
 | ||||
| @admin.register(m.Osoba) | ||||
| class OsobaAdmin(admin.ModelAdmin): | ||||
| 	actions = ['synchronizuj_maily'] | ||||
| 
 | ||||
| 	def synchronizuj_maily(self, request, queryset): | ||||
| 		for o in queryset: | ||||
| 			if o.user is not None: | ||||
| 				u = o.user | ||||
| 				u.email = o.email | ||||
| 				u.save() | ||||
| 		self.message_user(request, "E-maily synchronizovány.") | ||||
| 	synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů" | ||||
| 
 | ||||
| @admin.register(m.Problem) | ||||
| class ProblemAdmin(PolymorphicParentModelAdmin): | ||||
| 	base_model = m.Problem | ||||
|  | @ -39,11 +52,35 @@ class UlohaAdmin(PolymorphicChildModelAdmin): | |||
| 	base_model = m.Uloha | ||||
| 	show_in_index = True | ||||
| 
 | ||||
| 
 | ||||
| class TextAdminInline(admin.TabularInline): | ||||
| 	model = m.Text | ||||
| 	exclude = ['text_zkraceny_set','text_zkraceny'] | ||||
| admin.site.register(m.Text) | ||||
| admin.site.register(m.Reseni) | ||||
| admin.site.register(m.Hodnoceni) | ||||
| 
 | ||||
| class ResitelInline(admin.TabularInline): | ||||
| 	model = m.Resitel | ||||
| 	extra = 1 | ||||
| admin.site.register(m.Resitel) | ||||
| 
 | ||||
| class PrilohaReseniInline(admin.TabularInline): | ||||
| 	model = m.PrilohaReseni | ||||
| 	extra = 1 | ||||
| admin.site.register(m.PrilohaReseni) | ||||
| 
 | ||||
| class Reseni_ResiteleInline(admin.TabularInline): | ||||
| 	model = m.Reseni_Resitele | ||||
| 
 | ||||
| @admin.register(m.Reseni) | ||||
| class ReseniAdmin(ReverseModelAdmin): | ||||
| 	base_model = m.Reseni | ||||
| 	inline_type = 'tabular' | ||||
| 	inline_reverse = ['text_cely','resitele'] | ||||
| 	exclude = ['text_zkraceny', 'text_zkraceny_set'] | ||||
| 	inlines = [PrilohaReseniInline] | ||||
| # FAIL in template | ||||
| #	inlines = [PrilohaReseniInline,Reseni_ResiteleInline] | ||||
| 
 | ||||
| admin.site.register(m.Hodnoceni) | ||||
| admin.site.register(m.Pohadka) | ||||
| admin.site.register(m.Konfera) | ||||
| admin.site.register(m.Obrazek) | ||||
|  | @ -68,6 +105,17 @@ class TreeNodeAdmin(PolymorphicParentModelAdmin): | |||
| 		m.TextNode, | ||||
| 		] | ||||
| 
 | ||||
| 	actions = ['aktualizuj_nazvy'] | ||||
| 
 | ||||
| 	# XXX: nejspíš je to totální DB HOG, nechcete to použít moc často. | ||||
| 	def aktualizuj_nazvy(self, request, queryset): | ||||
| 		newqs = queryset.get_real_instances() | ||||
| 		for tn in newqs: | ||||
| 			tn.aktualizuj_nazev() | ||||
| 			tn.save() | ||||
| 		self.message_user(request, "Názvy aktualizovány.") | ||||
| 	aktualizuj_nazvy.short_description = "Aktualizuj vybraným TreeNodům názvy" | ||||
| 
 | ||||
| @admin.register(m.RocnikNode) | ||||
| class RocnikNodeAdmin(PolymorphicChildModelAdmin): | ||||
| 	base_model = m.RocnikNode | ||||
|  |  | |||
|  | @ -121,3 +121,92 @@ class PrihlaskaForm(forms.Form): | |||
| 				self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy')) | ||||
| 			elif data.get('skola_adresa')=='': | ||||
| 				self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) | ||||
| 
 | ||||
| 
 | ||||
| class EditForm(forms.Form): | ||||
| 	username = forms.CharField(label='Přihlašovací jméno',  | ||||
| 			max_length=256,  | ||||
| 			required=True) | ||||
| 
 | ||||
| 	jmeno = forms.CharField(label='Jméno', max_length=256, required=True) | ||||
| 	prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) | ||||
| 	pohlavi_muz = forms.ChoiceField(label='Pohlaví', | ||||
| 			choices = ((True,'muž'),(False,'žena')), required=True) | ||||
| 	email = forms.EmailField(label='E-mail',max_length=256, required=True) | ||||
| 	telefon = forms.CharField(label='Telefon',max_length=256, required=False) | ||||
| 	datum_narozeni = forms.DateField(label='Datum narození', required=False) | ||||
| 	ulice = forms.CharField(label='Ulice', max_length=256, required=False) | ||||
| 	mesto = forms.CharField(label='Město', max_length=256, required=False) | ||||
| 	psc = forms.CharField(label='PSČ', max_length=32, required=False) | ||||
| 	stat = forms.ChoiceField(label='Stát',  | ||||
| 			choices = (('CZ', 'Česká Republika'), | ||||
| 				('SK', 'Slovenská Republika'), | ||||
| 				('other', 'Jiné')), | ||||
| 			required=False) | ||||
| 	stat_text = forms.CharField(label='Stát', max_length=256, required=False) | ||||
| 
 | ||||
| 	skola = forms.ModelChoiceField(label="Škola", | ||||
| 		queryset=Skola.objects.all(), | ||||
| 		widget=autocomplete.ModelSelect2( | ||||
| 			url='autocomplete_skola', | ||||
| 			attrs = {'data-placeholder--id': '-1', | ||||
| 				'data-placeholder--text' : '---', | ||||
| 				'data-allow-clear': 'true'}) | ||||
|     		,required=False) | ||||
| 	 | ||||
| 	skola_nazev = forms.CharField(label='Název školy', max_length=256, required=False) | ||||
| 	skola_adresa = forms.CharField(label='Adresa školy', max_length=256, required=False) | ||||
| 
 | ||||
| #	trida = forms.CharField(label='Třída',max_length=10, required=True) | ||||
| 
 | ||||
| 	rok_maturity = forms.IntegerField( | ||||
| 		label='Rok maturity',  | ||||
| 		min_value=date.today().year,  | ||||
| 		max_value=date.today().year+8, | ||||
| 		required=True) | ||||
| 	zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True) | ||||
| 	spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False) | ||||
| #	def clean_username(self): | ||||
| #		err_logger = logging.getLogger('seminar.prihlaska.problem') | ||||
| #		username = self.cleaned_data.get('username') | ||||
| #		try: | ||||
| #			User.objects.get(username=username) | ||||
| #			msg = "Username {} exists".format(username) | ||||
| #			err_logger.info(msg) | ||||
| #			raise forms.ValidationError('Přihlašovací jméno je již použito') | ||||
| # | ||||
| #		except ObjectDoesNotExist: | ||||
| #			pass | ||||
| #		return username | ||||
| # | ||||
| #	def clean_email(self): | ||||
| #		err_logger = logging.getLogger('seminar.prihlaska.problem') | ||||
| #		email = self.cleaned_data.get('email') | ||||
| #		try: | ||||
| #			Osoba.objects.get(email=email) | ||||
| #			msg = "Email {} exists".format(email) | ||||
| #			err_logger.info(msg) | ||||
| #			raise forms.ValidationError('Email je již použit') | ||||
| # | ||||
| #		except ObjectDoesNotExist: | ||||
| #			pass | ||||
| #		return email | ||||
| 	#def clean(self): | ||||
| 	#	super().clean() | ||||
| 	#	 | ||||
| 	#	err_logger = logging.getLogger('seminar.prihlaska.problem') | ||||
| 
 | ||||
| 	#	data = self.cleaned_data | ||||
| 	#	if data.get('password') != data.get('password_check'): | ||||
| 	#		self.add_error('password_check',forms.ValidationError('Hesla se neshodují')) | ||||
| 	#	if data.get('stat') != '' and data.get('stat_text') != '': | ||||
| 	#		self.add_error('stat',forms.ValidationError('Nelze mít vybraný stát z menu a zároven zapsaný textem')) | ||||
| 	#	if data.get('skola') and (data.get('skola_nazev') or data.get('skola_adresa')): | ||||
| 	#		self.add_error('skola',forms.ValidationError('Pokud je škola v seznamu, nevypisujte ji ručně, pokud není, zrušte výběr ze seznamu (křížek vpravo)')) | ||||
| 	#	if not data.get('skola'): | ||||
| 	#		if data.get('skola_nazev')=='' and data.get('skola_adresa')=='': | ||||
| 	#			self.add_error('skola',forms.ValidationError('Je nutné vyplnit školu')) | ||||
| 	#		elif data.get('skola_nazev')=='': | ||||
| 	#			self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy')) | ||||
| 	#		elif data.get('skola_adresa')=='': | ||||
| 	#			self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) | ||||
|  |  | |||
							
								
								
									
										23
									
								
								seminar/migrations/0072_auto_20191204_2257.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								seminar/migrations/0072_auto_20191204_2257.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| # Generated by Django 2.2.7 on 2019-12-04 21:57 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0071_remove_nastaveni_aktualni_rocnik'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='treenode', | ||||
|             name='srolovatelne', | ||||
|             field=models.BooleanField(blank=True, help_text='Bude na stránce témátka možnost tuto položku skrýt', null=True, verbose_name='Srolovatelné'), | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name='treenode', | ||||
|             name='zajimave', | ||||
|             field=models.BooleanField(default=False, help_text='Zobrazí se daná věc na rozcestníku témátek', verbose_name='Zajímavé'), | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										22
									
								
								seminar/migrations/0073_copy_osoba_email_to_user_email.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								seminar/migrations/0073_copy_osoba_email_to_user_email.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| # Generated by Django 2.2.9 on 2020-01-15 21:28 | ||||
| 
 | ||||
| from django.db import migrations | ||||
| 
 | ||||
| def copy_mails(apps, schema_editor): | ||||
| 	Osoba = apps.get_model('seminar', 'Osoba') | ||||
| 
 | ||||
| 	for o in Osoba.objects.all(): | ||||
| 		if o.user is not None: | ||||
| 			u = o.user | ||||
| 			u.email = o.email | ||||
| 			u.save() | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0072_auto_20191204_2257'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.RunPython(copy_mails, migrations.RunPython.noop) | ||||
|     ] | ||||
|  | @ -21,9 +21,9 @@ from taggit.managers import TaggableManager | |||
| 
 | ||||
| from reversion import revisions as reversion | ||||
| 
 | ||||
| from seminar.utils import roman | ||||
| from seminar.utils import roman, FirstTagParser # Pro získání úryvku z TextNode | ||||
| 
 | ||||
| from unidecode import unidecode | ||||
| from unidecode import unidecode # Používám pro získání ID odkazu (ještě je to někde po někom zakomentované) | ||||
| 
 | ||||
| from polymorphic.models import PolymorphicModel | ||||
| 
 | ||||
|  | @ -130,6 +130,17 @@ class Osoba(SeminarModelBase): | |||
| 	def __str__(self): | ||||
| 		return self.plne_jmeno() | ||||
| 
 | ||||
| 	# Overridujeme save Osoby, aby když si změní e-mail, aby se projevil i v | ||||
| 	# Userovi (a tak se dal poslat mail s resetem hesla) | ||||
| 	def save(self, *args, **kwargs): | ||||
| 		if self.user is not None: | ||||
| 			u = self.user | ||||
| 			# U svatého tučňáka, prosím ať tohle funguje. | ||||
| 			# (Takhle se kódit asi nemá...) | ||||
| 			u.email = self.email | ||||
| 			u.save() | ||||
| 		super().save() | ||||
| 
 | ||||
| # | ||||
| # Mělo by být částečně vytaženo z Aesopa | ||||
| # viz https://ovvp.mff.cuni.cz/wiki/aesop/export-skol. | ||||
|  | @ -620,7 +631,7 @@ class Problem(SeminarModelBase,PolymorphicModel): | |||
| 	id = models.AutoField(primary_key = True) | ||||
| 
 | ||||
| 	# Název | ||||
| 	nazev = models.CharField('název', max_length=256) | ||||
| 	nazev = models.CharField('název', max_length=256) # Zveřejnitelný na stránky | ||||
| 
 | ||||
| 	# Problém má podproblémy | ||||
| 	nadproblem = models.ForeignKey('self', verbose_name='nadřazený problém', | ||||
|  | @ -785,8 +796,11 @@ class Text(SeminarModelBase): | |||
| 		for tn in self.textnode_set.all(): | ||||
| 			tn.save() | ||||
| 
 | ||||
| 
 | ||||
| 	 | ||||
| 	def __str__(self): | ||||
| 		parser = FirstTagParser()		 | ||||
| 		parser.feed(str(self.na_web)) | ||||
| 		return parser.firstTag | ||||
| 		 | ||||
| class Uloha(Problem): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_ulohy' | ||||
|  | @ -885,7 +899,7 @@ class Reseni(SeminarModelBase): | |||
| 	# Konfera | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 		return "{}: {}".format(self.resitel.osoba.plne_jmeno(), self.problem.nazev) | ||||
| 		return "{}({}): {}({})".format(self.resitele.first(),len(self.resitele.all()), self.problem.first() ,len(self.problem.all())) | ||||
| 		# NOTE: Potenciální DB HOG (bez select_related) | ||||
| 
 | ||||
| ## Pravdepodobne uz nebude potreba: | ||||
|  | @ -1239,8 +1253,15 @@ class TreeNode(PolymorphicModel): | |||
| 		on_delete=models.SET_NULL, | ||||
| 		verbose_name="další element na stejné úrovni") | ||||
| 	nazev = models.TextField("název tohoto node", | ||||
| 			help_text = "Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode", | ||||
| 			blank=False, null=True) | ||||
| 		help_text = "Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode", | ||||
| 		blank=False,  | ||||
| 		null=True) # Nezveřejnitelný název na stránky - pouze do adminu | ||||
| 	zajimave = models.BooleanField(default = False, | ||||
| 		verbose_name = "Zajímavé", | ||||
| 		help_text = "Zobrazí se daná věc na rozcestníku témátek") | ||||
| 	srolovatelne = models.BooleanField(null = True, blank = True, | ||||
| 		verbose_name = "Srolovatelné", | ||||
| 		help_text = "Bude na stránce témátka možnost tuto položku skrýt") | ||||
| 	 | ||||
| 	def print_tree(self,indent=0): | ||||
| 		print("{}TreeNode({})".format(" "*indent,self.id)) | ||||
|  | @ -1248,7 +1269,27 @@ class TreeNode(PolymorphicModel): | |||
| 			self.first_child.print_tree(indent=indent+2) | ||||
| 		if self.succ: | ||||
| 			self.succ.print_tree(indent=indent) | ||||
| 		 | ||||
| 
 | ||||
| 	def getOdkazStr(self): # String na rozcestník | ||||
| 		return self.first_child.getOdkazStr() | ||||
| 
 | ||||
| 	def getOdkaz(self): # ID HTML tagu, na který se bude scrollovat #{{self.getOdkaz}} | ||||
| 	# Jsem si vědom, že tu potenciálně vznikají kolize. | ||||
| 	# Přijdou mi natolik nepravděpodobné, že je neřeším | ||||
| 	# Chtěl jsem ale hezké odkazy | ||||
| 		string = unidecode(self.getOdkazStr()) | ||||
| 		returnVal = "" | ||||
| 		i = 0	 | ||||
| 		while len(returnVal) < 16: # Max 15 znaků | ||||
| 			if i == len(string): | ||||
| 				break | ||||
| 			if string[i] == " ": | ||||
| 				returnVal += "-" | ||||
| 			if string[i].isalnum(): | ||||
| 				returnVal += string[i].lower() | ||||
| 			i += 1 | ||||
| 		return returnVal | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 		if self.nazev: | ||||
| 			return self.nazev | ||||
|  | @ -1260,6 +1301,9 @@ class TreeNode(PolymorphicModel): | |||
| 		self.aktualizuj_nazev() | ||||
| 		super().save(*args, **kwargs) | ||||
| 
 | ||||
| 	def aktualizuj_nazev(self): | ||||
| 		raise NotImplementedError("Pokus o aktualizaci názvu obecného TreeNode místo konkrétní instance") | ||||
| 
 | ||||
| class RocnikNode(TreeNode): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_nodes_rocnik' | ||||
|  | @ -1284,6 +1328,9 @@ class CisloNode(TreeNode): | |||
| 	def aktualizuj_nazev(self): | ||||
| 		self.nazev = "CisloNode: "+str(self.cislo) | ||||
| 
 | ||||
| 	def getOdkazStr(self): | ||||
| 		return "Číslo " + str(self.cislo) | ||||
| 
 | ||||
| class MezicisloNode(TreeNode): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_nodes_mezicislo' | ||||
|  | @ -1305,6 +1352,8 @@ class MezicisloNode(TreeNode): | |||
| 		else: | ||||
| 			print("!!!!! Nějaké neidentifikované mezičíslo !!!!!") | ||||
| 			self.nazev = "MezicisloNode: Neidentifikovatelné mezičíslo!" | ||||
| 	def getOdkazStr(self): | ||||
| 		return "Obsah dostupný pouze na webu" | ||||
| 
 | ||||
| class TemaVCisleNode(TreeNode): | ||||
| 	""" Obsahuje příspěvky k tématu v daném čísle """ | ||||
|  | @ -1319,6 +1368,9 @@ class TemaVCisleNode(TreeNode): | |||
| 	def aktualizuj_nazev(self): | ||||
| 		self.nazev = "TemaVCisleNode: "+str(self.tema) | ||||
| 
 | ||||
| 	def getOdkazStr(self): | ||||
| 		return str(self.tema) | ||||
| 
 | ||||
| class KonferaNode(TreeNode): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_nodes_konfera' | ||||
|  | @ -1347,6 +1399,10 @@ class ClanekNode(TreeNode): | |||
| 	def aktualizuj_nazev(self): | ||||
| 		self.nazev = "ClanekNode: "+str(self.clanek) | ||||
| 
 | ||||
| 	def getOdkazStr(self): | ||||
| 		return str(self.clanek) | ||||
| 
 | ||||
| 
 | ||||
| class UlohaZadaniNode(TreeNode): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_nodes_uloha_zadani' | ||||
|  | @ -1361,6 +1417,10 @@ class UlohaZadaniNode(TreeNode): | |||
| 	def aktualizuj_nazev(self): | ||||
| 		self.nazev = "UlohaZadaniNode: "+str(self.uloha) | ||||
| 
 | ||||
| 	def getOdkazStr(self): | ||||
| 		return str(self.uloha) | ||||
| 
 | ||||
| 
 | ||||
| class PohadkaNode(TreeNode): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_nodes_pohadka' | ||||
|  | @ -1388,6 +1448,10 @@ class UlohaVzorakNode(TreeNode): | |||
| 	def aktualizuj_nazev(self): | ||||
| 		self.nazev = "UlohaVzorakNode: "+str(self.uloha) | ||||
| 
 | ||||
| 	def getOdkazStr(self): | ||||
| 		return str(self.uloha) | ||||
| 
 | ||||
| 
 | ||||
| class TextNode(TreeNode): | ||||
| 	class Meta: | ||||
| 		db_table = 'seminar_nodes_obsah' | ||||
|  | @ -1400,6 +1464,10 @@ class TextNode(TreeNode): | |||
| 	def aktualizuj_nazev(self): | ||||
| 		self.nazev = "TextNode: "+str(self.text) | ||||
| 
 | ||||
| 	def getOdkazStr(self): | ||||
| 		return str(self.text) | ||||
| 
 | ||||
| 
 | ||||
| ## FIXME: Logiku přesunout do views. | ||||
| #class VysledkyBase(SeminarModelBase): | ||||
| # | ||||
|  | @ -1491,6 +1559,7 @@ class Nastaveni(SingletonModel): | |||
| 	aktualni_cislo = models.ForeignKey(Cislo, verbose_name='poslední vydané číslo',  | ||||
| 		null=False, on_delete=models.PROTECT) | ||||
| 
 | ||||
| 	@property | ||||
| 	def aktualni_rocnik(self): | ||||
| 		return self.aktualni_cislo.rocnik | ||||
| 
 | ||||
|  | @ -1534,3 +1603,35 @@ class Novinky(models.Model): | |||
| 			return '[' + str(self.datum) + '] ' + self.text[0:50] | ||||
| 		else: | ||||
| 			return '[' + str(self.datum) + '] ' | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # FIXME: Tohle nepatří do aplikace 'seminar' | ||||
| # Nefunkční alternativa vestavěného Usera, který má jméno a mail v přidružené Osobě | ||||
| # from django.contrib.auth.models import User as Django_User | ||||
| #  | ||||
| # class Uzivatel(Django_User): | ||||
| # 	class Meta: | ||||
| # 		proxy = True | ||||
| #  | ||||
| # 	@property | ||||
| # 	def first_name(self): | ||||
| # 		osoby = Osoba.objects.filter(user=self) | ||||
| # 		if len(osoby) == 0: | ||||
| # 			return None | ||||
| # 		return osoby.first().krestni_jmeno | ||||
| #  | ||||
| # 	@property | ||||
| # 	def last_name(self): | ||||
| # 		osoby = Osoba.objects.filter(user=self) | ||||
| # 		if len(osoby) == 0: | ||||
| # 			return None | ||||
| # 		return osoby.first().prijmeni | ||||
| #  | ||||
| # 	@property | ||||
| # 	def email(self): | ||||
| # 		osoby = Osoba.objects.filter(user=self) | ||||
| # 		if len(osoby) == 0: | ||||
| # 			return None | ||||
| # 		return osoby.first().email | ||||
|  |  | |||
							
								
								
									
										78
									
								
								seminar/templates/seminar/edit.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								seminar/templates/seminar/edit.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | |||
| {% extends "seminar/zadani/base.html" %} | ||||
| {% load staticfiles %} | ||||
| 
 | ||||
| {% block script %} | ||||
|     <!--script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script!--> | ||||
|     {{form.media}} | ||||
|     <script src="{% static 'seminar/prihlaska.js' %}"></script> | ||||
| {% endblock %} | ||||
| {% block content %} | ||||
| <h1> | ||||
|   {% block nadpis1a %}{% block nadpis1b %} | ||||
|    Změna osobních údajů | ||||
|   {% endblock %}{% endblock %} | ||||
| </h1> | ||||
| <form action="{% url 'seminar_resitel_edit' %}" method="post"> | ||||
|  {% csrf_token %} | ||||
|  {{form.non_field_errors}} | ||||
|  <ul class="form"> | ||||
|      <li> | ||||
|      Přihlašovací údaje | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.username %} | ||||
|      </li><li> | ||||
|      Osobní údaje | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.jmeno %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.prijmeni %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.pohlavi_muz%} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.email %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.telefon %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.datum_narozeni %} | ||||
|      </li><li> | ||||
|   <hr> | ||||
|        Bydliště | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.ulice %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.mesto %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.psc %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.stat %} | ||||
|      </li> | ||||
|      <li id="id_li_stat_text"> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.stat_text %} | ||||
|      </li><li> | ||||
|  <hr> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.skola %} | ||||
|      </li><li> | ||||
|        <button id="id_skola_text_button" type="button">Škola není v seznamu</button> | ||||
|      </li> | ||||
|      <li id="id_li_skola_nazev"> | ||||
|        Vyplň prosím celý název a adresu školy.<br> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.skola_nazev %} | ||||
|      </li> | ||||
|      <li id="id_li_skola_adresa"> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.skola_adresa %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.rok_maturity %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.zasilat %} | ||||
|      </li><li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.spam %} | ||||
|      </li> | ||||
| </ul> | ||||
|     <input type="submit" value="Změnit"> | ||||
| </form> | ||||
| <script> | ||||
| $("#id_stat").on("change",addrCountryChanged); | ||||
| $("#id_skola_text_button").on("click",schoolNotInList); | ||||
| </script> | ||||
| {% endblock %} | ||||
| 
 | ||||
|  | @ -8,20 +8,13 @@ | |||
|     Přihlášení | ||||
|   {% endblock %}{% endblock %} | ||||
| </h1> | ||||
| {% if login_error %}  | ||||
| <span class="field_error">{{login_error}}<span> | ||||
| {% endif %} | ||||
| <form action="{% url 'login' %}" method="post"> | ||||
|   {% csrf_token %} | ||||
|   {{form.non_field_errors}} | ||||
|   <ul class="form"> | ||||
|      <li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.username %} | ||||
|      </li> | ||||
|      <li> | ||||
|        {% include "seminar/prihlaska_field.html" with field=form.password %} | ||||
|      </li> | ||||
|     {{ form.as_ul }} | ||||
| </ul> | ||||
| 	{# Django si posílá jméno další stránky jako obsah formuláře a výchozí hodnota (mi přišlo, že) nejde změnit... #} | ||||
| 	<input type="hidden" name='next' value="{{ next }}"> | ||||
|     <input type="submit" value="Přihlásit"> | ||||
| </form> | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										18
									
								
								seminar/templates/seminar/logout.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								seminar/templates/seminar/logout.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| {% extends "seminar/zadani/base.html" %} | ||||
| {% load staticfiles %} | ||||
| 
 | ||||
| 
 | ||||
| {% block content %} | ||||
| <h1> | ||||
|   {% block nadpis1a %}{% block nadpis1b %} | ||||
|     Odhlášení | ||||
|   {% endblock %}{% endblock %} | ||||
| </h1> | ||||
| 
 | ||||
| Byl jsi úspěšně odhlášen | ||||
| {# Tohle by se asi mělo udělat přes kontext (title), ale kašlu na to, stejně je to jen jednojazyčná stránka #} | ||||
| 
 | ||||
| {# TODO: odkaz na znovupřihlášení? #} | ||||
| 
 | ||||
| {% endblock %} | ||||
| 
 | ||||
							
								
								
									
										30
									
								
								seminar/templates/seminar/org/obalkovani.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								seminar/templates/seminar/org/obalkovani.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| {% extends "base.html" %} | ||||
| 
 | ||||
| {% block content %} | ||||
|   <h1> | ||||
|     {% block nadpis1a %}{% block nadpis1b %} | ||||
|       Obálkování {{ cislo }} | ||||
|     {% endblock %}{% endblock %} | ||||
|   </h1> | ||||
|   <ul> | ||||
|   {% for reseni in object_list %} | ||||
| 	{% ifchanged reseni.resitele %} | ||||
| 		{% if not forloop.first %} | ||||
| 		 </ul> | ||||
| 		{% endif %} | ||||
| 		<h4>{% for resitel in reseni.resitele.all %}{{resitel.osoba}},{% endfor %}</h4> | ||||
| 	<ul> | ||||
| 	{% endifchanged %} | ||||
| 
 | ||||
|   <li>Celkem {{reseni.hodnoceni__body__sum}} bodů z {{reseni.hodnoceni__count}} hodnocení | ||||
| 	<ul> | ||||
| 		{% for h in reseni.hodnoceni_set.all %} | ||||
| 		<li> {{ h.problem }}: {{ h.body }}b </li> | ||||
| 		{% endfor %} | ||||
| 	</ul> | ||||
|   </li> | ||||
|   {% endfor %} | ||||
|   </ul> | ||||
| 
 | ||||
| 
 | ||||
| {% endblock content %} | ||||
							
								
								
									
										14
									
								
								seminar/templates/seminar/tematka/rozcestnik.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								seminar/templates/seminar/tematka/rozcestnik.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| {% for tematko in tematka %} | ||||
| <h1>{{tematko.nazev}}</h1> | ||||
| <p>{{tematko.abstrakt}}</p> | ||||
| 	<ul> | ||||
| 	{% for cislo in tematko.cisla %} | ||||
| 		<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{cislo.0.1}}">{{cislo.0.0}}</a></li> | ||||
| 		<ul> | ||||
| 		{% for odkaz in cislo.1 %} | ||||
| 			<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{odkaz.1}}">{{odkaz.0}}</a></li>	 | ||||
| 		{% endfor %} | ||||
| 		</ul> | ||||
| 	{% endfor %} | ||||
| 	</ul> | ||||
| {% endfor %} | ||||
							
								
								
									
										1
									
								
								seminar/templates/seminar/tematka/toaletak.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								seminar/templates/seminar/tematka/toaletak.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| Stránká témátka | ||||
|  | @ -380,7 +380,8 @@ def gen_temata(rnd, rocniky, rocnik_cisla, organizatori): | |||
| 				kod=str(n), | ||||
| 				# atributy třídy Téma | ||||
| 				tema_typ=rnd.choice(Tema.TEMA_CHOICES)[0], | ||||
| 				rocnik=rocnik | ||||
| 				rocnik=rocnik, | ||||
| 				abstrakt = "Abstrakt tematka {}".format(n) | ||||
| 			) | ||||
| 			konec_tematu = min(rnd.randint(ci, 7), len(cisla)) | ||||
| 			for i in range(ci, konec_tematu+1): | ||||
|  |  | |||
|  | @ -8,6 +8,9 @@ from django.contrib.auth import views as auth_views | |||
| staff_member_required = user_passes_test(lambda u: u.is_staff) | ||||
| 
 | ||||
| urlpatterns = [ | ||||
|   path('aktualni/temata/', views.TemataRozcestnikView), | ||||
| 	path('<int:rocnik>/t<int:tematko>/', views.TematkoView), | ||||
| 
 | ||||
| 	# REDIRECTy | ||||
| 	path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')), | ||||
| 
 | ||||
|  | @ -86,24 +89,30 @@ urlpatterns = [ | |||
| 	path('stav', | ||||
| 		staff_member_required(views.StavDatabazeView), name='stav_databaze'), | ||||
| 	path('cislo/<int:rocnik>.<int:cislo>/obalkovani', | ||||
| 		staff_member_required(views.obalkovaniView), name='seminar_cislo_resitel_obalkovani'), | ||||
| 		staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'), | ||||
| 	path('cislo/<int:rocnik>.<int:cislo>/tex-download.json', | ||||
| 		staff_member_required(views.texDownloadView), name='seminar_tex_download'), | ||||
| 	path('soustredeni/<int:soustredeni>/obalky.pdf', | ||||
| 		staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), | ||||
| 
 | ||||
| 	path('tex-upload/login/', views.LoginView, name='seminar_login'), | ||||
| 	path('tex-upload/login/', views.TeXUploadLoginView, name='seminar_login'), | ||||
| 	path( | ||||
| 		'tex-upload/', | ||||
| 		staff_member_required(views.texUploadView), | ||||
| 		name='seminar_tex_upload' | ||||
| 	), | ||||
| 	path('org/vloz_body/<int:tema>/', | ||||
| 		staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'), | ||||
| 	path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), | ||||
| 	path('auth/login/', views.loginView, name='login'), | ||||
| 	path('auth/logout/', views.logoutView, name='logout'), | ||||
| 	path('auth/login/', views.LoginView.as_view(), name='login'), | ||||
| 	path('auth/logout/', views.LogoutView.as_view(), name='logout'), | ||||
| 	path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'), | ||||
| 	path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), | ||||
| 	path('auth/reset_password', views.resetPasswordView, name='reset_password'), | ||||
| 	path('auth/reset_password/', views.PasswordResetView.as_view(), name='reset_password'), | ||||
| 	path('auth/change_password/', views.PasswordChangeView.as_view(), name='change_password'), | ||||
| 	path('auth/reset_password_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'), | ||||
| 	path('auth/reset_password_confirm/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), | ||||
| 	path('auth/reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), | ||||
| 	path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'), | ||||
| 	path('', views.TitulniStranaView.as_view(), name='titulni_strana'), | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,9 +2,18 @@ | |||
| 
 | ||||
| import datetime | ||||
| from django.contrib.auth.decorators import user_passes_test | ||||
| from html.parser import HTMLParser  | ||||
| 
 | ||||
| staff_member_required = user_passes_test(lambda u: u.is_staff) | ||||
| 
 | ||||
| class FirstTagParser(HTMLParser): | ||||
| 	def __init__(self, *args, **kwargs): | ||||
| 		self.firstTag = None | ||||
| 		super().__init__(*args, **kwargs) | ||||
| 	def handle_data(self, data): | ||||
| 		if self.firstTag == None: | ||||
| 			self.firstTag = data | ||||
| 	 | ||||
| def histogram(seznam): | ||||
| 	d = {} | ||||
| 	for i in seznam: | ||||
|  |  | |||
							
								
								
									
										244
									
								
								seminar/views.py
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								seminar/views.py
									
									
									
									
									
								
							|  | @ -2,24 +2,26 @@ | |||
| 
 | ||||
| from django.shortcuts import get_object_or_404, render | ||||
| from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse | ||||
| from django.urls import reverse | ||||
| from django.urls import reverse,reverse_lazy | ||||
| from django.core.exceptions import PermissionDenied, ObjectDoesNotExist | ||||
| from django.views import generic | ||||
| from django.utils.translation import ugettext as _ | ||||
| from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect | ||||
| from django.db.models import Q | ||||
| from django.db.models import Q, Sum, Count | ||||
| from django.views.decorators.csrf import ensure_csrf_cookie | ||||
| from django.contrib.auth import authenticate, login, get_user_model, logout | ||||
| from django.contrib.auth import views as auth_views | ||||
| from django.contrib.auth.models import User | ||||
| from django.contrib.auth.mixins import LoginRequiredMixin | ||||
| from django.db import transaction | ||||
| from dal import autocomplete | ||||
| 
 | ||||
| from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola | ||||
| import seminar.models as s | ||||
| from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci | ||||
| #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | ||||
| from . import utils | ||||
| from .unicodecsv import UnicodeWriter | ||||
| from .forms import PrihlaskaForm, LoginForm | ||||
| from .forms import PrihlaskaForm, LoginForm, EditForm | ||||
| 
 | ||||
| from datetime import timedelta, date, datetime | ||||
| from django.utils import timezone | ||||
|  | @ -43,6 +45,45 @@ def verejna_temata(rocnik): | |||
| 	""" | ||||
| 	return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod') | ||||
| 
 | ||||
| def temata_v_rocniku(rocnik): | ||||
| 	return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik) | ||||
| 
 | ||||
| def get_problemy_k_tematu(tema): | ||||
| 	return Problemy.objects.filter(nadproblem = tema) | ||||
| 
 | ||||
| 
 | ||||
| class VlozBodyView(generic.ListView): | ||||
| 	template_name = 'seminar/org/vloz_body.html' | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		self.tema = get_object_or_404(Problem,id=self.kwargs['tema']) | ||||
| 		print(self.tema) | ||||
| 		self.problemy = Problem.objects.filter(nadproblem = self.tema) | ||||
| 		print(self.problemy) | ||||
| 		self.reseni = Reseni.objects.filter(problem__in=self.problemy)	 | ||||
| 		print(self.reseni) | ||||
| 		return self.reseni | ||||
| 
 | ||||
| 
 | ||||
| class ObalkovaniView(generic.ListView): | ||||
| 	template_name = 'seminar/org/obalkovani.html' | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
| 		rocnik = get_object_or_404(Rocnik,rocnik=self.kwargs['rocnik']) | ||||
| 		cislo = get_object_or_404(Cislo,rocnik=rocnik,poradi=self.kwargs['cislo']) | ||||
| 		self.cislo = cislo | ||||
| 		self.hodnoceni = s.Hodnoceni.objects.filter(cislo_body=cislo) | ||||
| 		self.reseni = Reseni.objects.filter(hodnoceni__in = self.hodnoceni).annotate(Sum('hodnoceni__body')).annotate(Count('hodnoceni')).order_by('resitele__osoba') | ||||
| 		return self.reseni | ||||
| 
 | ||||
| 	def get_context_data(self, **kwargs): | ||||
| 		context = super(ObalkovaniView, self).get_context_data(**kwargs) | ||||
| 		print(self.cislo) | ||||
| 		context['cislo'] = self.cislo  | ||||
| 		return context | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def AktualniZadaniView(request): | ||||
| 	nastaveni = get_object_or_404(Nastaveni) | ||||
|  | @ -73,6 +114,99 @@ def ZadaniTemataView(request): | |||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| # TODO Napsat tuto funkci znovu rekurzivně podle Jethrorad. Potom se podívat, jak lehce se dá modifikovat pro Rozcestník. Pokud lehce, rozšířit ji. Pokud složitě - použít tuhle | ||||
| def vytahniZLesaSeznam(tematko, koren, pouze_zajimave=False): | ||||
| 	returnVal = [] | ||||
| 
 | ||||
| 	stack = [] | ||||
| 	stack.append((koren.first_child, 0, False)) #Tuple of node, depth and relevance | ||||
| 
 | ||||
| 	while len(stack) > 0: | ||||
| 		wn, wd, wr = stack.pop() | ||||
| 
 | ||||
| 		if wn.succ != None: | ||||
| 			stack.append((wn.succ, wd, wr)) | ||||
| 		if isinstance(wn, s.TemaVCisleNode): | ||||
| 			print("TEMA") | ||||
| 			print(wn.tema.id)	 | ||||
| 			print(tematko.id)	 | ||||
| 			if wn.tema.id == tematko.id: | ||||
| 				returnVal.append((posledni_cislo, 0)) | ||||
| 				print("PRIDANO") | ||||
| 				wr = True | ||||
| 				wd = 1 | ||||
| 
 | ||||
| 		if wn.srolovatelne: | ||||
| 			tagOpen = s.Text(na_web = "Otevírací srolovací tag") | ||||
| 			tagOpenNode = s.TextNode(text = tagOpen) | ||||
| 			tagClose = s.Text(na_web = "Zavírací srolovací tag") | ||||
| 			tagCloseNode = s.TextNode(text = tagClose) | ||||
| 			stack.append((tagCloseNode, wd, True)) | ||||
| 			 | ||||
| 		if wn.first_child != None: | ||||
| 			stack.append((wn.first_child, wd + 1, wr)) | ||||
| 
 | ||||
| 		if isinstance(wn, s.CisloNode): | ||||
| 			posledni_cislo = wn | ||||
| 		print(wn) | ||||
| 
 | ||||
| 		if wr:						 | ||||
| 			print("ZAJIMAVE") | ||||
| 			if pouze_zajimave: | ||||
| 				if not wn.zajimave: | ||||
| 					continue | ||||
| 			returnVal.append((wn, wd)) | ||||
| 	return returnVal | ||||
|    | ||||
| def TematkoView(request, rocnik, tematko): | ||||
| 	nastaveni = s.Nastaveni.objects.first() | ||||
| 	rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik) | ||||
| 	tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko) | ||||
| 	seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode) | ||||
| 	for node, depth in seznam: | ||||
| 		if node.isinstance(node, s.KonferaNode): | ||||
| 			raise Exception("Not implemented yet") | ||||
| 		if node.isinstance(node, s.PohadkaNode): # Mohu ignorovat, má pod sebou | ||||
| 			pass | ||||
| 
 | ||||
| 	return render(request, 'seminar/tematka/toaletak.html', {}) | ||||
| 	 | ||||
| 
 | ||||
| def TemataRozcestnikView(request): | ||||
| 	print("=============================================") | ||||
| 	nastaveni = s.Nastaveni.objects.first() | ||||
| 	tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) | ||||
| 	tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku | ||||
| 	for tematko_object in tematka_objects: | ||||
| 		print("AKTUALNI TEMATKO") | ||||
| 		print(tematko_object.id) | ||||
| 		odkazy = vytahniZLesaSeznam(tematko_object, nastaveni.aktualni_rocnik().rocniknode, pouze_zajimave = True) #Odkazy jsou tuply (node, depth) v listu | ||||
| 		print(odkazy) | ||||
| 		cisla = [] # List tuplů (nazev cisla, list odkazů) | ||||
| 		vcisle = [] | ||||
| 		cislo = None | ||||
| 		for odkaz	in odkazy: | ||||
| 			if odkaz[1] == 0: | ||||
| 				if cislo != None: | ||||
| 					cisla.append((cislo, vcisle)) | ||||
| 				cislo = (odkaz[0].getOdkazStr(), odkaz[0].getOdkaz()) | ||||
| 				vcisle = [] | ||||
| 			else: | ||||
| 				print(odkaz[0].getOdkaz()) | ||||
| 				vcisle.append((odkaz[0].getOdkazStr(), odkaz[0].getOdkaz())) | ||||
| 		if cislo != None: | ||||
| 			cisla.append((cislo, vcisle)) | ||||
| 				 | ||||
| 		print(cisla) | ||||
| 		tematka.append({ | ||||
| 			"kod" : tematko_object.kod, | ||||
| 			"nazev" : tematko_object.nazev, | ||||
| 			"abstrakt" : tematko_object.abstrakt,  | ||||
| 			"obrazek": tematko_object.obrazek, | ||||
| 			"cisla" : cisla | ||||
| 		}) | ||||
| 	return render(request, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik}) | ||||
|      | ||||
| 
 | ||||
| #def ZadaniAktualniVysledkovkaView(request): | ||||
| #	nastaveni = get_object_or_404(Nastaveni) | ||||
|  | @ -672,7 +806,7 @@ def obalkyView(request,resitele): | |||
| 	return response | ||||
| 
 | ||||
| 
 | ||||
| def obalkovaniView(request, rocnik, cislo): | ||||
| def oldObalkovaniView(request, rocnik, cislo): | ||||
| 	rocnik = Rocnik.objects.get(rocnik=rocnik) | ||||
| 	cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo) | ||||
| 
 | ||||
|  | @ -809,7 +943,7 @@ def StavDatabazeView(request): | |||
| 
 | ||||
| 
 | ||||
| @ensure_csrf_cookie | ||||
| def LoginView(request): | ||||
| def TeXUploadLoginView(request): | ||||
| 	"""Pro přihlášení při nahrávání z texu""" | ||||
| 	q = request.POST | ||||
| 	# nastavení cookie csrftoken | ||||
|  | @ -1016,8 +1150,6 @@ class ResitelView(LoginRequiredMixin,generic.DetailView): | |||
| 		return Resitel.objects.get(osoba__user=self.request.user) | ||||
| 
 | ||||
| ## Formulare | ||||
| def resitelEditView(request): | ||||
| 	pass | ||||
| def resetPasswordView(request): | ||||
| 	pass | ||||
| 
 | ||||
|  | @ -1054,6 +1186,59 @@ def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data): | |||
| 	logger.warn(msg) | ||||
| 	gdpr_logger.warn(msg+", form:{}".format(form_data))		 | ||||
| 
 | ||||
| from django.forms.models import model_to_dict | ||||
| def resitelEditView(request): | ||||
|     err_logger = logging.getLogger('seminar.prihlaska.problem') | ||||
|     ## Načtení objektu Osoba a Resitel, patrici k aktuálně přihlášenému uživately | ||||
|     u = request.user | ||||
|     osoba_edit = Osoba.objects.get(user=u) | ||||
|     resitel_edit = osoba_edit.resitel | ||||
|     user_edit = osoba_edit.user | ||||
|     ## Vytvoření slovníku, kterým předvyplním formulář  | ||||
|     prefill_1=model_to_dict(user_edit) | ||||
|     prefill_2=model_to_dict(resitel_edit) | ||||
|     prefill_3=model_to_dict(osoba_edit) | ||||
|     prefill_1.update(prefill_2) | ||||
|     prefill_1.update(prefill_3) | ||||
|     form = EditForm(initial=prefill_1) | ||||
|     ## Změna údajů a jejich uložení | ||||
|     if request.method == 'POST': | ||||
|         form = EditForm(request.POST) | ||||
|         if form.is_valid(): | ||||
|             ## Změny v osobě | ||||
|             fcd = form.cleaned_data | ||||
|             osoba_edit.jmeno = fcd['jmeno'] | ||||
|             osoba_edit.prijmeni = fcd['prijmeni'] | ||||
|             osoba_edit.pohlavi_muz = fcd['pohlavi_muz'] | ||||
|             osoba_edit.email = fcd['email'] | ||||
|             osoba_edit.telefon = fcd['telefon'] | ||||
|             osoba_edit.ulice = fcd['ulice'] | ||||
|             osoba_edit.mesto = fcd['mesto'] | ||||
|             osoba_edit.psc = fcd['psc'] | ||||
|             ## Změny v osobě s podmínkami | ||||
|             if fcd.get('spam',False): | ||||
|                 osoba_edit.datum_souhlasu_zasilani = date.today() | ||||
|             if fcd.get('stat','') in ('CZ','SK'): | ||||
|                 osoba_edit.stat = fcd['stat'] | ||||
|             else: | ||||
|                 ## Neznámá země | ||||
|                 msg = "Unknown country {}".format(fcd['stat_text']) | ||||
| 
 | ||||
|             ## Změny v řešiteli | ||||
|             resitel_edit.skola = fcd['skola'] | ||||
|             resitel_edit.rok_maturity = fcd['rok_maturity'] | ||||
|             resitel_edit.zasilat = fcd['zasilat'] | ||||
|             if fcd.get('skola'): | ||||
|                 resitel_edit.skola = fcd['skola'] | ||||
|             else: | ||||
|                 # Unknown school - log it | ||||
|                 msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa']) | ||||
|             resitel_edit.save() | ||||
|             osoba_edit.save() | ||||
|             return HttpResponseRedirect('/thanks/') | ||||
|     else: | ||||
|         ## Stránka před odeslaním formuláře = předvyplněný formulář | ||||
|         return render(request, 'seminar/edit.html', {'form': form}) | ||||
| 
 | ||||
| def prihlaskaView(request): | ||||
| 	generic_logger = logging.getLogger('seminar.prihlaska') | ||||
|  | @ -1159,3 +1344,46 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView): | |||
| # 				Q(user__last_name__isstartswith=query)) | ||||
| # | ||||
| # 		return qs | ||||
| 
 | ||||
| # FIXME: Tohle asi vlastně vůbec nepatří do aplikace 'seminar' | ||||
| class LoginView(auth_views.LoginView): | ||||
| 	# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL | ||||
| 	template_name = 'seminar/login.html' | ||||
| 
 | ||||
| 	# Přesměrovací URL má být v kontextu: | ||||
| 	def get_context_data(self, **kwargs): | ||||
| 		ctx = super().get_context_data(**kwargs) | ||||
| 		ctx['next'] = reverse('titulni_strana') | ||||
| 		return ctx | ||||
| 
 | ||||
| class LogoutView(auth_views.LogoutView): | ||||
| 	# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL | ||||
| 	template_name = 'seminar/logout.html' | ||||
| 	# Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité. | ||||
| 	next_page = reverse_lazy('titulni_strana') | ||||
| 
 | ||||
| # "Chci resetovat heslo" | ||||
| class PasswordResetView(auth_views.PasswordResetView): | ||||
| 	#template_name = 'seminar/password_reset.html' | ||||
| 	# TODO: vlastní email_template_name a subject_template_name a html_email_template_name | ||||
| 	success_url = reverse_lazy('reset_password_done') | ||||
| 	from_email = 'login@mam.mff.cuni.cz' | ||||
| 
 | ||||
| # "Poslali jsme e-mail (pokud bylo kam))" | ||||
| class PasswordResetDoneView(auth_views.PasswordResetDoneView): | ||||
| 	#template_name = 'seminar/password_reset_done.html' | ||||
| 	pass | ||||
| 
 | ||||
| # "Vymysli si heslo" | ||||
| class PasswordResetConfirmView(auth_views.PasswordResetConfirmView): | ||||
| 	#template_name = 'seminar/password_confirm_done.html' | ||||
| 	success_url = reverse_lazy('reset_password_complete') | ||||
| 
 | ||||
| # "Heslo se asi změnilo." | ||||
| class PasswordResetCompleteView(auth_views.PasswordResetCompleteView): | ||||
| 	#template_name = 'seminar/password_complete_done.html' | ||||
| 	pass | ||||
| 
 | ||||
| class PasswordChangeView(auth_views.PasswordChangeView): | ||||
| 	#template_name = 'seminar/password_change.html' | ||||
| 	success_url = reverse_lazy('titulni_strana') | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Anet
						Anet