Merge branch 'refs/heads/prednasky'
This commit is contained in:
		
						commit
						683796ea7e
					
				
					 14 changed files with 567 additions and 218 deletions
				
			
		
							
								
								
									
										144
									
								
								data/groups.json
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								data/groups.json
									
									
									
									
									
								
							|  | @ -14,12 +14,12 @@ | |||
| 					"flatpage" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_flatpage", | ||||
| 					"change_flatpage", | ||||
| 					"flatpages", | ||||
| 					"flatpage" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_flatpage", | ||||
| 					"delete_flatpage", | ||||
| 					"flatpages", | ||||
| 					"flatpage" | ||||
| 				], | ||||
|  | @ -34,12 +34,12 @@ | |||
| 					"galerie" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_galerie", | ||||
| 					"change_galerie", | ||||
| 					"galerie", | ||||
| 					"galerie" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_galerie", | ||||
| 					"delete_galerie", | ||||
| 					"galerie", | ||||
| 					"galerie" | ||||
| 				], | ||||
|  | @ -54,12 +54,12 @@ | |||
| 					"obrazek" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_obrazek", | ||||
| 					"change_obrazek", | ||||
| 					"galerie", | ||||
| 					"obrazek" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_obrazek", | ||||
| 					"delete_obrazek", | ||||
| 					"galerie", | ||||
| 					"obrazek" | ||||
| 				], | ||||
|  | @ -104,12 +104,12 @@ | |||
| 					"komentar" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_komentar", | ||||
| 					"change_komentar", | ||||
| 					"korektury", | ||||
| 					"komentar" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_komentar", | ||||
| 					"delete_komentar", | ||||
| 					"korektury", | ||||
| 					"komentar" | ||||
| 				], | ||||
|  | @ -124,12 +124,12 @@ | |||
| 					"korekturovanepdf" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_korekturovanepdf", | ||||
| 					"change_korekturovanepdf", | ||||
| 					"korektury", | ||||
| 					"korekturovanepdf" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_korekturovanepdf", | ||||
| 					"delete_korekturovanepdf", | ||||
| 					"korektury", | ||||
| 					"korekturovanepdf" | ||||
| 				], | ||||
|  | @ -144,12 +144,12 @@ | |||
| 					"oprava" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_oprava", | ||||
| 					"change_oprava", | ||||
| 					"korektury", | ||||
| 					"oprava" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_oprava", | ||||
| 					"delete_oprava", | ||||
| 					"korektury", | ||||
| 					"oprava" | ||||
| 				], | ||||
|  | @ -164,12 +164,12 @@ | |||
| 					"novinky" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_novinky", | ||||
| 					"change_novinky", | ||||
| 					"novinky", | ||||
| 					"novinky" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_novinky", | ||||
| 					"delete_novinky", | ||||
| 					"novinky", | ||||
| 					"novinky" | ||||
| 				], | ||||
|  | @ -204,12 +204,12 @@ | |||
| 					"prijemce" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_prijemce", | ||||
| 					"change_prijemce", | ||||
| 					"personalni", | ||||
| 					"prijemce" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_prijemce", | ||||
| 					"delete_prijemce", | ||||
| 					"personalni", | ||||
| 					"prijemce" | ||||
| 				], | ||||
|  | @ -234,12 +234,12 @@ | |||
| 					"skola" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_skola", | ||||
| 					"change_skola", | ||||
| 					"personalni", | ||||
| 					"skola" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_skola", | ||||
| 					"delete_skola", | ||||
| 					"personalni", | ||||
| 					"skola" | ||||
| 				], | ||||
|  | @ -248,38 +248,28 @@ | |||
| 					"personalni", | ||||
| 					"skola" | ||||
| 				], | ||||
| 				[ | ||||
| 					"add_hlasovani", | ||||
| 					"prednasky", | ||||
| 					"hlasovani" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_hlasovani", | ||||
| 					"prednasky", | ||||
| 					"hlasovani" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_hlasovani", | ||||
| 					"prednasky", | ||||
| 					"hlasovani" | ||||
| 				], | ||||
| 				[ | ||||
| 					"view_hlasovani", | ||||
| 					"prednasky", | ||||
| 					"hlasovani" | ||||
| 				], | ||||
| 				[ | ||||
| 					"view_hlasovanioznalostech", | ||||
| 					"prednasky", | ||||
| 					"hlasovanioznalostech" | ||||
| 				], | ||||
| 				[ | ||||
| 					"add_prednaska", | ||||
| 					"prednasky", | ||||
| 					"prednaska" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_prednaska", | ||||
| 					"change_prednaska", | ||||
| 					"prednasky", | ||||
| 					"prednaska" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_prednaska", | ||||
| 					"delete_prednaska", | ||||
| 					"prednasky", | ||||
| 					"prednaska" | ||||
| 				], | ||||
|  | @ -294,12 +284,12 @@ | |||
| 					"seznam" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_seznam", | ||||
| 					"change_seznam", | ||||
| 					"prednasky", | ||||
| 					"seznam" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_seznam", | ||||
| 					"delete_seznam", | ||||
| 					"prednasky", | ||||
| 					"seznam" | ||||
| 				], | ||||
|  | @ -308,18 +298,38 @@ | |||
| 					"prednasky", | ||||
| 					"seznam" | ||||
| 				], | ||||
| 				[ | ||||
| 					"add_znalost", | ||||
| 					"prednasky", | ||||
| 					"znalost" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_znalost", | ||||
| 					"prednasky", | ||||
| 					"znalost" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_znalost", | ||||
| 					"prednasky", | ||||
| 					"znalost" | ||||
| 				], | ||||
| 				[ | ||||
| 					"view_znalost", | ||||
| 					"prednasky", | ||||
| 					"znalost" | ||||
| 				], | ||||
| 				[ | ||||
| 					"add_konfera", | ||||
| 					"soustredeni", | ||||
| 					"konfera" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_konfera", | ||||
| 					"change_konfera", | ||||
| 					"soustredeni", | ||||
| 					"konfera" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_konfera", | ||||
| 					"delete_konfera", | ||||
| 					"soustredeni", | ||||
| 					"konfera" | ||||
| 				], | ||||
|  | @ -334,12 +344,12 @@ | |||
| 					"konfery_ucastnici" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_konfery_ucastnici", | ||||
| 					"change_konfery_ucastnici", | ||||
| 					"soustredeni", | ||||
| 					"konfery_ucastnici" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_konfery_ucastnici", | ||||
| 					"delete_konfery_ucastnici", | ||||
| 					"soustredeni", | ||||
| 					"konfery_ucastnici" | ||||
| 				], | ||||
|  | @ -354,12 +364,12 @@ | |||
| 					"soustredeni" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_soustredeni", | ||||
| 					"change_soustredeni", | ||||
| 					"soustredeni", | ||||
| 					"soustredeni" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_soustredeni", | ||||
| 					"delete_soustredeni", | ||||
| 					"soustredeni", | ||||
| 					"soustredeni" | ||||
| 				], | ||||
|  | @ -374,12 +384,12 @@ | |||
| 					"soustredeni_organizatori" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_soustredeni_organizatori", | ||||
| 					"change_soustredeni_organizatori", | ||||
| 					"soustredeni", | ||||
| 					"soustredeni_organizatori" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_soustredeni_organizatori", | ||||
| 					"delete_soustredeni_organizatori", | ||||
| 					"soustredeni", | ||||
| 					"soustredeni_organizatori" | ||||
| 				], | ||||
|  | @ -394,12 +404,12 @@ | |||
| 					"soustredeni_ucastnici" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_soustredeni_ucastnici", | ||||
| 					"change_soustredeni_ucastnici", | ||||
| 					"soustredeni", | ||||
| 					"soustredeni_ucastnici" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_soustredeni_ucastnici", | ||||
| 					"delete_soustredeni_ucastnici", | ||||
| 					"soustredeni", | ||||
| 					"soustredeni_ucastnici" | ||||
| 				], | ||||
|  | @ -414,12 +424,12 @@ | |||
| 					"tag" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_tag", | ||||
| 					"change_tag", | ||||
| 					"taggit", | ||||
| 					"tag" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_tag", | ||||
| 					"delete_tag", | ||||
| 					"taggit", | ||||
| 					"tag" | ||||
| 				], | ||||
|  | @ -434,12 +444,12 @@ | |||
| 					"taggeditem" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_taggeditem", | ||||
| 					"change_taggeditem", | ||||
| 					"taggit", | ||||
| 					"taggeditem" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_taggeditem", | ||||
| 					"delete_taggeditem", | ||||
| 					"taggit", | ||||
| 					"taggeditem" | ||||
| 				], | ||||
|  | @ -454,12 +464,12 @@ | |||
| 					"cislo" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_cislo", | ||||
| 					"change_cislo", | ||||
| 					"tvorba", | ||||
| 					"cislo" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_cislo", | ||||
| 					"delete_cislo", | ||||
| 					"tvorba", | ||||
| 					"cislo" | ||||
| 				], | ||||
|  | @ -474,12 +484,12 @@ | |||
| 					"clanek" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_clanek", | ||||
| 					"change_clanek", | ||||
| 					"tvorba", | ||||
| 					"clanek" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_clanek", | ||||
| 					"delete_clanek", | ||||
| 					"tvorba", | ||||
| 					"clanek" | ||||
| 				], | ||||
|  | @ -509,12 +519,12 @@ | |||
| 					"pohadka" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_pohadka", | ||||
| 					"change_pohadka", | ||||
| 					"tvorba", | ||||
| 					"pohadka" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_pohadka", | ||||
| 					"delete_pohadka", | ||||
| 					"tvorba", | ||||
| 					"pohadka" | ||||
| 				], | ||||
|  | @ -529,12 +539,12 @@ | |||
| 					"problem" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_problem", | ||||
| 					"change_problem", | ||||
| 					"tvorba", | ||||
| 					"problem" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_problem", | ||||
| 					"delete_problem", | ||||
| 					"tvorba", | ||||
| 					"problem" | ||||
| 				], | ||||
|  | @ -549,12 +559,12 @@ | |||
| 					"rocnik" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_rocnik", | ||||
| 					"change_rocnik", | ||||
| 					"tvorba", | ||||
| 					"rocnik" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_rocnik", | ||||
| 					"delete_rocnik", | ||||
| 					"tvorba", | ||||
| 					"rocnik" | ||||
| 				], | ||||
|  | @ -569,12 +579,12 @@ | |||
| 					"tema" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_tema", | ||||
| 					"change_tema", | ||||
| 					"tvorba", | ||||
| 					"tema" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_tema", | ||||
| 					"delete_tema", | ||||
| 					"tvorba", | ||||
| 					"tema" | ||||
| 				], | ||||
|  | @ -589,12 +599,12 @@ | |||
| 					"uloha" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_uloha", | ||||
| 					"change_uloha", | ||||
| 					"tvorba", | ||||
| 					"uloha" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_uloha", | ||||
| 					"delete_uloha", | ||||
| 					"tvorba", | ||||
| 					"uloha" | ||||
| 				], | ||||
|  | @ -609,12 +619,12 @@ | |||
| 					"nastaveni" | ||||
| 				], | ||||
| 				[ | ||||
| 					"delete_nastaveni", | ||||
| 					"change_nastaveni", | ||||
| 					"various", | ||||
| 					"nastaveni" | ||||
| 				], | ||||
| 				[ | ||||
| 					"change_nastaveni", | ||||
| 					"delete_nastaveni", | ||||
| 					"various", | ||||
| 					"nastaveni" | ||||
| 				], | ||||
|  |  | |||
|  | @ -57,6 +57,7 @@ DOBA_ODHLASENI_PRI_ZASKRTNUTI_NEODHLASOVAT = 365 * 24 * 3600  # rok | |||
| CSRF_FAILURE_VIEW = 'various.views.csrf.csrf_error' | ||||
| 
 | ||||
| # Modules configuration | ||||
| FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer" | ||||
| 
 | ||||
| AUTHENTICATION_BACKENDS = ( | ||||
| 	'django.contrib.auth.backends.ModelBackend', | ||||
|  |  | |||
|  | @ -503,5 +503,10 @@ label[for=id_skola] { | |||
| 	font-weight: bold; | ||||
| } | ||||
| 
 | ||||
| /* Přednášky */ | ||||
| .textznalosti, .textprednasky { | ||||
| 	font-style: italic; | ||||
| } | ||||
| 
 | ||||
| /*******************/ | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| """ | ||||
| Aplikace umožňující orgům vypisovat si přednášky a účastníkům o nich hlasovat. | ||||
| """ | ||||
|  | @ -4,11 +4,15 @@ from reversion.admin import VersionAdmin | |||
| from django.utils.safestring import mark_safe | ||||
| from django.utils.html import escape | ||||
| 
 | ||||
| from .models import Prednaska, Seznam, STAV_NAVRH | ||||
| from .models import Prednaska, Seznam, Znalost | ||||
| from soustredeni.models import Soustredeni | ||||
| 
 | ||||
| 
 | ||||
| class Seznam_PrednaskaInline(admin.TabularInline): | ||||
| 	""" | ||||
| 		Pomůcka pro :py:class:`prednasky.admin.SeznamAdmin` zobrazující hezky :py:class:`Přednášky <prednasky.models.Prednaska>` | ||||
| 		v adminu :py:class:`Seznamu <prednasky.models.Seznam>`. | ||||
| 	""" | ||||
| 	model = Prednaska.seznamy.through | ||||
| 	extra = 0 | ||||
| 
 | ||||
|  | @ -54,24 +58,57 @@ class Seznam_PrednaskaInline(admin.TabularInline): | |||
| 	def has_add_permission(self, req, obj): return False | ||||
| 
 | ||||
| 
 | ||||
| class Seznam_ZnalostInline(admin.TabularInline): | ||||
| 	""" | ||||
| 		Pomůcka pro :py:class:`prednasky.admin.SeznamAdmin` zobrazující hezky :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 		v adminu :py:class:`Seznamu <prednasky.models.Seznam>`. | ||||
| 	""" | ||||
| 	model = Znalost.seznamy.through | ||||
| 	extra = 0 | ||||
| 
 | ||||
| 	def znalost__nazev(self, obj): | ||||
| 		return mark_safe( | ||||
| 			f"<a href='/admin/prednasky/znalost/{obj.znalost.id}'>{obj.znalost.nazev}</a>" | ||||
| 		) | ||||
| 
 | ||||
| 	def znalost__text(self, obj): | ||||
| 		return mark_safe( | ||||
| 			f"<div style='width: 200px'>{escape(obj.znalost.text)}</div>" | ||||
| 		) | ||||
| 
 | ||||
| 	znalost__nazev.short_description = u'Přednáška' | ||||
| 	znalost__text.short_description = u'Popis pro orgy' | ||||
| 
 | ||||
| 	readonly_fields = [ | ||||
| 		'znalost__nazev', | ||||
| 		'znalost__text', | ||||
| 	] | ||||
| 	exclude = ['znalost'] | ||||
| 
 | ||||
| 	def has_add_permission(self, req, obj): return False | ||||
| 
 | ||||
| 
 | ||||
| class SeznamAdmin(VersionAdmin): | ||||
| 	""" Admin pro :py:class:`Seznam <prednasky.models.Seznam>` """ | ||||
| 	list_display = ['soustredeni', 'stav'] | ||||
| 	inlines = [Seznam_PrednaskaInline] | ||||
| 	inlines = [Seznam_PrednaskaInline, Seznam_ZnalostInline] | ||||
| 
 | ||||
| admin.site.register(Seznam, SeznamAdmin) | ||||
| 
 | ||||
| 
 | ||||
| class PrednaskaAdmin(VersionAdmin): | ||||
| 	""" Admin pro :py:class:`Přednášku <prednasky.models.Prednaska> """ | ||||
| 	list_display = ['nazev', 'org', 'obor'] | ||||
| 	list_filter = ['org', 'obor'] | ||||
| 	search_fields = [] | ||||
| 	search_fields = ['nazev'] | ||||
| 	filter_horizontal = ('seznamy', ) | ||||
| 
 | ||||
| 	actions = ['move_to_soustredeni'] | ||||
| 
 | ||||
| 	def move_to_soustredeni(self, request, queryset): | ||||
| 		""" Přidá dané přednášky do seznamu, o kterém se právě hlasuje """ | ||||
| 		sous = Soustredeni.objects.first() | ||||
| 		seznam = Seznam.objects.filter(soustredeni=sous, stav=STAV_NAVRH) | ||||
| 		seznam = Seznam.objects.filter(soustredeni=sous, stav=Seznam.Stav.NAVRH) | ||||
| 		if len(seznam) == 0: | ||||
| 			self.message_user( | ||||
| 				request, | ||||
|  | @ -97,3 +134,14 @@ class PrednaskaAdmin(VersionAdmin): | |||
| 
 | ||||
| 
 | ||||
| admin.site.register(Prednaska, PrednaskaAdmin) | ||||
| 
 | ||||
| 
 | ||||
| class ZnalostAdmin(PrednaskaAdmin): # Trochu hack, ať nemusím vypisovat všechno znovu | ||||
| 	""" | ||||
| 		Admin pro :py:class:`Znalost <prednasky.models.Znalost> | ||||
| 		TODO předělat, aby nedědila z :py:class:`prednasky.admin.PrednaskaAdmin`, ale společné věci byly zvlášť | ||||
| 	""" | ||||
| 	list_display = ("__str__",) | ||||
| 	list_filter = () | ||||
| 
 | ||||
| admin.site.register(Znalost, ZnalostAdmin) | ||||
|  |  | |||
|  | @ -1,7 +1,31 @@ | |||
| from django import forms | ||||
| 
 | ||||
| class NewPrednaskyForm(forms.Form): | ||||
| 	ucastnik = forms.CharField(label = 'Tvoje jméno', max_length = 100) | ||||
| from .models import Hlasovani, HlasovaniOZnalostech | ||||
| 
 | ||||
| class HlasovaniPrednaskaForm(forms.Form): | ||||
| 	""" :py:class:`Formulář <django.forms.Form>` pro pro :py:class:`Hlasování <prednasky.models.Hlasovani>` o jedné :py:class:`Přednášce <prednasky.models.Prednaska>` | ||||
| 	(neobsahuje téměř nic, většina se musí doplnit jiným způsobem) | ||||
| 	""" | ||||
| 
 | ||||
| 	#: ID :py:class:`Přednášky <prednasky.models.Prednaska>`, o které se hlasuje | ||||
| 	prednaska_id = forms.IntegerField(widget=forms.HiddenInput) | ||||
| 	#: :py:class:`Hodnocení (Body) <prednasky.models.Hlasovani.Body>` této přednášky | ||||
| 	body = forms.ChoiceField(label=False, widget=forms.RadioSelect, choices=Hlasovani.Body.choices, initial=Hlasovani.Body.JEDNO) | ||||
| 
 | ||||
| #: Množina formulářů (:py:class:`formset <django.forms.formsets.BaseFormSet>` :py:class:`HlasovaniPrednaskaFormů <prednasky.forms.HlasovaniPrednaskaForm>`) | ||||
| #: pro :py:class:`Hlasování <prednasky.models.Hlasovani>` o množině :py:class:`Přednášek <prednasky.models.Prednaska>` | ||||
| HlasovaniPrednaskaFormSet = forms.formset_factory(HlasovaniPrednaskaForm, extra=0) | ||||
| 
 | ||||
| class HlasovaniZnalostiForm(forms.Form): | ||||
| 	""" :py:class:`Formulář <django.forms.Form>` pro pro :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>` o jedné :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 	(neobsahuje téměř nic, většina se musí doplnit jiným způsobem) | ||||
| 	""" | ||||
| 
 | ||||
| 	#: ID :py:class:`Znalosti <prednasky.models.Znalost>`, o které hlasujeme | ||||
| 	znalost_id = forms.IntegerField(widget=forms.HiddenInput) | ||||
| 	#: :py:class:`Odpověď <prednasky.models.HlasovaniOZnalostech.Odpoved>` na tuto znalost | ||||
| 	odpoved = forms.ChoiceField(label=False, widget=forms.RadioSelect, choices=HlasovaniOZnalostech.Odpoved.choices) | ||||
| 
 | ||||
| #: Množina formulářů (:py:class:`formset <django.forms.formsets.BaseFormSet>` :py:class:`HlasovaniZnalostiFormů <prednasky.forms.HlasovaniZnalostiForm>`) | ||||
| #: pro :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>` o množině :py:class:`Znalostí <prednasky.models.Znalost>` | ||||
| HlasovaniZnalostiFormSet = forms.formset_factory(HlasovaniZnalostiForm, extra=0) | ||||
|  |  | |||
							
								
								
									
										39
									
								
								prednasky/migrations/0019_znalost_hlasovanioznalostech.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								prednasky/migrations/0019_znalost_hlasovanioznalostech.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| # Generated by Django 4.2.16 on 2025-01-24 13:41 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('personalni', '0019_rename_upozorneni_resitel_upozornovat_na_opravy_reseni'), | ||||
|         ('prednasky', '0018_post_split_soustredeni'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='Znalost', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||
|                 ('nazev', models.CharField(help_text='Např. Neuronové sítě', max_length=200, verbose_name='Nadpis')), | ||||
|                 ('text', models.TextField(blank=True, help_text='Např. Perceptron, vrstevnatá síť, forward a backward propagation', null=True, verbose_name='Detailní popis')), | ||||
|                 ('seznamy', models.ManyToManyField(to='prednasky.seznam')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'Znalost k přednáškám', | ||||
|                 'verbose_name_plural': 'Znalosti k přednáškám', | ||||
|                 'db_table': 'prednasky_znalost', | ||||
|             }, | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='HlasovaniOZnalostech', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||
|                 ('odpoved', models.CharField(choices=[(-1, 'Tohle celkem umím'), (0, 'Už jsem o tom slyšel, ale neřekl bychm, že to úplně umím'), (1, 'Tohle vůbec neznám')], max_length=16, verbose_name='odpověď')), | ||||
|                 ('seznam', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='prednasky.seznam')), | ||||
|                 ('ucastnik', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='personalni.osoba')), | ||||
|                 ('znalost', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='prednasky.znalost')), | ||||
|             ], | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										18
									
								
								prednasky/migrations/0020_alter_hlasovani_body.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								prednasky/migrations/0020_alter_hlasovani_body.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| # Generated by Django 4.2.16 on 2025-01-24 20:04 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('prednasky', '0019_znalost_hlasovanioznalostech'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AlterField( | ||||
|             model_name='hlasovani', | ||||
|             name='body', | ||||
|             field=models.IntegerField(choices=[(-1, 'rozhodně nechci'), (0, 'je mi to jedno'), (1, 'rozhodně chci')], default=0, verbose_name='Body'), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -0,0 +1,24 @@ | |||
| # Generated by Django 4.2.16 on 2025-02-04 20:09 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| 
 | ||||
| def zmena_bodu(apps, _schema_editor): | ||||
|     HlasovaniOZnalostech = apps.get_model('prednasky','HlasovaniOZnalostech') | ||||
|     for h in HlasovaniOZnalostech.objects.all(): | ||||
|         h.odpoved = -int(h.odpoved) | ||||
|         h.save() | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('prednasky', '0020_alter_hlasovani_body'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AlterField( | ||||
|             model_name='hlasovanioznalostech', | ||||
|             name='odpoved', | ||||
|             field=models.IntegerField(choices=[(1, 'Tohle celkem umím'), (0, 'Už jsem o tom slyšel, ale neřekl bychm, že to úplně umím'), (-1, 'Tohle vůbec neznám')], verbose_name='odpověď'), | ||||
|         ), | ||||
|         migrations.RunPython(zmena_bodu, reverse_code=zmena_bodu), | ||||
|     ] | ||||
|  | @ -1,81 +1,134 @@ | |||
| from django.db import models | ||||
| 
 | ||||
| from soustredeni.models import Soustredeni | ||||
| from personalni.models import Organizator | ||||
| 
 | ||||
| STAV_NAVRH = 1 | ||||
| STAV_BUDE = 2 | ||||
| 
 | ||||
| 
 | ||||
| STAV_CHOICES = ( | ||||
| (STAV_NAVRH, 'Návrh'), | ||||
| (STAV_BUDE, 'Bude') | ||||
| ) | ||||
| from personalni.models import Organizator, Osoba | ||||
| 
 | ||||
| 
 | ||||
| class Seznam(models.Model): | ||||
| 	class Meta: | ||||
| 		db_table = 'prednasky_seznam' | ||||
| 		verbose_name = 'Seznam přednášek' | ||||
| 		verbose_name_plural = 'Seznamy přednášek' | ||||
| 		ordering = ['soustredeni', 'stav'] | ||||
| 	""" | ||||
| 		Spojuje :py:class:`Přednášky <prednasky.models.Prednaska>` | ||||
| 		se :py:class:`Soustředěními <soustredeni.models.Soustredeni>`, | ||||
| 		kde by mohly zaznít, nebo zazní/zazněly. | ||||
| 	""" | ||||
| 
 | ||||
| 	id = models.AutoField(primary_key = True)  | ||||
| 	soustredeni = models.ForeignKey(Soustredeni,null = True, default = None,  | ||||
| 		on_delete=models.PROTECT) | ||||
| 	stav = models.IntegerField('Stav',choices=STAV_CHOICES,default = STAV_NAVRH) | ||||
| 	class Meta: | ||||
| 		db_table = "prednasky_seznam" | ||||
| 		verbose_name = "Seznam přednášek" | ||||
| 		verbose_name_plural = "Seznamy přednášek" | ||||
| 		ordering = ["soustredeni", "stav"] | ||||
| 
 | ||||
| 	class Stav(models.IntegerChoices): | ||||
| 		""" Stav seznamu přednášek (NAVRH se používá k hlasování viz :py:func:`daný view <prednasky.views.newPrednaska>`). """ | ||||
| 		NAVRH = 1, "Návrh" | ||||
| 		BUDE = 2, "Bude" | ||||
| 
 | ||||
| 	id = models.AutoField(primary_key=True) | ||||
| 	soustredeni = models.ForeignKey(Soustredeni, null=True, default=None, on_delete=models.PROTECT) | ||||
| 	stav = models.IntegerField("Stav", choices=Stav.choices, default=Stav.NAVRH) #: :py:class:`Stav <prednasky.models.Seznam.Stav>` Seznamu | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 			return "Seznam {}přednášek na {}".format("návrhů "  | ||||
| 					if self.stav == STAV_NAVRH else "", self.soustredeni) | ||||
| 		return f"Seznam {'návrhů ' if self.stav == Seznam.Stav.NAVRH else ''}přednášek na {self.soustredeni}" | ||||
| 
 | ||||
| 
 | ||||
| CHOICES_OBTIZNOST = ( | ||||
| 				(1, 'Lehká'), | ||||
| 				(2, 'Střední'), | ||||
| 				(3, 'Těžká'), | ||||
| 				) | ||||
| 
 | ||||
| CHOICES_BODY = ( | ||||
| 		(-1, '-1'), | ||||
| 		(0, '0'), | ||||
| 		(1, '1'), | ||||
| 		) | ||||
| 
 | ||||
| class Prednaska(models.Model): | ||||
| 	""" | ||||
| 		Reprezentuje přednášku, kterou si org může vypsat a účastník o ní hlasovat. | ||||
| 		(Viz :py:class:`Hlasování <prednasky.models.Hlasovani>`.) | ||||
| 	""" | ||||
| 	class Meta: | ||||
| 		db_table = 'prednasky_prednaska' | ||||
| 		verbose_name = 'Přednáška' | ||||
| 		verbose_name_plural = 'Přednášky' | ||||
| 		ordering = ['org', 'nazev'] | ||||
| 		db_table = "prednasky_prednaska" | ||||
| 		verbose_name = "Přednáška" | ||||
| 		verbose_name_plural = "Přednášky" | ||||
| 		ordering = ["org", "nazev"] | ||||
| 
 | ||||
| 	id = models.AutoField(primary_key = True)  | ||||
| 	nazev = models.CharField('Název', max_length = 300) | ||||
| 	class Obtiznost(models.IntegerChoices): | ||||
| 		LEHKA = 1, "Lehká" | ||||
| 		STREDNI = 2, "Střední" | ||||
| 		TEZKA = 3, "Těžká" | ||||
| 
 | ||||
| 	id = models.AutoField(primary_key=True) | ||||
| 	nazev = models.CharField("Název", max_length=300) | ||||
| 	org = models.ForeignKey(Organizator, on_delete=models.PROTECT) | ||||
| 	popis = models.TextField('Popis pro orgy',null = True, blank = True,help_text = 'Neveřejný popis pro ostatní orgy') | ||||
| 	anotace = models.TextField('Anotace',null = True, blank = True, help_text = 'Veřejná anotace v hlasování') | ||||
| 	obtiznost = models.IntegerField('Obtížnost', choices=CHOICES_OBTIZNOST) | ||||
| 	obor = models.CharField('Obor', max_length = 5, help_text = 'Podmnožina MFIOB') | ||||
| 	klicova = models.CharField('Klíčová slova', max_length = 200, null = True, blank = True) | ||||
| 	popis = models.TextField("Popis pro orgy", null=True, blank=True, help_text="Neveřejný popis pro ostatní orgy") | ||||
| 	anotace = models.TextField("Anotace", null=True, blank=True, help_text="Veřejná anotace v hlasování") | ||||
| 	obtiznost = models.IntegerField("Obtížnost", choices=Obtiznost.choices) #: :py:class:`Obtížnost <prednasky.models.Prednaska.Obtiznost>` Přednášky | ||||
| 	obor = models.CharField("Obor", max_length=5, help_text="Podmnožina MFIOB") | ||||
| 	klicova = models.CharField("Klíčová slova", max_length=200, null=True, blank=True) | ||||
| 	seznamy = models.ManyToManyField(Seznam) | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 		return "{} ({})".format(self.nazev, self.org) | ||||
| 		return f"{self.nazev} ({self.org})" | ||||
| 
 | ||||
| 
 | ||||
| class Hlasovani(models.Model): | ||||
| 	""" | ||||
| 		Reprezentuje hlasování jednoho účastníka | ||||
| 		o jedné :py:class:`Přednášce <prednasky.models.Prednaska>` | ||||
| 		v jednom :py:class:`Seznamu <prednasky.models.Seznam>` (účastníkův pohled se totiž mezi sousy změnit) | ||||
| 	""" | ||||
| 	class Meta: | ||||
| 		db_table = 'prednasky_hlasovani' | ||||
| 		verbose_name = 'Hlasování' | ||||
| 		verbose_name_plural = 'Hlasování' | ||||
| 		ordering = ['ucastnik', 'prednaska'] | ||||
| 	id = models.AutoField(primary_key = True)  | ||||
| 		db_table = "prednasky_hlasovani" | ||||
| 		verbose_name = "Hlasování" | ||||
| 		verbose_name_plural = "Hlasování" | ||||
| 		ordering = ["ucastnik", "prednaska"] | ||||
| 
 | ||||
| 	class Body(models.IntegerChoices): | ||||
| 		""" Ohodnocení přednášky v daném Hlasování (větší číslo = víc chci) """ | ||||
| 		NECHCI = -1, "rozhodně nechci" | ||||
| 		JEDNO = 0, "je mi to jedno" | ||||
| 		CHCI = 1, "rozhodně chci" | ||||
| 
 | ||||
| 	id = models.AutoField(primary_key=True) | ||||
| 	prednaska = models.ForeignKey(Prednaska, on_delete=models.CASCADE) | ||||
| 	body = models.IntegerField('Body', default = 0, choices = CHOICES_BODY) | ||||
| 	ucastnik = models.CharField('Účastník', max_length = 100) | ||||
| 	seznam = models.ForeignKey(Seznam,null=True,on_delete=models.SET_NULL) | ||||
| 	#: Příslušné hlasování: :py:class:`Body <prednasky.models.Hlasovani.Body>` | ||||
| 	body = models.IntegerField("Body", default=Body.JEDNO, choices=Body.choices) | ||||
| 
 | ||||
| 	#: Účastník, který hlasoval. Pouze string: | ||||
| 	#: *(přechod z jména na objekt Osoby nějak kape na tom, | ||||
| 	#: že všechna předchozí hlasování zde mají náhodný string…) | ||||
| 	#: TODO Změnit to na Osobu* | ||||
| 	ucastnik = models.CharField("Účastník", max_length=100) | ||||
| 	seznam = models.ForeignKey(Seznam, null=True, on_delete=models.SET_NULL) | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 		return "{} dal {} bodů {} v seznamu {}".format(self.ucastnik,  | ||||
| 					self.body, self.prednaska, self.seznam) | ||||
| 		return f"{self.ucastnik} dal {self.body} bodů {self.prednaska} v seznamu {self.seznam}" | ||||
| 
 | ||||
| 
 | ||||
| class Znalost(models.Model): | ||||
| 	""" | ||||
| 		Reprezentuje znalost, na kterou se můžeme účastníka ptát (nechat je hlasovat). | ||||
| 		(Viz :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>`.) | ||||
| 	""" | ||||
| 	class Meta: | ||||
| 		db_table = "prednasky_znalost" | ||||
| 		verbose_name = "Znalost k přednáškám" | ||||
| 		verbose_name_plural = "Znalosti k přednáškám" | ||||
| 
 | ||||
| 	nazev = models.CharField("Nadpis", max_length=200, blank=False, null=False, help_text="Např. Neuronové sítě") | ||||
| 	text = models.TextField("Detailní popis", blank=True, null=True, help_text="Např. Perceptron, vrstevnatá síť, forward a backward propagation") | ||||
| 	seznamy = models.ManyToManyField(Seznam) | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 		return self.nazev | ||||
| 
 | ||||
| 
 | ||||
| class HlasovaniOZnalostech(models.Model): | ||||
| 	""" | ||||
| 		Reprezentuje hlasování jednoho účastníka | ||||
| 		o jedné :py:class:`Znalosti <prednasky.models.Znalost>` | ||||
| 		v jednom :py:class:`Seznamu <prednasky.models.Seznam>` (účastníkův pohled se totiž mezi sousy změnit) | ||||
| 	""" | ||||
| 	class Odpoved(models.IntegerChoices): | ||||
| 		""" Na kolik danou znalost účastník ovládá v daném Hlasování (větší číslo = víc zná) """ | ||||
| 		UMIM = 1, "Tohle celkem umím" | ||||
| 		CIRCA = 0, "Už jsem o tom slyšel, ale neřekl bychm, že to úplně umím" | ||||
| 		NEUMIM = -1, "Tohle vůbec neznám" | ||||
| 
 | ||||
| 	odpoved = models.IntegerField(u"odpověď", choices=Odpoved.choices, blank=False, null=False) #: :py:class:`Odpověď <prednasky.models.Prednaska.Odpoved>` na HlasováníOZnalostech | ||||
| 	znalost = models.ForeignKey(Znalost, on_delete=models.CASCADE, blank=False, null=False) | ||||
| 	ucastnik = models.ForeignKey(Osoba, on_delete=models.CASCADE, blank=False, null=False) | ||||
| 	seznam = models.ForeignKey(Seznam, on_delete=models.SET_NULL, blank=True, null=True) | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 		return f"{self.ucastnik} dal {self.znalost} bodů {self.znalost} v seznamu {self.seznam}" | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,36 +5,36 @@ | |||
| 
 | ||||
| 
 | ||||
| {% block content %} | ||||
| <h1> | ||||
| {% block nadpis1a %}Hlasování o přednáškách{% endblock %} | ||||
| </h1> | ||||
| 
 | ||||
| <p> | ||||
| Jak moc by ses chtěl(a) zúčastnit následujících přednášek? | ||||
| <br> | ||||
| <span style="font-size: 75%">Obtížnost 1 je nejlehčí, 3 nejtěžší.</span> | ||||
| </p> | ||||
| <h1>{% block nadpis1a %}Hlasování o přednáškách{% endblock %}</h1> | ||||
| 
 | ||||
| <form enctype="multipart/form-data" action="." method="post"> | ||||
|   {% csrf_token %} | ||||
|   <table> | ||||
|     {% for p, h in prednasky %} | ||||
|     <tr><td><label>{{p.org}}: <span style="font-size: 175%">{{p.nazev}}</span></label></td></tr> | ||||
|     <tr><td><p><i>{{p.anotace}}</i></p></td></tr> | ||||
|     <tr><td><label>Obor: </label> {{p.obor}}</td></tr> | ||||
|     <tr><td><label>Obtížnost: </label> {{p.obtiznost}}</td>   </tr> | ||||
|     {% if p.klicova %}<tr><td><label>Klíčová slova: </label> {{p.klicova}}</td></tr>{% endif%} | ||||
|     <tr><td>Hodnocení: | ||||
|         <INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="-1" {% if h == -1 %} CHECKED="checked" {% endif %} > rozhodně nechci | ||||
|         <INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="0" {% if h == 0 %} CHECKED="checked" {% endif %}> je mi to jedno | ||||
|         <INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci | ||||
|     </td></tr> | ||||
|     <tr><td> </td></tr> | ||||
|     {% empty %} | ||||
|       Nejsou žádné přednášky o kterých by šlo hlasovat. | ||||
|     {% endfor %} | ||||
|     <tr><td><input name="odeslat" type="submit" value="Odeslat"></td><tr> | ||||
|   </table> | ||||
| 
 | ||||
| <h3>Jak moc by ses chtěl(a) zúčastnit následujících přednášek?</h3> | ||||
| <p>Obtížnost 1 je nejlehčí, 3 nejtěžší.</p> | ||||
|   {{ form_set_prednasky.management_form }} | ||||
|   {% for f, p in formy_a_prednasky %} | ||||
|     <h4>{{p.nazev}} ({{p.org}})</h4> | ||||
|     <p class="textprednasky">{{p.anotace}}</p> | ||||
|     <label>Obor: </label> {{p.obor}}<br> | ||||
|     <label>Obtížnost: </label> {{p.obtiznost}}<br> | ||||
|     {% if p.klicova %}<label>Klíčová slova: </label> {{p.klicova}}<br>{% endif%} | ||||
|     <br> | ||||
|     {{ f }} | ||||
|     <br> | ||||
|   {% empty %} | ||||
|     Nejsou žádné přednášky o kterých by šlo hlasovat. | ||||
|   {% endfor %} | ||||
| 
 | ||||
|   {{ form_set_znalosti.management_form }} | ||||
|   {% for f, z in formy_a_znalosti %} | ||||
|     {% if forloop.first %}<hr/><h3>Jak moc znáš následující?</h3>{% endif %} | ||||
|     <h4>{{z.nazev}}</h4> | ||||
|     <p class="textznalosti">{{z.text}}</p> | ||||
|     {{ f }} | ||||
|     <br> | ||||
|   {% endfor %} | ||||
|   <input type="submit" value="Odeslat"/> | ||||
| </form> | ||||
|     | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
|     {% else %} | ||||
|         <a href="/prednasky/seznam_prednasek/{{seznam.id}}">Seznam přednášek na soustředění {{seznam.soustredeni.misto}} </a> | ||||
|     {% endif %} | ||||
|     <a href="/prednasky/seznam_prednasek/{{seznam.id}}/export">Export</a> | ||||
|     <a href="/prednasky/seznam_prednasek/{{seznam.id}}/hlasovani.csv">Export</a> | ||||
|     </li> | ||||
|   {% endfor %} | ||||
|   </ul> | ||||
|  |  | |||
|  | @ -12,10 +12,15 @@ urlpatterns = [ | |||
| 		'prednasky/metaseznam_prednasek', | ||||
| 		org_required(views.MetaSeznamListView.as_view()), | ||||
| 		name='metaseznam-list'), | ||||
| 	# path( | ||||
| 	# 	'prednasky/seznam_prednasek/<int:seznam>/export', | ||||
| 	# 	org_required(views.SeznamExportView), | ||||
| 	# 	name='seznam-export' | ||||
| 	# ), | ||||
| 	path( | ||||
| 		'prednasky/seznam_prednasek/<int:seznam>/export', | ||||
| 		org_required(views.SeznamExportView), | ||||
| 		name='seznam-export' | ||||
| 		'prednasky/seznam_prednasek/<int:seznam>/hlasovani.csv', | ||||
| 		org_required(views.PrednaskyExportView), | ||||
| 		name='seznam-export-csv' | ||||
| 	), | ||||
| 	path( | ||||
| 		'prednasky/seznam_prednasek/<int:seznam>/', | ||||
|  |  | |||
|  | @ -1,77 +1,142 @@ | |||
| import csv | ||||
| import http | ||||
| import logging | ||||
| 
 | ||||
| from django.http import HttpResponse, HttpRequest | ||||
| from django.shortcuts import render, get_object_or_404 | ||||
| from django.views import generic | ||||
| from django.shortcuts import HttpResponseRedirect | ||||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| from django.db.models import Sum | ||||
| from django.forms import Form | ||||
| from django.db import transaction | ||||
| 
 | ||||
| from various.views.pomocne import formularOKView | ||||
| from .forms import HlasovaniPrednaskaFormSet, HlasovaniZnalostiFormSet | ||||
| 
 | ||||
| from various.models import Nastaveni | ||||
| from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH | ||||
| from prednasky.models import Prednaska, Hlasovani, Znalost, HlasovaniOZnalostech, Seznam | ||||
| from soustredeni.models import Soustredeni | ||||
| from personalni.models import Osoba | ||||
| 
 | ||||
| def newPrednaska(request): | ||||
| PREDNASKY_PREFIX = "prednasky" | ||||
| ZNALOSTI_PREFIX = "znalosti" | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| def newPrednaska(request: HttpRequest) -> HttpResponse: | ||||
| 	""" | ||||
| 		View zobrazující a ukládající účastnické hlasování | ||||
| 		(:py:class:`Hlasování <prednasky.models.Hlasovani>` | ||||
| 		a :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>`) | ||||
| 		o :py:class:`Přednáškách <prednasky.models.Prednaska>` | ||||
| 		a :py:class:`Znalostech <prednasky.models.Znalost>` | ||||
| 	""" | ||||
| 	# hlasovani se vztahuje k nejnovejsimu soustredeni | ||||
| 	sous = Nastaveni.get_solo().aktualni_sous | ||||
| 	seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() | ||||
| 	seznam = Seznam.objects.filter(soustredeni = sous, stav=Seznam.Stav.NAVRH).first() | ||||
| 	if sous is None or seznam is None: | ||||
| 		return render(request, 'universal.html', { | ||||
| 			'title': "Nelze hlasovat", | ||||
| 			'text': "Není žádný seznam přednášek, o kterém by se dalo hlasovat.", | ||||
| 		}, status=http.HTTPStatus.NOT_FOUND) | ||||
| 
 | ||||
| 	osoba = Osoba.objects.filter(user=request.user).first() | ||||
| 	ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id) | ||||
| 	# obsluha formulare | ||||
| 	if request.method == 'POST': | ||||
| 		form = Form(request.POST, request.FILES) | ||||
| 		if form.is_valid(): | ||||
| 			# id z důvodu duplicitních jmen (přechod z jména na objekt Osoby nějak kape na tom, | ||||
| 			# že všechna předchozí hlasování zde mají náhodný string…) | ||||
| 			# TODO Změnit to na Osobu | ||||
| 	ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id) # id, kvůli kolizi jmen | ||||
| 
 | ||||
| 			# TODO v následujících řádcích je zbytečně mnoho dotazů na QuerySet (pokud účastník hlasoval, hlasoval u všech) | ||||
| 			for i in request.POST: | ||||
| 				if i[0] == 'q': | ||||
| 					prednaska = Prednaska.objects.filter(pk=int(i[1:]))[0] | ||||
| 					hlasovani = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first() | ||||
| 					if not hlasovani: | ||||
| 						hlasovani = Hlasovani() | ||||
| 						hlasovani.prednaska = prednaska | ||||
| 						hlasovani.ucastnik = ucastnik | ||||
| 						hlasovani.seznam = seznam | ||||
| 					hlasovani.body = int(request.POST[i]) | ||||
| 					hlasovani.save() | ||||
| 	if request.method == 'POST': # Když to byl POST, tak ukládáme. | ||||
| 		# Načteme data do formsetů | ||||
| 		form_set_prednasky = HlasovaniPrednaskaFormSet(request.POST, prefix=PREDNASKY_PREFIX) | ||||
| 		form_set_znalosti = HlasovaniZnalostiFormSet(request.POST, prefix=ZNALOSTI_PREFIX) | ||||
| 
 | ||||
| 		if form_set_prednasky.is_valid() and form_set_znalosti.is_valid(): | ||||
| 			with transaction.atomic(): | ||||
| 				# Místo updatování data prostě smažeme a vytvoříme nová | ||||
| 				seznam.hlasovani_set.filter(ucastnik=ucastnik).delete() | ||||
| 				seznam.hlasovanioznalostech_set.filter(ucastnik=osoba).delete() | ||||
| 
 | ||||
| 				for form in form_set_prednasky: | ||||
| 					prednaska_id = form.cleaned_data['prednaska_id'] | ||||
| 					prednaska = Prednaska.objects.filter(id=prednaska_id).first() | ||||
| 					if prednaska is None: | ||||
| 						logger.error(f"Účastník {ucastnik} hodnotil neexistující přednášku {prednaska_id} číslem {form.cleaned_data['body']}") | ||||
| 						continue | ||||
| 
 | ||||
| 					Hlasovani.objects.create( | ||||
| 						prednaska=prednaska, | ||||
| 						body=form.cleaned_data['body'], | ||||
| 						ucastnik=ucastnik, | ||||
| 						seznam=seznam, | ||||
| 					) | ||||
| 
 | ||||
| 				for form in form_set_znalosti: | ||||
| 					znalost_id = form.cleaned_data['znalost_id'] | ||||
| 					znalost = Znalost.objects.filter(id=znalost_id).first() | ||||
| 					if znalost is None: | ||||
| 						logger.error(f"Účastník {ucastnik} hodnotil neexistující znalost {znalost_id} číslem {form.cleaned_data['odpoved']}") | ||||
| 						continue | ||||
| 
 | ||||
| 					HlasovaniOZnalostech.objects.create( | ||||
| 						odpoved=form.cleaned_data['odpoved'], | ||||
| 						znalost=znalost, | ||||
| 						ucastnik=osoba, | ||||
| 						seznam=seznam, | ||||
| 					) | ||||
| 
 | ||||
| 			# presmerovani na prave vzniklou galerii | ||||
| 			return HttpResponseRedirect('./hotovo') | ||||
| 
 | ||||
| 	def prednaska_hodnoceni(prednaska): | ||||
| 		h = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first() | ||||
| 		if h: | ||||
| 			return prednaska, h.body | ||||
| 		else: | ||||
| 			return prednaska, 0 | ||||
| 		else: # Pokud je nějaký formset nevalidní, vracíme je k přepracování | ||||
| 			prednasky = seznam.prednaska_set.all() | ||||
| 			znalosti = seznam.znalost_set.all() | ||||
| 			# FIXME Spadnout, pokud nesedí přednáška/znalost s formulářem. (Nějak se mi to nepovedlo.) | ||||
| 			# Může se totiž stát, že se mezitím změnily přednášky (nějaká byla přidána/odebrána) | ||||
| 
 | ||||
| 	else: # Když to nebyl POST, tak inicializujeme (pokud už o přednášce/znalosti účastník hlasoval, předvyplníme mu to). | ||||
| 		def odpoved_prednasky(p: Prednaska) -> Hlasovani.Body: | ||||
| 			hlasovani = p.hlasovani_set.filter(ucastnik=ucastnik).first() | ||||
| 			return hlasovani.body if hlasovani else Hlasovani.Body.JEDNO | ||||
| 
 | ||||
| 		def odpoved_znalosti(z: Znalost) -> HlasovaniOZnalostech.Odpoved: | ||||
| 			hlasovani = z.hlasovanioznalostech_set.filter(ucastnik=osoba).first() | ||||
| 			return hlasovani.odpoved if hlasovani else HlasovaniOZnalostech.Odpoved.CIRCA | ||||
| 
 | ||||
| 		prednasky = seznam.prednaska_set.all() | ||||
| 		znalosti = seznam.znalost_set.all() | ||||
| 
 | ||||
| 		form_set_prednasky = HlasovaniPrednaskaFormSet(initial=[ | ||||
| 			{"prednaska_id": p.id, "body": odpoved_prednasky(p)} for p in prednasky | ||||
| 		], prefix=PREDNASKY_PREFIX) | ||||
| 
 | ||||
| 		form_set_znalosti = HlasovaniZnalostiFormSet(initial=[ | ||||
| 			{"znalost_id": z.id, "odpoved": odpoved_znalosti(z)} for z in znalosti | ||||
| 		], prefix=ZNALOSTI_PREFIX) | ||||
| 
 | ||||
| 
 | ||||
| 	# V případě nePOSTu nebo chyby při ukládání vracíme hlasování | ||||
| 	return render( | ||||
| 		request, | ||||
| 		'prednasky/base.html', | ||||
| 		{'prednasky': map(prednaska_hodnoceni, seznam.prednaska_set.all())} | ||||
| 		{ | ||||
| 			'form_set_prednasky': form_set_prednasky, 'form_set_znalosti': form_set_znalosti, | ||||
| 			'formy_a_prednasky': zip(form_set_prednasky, prednasky), | ||||
| 			'formy_a_znalosti': zip(form_set_znalosti, znalosti), | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| 
 | ||||
| def Prednaska_hotovo(request): | ||||
| def Prednaska_hotovo(request: HttpRequest) -> HttpResponse: | ||||
| 	""" View po vyplnění :py:func:`hlasování <prednasky.views.newPrednaska>` """ | ||||
| 	return formularOKView(request, "Děkujeme za vyplnění hlasování o přednáškách a těšíme se na soustředění.") | ||||
| 
 | ||||
| class MetaSeznamListView(generic.ListView): | ||||
| 	""" Seznam všech :py:class:`Seznamů <prednasky.models.Seznam>` s odkazy na exporty """ | ||||
| 	model = Seznam | ||||
| 	template_name = 'prednasky/metaseznam_prednasek.html' | ||||
| 
 | ||||
| 
 | ||||
| class SeznamListView(generic.ListView): | ||||
| 	""" | ||||
| 		Náhled na to, kolik má která přednáška v :py:class:`Seznamu <prednasky.models.Seznam>` :py:class:`hlasů <prednasky.models.Hlasovani.Body>`. | ||||
| 		(Je otázka, zda tento View vůbec chceme. Pokud ano, hodilo by se do něj přidat i znalosti.) | ||||
| 	""" | ||||
| 	template_name = 'prednasky/seznam_prednasek.html' | ||||
| 
 | ||||
| 	def get_queryset(self): | ||||
|  | @ -87,7 +152,7 @@ class SeznamListView(generic.ListView): | |||
| 
 | ||||
| 		# hlasovani se vztahuje k nejnovejsimu soustredeni | ||||
| 		sous = Soustredeni.objects.first() | ||||
| 		seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() | ||||
| 		seznam = Seznam.objects.filter(soustredeni = sous, stav=Seznam.Stav.NAVRH).first() | ||||
| 	 | ||||
| 		for obj in self.object_list: | ||||
| 			hlasovani_set = obj.hlasovani_set.filter(seznam=seznam).only('body') | ||||
|  | @ -96,32 +161,86 @@ class SeznamListView(generic.ListView): | |||
| 		return context | ||||
| 
 | ||||
| 
 | ||||
| def SeznamExportView(request, seznam): | ||||
| 	"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" | ||||
| 	# TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro | ||||
| 	# lidi? | ||||
| 	hlasovani = Hlasovani.objects.filter(seznam=seznam) | ||||
| 	prednasky = Prednaska.objects.filter(seznamy=seznam) | ||||
| 	orgove = set(p.org for p in prednasky) | ||||
| 	ucastnici = set(h.ucastnik for h in hlasovani) | ||||
| # def SeznamExportView(request, seznam): | ||||
| # 	"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" | ||||
| # 	# TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro | ||||
| # 	# lidi? | ||||
| # 	hlasovani = Hlasovani.objects.filter(seznam=seznam) | ||||
| # 	prednasky = Prednaska.objects.filter(seznamy=seznam) | ||||
| # 	orgove = set(p.org for p in prednasky) | ||||
| # 	ucastnici = set(h.ucastnik for h in hlasovani) | ||||
| # | ||||
| # 	for p in prednasky: | ||||
| # 		p.body = [] | ||||
| # 		for u in ucastnici: | ||||
| # 			try: | ||||
| # 				p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body) | ||||
| # 			except ObjectDoesNotExist: | ||||
| # 				# účastník nehlasoval | ||||
| # 				p.body.append("?") | ||||
| # | ||||
| # 	for h in hlasovani: | ||||
| # 		h.ucastnik = hash(h.ucastnik) | ||||
| # | ||||
| # 	return render( | ||||
| # 		request, | ||||
| # 		'prednasky/seznam_prednasek_export.txt', | ||||
| # 		{"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove}, | ||||
| # 		content_type="text/plain" | ||||
| # 	) | ||||
| 
 | ||||
| 	for p in prednasky: | ||||
| 		p.body = [] | ||||
| 		for u in ucastnici: | ||||
| 			try: | ||||
| 				p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body) | ||||
| 			except ObjectDoesNotExist: | ||||
| 				# účastník nehlasoval | ||||
| 				p.body.append("?") | ||||
| 
 | ||||
| def PrednaskyExportView(request: HttpRequest, seznam: int, **kwargs) -> HttpResponse: | ||||
| 	""" | ||||
| 		Vrátí všechna :py:class:`Hlasování <prednasky.models.Hlasovani>` | ||||
| 		i :py:class:`HlasováníOZnalostech <prednasky.models.HlasovaniOZnalostech>` | ||||
| 		v daném :py:class:`Seznamu <prednasky.models.Seznam>` | ||||
| 		jako csv soubor (řádky = účastníci, sloupce = přednášky&znalosti). | ||||
| 
 | ||||
| 		:param seznam: ID daného :py:class:`Seznamu <prednasky.models.Seznam>` | ||||
| 	""" | ||||
| 	hlasovani = Hlasovani.objects.filter(seznam=seznam).select_related("prednaska") | ||||
| 	hlasovani_o_znalostech = HlasovaniOZnalostech.objects.filter(seznam=seznam).select_related('ucastnik', 'znalost') | ||||
| 
 | ||||
| 	# Inicializujeme sloupce | ||||
| 	prednasky = list(Prednaska.objects.filter(seznamy=seznam)) | ||||
| 	znalosti = list(Znalost.objects.filter(seznamy=seznam)) | ||||
| 
 | ||||
| 	prednasky_map: dict[int, int] = {p.id: i for i, p in enumerate(prednasky, 1)} | ||||
| 	offset = len(prednasky_map) | ||||
| 	znalosti_map: dict[int, int] = {z.id: i for i, z in enumerate(znalosti, offset + 1)} | ||||
| 	width = offset + len(znalosti_map) | ||||
| 
 | ||||
| 	# A po inicializaci sloupců vyplníme tabulku | ||||
| 	table: [str, list[str|Prednaska|Znalost,]] = {} | ||||
| 
 | ||||
| 	for h in hlasovani: | ||||
| 		h.ucastnik = hash(h.ucastnik) | ||||
| 		if h.ucastnik not in table: # Pokud jsme účastníka ještě neviděli, předgenerujeme si jeho řádek | ||||
| 			table[h.ucastnik] = [h.ucastnik] + ([""] * width) | ||||
| 
 | ||||
| 	return render( | ||||
| 		request, | ||||
| 		'prednasky/seznam_prednasek_export.txt', | ||||
| 		{"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove}, | ||||
| 		content_type="text/plain" | ||||
| 	) | ||||
| 		if h.prednaska.id in prednasky_map: | ||||
| 			table[h.ucastnik][prednasky_map[h.prednaska.id]] = h.body | ||||
| 		else: | ||||
| 			pass # TODO Padat hlasitě? | ||||
| 
 | ||||
| 	for h in hlasovani_o_znalostech: | ||||
| 		ucastnik = str(h.ucastnik) + ' ' + str(h.ucastnik.id) # id, kvůli kolizi jmen | ||||
| 		if ucastnik not in table: # Pokud jsme účastníka ještě neviděli, předgenerujeme si jeho řádek | ||||
| 			table[ucastnik] = [ucastnik] + ([""] * width) | ||||
| 
 | ||||
| 		if h.znalost.id in znalosti_map: | ||||
| 			table[ucastnik][znalosti_map[h.znalost.id]] = h.odpoved | ||||
| 		else: | ||||
| 			pass # TODO Padat hlasitě? | ||||
| 
 | ||||
| 
 | ||||
| 	response = HttpResponse(content_type="text/csv", charset="utf-8") | ||||
| 	response["Content-Disposition"] = 'attachment; filename="hlasovani.csv"' | ||||
| 
 | ||||
| 	writer = csv.writer(response) | ||||
| 	writer.writerow(["jména \\ přednáška|znalost"] + list(map(str, prednasky + znalosti))) | ||||
| 	for row in table.values(): | ||||
| 		writer.writerow(list(map(str, row))) | ||||
| 	return response | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue