Merge branch 'data_migrations' of gimli.ms.mff.cuni.cz:/akce/mam/git/mamweb into data_migrations
This commit is contained in:
		
						commit
						d5c4884a35
					
				
					 19 changed files with 1341 additions and 46 deletions
				
			
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -123,6 +123,7 @@ INSTALLED_APPS = ( | ||||||
|      |      | ||||||
|     'webpack_loader', |     'webpack_loader', | ||||||
|     'rest_framework', |     'rest_framework', | ||||||
|  |     'rest_framework.authtoken', | ||||||
| 
 | 
 | ||||||
|     # MaMweb |     # MaMweb | ||||||
|     'mamweb', |     'mamweb', | ||||||
|  | @ -294,6 +295,9 @@ LOGGING = { | ||||||
|             }, |             }, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | # Permissions for uploads | ||||||
|  | FILE_UPLOAD_PERMISSIONS = 0o0644 | ||||||
|  | 
 | ||||||
| # MaM specific | # MaM specific | ||||||
| 
 | 
 | ||||||
| SEMINAR_RESENI_DIR = os.path.join('reseni') | SEMINAR_RESENI_DIR = os.path.join('reseni') | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								seminar/.~lock.profile_vysledkovka.txt#
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								seminar/.~lock.profile_vysledkovka.txt#
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | ,anet,erebus,25.03.2020 22:21,file:///home/anet/.config/libreoffice/4; | ||||||
|  | @ -743,12 +743,20 @@ class Problem(SeminarModelBase,PolymorphicModel): | ||||||
| 		return '<Není zadaný>' | 		return '<Není zadaný>' | ||||||
| 
 | 
 | ||||||
| 	def verejne(self): | 	def verejne(self): | ||||||
| 		# FIXME: Tohle se liší podle typu problému, má se udělat polymorfně. | 		# aktuálně podle stavu problému | ||||||
| 		# Zatím je tu jen dummy fail-safe default: nic není veřejné. | 		# FIXME pro některé problémy možná chceme override | ||||||
| 		# Doporučené řešení: dělat tohle podle stavu problému a veřejnosti čísla, ve kterém je | 		# FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.  | ||||||
| 		return False | 		# Je to tak správně? | ||||||
| 		# FIXME: Tohle je blbost | 		stav_verejny = False | ||||||
| 		return (self.cislo_zadani and self.cislo_zadani.verejne()) | 		if self.stav == 'zadany' or self.stav == 'vyreseny': | ||||||
|  | 			stav_verejny = True | ||||||
|  | 		return stav_verejny | ||||||
|  | 		 | ||||||
|  | 		#cislo_verejne = False | ||||||
|  | 		#if (self.cislo_zadani and self.cislo_zadani.verejne()): | ||||||
|  | 		#	cislo_verejne = True | ||||||
|  | 		 | ||||||
|  | 		#return (stav_verejny and cislo_verejne) | ||||||
| 	verejne.boolean = True | 	verejne.boolean = True | ||||||
| 
 | 
 | ||||||
| 	def verejne_url(self): | 	def verejne_url(self): | ||||||
|  | @ -986,7 +994,7 @@ def aux_generate_filename(self, filename): | ||||||
| 		unidecode(filename.replace('/', '-').replace('\0', '')) | 		unidecode(filename.replace('/', '-').replace('\0', '')) | ||||||
| 	) | 	) | ||||||
| 	datedir = timezone.now().strftime('%Y-%m') | 	datedir = timezone.now().strftime('%Y-%m') | ||||||
| 	fname = "{}_{}".format( | 	fname = "{}/{}".format( | ||||||
| 		timezone.now().strftime('%Y-%m-%d-%H:%M'), | 		timezone.now().strftime('%Y-%m-%d-%H:%M'), | ||||||
| 		clean) | 		clean) | ||||||
| 	return os.path.join(datedir, fname) | 	return os.path.join(datedir, fname) | ||||||
|  | @ -1039,6 +1047,11 @@ class PrilohaReseni(SeminarModelBase): | ||||||
| 	def __str__(self): | 	def __str__(self): | ||||||
| 		return str(self.soubor) | 		return str(self.soubor) | ||||||
| 
 | 
 | ||||||
|  | 	def split(self): | ||||||
|  | 		"Vrátí cestu rozsekanou po složkách. To se hodí v templatech" | ||||||
|  | 		# Věřím, že tohle funguje, případně použít os.path nebo pathlib. | ||||||
|  | 		return self.soubor.url.split('/') | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class Pohadka(SeminarModelBase): | class Pohadka(SeminarModelBase): | ||||||
| 	"""Kus pohádky před/za úlohou v čísle""" | 	"""Kus pohádky před/za úlohou v čísle""" | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								seminar/permissions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								seminar/permissions.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | from rest_framework.permissions import BasePermission | ||||||
|  | 
 | ||||||
|  | class AllowWrite(BasePermission): | ||||||
|  | 
 | ||||||
|  |          def has_permission(self, request, view): | ||||||
|  |                   return request.user.has_perm('auth.org') | ||||||
|  | 
 | ||||||
							
								
								
									
										97
									
								
								seminar/templates/seminar/archiv/cislo-normal.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								seminar/templates/seminar/archiv/cislo-normal.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,97 @@ | ||||||
|  | {% extends "seminar/archiv/base_cisla.html" %} | ||||||
|  | 
 | ||||||
|  | {# {% block content %} | ||||||
|  |  <div> | ||||||
|  | 
 | ||||||
|  |   <h1> | ||||||
|  |     {% block nadpis1a %}{% block nadpis1b %} | ||||||
|  |       Číslo {{ cislo }} | ||||||
|  |     {% endblock %}{% endblock %} | ||||||
|  |   </h1> | ||||||
|  | 
 | ||||||
|  |   {% if cislo.pdf %} | ||||||
|  |     <p><a href='{{ cislo.pdf.url }}'>Číslo v pdf</a> | ||||||
|  |   {% endif %} | ||||||
|  |   <p><a href='{{ cislo.rocnik.verejne_url }}'>Ročník {{ cislo.rocnik }}</a> | ||||||
|  | 
 | ||||||
|  |   {% if v_cisle_zadane %} | ||||||
|  |     <h2>Zadané problémy</h2> | ||||||
|  |     <ul> | ||||||
|  |     {% for p in v_cisle_zadane %} | ||||||
|  |       <li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> | ||||||
|  |         {% if user.is_staff or cislo.verejne %} | ||||||
|  |           <a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} | ||||||
|  |     {% endfor %} | ||||||
|  |     </ul> | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  |   {% if resene_problemy %} | ||||||
|  |     <h2>Řešené problémy</h2> | ||||||
|  |     <ul> | ||||||
|  |     {% for p in resene_problemy %} | ||||||
|  |       <li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> | ||||||
|  |         {% if user.is_staff or cislo.verejne %} | ||||||
|  |           <a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} | ||||||
|  |     {% endfor %} | ||||||
|  |     </ul> | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  |   {% if user.is_staff %} | ||||||
|  |       <div class="mam-org-only"> | ||||||
|  |         <h2> Orgovské odkazy </h2> | ||||||
|  |         <ul> | ||||||
|  |           <li><a href="obalky.pdf">Obálky (PDF)</a></li> | ||||||
|  |           <li><a href="tituly.tex">Tituly (TeX)</a></li> | ||||||
|  |           <li><a href="vysledkovka.tex">Výsledkovka (TeX)</a></li> | ||||||
|  |           <li><a href="obalkovani">Obálkování</a></li> | ||||||
|  |         </ul> | ||||||
|  |       </div> | ||||||
|  |   {% endif %}  | ||||||
|  | 
 | ||||||
|  |   {% if cislo.verejna_vysledkovka %} | ||||||
|  |   <h2>Výsledkovka</h2> | ||||||
|  |   {% else %} | ||||||
|  |     {% if user.is_staff %} | ||||||
|  |       <div class='mam-org-only'> | ||||||
|  |       <h2>Výsledkovka (neveřejná)</h2> | ||||||
|  |     {% endif %} | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  |   {% if cislo.verejna_vysledkovka or user.is_staff %} | ||||||
|  |     <table class='vysledkovka'> | ||||||
|  |       <tr class='border-b'> | ||||||
|  |         <th class='border-r'># | ||||||
|  |         <th class='border-r'>Jméno #} | ||||||
|  |         {# problémy by měly být veřejné, když je veřejná výsledkovka #} | ||||||
|  | {#        {% for p in problemy %} | ||||||
|  |         <th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a> | ||||||
|  |         {% endfor %} | ||||||
|  |         <th class='border-r'>Za číslo</sup> | ||||||
|  |         <th class='border-r'>Za ročník | ||||||
|  |         <th class='border-r'>Odjakživa | ||||||
|  |     {% for rv in radky_vysledkovky %} | ||||||
|  |       <tr> | ||||||
|  |         <td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %} | ||||||
|  |             <th class='border-r'> | ||||||
|  |             {% if rv.resitel.titul != "" %} | ||||||
|  |               {{ rv.resitel.titul }}<sup>MM</sup> | ||||||
|  |             {% endif %} | ||||||
|  |             {{ rv.resitel.osoba.plne_jmeno }} | ||||||
|  |         {% for b in rv.hlavni_problemy_body %} | ||||||
|  |         <td class='border-r'>{{ b }} | ||||||
|  |         {% endfor %} | ||||||
|  |         <td class='border-r'>{{ rv.body_cislo }} | ||||||
|  |         <td class='border-r'><b>{{ rv.body_rocnik }}</b> | ||||||
|  |         <td class='border-r'>{{ rv.body_celkem_odjakziva }} | ||||||
|  |       </tr> | ||||||
|  |     {% endfor %} | ||||||
|  |     </table> | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  |   {% if not cislo.verejna_vysledkovka and user.is_staff %} | ||||||
|  |       </div> | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  | </div>  | ||||||
|  | {% endblock content %} #} | ||||||
|  | 
 | ||||||
							
								
								
									
										19
									
								
								seminar/templates/seminar/archiv/problem_tema.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								seminar/templates/seminar/archiv/problem_tema.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | {% extends "seminar/archiv/problem.html" %} | ||||||
|  | 
 | ||||||
|  | {% block problem %} | ||||||
|  |     <h1> | ||||||
|  |       {% block nadpis1a %}{% block nadpis1b %} | ||||||
|  |         {{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }} | ||||||
|  |       {% endblock %}{% endblock %} | ||||||
|  |     </h1> | ||||||
|  | 
 | ||||||
|  |   <h2>Zadání</h2> | ||||||
|  |   {{ problem.text_zadani |safe }} | ||||||
|  |   {% if problem.text_reseni %} | ||||||
|  |     <h2>Řešení</h2> | ||||||
|  |     {{ problem.text_reseni |safe }} | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  |   {# TODO vysledkovka tematu #} | ||||||
|  | 
 | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										23
									
								
								seminar/templates/seminar/archiv/problem_uloha.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								seminar/templates/seminar/archiv/problem_uloha.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | ||||||
|  | {% extends "seminar/archiv/problem.html" %} | ||||||
|  | 
 | ||||||
|  | {% block problem %} | ||||||
|  |     <h1> | ||||||
|  |       {% block nadpis1a %}{% block nadpis1b %} | ||||||
|  |         {{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }} {{ problem.body_v_zavorce }} | ||||||
|  |       {% endblock %}{% endblock %} | ||||||
|  |     </h1> | ||||||
|  |   {% if problem.cislo_zadani %} | ||||||
|  |     <p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>. | ||||||
|  |   {% endif %} | ||||||
|  |   {% if problem.cislo_reseni %} | ||||||
|  |     <p>Řešeno v čísle <a href='{{ problem.cislo_reseni.verejne_url }}'>{{ problem.cislo_reseni.kod }}</a>. | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  |   <h2>Zadání</h2> | ||||||
|  |   {{ problem.text_zadani |safe }} | ||||||
|  |   {% if problem.text_reseni %} | ||||||
|  |     <h2>Řešení</h2> | ||||||
|  |     {{ problem.text_reseni |safe }} | ||||||
|  |   {% endif %} | ||||||
|  | 
 | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										47
									
								
								seminar/templates/seminar/odevzdavatko/detail.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								seminar/templates/seminar/odevzdavatko/detail.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  | 
 | ||||||
|  | <p>Řešené problémy: {{ object.problem.all | join:", " }}</p> | ||||||
|  | 
 | ||||||
|  | <p>Řešitelé: {{ object.resitele.all | join:", " }}</p> | ||||||
|  | 
 | ||||||
|  | {# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #} | ||||||
|  | <p>Forma: {{ object.get_forma_display }}, doručeno {{ object.cas_doruceni }}</p> | ||||||
|  | 
 | ||||||
|  | {# Soubory: #} | ||||||
|  | <h3>Přílohy:</h3> | ||||||
|  | {% if object.prilohy.all %} | ||||||
|  | <table> | ||||||
|  | <tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr> | ||||||
|  | {% for priloha in object.prilohy.all %} | ||||||
|  | <tr> | ||||||
|  | 	<td><a href="{{ priloha.soubor.url }}" download>{{ priloha.split | last }}</a></td> | ||||||
|  | 	<td>{{ priloha.res_poznamka }}</td> | ||||||
|  | 	<td>{{ priloha.vytvoreno }}</td></tr> | ||||||
|  | 	{# TODO: Orgo-poznámka, ideálně jako formulář #} | ||||||
|  | {% endfor %} | ||||||
|  | </table> | ||||||
|  | {% else %} | ||||||
|  | <p>Žádné přílohy</p> | ||||||
|  | {% endif %} | ||||||
|  | 
 | ||||||
|  | {# Hodnocení: #} | ||||||
|  | {# FIXME: Udělat jako formulář #} | ||||||
|  | <h3>Hodnocení:</h3> | ||||||
|  | {% if object.hodnoceni_set.all %} | ||||||
|  | <table> | ||||||
|  | <tr><th>Problém</th><th>Body</th><th>Číslo pro body</th></tr> | ||||||
|  | {% for h in object.hodnoceni_set.all %} | ||||||
|  | <tr> | ||||||
|  | 	<td>{{ h.problem }}</a></td> | ||||||
|  | 	<td>{{ h.body }}</td> | ||||||
|  | 	<td>{{ h.cislo_body }}</td></tr> | ||||||
|  | {% endfor %} | ||||||
|  | </table> | ||||||
|  | {% else %} | ||||||
|  | <p>Ještě nebylo hodnoceno</p> | ||||||
|  | {% endif %} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										11
									
								
								seminar/templates/seminar/odevzdavatko/seznam.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								seminar/templates/seminar/odevzdavatko/seznam.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  | 
 | ||||||
|  | <ul> | ||||||
|  | 	{% for obj in object_list %} | ||||||
|  | 	<li><a href="{% url 'odevzdavatko_detail_reseni' pk=obj.id %}">{{ obj }}</a> ({{ obj.get_forma_display }} {{ obj.cas_doruceni }}) | ||||||
|  | 	{% endfor %} | ||||||
|  | </ul> | ||||||
|  | 
 | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										36
									
								
								seminar/templates/seminar/odevzdavatko/tabulka.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								seminar/templates/seminar/odevzdavatko/tabulka.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | 
 | ||||||
|  | {% load utils %} {# Možná by mohlo být někde výš v hierarchii templatů... #} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  | 
 | ||||||
|  | <table> | ||||||
|  | 	<tr> | ||||||
|  | 		<td></td> {# Prázdná buňka v levém horním rohu #} | ||||||
|  | 		{% for p in problemy %} | ||||||
|  | 		<th> | ||||||
|  | 			{# TODO: Přehled řešení k problému, odkázaný odsud? #} | ||||||
|  | 			{{ p }} | ||||||
|  | 		</th> | ||||||
|  | 		{% endfor %} | ||||||
|  | 	</tr> | ||||||
|  | 	{% for resitel,hodnoty in radky%} | ||||||
|  | 	<tr> | ||||||
|  | 		<td> | ||||||
|  | 			{# TODO: Chceme mít view i na řešení konkrétního řešitele ke všem problémům? #} | ||||||
|  | 			{{ resitel }} | ||||||
|  | 		</td> | ||||||
|  | 		{% for hodn in hodnoty %} | ||||||
|  | 			<td> | ||||||
|  | 			{% if hodn %} | ||||||
|  | 			<a href="{% url 'odevzdavatko_reseni_resitele_k_problemu' problem=hodn.problem_id resitel=hodn.resitel_id %}"> | ||||||
|  | 				{{ hodn.pocet_reseni }} řeš.<br>{{ hodn.body }} b<br>{{ hodn.posledni_odevzdani|kratke_datum|default_if_none:"Nikdy"|default:"???"}} | ||||||
|  | 			</a> | ||||||
|  | 			{% endif %} | ||||||
|  | 			</td> | ||||||
|  | 		{% endfor %} | ||||||
|  | 	</tr> | ||||||
|  | 	{% endfor %} | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										27
									
								
								seminar/templatetags/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								seminar/templatetags/utils.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | from django import template | ||||||
|  | from datetime import datetime, timedelta | ||||||
|  | from pytz import timezone | ||||||
|  | from mamweb.settings import TIME_ZONE | ||||||
|  | import logging | ||||||
|  | register = template.Library() | ||||||
|  | 
 | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  | 
 | ||||||
|  | @register.filter(name='kratke_datum', expects_localtime=True) | ||||||
|  | def kratke_datum(dt): | ||||||
|  | 	# None dává None, ne-datum dává False, aby se daly použít filtry typu "default". | ||||||
|  | 	if dt is None: | ||||||
|  | 		return None | ||||||
|  | 	if not isinstance(dt, datetime): | ||||||
|  | 		logger.warning(f"Špatné volání filtru {__name__}: {dt}") | ||||||
|  | 		return False | ||||||
|  | 	naive_now = datetime.now() | ||||||
|  | 	tz = timezone(TIME_ZONE) | ||||||
|  | 	now = tz.localize(naive_now) | ||||||
|  | 	delta = now - dt | ||||||
|  | 	if delta <= timedelta(days=1): | ||||||
|  | 		return dt.strftime("%k:%M") | ||||||
|  | 	if delta <= timedelta(days=365):	# Timedelta neumí vyjádřit 1 rok | ||||||
|  | 		return dt.strftime("%d. %m.") | ||||||
|  | 	return dt.strftime("%d. %m. %Y") | ||||||
|  | 
 | ||||||
|  | @ -140,7 +140,7 @@ def gen_resitele(rnd, osoby, skoly): | ||||||
| 				x += 1 | 				x += 1 | ||||||
| 				os.user = user | 				os.user = user | ||||||
| 				os.save() | 				os.save() | ||||||
| 			os.user.user_permissions.add(resitel_perm) | 				os.user.user_permissions.add(resitel_perm) | ||||||
| 			resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice(skoly), | 			resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice(skoly), | ||||||
| 				rok_maturity=rnd.randint(2019, 2029), | 				rok_maturity=rnd.randint(2019, 2029), | ||||||
| 				zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0])) | 				zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0])) | ||||||
|  | @ -199,7 +199,7 @@ def gen_organizatori(rnd, osoby, last_rocnik): | ||||||
| 				x += 1 | 				x += 1 | ||||||
| 				os.user = user | 				os.user = user | ||||||
| 				os.save() | 				os.save() | ||||||
| 			os.user.user_permissions.add(org_perm) | 				os.user.user_permissions.add(org_perm) | ||||||
| 			organizatori.append(Organizator.objects.create(osoba=os, | 			organizatori.append(Organizator.objects.create(osoba=os, | ||||||
| 				organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga)) | 				organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga)) | ||||||
| 	return organizatori | 	return organizatori | ||||||
|  |  | ||||||
|  | @ -168,5 +168,10 @@ urlpatterns = [ | ||||||
| 	# org_member_required(views.OrganizatorAutocomplete.as_view()), | 	# org_member_required(views.OrganizatorAutocomplete.as_view()), | ||||||
| 	# name='seminar_autocomplete_organizator') | 	# name='seminar_autocomplete_organizator') | ||||||
| 
 | 
 | ||||||
|  | 	path('temp/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), | ||||||
|  | 	path('temp/reseni/<int:problem>/<int:resitel>/', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'), | ||||||
|  | 	path('temp/reseni/<int:pk>', org_required(views.DetailReseniView.as_view()), name='odevzdavatko_detail_reseni'), | ||||||
|  | 	path('temp/reseni/all', org_required(views.SeznamReseniView.as_view())), | ||||||
|  | 	path('temp/reseni/akt', org_required(views.SeznamAktualnichReseniView.as_view())), | ||||||
| 
 | 
 | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -148,16 +148,12 @@ def resi_v_rocniku(rocnik, cislo=None): | ||||||
| 
 | 
 | ||||||
| 	if cislo is None: | 	if cislo is None: | ||||||
| 		# filtrujeme pouze podle ročníku | 		# filtrujeme pouze podle ročníku | ||||||
| 		letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik) | 		return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(), | ||||||
|  | 										reseni__hodnoceni__cislo_body__rocnik=rocnik).distinct() | ||||||
| 	else:  # filtrujeme podle ročníku i čísla | 	else:  # filtrujeme podle ročníku i čísla | ||||||
| 		letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik, | 		return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(), | ||||||
| 												 hodnoceni__cislo_body__poradi__lte=cislo.poradi) | 										reseni__hodnoceni__cislo_body__rocnik=rocnik, | ||||||
| 
 | 										reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi).distinct() | ||||||
| 	# vygenerujeme queryset řešitelů, co letos něco poslali |  | ||||||
| 	letosni_resitele = m.Resitel.objects.none() |  | ||||||
| 	for reseni in letosni_reseni: |  | ||||||
| 		letosni_resitele = letosni_resitele | reseni.resitele.filter(rok_maturity__gte=rocnik.druhy_rok()) |  | ||||||
| 	return letosni_resitele.distinct() |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def aktivniResitele(cislo, pouze_letosni=False): | def aktivniResitele(cislo, pouze_letosni=False): | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
| from .views_all import * | from .views_all import * | ||||||
| from .autocomplete import * | from .autocomplete import * | ||||||
| from .views_rest import * | from .views_rest import * | ||||||
|  | from .odevzdavatko import * | ||||||
|  |  | ||||||
							
								
								
									
										129
									
								
								seminar/views/odevzdavatko.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								seminar/views/odevzdavatko.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,129 @@ | ||||||
|  | from django.views.generic import ListView, DetailView | ||||||
|  | from django.views.generic.base import TemplateView | ||||||
|  | 
 | ||||||
|  | from dataclasses import dataclass | ||||||
|  | import datetime | ||||||
|  | 
 | ||||||
|  | import seminar.models as m | ||||||
|  | from seminar.utils import aktivniResitele, resi_v_rocniku | ||||||
|  | 
 | ||||||
|  | # Co chceme? | ||||||
|  | # - "Tabulku" aktuální řešitelé x zveřejněné problémy, v buňkách počet řešení | ||||||
|  | # 	- TabulkaOdevzdanychReseniView | ||||||
|  | # - Detail konkrétního problému a řešitele -- přehled všech řešení odevzdaných k tomuto problému | ||||||
|  | # 	- ReseniProblemuView | ||||||
|  | # - Detail konkrétního řešení -- všechny soubory, datum, ... | ||||||
|  | # 	- DetailReseniView | ||||||
|  | # | ||||||
|  | # Taky se může hodit: | ||||||
|  | # - Tabulka všech řešitelů x všech problémů? | ||||||
|  | 
 | ||||||
|  | @dataclass | ||||||
|  | class SouhrnReseni: | ||||||
|  | 	"""Dataclass reprezentující data o odevzdaných řešeních pro zobrazení v tabulce.""" | ||||||
|  | 	pocet_reseni : int | ||||||
|  | 	posledni_odevzdani : datetime.datetime | ||||||
|  | 	body : float | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TabulkaOdevzdanychReseniView(ListView): | ||||||
|  | 	template_name = 'seminar/odevzdavatko/tabulka.html' | ||||||
|  | 	model = m.Hodnoceni | ||||||
|  | 
 | ||||||
|  | 	def get_queryset(self): | ||||||
|  | 		# FIXME: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistuje Nastavení. | ||||||
|  | 		self.akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik	# .get_solo() vrátí tu jedinou instanci, asi... | ||||||
|  | 		self.resitele = resi_v_rocniku(self.akt_rocnik) | ||||||
|  | 		# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy. | ||||||
|  | 		self.zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() | ||||||
|  | 
 | ||||||
|  | 		qs = super().get_queryset() | ||||||
|  | 		qs = qs.filter(problem__in=self.zadane_problemy).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba') | ||||||
|  | 		return qs | ||||||
|  | 
 | ||||||
|  | 	def get_context_data(self, *args, **kwargs): | ||||||
|  | 		# FIXME: Tenhle blok nemůže být přímo ve třídě, protože před vyrobením databáze neexistuje Nastavení. | ||||||
|  | 		self.akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik	# .get_solo() vrátí tu jedinou instanci, asi... | ||||||
|  | 		self.resitele = resi_v_rocniku(self.akt_rocnik) | ||||||
|  | 		# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy. | ||||||
|  | 		self.zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() | ||||||
|  | 
 | ||||||
|  | 		ctx = super().get_context_data(*args, **kwargs) | ||||||
|  | 		ctx['problemy'] = self.zadane_problemy | ||||||
|  | 		ctx['resitele'] = self.resitele | ||||||
|  | 		tabulka = dict() | ||||||
|  | 
 | ||||||
|  | 		def pridej_reseni(problem, resitel, body, cas): | ||||||
|  | 			if problem not in tabulka: | ||||||
|  | 				tabulka[problem] = dict() | ||||||
|  | 			if resitel not in tabulka[problem]: | ||||||
|  | 				tabulka[problem][resitel] = SouhrnReseni(pocet_reseni=1, posledni_odevzdani=cas, body=body) | ||||||
|  | 			else: | ||||||
|  | 				tabulka[problem][resitel].posledni_odevzdani = max(tabulka[problem][resitel].posledni_odevzdani, cas) | ||||||
|  | 				tabulka[problem][resitel].body = max(tabulka[problem][resitel].body, body, | ||||||
|  | 					key=lambda x: x if x is not None else -1 # None je malé číslo | ||||||
|  | 					# FIXME: Možná dává smysl i mít None jako velké číslo -- jakože "TODO: zadat body" | ||||||
|  | 					) | ||||||
|  | 				tabulka[problem][resitel].pocet_reseni += 1 | ||||||
|  | 			# Pro jednoduchost template si ještě poznamenáme ID problému a řešitele | ||||||
|  | 			tabulka[problem][resitel].problem_id = problem.id | ||||||
|  | 			tabulka[problem][resitel].resitel_id = resitel.id | ||||||
|  | 		 | ||||||
|  | 		for hodnoceni in self.get_queryset(): | ||||||
|  | 			for resitel in hodnoceni.reseni.resitele.all(): | ||||||
|  | 				pridej_reseni(hodnoceni.problem, resitel, hodnoceni.body, hodnoceni.reseni.cas_doruceni) | ||||||
|  | 
 | ||||||
|  | 		hodnoty = [] | ||||||
|  | 		for resitel in self.resitele: | ||||||
|  | 			resiteluv_radek = [] | ||||||
|  | 			for problem in self.zadane_problemy: | ||||||
|  | 				if problem in tabulka and resitel in tabulka[problem]: | ||||||
|  | 					resiteluv_radek.append(tabulka[problem][resitel]) | ||||||
|  | 				else: | ||||||
|  | 					resiteluv_radek.append(None) | ||||||
|  | 			hodnoty.append(resiteluv_radek) | ||||||
|  | 		ctx['radky'] = list(zip(self.resitele, hodnoty)) | ||||||
|  | 
 | ||||||
|  | 		return ctx | ||||||
|  | 
 | ||||||
|  | class ReseniProblemuView(ListView): | ||||||
|  | 	model = m.Reseni | ||||||
|  | 	template_name = 'seminar/odevzdavatko/seznam.html' | ||||||
|  | 	 | ||||||
|  | 	def get_queryset(self): | ||||||
|  | 		qs = super().get_queryset() | ||||||
|  | 		resitel_id = self.kwargs['resitel'] | ||||||
|  | 		if resitel_id is None: | ||||||
|  | 			raise ValueError("Nemám řešitele!") | ||||||
|  | 		problem_id = self.kwargs['problem'] | ||||||
|  | 		if problem_id is None: | ||||||
|  | 			raise ValueError("Nemám problém! (To je problém!)") | ||||||
|  | 		 | ||||||
|  | 		resitel = m.Resitel.objects.get(id=resitel_id) | ||||||
|  | 		problem = m.Problem.objects.get(id=problem_id) | ||||||
|  | 		qs = qs.filter( | ||||||
|  | 			problem__in=[problem], | ||||||
|  | 			resitele__in=[resitel], | ||||||
|  | 			) | ||||||
|  | 		return qs | ||||||
|  | 	 | ||||||
|  | 	# Kontext automaticky? | ||||||
|  | 
 | ||||||
|  | class DetailReseniView(DetailView): | ||||||
|  | 	model = m.Reseni | ||||||
|  | 	template_name = 'seminar/odevzdavatko/detail.html' | ||||||
|  | 	# To je všechno? Najde se to podle pk... | ||||||
|  | 
 | ||||||
|  | # Přehled všech řešení kvůli debugování | ||||||
|  | 
 | ||||||
|  | class SeznamReseniView(ListView): | ||||||
|  | 	model = m.Reseni | ||||||
|  | 	template_name = 'seminar/odevzdavatko/seznam.html' | ||||||
|  | 
 | ||||||
|  | class SeznamAktualnichReseniView(SeznamReseniView): | ||||||
|  | 	def get_queryset(self): | ||||||
|  | 		qs = super().get_queryset() | ||||||
|  | 		akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik	# .get_solo() vrátí tu jedinou instanci, asi... | ||||||
|  | 		resitele = resi_v_rocniku(akt_rocnik) | ||||||
|  | 		qs = qs.filter(resitele__in=resitele)	# FIXME: Najde řešení i ze starých ročníků, která odevzdal alespoň jeden aktuální řešitel | ||||||
|  | 		return qs | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| # coding:utf-8 | 
 | ||||||
| 
 | 
 | ||||||
| from django.shortcuts import get_object_or_404, render, redirect | from django.shortcuts import get_object_or_404, render, redirect | ||||||
| from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse | from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse | ||||||
|  | @ -17,6 +17,7 @@ from django.contrib.auth.models import User, Permission | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
| from django.db import transaction | from django.db import transaction | ||||||
| from django.core import serializers | from django.core import serializers | ||||||
|  | from django.core.exceptions import PermissionDenied | ||||||
| from django.forms.models import model_to_dict | from django.forms.models import model_to_dict | ||||||
| 
 | 
 | ||||||
| import seminar.models as s | import seminar.models as s | ||||||
|  | @ -120,14 +121,57 @@ class TNLData(object): | ||||||
| 			self.appendable_siblings = tnltt.appendableChildren(self.parent) | 			self.appendable_siblings = tnltt.appendableChildren(self.parent) | ||||||
| 		else: | 		else: | ||||||
| 			self.appendable_siblings = [] | 			self.appendable_siblings = [] | ||||||
|  | 	@classmethod | ||||||
|  | 	def public_above(cls, anode): | ||||||
|  | 		""" Returns output of verejne for closest Rocnik, Cislo or Problem above. | ||||||
|  | 		(All of them have method verejne.)""" | ||||||
|  | 		parent = anode # chceme začít už od konkrétního node včetně | ||||||
|  | 		while True: | ||||||
|  | 			rocnik = isinstance(parent, s.RocnikNode) | ||||||
|  | 			cislo = isinstance(parent, s.CisloNode) | ||||||
|  | 			uloha = (isinstance(parent, s.UlohaVzorakNode) or  | ||||||
|  | 				isinstance(parent, s.UlohaZadaniNode)) | ||||||
|  | 			tema = isinstance(parent, s.TemaVCisleNode) | ||||||
| 
 | 
 | ||||||
| 
 | 			if (rocnik or cislo or uloha or tema) or parent==None: | ||||||
|  | 				break | ||||||
|  | 			else: | ||||||
|  | 				parent = treelib.get_parent(parent) | ||||||
|  | 		if rocnik: | ||||||
|  | 			return parent.rocnik.verejne() | ||||||
|  | 		elif cislo: | ||||||
|  | 			return parent.cislo.verejne() | ||||||
|  | 		elif uloha: | ||||||
|  | 			return parent.uloha.verejne() | ||||||
|  | 		elif tema: | ||||||
|  | 			return parent.tema.verejne() | ||||||
|  | 		elif None: | ||||||
|  | 			print("Existuje TreeNode, který není pod číslem, ročníkem, úlohou" | ||||||
|  | 			"ani tématem. {}".format(anode)) | ||||||
|  | 			return False | ||||||
| 	 | 	 | ||||||
| 	@classmethod | 	@classmethod | ||||||
| 	def from_treenode(cls,anode,parent=None,index=None): | 	def all_public_children(cls, anode): | ||||||
| 		out = cls(anode,parent,index) | 		for ch in treelib.all_children(anode): | ||||||
| 		for (idx,ch) in enumerate(treelib.all_children(anode)): | 			if TNLData.public_above(ch): | ||||||
| 			outitem = cls.from_treenode(ch,out,idx) | 				yield ch | ||||||
|  | 			else: | ||||||
|  | 				continue | ||||||
|  | 
 | ||||||
|  | 	@classmethod | ||||||
|  | 	def from_treenode(cls, anode, user, parent=None, index=None): | ||||||
|  | 		if TNLData.public_above(anode) or user.has_perm('auth.org'): | ||||||
|  | 			out = cls(anode,parent,index) | ||||||
|  | 		else: | ||||||
|  | 			raise PermissionDenied() | ||||||
|  | 
 | ||||||
|  | 		if user.has_perm('auth.org'): | ||||||
|  | 			enum_children = enumerate(treelib.all_children(anode)) | ||||||
|  | 		else: | ||||||
|  | 			enum_children = enumerate(TNLData.all_public_children(anode))	 | ||||||
|  | 	 | ||||||
|  | 		for (idx,ch) in enum_children: | ||||||
|  | 			outitem = cls.from_treenode(ch, user, out,  idx) | ||||||
| 			out.children.append(outitem) | 			out.children.append(outitem) | ||||||
| 		out.add_edit_options() | 		out.add_edit_options() | ||||||
| 		return out | 		return out | ||||||
|  | @ -194,7 +238,7 @@ class TreeNodeView(generic.DetailView): | ||||||
| 
 | 
 | ||||||
| 	def get_context_data(self,**kwargs): | 	def get_context_data(self,**kwargs): | ||||||
| 		context = super().get_context_data(**kwargs) | 		context = super().get_context_data(**kwargs) | ||||||
| 		context['tnldata'] = TNLData.from_treenode(self.object) | 		context['tnldata'] = TNLData.from_treenode(self.object,self.request.user) | ||||||
| 		return context | 		return context | ||||||
| 
 | 
 | ||||||
| class TreeNodeJSONView(generic.DetailView): | class TreeNodeJSONView(generic.DetailView): | ||||||
|  | @ -202,7 +246,7 @@ class TreeNodeJSONView(generic.DetailView): | ||||||
| 
 | 
 | ||||||
| 	def get(self,request,*args, **kwargs): | 	def get(self,request,*args, **kwargs): | ||||||
| 		self.object = self.get_object() | 		self.object = self.get_object() | ||||||
| 		data = TNLData.from_treenode(self.object).to_json() | 		data = TNLData.from_treenode(self.object,self.request.user).to_json() | ||||||
| 		return JsonResponse(data) | 		return JsonResponse(data) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -331,6 +375,7 @@ class ProblemView(generic.DetailView): | ||||||
| 
 | 
 | ||||||
| 	def get_context_data(self, **kwargs): | 	def get_context_data(self, **kwargs): | ||||||
| 		context = super().get_context_data(**kwargs) | 		context = super().get_context_data(**kwargs) | ||||||
|  | 		user = self.request.user | ||||||
| 		# Teď potřebujeme doplnit tnldata do kontextu. | 		# Teď potřebujeme doplnit tnldata do kontextu. | ||||||
| 		# Ošklivý type switch, hezčí by bylo udělat to polymorfni. FIXME. | 		# Ošklivý type switch, hezčí by bylo udělat to polymorfni. FIXME. | ||||||
| 		if False: | 		if False: | ||||||
|  | @ -338,11 +383,11 @@ class ProblemView(generic.DetailView): | ||||||
| 			pass | 			pass | ||||||
| 		elif isinstance(self.object, s.Clanek) or  isinstance(self.object, s.Konfera): | 		elif isinstance(self.object, s.Clanek) or  isinstance(self.object, s.Konfera): | ||||||
| 			# Tyhle Problémy mají ŘešeníNode | 			# Tyhle Problémy mají ŘešeníNode | ||||||
| 			context['tnldata'] = TNLData.from_treenode(self.object.reseninode) | 			context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user) | ||||||
| 		elif isinstance(self.object, s.Uloha): | 		elif isinstance(self.object, s.Uloha): | ||||||
| 			# FIXME: Teď vždycky zobrazujeme i vzorák! Možná by bylo hezčí/lepší mít to stejně jako pro Téma: procházet jen dosažitelné z Ročníku / čísla / whatever | 			# FIXME: Teď vždycky zobrazujeme i vzorák! Možná by bylo hezčí/lepší mít to stejně jako pro Téma: procházet jen dosažitelné z Ročníku / čísla / whatever | ||||||
| 			tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode) | 			tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user) | ||||||
| 			tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode) | 			tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user) | ||||||
| 			context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak]) | 			context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak]) | ||||||
| 		elif isinstance(self.object, s.Tema): | 		elif isinstance(self.object, s.Tema): | ||||||
| 			rocniknode = self.object.rocnik.rocniknode | 			rocniknode = self.object.rocnik.rocniknode | ||||||
|  | @ -384,16 +429,16 @@ class AktualniZadaniView(generic.TemplateView): | ||||||
| #			) | #			) | ||||||
| # | # | ||||||
| def ZadaniTemataView(request): | def ZadaniTemataView(request): | ||||||
|         nastaveni = get_object_or_404(Nastaveni) | 	nastaveni = get_object_or_404(Nastaveni) | ||||||
|         verejne = nastaveni.aktualni_cislo.verejne() | 	verejne = nastaveni.aktualni_cislo.verejne() | ||||||
|         akt_rocnik = nastaveni.aktualni_cislo.rocnik | 	akt_rocnik = nastaveni.aktualni_cislo.rocnik | ||||||
|         temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') | 	temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany') | ||||||
|         return render(request, 'seminar/tematka/rozcestnik.html', | 	return render(request, 'seminar/tematka/rozcestnik.html', | ||||||
|                         { | 			{ | ||||||
|                          'tematka': temata, | 			 'tematka': temata, | ||||||
|                          'verejne': verejne, | 			 'verejne': verejne, | ||||||
|                                 }, | 				}, | ||||||
|                         ) | 			) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #	nastaveni = get_object_or_404(Nastaveni) | #	nastaveni = get_object_or_404(Nastaveni) | ||||||
|  |  | ||||||
|  | @ -1,7 +1,23 @@ | ||||||
| from rest_framework import viewsets,filters | from rest_framework import viewsets,filters | ||||||
|  | from rest_framework.permissions import BasePermission, AllowAny | ||||||
| from . import models as m | from . import models as m | ||||||
| from . import views | from . import views | ||||||
| 
 | 
 | ||||||
|  | from seminar.permissions import AllowWrite  | ||||||
|  | 
 | ||||||
|  | class PermissionMixin(object): | ||||||
|  | 	""" Redefines get_permissions so that only organizers can make changes. """ | ||||||
|  | 
 | ||||||
|  | 	def get_permissions(self): | ||||||
|  | 		permission_classes = [] | ||||||
|  | 		print("get_permissions have been called.") | ||||||
|  | 		if self.action in ["create", "update", "partial_update", "destroy"]: | ||||||
|  | 			permission_classes = [AllowWrite] # speciální permission na zápis - orgové | ||||||
|  | 		else: | ||||||
|  | 			permission_classes = [AllowAny]  | ||||||
|  | 		# návštěvník nemusí být zalogován, aby si prohlížel obsah | ||||||
|  | 		return [permission() for permission in permission_classes] | ||||||
|  | 
 | ||||||
| class ReadWriteSerializerMixin(object): | class ReadWriteSerializerMixin(object): | ||||||
| 	""" | 	""" | ||||||
| 	Overrides get_serializer_class to choose the read serializer | 	Overrides get_serializer_class to choose the read serializer | ||||||
|  | @ -46,27 +62,27 @@ class ReadWriteSerializerMixin(object): | ||||||
| 		) | 		) | ||||||
| 		return self.create_serializer_class | 		return self.create_serializer_class | ||||||
| 
 | 
 | ||||||
| class UlohaVzorakNodeViewSet(viewsets.ModelViewSet): | class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet): | ||||||
| 	queryset = m.UlohaVzorakNode.objects.all() | 	queryset = m.UlohaVzorakNode.objects.all() | ||||||
| 	serializer_class = views.UlohaVzorakNodeSerializer | 	serializer_class = views.UlohaVzorakNodeSerializer | ||||||
| 
 | 
 | ||||||
| class TextViewSet(viewsets.ModelViewSet): | class TextViewSet(PermissionMixin, viewsets.ModelViewSet): | ||||||
| 	queryset = m.Text.objects.all() | 	queryset = m.Text.objects.all() | ||||||
| 	serializer_class = views.TextSerializer | 	serializer_class = views.TextSerializer | ||||||
| 
 | 
 | ||||||
| class TextNodeViewSet(ReadWriteSerializerMixin,viewsets.ModelViewSet): | class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | ||||||
| 	queryset = m.TextNode.objects.all() | 	queryset = m.TextNode.objects.all() | ||||||
| 	read_serializer_class = views.TextNodeSerializer | 	read_serializer_class = views.TextNodeSerializer | ||||||
| 	write_serializer_class = views.TextNodeWriteSerializer | 	write_serializer_class = views.TextNodeWriteSerializer | ||||||
| 	create_serializer_class = views.TextNodeCreateSerializer | 	create_serializer_class = views.TextNodeCreateSerializer | ||||||
| 
 | 
 | ||||||
| class CastNodeViewSet(ReadWriteSerializerMixin,viewsets.ModelViewSet): | class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): | ||||||
| 	queryset = m.CastNode.objects.all() | 	queryset = m.CastNode.objects.all() | ||||||
| 	read_serializer_class = views.CastNodeSerializer | 	read_serializer_class = views.CastNodeSerializer | ||||||
| 	write_serializer_class = views.CastNodeSerializer | 	write_serializer_class = views.CastNodeSerializer | ||||||
| 	create_serializer_class = views.CastNodeCreateSerializer | 	create_serializer_class = views.CastNodeCreateSerializer | ||||||
| 
 | 
 | ||||||
| class UlohaVzorakNodeViewSet(viewsets.ModelViewSet): | class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet): | ||||||
| 	serializer_class = views.UlohaVzorakNodeSerializer | 	serializer_class = views.UlohaVzorakNodeSerializer | ||||||
| 
 | 
 | ||||||
| 	def get_queryset(self): | 	def get_queryset(self): | ||||||
|  | @ -74,4 +90,7 @@ class UlohaVzorakNodeViewSet(viewsets.ModelViewSet): | ||||||
| 		nazev = self.request.query_params.get('nazev',None) | 		nazev = self.request.query_params.get('nazev',None) | ||||||
| 		if nazev is not None: | 		if nazev is not None: | ||||||
| 			queryset = queryset.filter(nazev__contains=nazev) | 			queryset = queryset.filter(nazev__contains=nazev) | ||||||
| 		return queryset | 		if self.request.user.has_perm('auth.org'): | ||||||
|  | 			return queryset | ||||||
|  | 		else: # pro neorgy jen zveřejněné vzoráky | ||||||
|  | 			return queryset.filter(uloha__cislo_reseni__verejne_db=True) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Kateřina Č
						Kateřina Č