'
def verejne(self):
- # FIXME: Tohle se liší podle typu problému, má se udělat polymorfně.
- # Zatím je tu jen dummy fail-safe default: nic není veřejné.
- # Doporučené řešení: dělat tohle podle stavu problému a veřejnosti čísla, ve kterém je
- return False
- # FIXME: Tohle je blbost
- return (self.cislo_zadani and self.cislo_zadani.verejne())
+ # aktuálně podle stavu problému
+ # FIXME pro některé problémy možná chceme override
+ # FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.
+ # Je to tak správně?
+ stav_verejny = False
+ 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
def verejne_url(self):
@@ -986,7 +994,7 @@ def aux_generate_filename(self, filename):
unidecode(filename.replace('/', '-').replace('\0', ''))
)
datedir = timezone.now().strftime('%Y-%m')
- fname = "{}_{}".format(
+ fname = "{}/{}".format(
timezone.now().strftime('%Y-%m-%d-%H:%M'),
clean)
return os.path.join(datedir, fname)
@@ -1039,6 +1047,11 @@ class PrilohaReseni(SeminarModelBase):
def __str__(self):
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):
"""Kus pohádky před/za úlohou v čísle"""
diff --git a/seminar/permissions.py b/seminar/permissions.py
new file mode 100644
index 00000000..5503832f
--- /dev/null
+++ b/seminar/permissions.py
@@ -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')
+
diff --git a/seminar/templates/seminar/archiv/cislo-normal.html b/seminar/templates/seminar/archiv/cislo-normal.html
new file mode 100644
index 00000000..e23da09c
--- /dev/null
+++ b/seminar/templates/seminar/archiv/cislo-normal.html
@@ -0,0 +1,97 @@
+{% extends "seminar/archiv/base_cisla.html" %}
+
+{# {% block content %}
+
+
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ Číslo {{ cislo }}
+ {% endblock %}{% endblock %}
+
+
+ {% if cislo.pdf %}
+
Číslo v pdf
+ {% endif %}
+
Ročník {{ cislo.rocnik }}
+
+ {% if v_cisle_zadane %}
+
Zadané problémy
+
+ {% endif %}
+
+ {% if resene_problemy %}
+
Řešené problémy
+
+ {% endif %}
+
+ {% if user.is_staff %}
+
+ {% endif %}
+
+ {% if cislo.verejna_vysledkovka %}
+
Výsledkovka
+ {% else %}
+ {% if user.is_staff %}
+
+
Výsledkovka (neveřejná)
+ {% endif %}
+ {% endif %}
+
+ {% if cislo.verejna_vysledkovka or user.is_staff %}
+
+
+ #
+ | Jméno #}
+ {# problémy by měly být veřejné, když je veřejná výsledkovka #}
+{# {% for p in problemy %}
+ | {{ p.kod_v_rocniku }}
+ {% endfor %}
+ | Za číslo
+ | Za ročník
+ | Odjakživa
+ {% for rv in radky_vysledkovky %}
+ |
+ {% autoescape off %}{{ rv.poradi }}{% endautoescape %}
+ |
+ {% if rv.resitel.titul != "" %}
+ {{ rv.resitel.titul }}MM
+ {% endif %}
+ {{ rv.resitel.osoba.plne_jmeno }}
+ {% for b in rv.hlavni_problemy_body %}
+ | {{ b }}
+ {% endfor %}
+ | {{ rv.body_cislo }}
+ | {{ rv.body_rocnik }}
+ | {{ rv.body_celkem_odjakziva }}
+ |
+ {% endfor %}
+
+ {% endif %}
+
+ {% if not cislo.verejna_vysledkovka and user.is_staff %}
+
+ {% endif %}
+
+
+{% endblock content %} #}
+
diff --git a/seminar/templates/seminar/archiv/problem_tema.html b/seminar/templates/seminar/archiv/problem_tema.html
new file mode 100644
index 00000000..421d73bd
--- /dev/null
+++ b/seminar/templates/seminar/archiv/problem_tema.html
@@ -0,0 +1,19 @@
+{% extends "seminar/archiv/problem.html" %}
+
+{% block problem %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ {{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }}
+ {% endblock %}{% endblock %}
+
+
+ Zadání
+ {{ problem.text_zadani |safe }}
+ {% if problem.text_reseni %}
+ Řešení
+ {{ problem.text_reseni |safe }}
+ {% endif %}
+
+ {# TODO vysledkovka tematu #}
+
+{% endblock %}
diff --git a/seminar/templates/seminar/archiv/problem_uloha.html b/seminar/templates/seminar/archiv/problem_uloha.html
new file mode 100644
index 00000000..df5e97f7
--- /dev/null
+++ b/seminar/templates/seminar/archiv/problem_uloha.html
@@ -0,0 +1,23 @@
+{% extends "seminar/archiv/problem.html" %}
+
+{% block problem %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ {{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }} {{ problem.body_v_zavorce }}
+ {% endblock %}{% endblock %}
+
+ {% if problem.cislo_zadani %}
+ Zadáno v čísle {{ problem.cislo_zadani.kod }}.
+ {% endif %}
+ {% if problem.cislo_reseni %}
+
Řešeno v čísle {{ problem.cislo_reseni.kod }}.
+ {% endif %}
+
+
Zadání
+ {{ problem.text_zadani |safe }}
+ {% if problem.text_reseni %}
+ Řešení
+ {{ problem.text_reseni |safe }}
+ {% endif %}
+
+{% endblock %}
diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html
new file mode 100644
index 00000000..6cee990d
--- /dev/null
+++ b/seminar/templates/seminar/odevzdavatko/detail.html
@@ -0,0 +1,47 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+Řešené problémy: {{ object.problem.all | join:", " }}
+
+Řešitelé: {{ object.resitele.all | join:", " }}
+
+{# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #}
+Forma: {{ object.get_forma_display }}, doručeno {{ object.cas_doruceni }}
+
+{# Soubory: #}
+Přílohy:
+{% if object.prilohy.all %}
+
+Soubor | Řešitelova poznámka | Datum |
+{% for priloha in object.prilohy.all %}
+
+ {{ priloha.split | last }} |
+ {{ priloha.res_poznamka }} |
+ {{ priloha.vytvoreno }} |
+ {# TODO: Orgo-poznámka, ideálně jako formulář #}
+{% endfor %}
+
+{% else %}
+Žádné přílohy
+{% endif %}
+
+{# Hodnocení: #}
+{# FIXME: Udělat jako formulář #}
+Hodnocení:
+{% if object.hodnoceni_set.all %}
+
+Problém | Body | Číslo pro body |
+{% for h in object.hodnoceni_set.all %}
+
+ {{ h.problem }} |
+ {{ h.body }} |
+ {{ h.cislo_body }} |
+{% endfor %}
+
+{% else %}
+Ještě nebylo hodnoceno
+{% endif %}
+
+
+{% endblock %}
diff --git a/seminar/templates/seminar/odevzdavatko/seznam.html b/seminar/templates/seminar/odevzdavatko/seznam.html
new file mode 100644
index 00000000..b58dcb54
--- /dev/null
+++ b/seminar/templates/seminar/odevzdavatko/seznam.html
@@ -0,0 +1,11 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+
+ {% for obj in object_list %}
+ - {{ obj }} ({{ obj.get_forma_display }} {{ obj.cas_doruceni }})
+ {% endfor %}
+
+
+{% endblock %}
diff --git a/seminar/templates/seminar/odevzdavatko/tabulka.html b/seminar/templates/seminar/odevzdavatko/tabulka.html
new file mode 100644
index 00000000..ff396ce4
--- /dev/null
+++ b/seminar/templates/seminar/odevzdavatko/tabulka.html
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% load utils %} {# Možná by mohlo být někde výš v hierarchii templatů... #}
+
+{% block content %}
+
+
+
+{% endblock %}
diff --git a/seminar/templatetags/utils.py b/seminar/templatetags/utils.py
new file mode 100644
index 00000000..1cb92d6a
--- /dev/null
+++ b/seminar/templatetags/utils.py
@@ -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")
+
diff --git a/seminar/testutils.py b/seminar/testutils.py
index 3e81f356..94fa78b6 100644
--- a/seminar/testutils.py
+++ b/seminar/testutils.py
@@ -140,7 +140,7 @@ def gen_resitele(rnd, osoby, skoly):
x += 1
os.user = user
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),
rok_maturity=rnd.randint(2019, 2029),
zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0]))
@@ -199,7 +199,7 @@ def gen_organizatori(rnd, osoby, last_rocnik):
x += 1
os.user = user
os.save()
- os.user.user_permissions.add(org_perm)
+ os.user.user_permissions.add(org_perm)
organizatori.append(Organizator.objects.create(osoba=os,
organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga))
return organizatori
diff --git a/seminar/urls.py b/seminar/urls.py
index 91e0ce15..bf0658d6 100644
--- a/seminar/urls.py
+++ b/seminar/urls.py
@@ -168,5 +168,10 @@ urlpatterns = [
# org_member_required(views.OrganizatorAutocomplete.as_view()),
# name='seminar_autocomplete_organizator')
+ path('temp/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
+ path('temp/reseni///', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'),
+ path('temp/reseni/', 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())),
]
diff --git a/seminar/utils.py b/seminar/utils.py
index ad9be95e..bcc67013 100644
--- a/seminar/utils.py
+++ b/seminar/utils.py
@@ -148,16 +148,12 @@ def resi_v_rocniku(rocnik, cislo=None):
if cislo is None:
# 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
- letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik,
- hodnoceni__cislo_body__poradi__lte=cislo.poradi)
-
- # 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()
+ return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
+ reseni__hodnoceni__cislo_body__rocnik=rocnik,
+ reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi).distinct()
def aktivniResitele(cislo, pouze_letosni=False):
diff --git a/seminar/views/__init__.py b/seminar/views/__init__.py
index 222d19bb..a9eb3ea9 100644
--- a/seminar/views/__init__.py
+++ b/seminar/views/__init__.py
@@ -1,3 +1,4 @@
from .views_all import *
from .autocomplete import *
from .views_rest import *
+from .odevzdavatko import *
diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py
new file mode 100644
index 00000000..de8ceec3
--- /dev/null
+++ b/seminar/views/odevzdavatko.py
@@ -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
diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py
index 316211fd..79b75b0f 100644
--- a/seminar/views/views_all.py
+++ b/seminar/views/views_all.py
@@ -1,4 +1,4 @@
-# coding:utf-8
+
from django.shortcuts import get_object_or_404, render, redirect
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.db import transaction
from django.core import serializers
+from django.core.exceptions import PermissionDenied
from django.forms.models import model_to_dict
import seminar.models as s
@@ -120,14 +121,57 @@ class TNLData(object):
self.appendable_siblings = tnltt.appendableChildren(self.parent)
else:
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
+ def all_public_children(cls, anode):
+ for ch in treelib.all_children(anode):
+ if TNLData.public_above(ch):
+ yield ch
+ else:
+ continue
@classmethod
- def from_treenode(cls,anode,parent=None,index=None):
- out = cls(anode,parent,index)
- for (idx,ch) in enumerate(treelib.all_children(anode)):
- outitem = cls.from_treenode(ch,out,idx)
+ 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.add_edit_options()
return out
@@ -194,7 +238,7 @@ class TreeNodeView(generic.DetailView):
def get_context_data(self,**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
class TreeNodeJSONView(generic.DetailView):
@@ -202,7 +246,7 @@ class TreeNodeJSONView(generic.DetailView):
def get(self,request,*args, **kwargs):
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)
@@ -331,6 +375,7 @@ class ProblemView(generic.DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
+ user = self.request.user
# Teď potřebujeme doplnit tnldata do kontextu.
# Ošklivý type switch, hezčí by bylo udělat to polymorfni. FIXME.
if False:
@@ -338,11 +383,11 @@ class ProblemView(generic.DetailView):
pass
elif isinstance(self.object, s.Clanek) or isinstance(self.object, s.Konfera):
# 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):
# 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_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode)
+ tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user)
+ tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user)
context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak])
elif isinstance(self.object, s.Tema):
rocniknode = self.object.rocnik.rocniknode
@@ -384,16 +429,16 @@ class AktualniZadaniView(generic.TemplateView):
# )
#
def ZadaniTemataView(request):
- nastaveni = get_object_or_404(Nastaveni)
- verejne = nastaveni.aktualni_cislo.verejne()
- akt_rocnik = nastaveni.aktualni_cislo.rocnik
- temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany')
- return render(request, 'seminar/tematka/rozcestnik.html',
- {
- 'tematka': temata,
- 'verejne': verejne,
- },
- )
+ nastaveni = get_object_or_404(Nastaveni)
+ verejne = nastaveni.aktualni_cislo.verejne()
+ akt_rocnik = nastaveni.aktualni_cislo.rocnik
+ temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany')
+ return render(request, 'seminar/tematka/rozcestnik.html',
+ {
+ 'tematka': temata,
+ 'verejne': verejne,
+ },
+ )
# nastaveni = get_object_or_404(Nastaveni)
diff --git a/seminar/viewsets.py b/seminar/viewsets.py
index 8c83c067..163d2d5a 100644
--- a/seminar/viewsets.py
+++ b/seminar/viewsets.py
@@ -1,7 +1,23 @@
from rest_framework import viewsets,filters
+from rest_framework.permissions import BasePermission, AllowAny
from . import models as m
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):
"""
Overrides get_serializer_class to choose the read serializer
@@ -46,27 +62,27 @@ class ReadWriteSerializerMixin(object):
)
return self.create_serializer_class
-class UlohaVzorakNodeViewSet(viewsets.ModelViewSet):
+class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet):
queryset = m.UlohaVzorakNode.objects.all()
serializer_class = views.UlohaVzorakNodeSerializer
-class TextViewSet(viewsets.ModelViewSet):
+class TextViewSet(PermissionMixin, viewsets.ModelViewSet):
queryset = m.Text.objects.all()
serializer_class = views.TextSerializer
-class TextNodeViewSet(ReadWriteSerializerMixin,viewsets.ModelViewSet):
+class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet):
queryset = m.TextNode.objects.all()
read_serializer_class = views.TextNodeSerializer
write_serializer_class = views.TextNodeWriteSerializer
create_serializer_class = views.TextNodeCreateSerializer
-class CastNodeViewSet(ReadWriteSerializerMixin,viewsets.ModelViewSet):
+class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet):
queryset = m.CastNode.objects.all()
read_serializer_class = views.CastNodeSerializer
write_serializer_class = views.CastNodeSerializer
create_serializer_class = views.CastNodeCreateSerializer
-class UlohaVzorakNodeViewSet(viewsets.ModelViewSet):
+class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet):
serializer_class = views.UlohaVzorakNodeSerializer
def get_queryset(self):
@@ -74,4 +90,7 @@ class UlohaVzorakNodeViewSet(viewsets.ModelViewSet):
nazev = self.request.query_params.get('nazev',None)
if nazev is not None:
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)