Merge branch 'data_migrations' of gimli.ms.mff.cuni.cz:/akce/mam/git/mamweb into data_migrations
This commit is contained in:
		
						commit
						6e882f75f7
					
				
					 8 changed files with 376 additions and 145 deletions
				
			
		
							
								
								
									
										27
									
								
								seminar/migrations/0078_otistenereseninode.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								seminar/migrations/0078_otistenereseninode.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | # Generated by Django 2.2.9 on 2020-03-18 23:59 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('seminar', '0077_auto_20200318_2146'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='OtisteneReseniNode', | ||||||
|  |             fields=[ | ||||||
|  |                 ('treenode_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='seminar.TreeNode')), | ||||||
|  |                 ('reseni', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='seminar.Reseni', verbose_name='reseni')), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 'verbose_name': 'Otištěné řešení (Node)', | ||||||
|  |                 'verbose_name_plural': 'Otištěná řešení (Node)', | ||||||
|  |                 'db_table': 'seminar_nodes_otistene_reseni', | ||||||
|  |             }, | ||||||
|  |             bases=('seminar.treenode',), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -1474,6 +1474,26 @@ class CastNode(TreeNode): | ||||||
| 	 | 	 | ||||||
| 	nadpis = models.CharField('Nadpis', max_length=100, help_text = 'Nadpis podvěšené části obsahu') | 	nadpis = models.CharField('Nadpis', max_length=100, help_text = 'Nadpis podvěšené části obsahu') | ||||||
| 
 | 
 | ||||||
|  | 	def aktualizuj_nazev(self): | ||||||
|  | 		self.nazev = "CastNode: "+str(self.nadpis) | ||||||
|  | 
 | ||||||
|  | 	def getOdkazStr(self): | ||||||
|  | 		return str(self.nadpis) | ||||||
|  | 
 | ||||||
|  | class OtisteneReseniNode(TreeNode): | ||||||
|  | 	class Meta: | ||||||
|  | 		db_table = 'seminar_nodes_otistene_reseni' | ||||||
|  | 		verbose_name = 'Otištěné řešení (Node)' | ||||||
|  | 		verbose_name_plural = 'Otištěná řešení (Node)' | ||||||
|  | 	reseni = models.ForeignKey(Reseni, | ||||||
|  | 		on_delete=models.PROTECT, | ||||||
|  | 		verbose_name = 'reseni') | ||||||
|  | 	 | ||||||
|  | 	def aktualizuj_nazev(self): | ||||||
|  | 		self.nazev = "OtisteneReseniNode: "+str(self.reseni) | ||||||
|  | 
 | ||||||
|  | 	def getOdkazStr(self): | ||||||
|  | 		return str(self.reseni) | ||||||
| 
 | 
 | ||||||
| ## FIXME: Logiku přesunout do views. | ## FIXME: Logiku přesunout do views. | ||||||
| #class VysledkyBase(SeminarModelBase): | #class VysledkyBase(SeminarModelBase): | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								seminar/templates/seminar/treenode.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								seminar/templates/seminar/treenode.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | {% extends "seminar/archiv/base_ulohy.html" %} | ||||||
|  | 
 | ||||||
|  | {% load comments %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  | 
 | ||||||
|  | {%with obj=tnldata depth=1 template_name="seminar/treenode_recursive.html" %} | ||||||
|  |    {%include template_name%} | ||||||
|  | {%endwith%} | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										28
									
								
								seminar/templates/seminar/treenode_recursive.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								seminar/templates/seminar/treenode_recursive.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | {% load treenodes %} | ||||||
|  | {# <b>{{depth}}</b> #} | ||||||
|  | <div> | ||||||
|  | {%   if obj.node|isRocnik %} | ||||||
|  | <h{{depth}}> Ročník {{obj.node.rocnik}} </h{{depth}}> | ||||||
|  | {% elif obj.node|isCislo %} | ||||||
|  | <h{{depth}}> Číslo {{obj.node.cislo}} </h{{depth}}> | ||||||
|  | {% elif obj.node|isTemaVCisle %} | ||||||
|  | <h{{depth}}> Téma {{obj.node.tema.nazev}} </h{{depth}}> | ||||||
|  | {% elif obj.node|isUlohaZadani %} | ||||||
|  | <h{{depth}}>Úloha {{obj.node.uloha.kod_v_rocniku}} ({{obj.node.uloha.max_body}} b)</h{{depth}}> | ||||||
|  | {% elif obj.node|isUlohaVzorak %} | ||||||
|  | <h{{depth}}>Řešení: {{obj.node.uloha.kod_v_rocniku}}</h{{depth}}> | ||||||
|  | {% elif obj.node|isText %} | ||||||
|  | {{obj.node.text.na_web}} | ||||||
|  | {% else %} | ||||||
|  | Objekt jiného typu {{obj.node}} | ||||||
|  | {% endif %} | ||||||
|  |     {%if obj.children %} | ||||||
|  | 	<div> | ||||||
|  |          {%for ch in obj.children %} | ||||||
|  |               {%with obj=ch depth=depth|add:"1" template_name="seminar/treenode_recursive.html" %} | ||||||
|  |                    {%include template_name%} | ||||||
|  |               {%endwith%} | ||||||
|  |          {%endfor%} | ||||||
|  | 	</div> | ||||||
|  |     {%endif%} | ||||||
|  | </div> | ||||||
							
								
								
									
										49
									
								
								seminar/templatetags/treenodes.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								seminar/templatetags/treenodes.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | from django import template | ||||||
|  | import seminar.models as m | ||||||
|  | 
 | ||||||
|  | register = template.Library() | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isRocnik(value): | ||||||
|  |     return isinstance(value, m.RocnikNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isCislo(value): | ||||||
|  |     return isinstance(value, m.CisloNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isCast(value): | ||||||
|  |     return isinstance(value, m.CastNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isText(value): | ||||||
|  |     return isinstance(value, m.TextNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isTemaVCisle(value): | ||||||
|  |     return isinstance(value, m.TemaVCisleNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isKonfera(value): | ||||||
|  |     return isinstance(value, m.KonferaNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isClanek(value): | ||||||
|  |     return isinstance(value, m.ClanekNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isUlohaVzorak(value): | ||||||
|  |     return isinstance(value, m.UlohaVzorakNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isUlohaZadani(value): | ||||||
|  |     return isinstance(value, m.UlohaZadaniNode) | ||||||
|  | 
 | ||||||
|  | @register.filter | ||||||
|  | def isPohadka(value): | ||||||
|  |     return isinstance(value, m.PohadkaNode) | ||||||
|  | 
 | ||||||
|  | #@register.filter | ||||||
|  | #def isOtisteneReseniNode(value): | ||||||
|  | #    return isinstance(value, m.OtisteneReseniNode) | ||||||
|  | 
 | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| from django.core.exceptions import ObjectDoesNotExist | from django.core.exceptions import ObjectDoesNotExist | ||||||
| # NOTE: node.prev a node.succ jsou implementovány přímo v models.TreeNode | # NOTE: node.prev a node.succ jsou implementovány přímo v models.TreeNode | ||||||
| # TODO: Všechny tyto funkce se naivně spoléhají na to, že jako parametr dostanou nějaký TreeNode (některé možná zvládnou i None) | # TODO: Všechny tyto funkce se naivně spoléhají na to, že jako parametr dostanou nějaký TreeNode (některé možná zvládnou i None) | ||||||
|  | # TODO: Chceme, aby všechno nějak zvládlo None jako parametr. | ||||||
| 
 | 
 | ||||||
| # Slouží k debugování pro rychlé získání představy o podobě podstromu pod tímto TreeNode. | # Slouží k debugování pro rychlé získání představy o podobě podstromu pod tímto TreeNode. | ||||||
| def print_tree(node,indent=0): | def print_tree(node,indent=0): | ||||||
|  | @ -18,9 +19,19 @@ def safe_pred(node): | ||||||
| 	except ObjectDoesNotExist: | 	except ObjectDoesNotExist: | ||||||
| 		return None | 		return None | ||||||
| 
 | 
 | ||||||
|  | def first_brother(node): | ||||||
|  | 	if node is None: | ||||||
|  | 		return None | ||||||
|  | 	brother = node | ||||||
|  | 	while safe_pred(brother) is not None: | ||||||
|  | 		brother = safe_pred(brother) | ||||||
|  | 	return brother | ||||||
|  | 
 | ||||||
| # A to samé pro .father_of_first | # A to samé pro .father_of_first | ||||||
| def safe_father_of_first(node): | def safe_father_of_first(node): | ||||||
| 		return node.prev | 	first = first_brother(node) | ||||||
|  | 	try: | ||||||
|  | 		return first.father_of_first | ||||||
| 	except ObjectDoesNotExist: | 	except ObjectDoesNotExist: | ||||||
| 		return None | 		return None | ||||||
| 
 | 
 | ||||||
|  | @ -61,14 +72,34 @@ def general_prev(node): | ||||||
| 	# pred nyní nemá žádné potomky, takže je to poslední rekurzivní potomek původního předchůdce | 	# pred nyní nemá žádné potomky, takže je to poslední rekurzivní potomek původního předchůdce | ||||||
| 	return pred | 	return pred | ||||||
| 
 | 
 | ||||||
| # Generátor bratrů | # Generátor pravých bratrů (konkrétně sebe a následujících potomků) | ||||||
| # Generátor potomků níže spoléhá na to, že se tohle dá volat i s parametrem None. | # Generátor potomků níže spoléhá na to, že se tohle dá volat i s parametrem None. | ||||||
| def all_brothers(node): | def me_and_right_brothers(node): | ||||||
| 	current = node | 	current = node | ||||||
| 	while current is not None: | 	while current is not None: | ||||||
| 		yield current | 		yield current | ||||||
| 		current = current.succ | 		current = current.succ | ||||||
| 
 | 
 | ||||||
|  | def right_brothers(node): | ||||||
|  | 	generator = me_and_right_brothers(node.succ) | ||||||
|  | 	for item in generator: | ||||||
|  | 		yield item | ||||||
|  | 
 | ||||||
|  | # Generátor všech sourozenců (vč. sám sebe) | ||||||
|  | def all_brothers(node): | ||||||
|  | 	# Najdeme prvního bratra | ||||||
|  | 	fb = first_brother(node) | ||||||
|  | 	marb = me_and_right_brothers(fb) | ||||||
|  | 	for cur in marb: | ||||||
|  | 		yield cur | ||||||
|  | 	 | ||||||
|  | def all_proper_brothers(node): | ||||||
|  | 	all = all_brothers(node) | ||||||
|  | 	for br in all: | ||||||
|  | 		if br is node: | ||||||
|  | 			continue | ||||||
|  | 		yield br | ||||||
|  | 
 | ||||||
| # Generátor potomků | # Generátor potomků | ||||||
| def all_children(node): | def all_children(node): | ||||||
| 	brothers = all_brothers(node.first_child) | 	brothers = all_brothers(node.first_child) | ||||||
|  | @ -76,44 +107,129 @@ def all_children(node): | ||||||
| 		yield br | 		yield br | ||||||
| 
 | 
 | ||||||
| # Generátor následníků v "the-right-order" | # Generátor následníků v "the-right-order" | ||||||
|  | # Bez tohoto vrcholu | ||||||
|  | def all_following(node): | ||||||
|  | 	current = general_next(node) | ||||||
|  | 	while current is not None: | ||||||
|  | 		yield current | ||||||
|  | 		current = general_next(current) | ||||||
| 
 | 
 | ||||||
| ## Filtrační hledání | ## Filtrační hledání | ||||||
| # Najdi dalšího bratra nějakého typu, nebo None. | # Najdi dalšího bratra nějakého typu, nebo None. | ||||||
| # hledá i podtřídy, i.e. get_next_brother_of_type(neco, TreeNode) je prostě succ. | # hledá i podtřídy, i.e. get_next_brother_of_type(neco, TreeNode) je prostě succ. | ||||||
| def get_next_brother_of_type(current, type): | def get_next_brother_of_type(node, type): | ||||||
| 	pass | 	for current in right_brothers(node): | ||||||
| def get_prev_brother_of_type(current, type): | 		if isinstance(current, type): | ||||||
| 	pass | 			return current | ||||||
|  | 	return None | ||||||
|  | 	 | ||||||
|  | def get_prev_brother_of_type(node, type): | ||||||
|  | 	# Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem. | ||||||
|  | 	current = node | ||||||
|  | 	while safe_pred(current) is not None: | ||||||
|  | 		current = safe_pred(current) | ||||||
|  | 		if isinstance(current, type): | ||||||
|  | 			return current | ||||||
|  | 	return None | ||||||
| 
 | 
 | ||||||
| # Totéž pro "the-right-order" pořadí | # Totéž pro "the-right-order" pořadí | ||||||
| def get_next_node_of_type(current, type): | def get_next_node_of_type(node, type): | ||||||
| 	pass | 	for cur in all_folowing(node): | ||||||
| def get_next_node_of_type(current, type): | 		if isinstance(cur, type): | ||||||
| 	pass | 			return cur | ||||||
|  | 	return None | ||||||
|  | 
 | ||||||
|  | def get_prev_node_of_type(node, type): | ||||||
|  | 	# Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem. | ||||||
|  | 	current = node | ||||||
|  | 	while general_prev(current) is not None: | ||||||
|  | 		current = general_prev(current) | ||||||
|  | 		if isinstance(current, type): | ||||||
|  | 			return current | ||||||
|  | 	return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Editace stromu: | # Editace stromu: | ||||||
| def create_node_after(predecessor, type, **kwargs): | def create_node_after(predecessor, type, **kwargs): | ||||||
| 	pass | 	new_node = type.objects.create(**kwargs) | ||||||
|  | 	new_node.save() | ||||||
|  | 	succ = predecessor.succ | ||||||
|  | 	predecessor.succ = new_node | ||||||
|  | 	predecessor.save() | ||||||
|  | 	new_node.succ = succ | ||||||
|  | 	new_node.save() | ||||||
| 
 | 
 | ||||||
| # Vyrábí prvního syna, ostatní nalepí za (existují-li) | # Vyrábí prvního syna, ostatní nalepí za (existují-li) | ||||||
| def create_child(parent, type, **kwargs): | def create_child(parent, type, **kwargs): | ||||||
| 	pass | 	new_node = type.objects.create(**kwargs) | ||||||
|  | 	new_node.save() | ||||||
|  | 	orig_child = parent.first_child | ||||||
|  | 	parent.first_child = new_node | ||||||
|  | 	parent.save() | ||||||
|  | 	if orig_child is not None: | ||||||
|  | 		# Přidáme původního prvního syna jako potomka nového vrcholu | ||||||
|  | 		new_node.succ = orig_child | ||||||
|  | 		new_node.save() | ||||||
|  | 
 | ||||||
|  | def create_node_before(successor, type, **kwargs): | ||||||
|  | 	if safe_pred(successor) is not None: | ||||||
|  | 		# Easy: přidáme za předchůdce | ||||||
|  | 		create_node_after(successor.prev, type, **kwargs) | ||||||
|  | 	# Nemáme předchůdce, jsme tedy první z bratrů. Máme otce? | ||||||
|  | 	if safe_father_of_first(successor) is not None: | ||||||
|  | 		# Ano -> Easy: vyrobíme nového potomka | ||||||
|  | 		# NOTE: Tohle je možná trošku abuse implementace výše, ale to nevadí moc... | ||||||
|  | 		create_child(successor.father_of_first, type, **kwargs) | ||||||
|  | 	# Teď už easy: Jsme sirotci, takže se vyrobíme a našeho následníka si přidáme jako succ | ||||||
|  | 	new = type.objects.create(**kwargs) | ||||||
|  | 	new.succ = successor | ||||||
|  | 	new.save() | ||||||
| 
 | 
 | ||||||
| def create_node_before(some, arguments, but, i, dont, know, which, yet): |  | ||||||
| 	pass |  | ||||||
| 	# Tohle bude hell. |  | ||||||
| 
 | 
 | ||||||
| # ValueError, pokud je (aspoň) jeden parametr None | # ValueError, pokud je (aspoň) jeden parametr None | ||||||
| def swap(node, other): | def swap(node, other): | ||||||
|  | 	raise NotImplementedError("YAGNI (You aren't gonna need it).") | ||||||
|  | 
 | ||||||
|  | # Exception, kterou některé metody při špatném použití mohou házet | ||||||
|  | # Hlavní důvod je možnost informovat o selhání, aby se příslušný problém dal zobrazit na frontendu, | ||||||
|  | class TreeLibError(RuntimeError): | ||||||
| 	pass | 	pass | ||||||
| 
 | 
 | ||||||
| def swap_pred(node): | def swap_pred(node): | ||||||
| 	pass | 	if node is None: | ||||||
|  | 		raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.") | ||||||
|  | 	pred = safe_pred(node) | ||||||
|  | 	if pred is None: | ||||||
|  | 		raise TreeLibError("Nelze posunout vlevo, není tam žádný další uzel.") | ||||||
|  | 	pre_pred = safe_pred(pred) | ||||||
|  | 	succ = node.succ | ||||||
|  | 
 | ||||||
|  | 	if pre_pred is not None: | ||||||
|  | 		pre_pred.succ = node | ||||||
|  | 		pre_pred.save() | ||||||
|  | 	node.succ = pred | ||||||
|  | 	node.save() | ||||||
|  | 	pred.succ = succ | ||||||
|  | 	pred.save() | ||||||
|  | 
 | ||||||
| def swap_succ(node): | def swap_succ(node): | ||||||
| 	pass | 	if node is None: | ||||||
|  | 		raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.") | ||||||
|  | 	succ = node.succ | ||||||
|  | 	if succ is None: | ||||||
|  | 		raise TreeLibError("Nelze posunout vpravo, není tam žádný další uzel") | ||||||
|  | 	pred = safe_pred(node) | ||||||
|  | 	post_succ = succ.succ | ||||||
|  | 
 | ||||||
|  | 	if pred is not None: | ||||||
|  | 		pred.succ = succ | ||||||
|  | 		pred.save() | ||||||
|  | 	succ.succ = node | ||||||
|  | 	succ.save() | ||||||
|  | 	node.succ = post_succ | ||||||
|  | 	node.save() | ||||||
| 
 | 
 | ||||||
| # Rotace stromu | # Rotace stromu | ||||||
| # Dokumentace viz wiki: | # Dokumentace viz wiki: | ||||||
|  |  | ||||||
|  | @ -8,8 +8,8 @@ from django.contrib.auth import views as auth_views | ||||||
| staff_member_required = user_passes_test(lambda u: u.is_staff) | staff_member_required = user_passes_test(lambda u: u.is_staff) | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|   path('aktualni/temata/', views.TemataRozcestnikView), | #	path('aktualni/temata/', views.TemataRozcestnikView), | ||||||
| 	path('<int:rocnik>/t<int:tematko>/', views.TematkoView), | #	path('<int:rocnik>/t<int:tematko>/', views.TematkoView), | ||||||
| 
 | 
 | ||||||
| 	# REDIRECTy | 	# REDIRECTy | ||||||
| 	path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')), | 	path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')), | ||||||
|  | @ -25,6 +25,7 @@ urlpatterns = [ | ||||||
| 	path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'), | 	path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'), | ||||||
| 	path('cislo/<int:rocnik>.<int:cislo>/', views.CisloView.as_view(), name='seminar_cislo'), | 	path('cislo/<int:rocnik>.<int:cislo>/', views.CisloView.as_view(), name='seminar_cislo'), | ||||||
| 	path('problem/<int:pk>/', views.ProblemView.as_view(), name='seminar_problem'), | 	path('problem/<int:pk>/', views.ProblemView.as_view(), name='seminar_problem'), | ||||||
|  | 	path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='seminar_treenode'), | ||||||
| 	#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), | 	#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), | ||||||
| 
 | 
 | ||||||
| 	# Soustredeni | 	# Soustredeni | ||||||
|  | @ -59,8 +60,8 @@ urlpatterns = [ | ||||||
| 	), | 	), | ||||||
| 
 | 
 | ||||||
| 	# Zadani | 	# Zadani | ||||||
| 	path('zadani/aktualni/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), | #	path('zadani/aktualni/', views.AktualniZadaniView, name='seminar_aktualni_zadani'), | ||||||
| 	path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'), | #	path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'), | ||||||
| 	#path('zadani/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'), | 	#path('zadani/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'), | ||||||
| 	path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), | 	path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'), | ||||||
| 
 | 
 | ||||||
|  | @ -107,9 +108,6 @@ urlpatterns = [ | ||||||
| 	path('auth/login/', views.LoginView.as_view(), name='login'), | 	path('auth/login/', views.LoginView.as_view(), name='login'), | ||||||
| 	path('auth/logout/', views.LogoutView.as_view(), name='logout'), | 	path('auth/logout/', views.LogoutView.as_view(), name='logout'), | ||||||
| 	path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'), | 	path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'), | ||||||
| 	path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), |  | ||||||
| 	path('autocomplete/resitel/',views.ResitelAutocomplete.as_view(), name='autocomplete_resitel'), |  | ||||||
| 	path('autocomplete/problem/odevzdatelny',views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), |  | ||||||
| 	path('auth/reset_password/', views.PasswordResetView.as_view(), 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/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_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'), | ||||||
|  | @ -117,6 +115,10 @@ urlpatterns = [ | ||||||
| 	path('auth/reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), | 	path('auth/reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), | ||||||
| 	path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'), | 	path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'), | ||||||
| 
 | 
 | ||||||
|  | 	# Autocomplete | ||||||
|  | 	path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), | ||||||
|  | 	path('autocomplete/resitel/',views.ResitelAutocomplete.as_view(), name='autocomplete_resitel'), | ||||||
|  | 	path('autocomplete/problem/odevzdatelny',views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), | ||||||
| 
 | 
 | ||||||
| 	path('temp/add_solution', views.AddSolutionView.as_view(),name='seminar_vloz_reseni'), | 	path('temp/add_solution', views.AddSolutionView.as_view(),name='seminar_vloz_reseni'), | ||||||
| 	path('temp/submit_solution', views.SubmitSolutionView.as_view(),name='seminar_nahraj_reseni'), | 	path('temp/submit_solution', views.SubmitSolutionView.as_view(),name='seminar_nahraj_reseni'), | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ from django.db import transaction | ||||||
| import seminar.models as s | import seminar.models as s | ||||||
| from seminar.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 seminar.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 .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | ||||||
| from seminar import utils | from seminar import utils,treelib | ||||||
| from .unicodecsv import UnicodeWriter | from .unicodecsv import UnicodeWriter | ||||||
| from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm | from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm | ||||||
| import seminar.forms as f | import seminar.forms as f | ||||||
|  | @ -83,131 +83,110 @@ class ObalkovaniView(generic.ListView): | ||||||
| 		context['cislo'] = self.cislo  | 		context['cislo'] = self.cislo  | ||||||
| 		return context | 		return context | ||||||
| 
 | 
 | ||||||
|  | class TNLData(object): | ||||||
|  | 	def __init__(self,anode): | ||||||
|  | 		self.node = anode | ||||||
|  | 		self.children = [] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def treenode_strom_na_seznamy(node): | ||||||
|  | 	out = TNLData(node) | ||||||
|  | 	for ch in treelib.all_children(node): | ||||||
|  | 		outitem = treenode_strom_na_seznamy(ch) | ||||||
|  | 		out.children.append(outitem) | ||||||
|  | 	return out | ||||||
| 
 | 
 | ||||||
| def AktualniZadaniView(request): | class TreeNodeView(generic.DetailView): | ||||||
| 	nastaveni = get_object_or_404(Nastaveni) | 	model = s.TreeNode | ||||||
| 	verejne = nastaveni.aktualni_cislo.verejne() | 	template_name = 'seminar/treenode.html' | ||||||
| 	problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') |  | ||||||
| 	ulohy = problemy.filter(typ = 'uloha').order_by('kod') |  | ||||||
| 	serialy = problemy.filter(typ = 'serial').order_by('kod') |  | ||||||
| 	jednorazove_problemy = [ulohy, serialy] |  | ||||||
| 	return render(request, 'seminar/zadani/AktualniZadani.html', |  | ||||||
| 			{'nastaveni': nastaveni, |  | ||||||
| 			 'jednorazove_problemy': jednorazove_problemy, |  | ||||||
| 			 'temata': verejna_temata(nastaveni.aktualni_rocnik), |  | ||||||
| 			 'verejne': verejne, |  | ||||||
| 				}, |  | ||||||
| 			) |  | ||||||
| 
 | 
 | ||||||
| def ZadaniTemataView(request): | 	def get_context_data(self,**kwargs): | ||||||
| 	nastaveni = get_object_or_404(Nastaveni) | 		context = super().get_context_data(**kwargs) | ||||||
| 	temata = verejna_temata(nastaveni.aktualni_rocnik) | 		context['tnldata'] = treenode_strom_na_seznamy(self.object) | ||||||
| 	for t in temata: | 		return context | ||||||
| 		if request.user.is_staff: |  | ||||||
| 			t.prispevky = t.prispevek_set.filter(problem=t) |  | ||||||
| 		else: |  | ||||||
| 			t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True) |  | ||||||
| 	return render(request, 'seminar/zadani/Temata.html', |  | ||||||
| 		{ |  | ||||||
| 			'temata': temata, |  | ||||||
| 		} |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| # 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("=============================================") | #def AktualniZadaniView(request): | ||||||
| 	nastaveni = s.Nastaveni.objects.first() | #	nastaveni = get_object_or_404(Nastaveni) | ||||||
| 	tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik()) | #	verejne = nastaveni.aktualni_cislo.verejne() | ||||||
| 	tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku | #	problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany') | ||||||
| 	for tematko_object in tematka_objects: | #	ulohy = problemy.filter(typ = 'uloha').order_by('kod') | ||||||
| 		print("AKTUALNI TEMATKO") | #	serialy = problemy.filter(typ = 'serial').order_by('kod') | ||||||
| 		print(tematko_object.id) | #	jednorazove_problemy = [ulohy, serialy] | ||||||
| 		odkazy = vytahniZLesaSeznam(tematko_object, nastaveni.aktualni_rocnik().rocniknode, pouze_zajimave = True) #Odkazy jsou tuply (node, depth) v listu | #	return render(request, 'seminar/zadani/AktualniZadani.html', | ||||||
| 		print(odkazy) | #			{'nastaveni': nastaveni, | ||||||
| 		cisla = [] # List tuplů (nazev cisla, list odkazů) | #			 'jednorazove_problemy': jednorazove_problemy, | ||||||
| 		vcisle = [] | #			 'temata': verejna_temata(nastaveni.aktualni_rocnik), | ||||||
| 		cislo = None | #			 'verejne': verejne, | ||||||
| 		for odkaz	in odkazy: | #				}, | ||||||
| 			if odkaz[1] == 0: | #			) | ||||||
| 				if cislo != None: | # | ||||||
| 					cisla.append((cislo, vcisle)) | #def ZadaniTemataView(request): | ||||||
| 				cislo = (odkaz[0].getOdkazStr(), odkaz[0].getOdkaz()) | #	nastaveni = get_object_or_404(Nastaveni) | ||||||
| 				vcisle = [] | #	temata = verejna_temata(nastaveni.aktualni_rocnik) | ||||||
| 			else: | #	for t in temata: | ||||||
| 				print(odkaz[0].getOdkaz()) | #		if request.user.is_staff: | ||||||
| 				vcisle.append((odkaz[0].getOdkazStr(), odkaz[0].getOdkaz())) | #			t.prispevky = t.prispevek_set.filter(problem=t) | ||||||
| 		if cislo != None: | #		else: | ||||||
| 			cisla.append((cislo, vcisle)) | #			t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True) | ||||||
| 				 | #	return render(request, 'seminar/zadani/Temata.html', | ||||||
| 		print(cisla) | #		{ | ||||||
| 		tematka.append({ | #			'temata': temata, | ||||||
| 			"kod" : tematko_object.kod, | #		} | ||||||
| 			"nazev" : tematko_object.nazev, | #	) | ||||||
| 			"abstrakt" : tematko_object.abstrakt,  | # | ||||||
| 			"obrazek": tematko_object.obrazek, | # | ||||||
| 			"cisla" : cisla | #   | ||||||
| 		}) | #def TematkoView(request, rocnik, tematko): | ||||||
| 	return render(request, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik}) | #	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): | #def ZadaniAktualniVysledkovkaView(request): | ||||||
| #	nastaveni = get_object_or_404(Nastaveni) | #	nastaveni = get_object_or_404(Nastaveni) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Anet
						Anet