From 90c7b181c160b28231184ebba02746548d153594 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Mon, 17 Aug 2020 20:07:49 +0200 Subject: [PATCH 01/31] =?UTF-8?q?WIP:=20Za=C4=8D=C3=A1tek=20k=C3=B3du=20od?= =?UTF-8?q?evzd=C3=A1v=C3=A1tka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 93 +++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 seminar/views/odevzdavatko.py diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py new file mode 100644 index 00000000..bf4ab0fa --- /dev/null +++ b/seminar/views/odevzdavatko.py @@ -0,0 +1,93 @@ +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(TemplateView): + template_name = 'TODO' + + def get_context_data(self, *args, **kwargs): + akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi... + resitele = resi_v_rocniku(akt_rocnik) + zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY) + + ctx = dict() + ctx['problemy'] = zadane_problemy + ctx['resitele'] = resitele + + # Zkonstruujeme jednotlivé řádky + # Řádky budou indexované řešiteli a budou obsahovat SouhrnyReseni + # TODO: Tohle se asi nějak dá urychlit / zpřehlednit... + ctx['radky'] = dict() + for resitel in resitele: + ctx['radky'][resitel] = [] + for problem in zadane_problemy: + reseni_k_tomuto_problemu = m.Reseni.objects.filter( + resitele__in=[resitel], # Snad funguje i takhle + hodnoceni__problem__in=[problem], # ditto + ) + .order_by('-cas_doruceni') + pocet_reseni = reseni_k_tomuto_problemu.count() + nejnovejsi = reseni_k_tomuto_problemu.first().cas_doruceni + pocet_bodu = max( + [h.body for h in m.Hodnoceni.objects.filter( + reseni__in=reseni_k_tomuto_problemu, + problem=problem, + ) + ] + ) + ctx['radky'][resitel].append( + SouhrnReseni( + pocet_reseni=pocet_reseni, + posledni_odevzdani=nejnovejsi, + body=pocet_bodu, + ) + return ctx + +class ReseniProblemuView(ListView): + model = m.Reseni + template_name = 'TODO' + + def get_queryset(self): + qs = super().get_queryset() + + + + + +# Přehled všech řešení kvůli debugování + +class SeznamReseniView(ListView): + model = m.Reseni + template_name = 'TODO' + +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) # Doufám, že tohle najde řešení, která maji alespoň jednoho řešitele řešícího v aktuálním ročníku + return qs From b2539d6a24ee36e47aed84e77c509500580cffe9 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 27 Oct 2020 22:35:36 +0100 Subject: [PATCH 02/31] Fix syntax --- seminar/views/odevzdavatko.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index bf4ab0fa..137f1fc0 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -48,8 +48,7 @@ class TabulkaOdevzdanychReseniView(TemplateView): reseni_k_tomuto_problemu = m.Reseni.objects.filter( resitele__in=[resitel], # Snad funguje i takhle hodnoceni__problem__in=[problem], # ditto - ) - .order_by('-cas_doruceni') + ).order_by('-cas_doruceni') pocet_reseni = reseni_k_tomuto_problemu.count() nejnovejsi = reseni_k_tomuto_problemu.first().cas_doruceni pocet_bodu = max( @@ -65,6 +64,7 @@ class TabulkaOdevzdanychReseniView(TemplateView): posledni_odevzdani=nejnovejsi, body=pocet_bodu, ) + ) return ctx class ReseniProblemuView(ListView): From 1a1eccb7ed5474e3d572a5d72b340c287635f482 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 27 Oct 2020 22:37:03 +0100 Subject: [PATCH 03/31] =?UTF-8?q?Implementace=20zbyl=C3=BDch=20views=20ohl?= =?UTF-8?q?edn=C4=9B=20odevzd=C3=A1v=C3=A1tka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 137f1fc0..0a121e78 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -73,10 +73,27 @@ class ReseniProblemuView(ListView): 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.Resitel.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 = 'TODO' + # To je všechno? Najde se to bude slugem... # Přehled všech řešení kvůli debugování From beba4c5062550f405b8abd10d2aaf5d93c69b97c Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 27 Oct 2020 22:37:27 +0100 Subject: [PATCH 04/31] =?UTF-8?q?P=C5=99id=C3=A1n=C3=AD=20do=20URLs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/urls.py | 5 +++++ seminar/views/__init__.py | 1 + 2 files changed, 6 insertions(+) diff --git a/seminar/urls.py b/seminar/urls.py index ba74dc04..fde4cadb 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -157,5 +157,10 @@ urlpatterns = [ # org_member_required(views.OrganizatorAutocomplete.as_view()), # name='seminar_autocomplete_organizator') + path('temp/reseni/', views.TabulkaOdevzdanychReseniView.as_view()), + path('temp/reseni///', views.ReseniProblemuView.as_view()), + path('temp/reseni/', views.DetailReseniView.as_view()), + path('temp/reseni/all', views.SeznamReseniView.as_view()), + path('temp/reseni/akt', views.SeznamAktualnichReseniView.as_view()), ] diff --git a/seminar/views/__init__.py b/seminar/views/__init__.py index 976a34fe..6e5f1eae 100644 --- a/seminar/views/__init__.py +++ b/seminar/views/__init__.py @@ -1,2 +1,3 @@ from .views_all import * from .autocomplete import * +from .odevzdavatko import * From 797256fcfed7398090cc1bd1578e3b138691c9b9 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 27 Oct 2020 23:50:05 +0100 Subject: [PATCH 05/31] =?UTF-8?q?Patch,=20kdy=C5=BE=20jsou=20bez=20=C5=99e?= =?UTF-8?q?=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 0a121e78..effb1135 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -50,14 +50,18 @@ class TabulkaOdevzdanychReseniView(TemplateView): hodnoceni__problem__in=[problem], # ditto ).order_by('-cas_doruceni') pocet_reseni = reseni_k_tomuto_problemu.count() - nejnovejsi = reseni_k_tomuto_problemu.first().cas_doruceni - pocet_bodu = max( - [h.body for h in m.Hodnoceni.objects.filter( - reseni__in=reseni_k_tomuto_problemu, - problem=problem, - ) - ] - ) + if pocet_reseni > 0: + nejnovejsi = reseni_k_tomuto_problemu.first().cas_doruceni + pocet_bodu = max( + [h.body for h in m.Hodnoceni.objects.filter( + reseni__in=reseni_k_tomuto_problemu, + problem=problem, + ) + ] + ) + else: + nejnovejsi = None + pocet_bodu = None ctx['radky'][resitel].append( SouhrnReseni( pocet_reseni=pocet_reseni, From 8145932942a9ce4c1cbce8419c0364f6b25becc4 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 27 Oct 2020 23:54:14 +0100 Subject: [PATCH 06/31] =?UTF-8?q?=C3=9Aprava=20koment=C3=A1=C5=99e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index effb1135..ad79f1d8 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -97,7 +97,7 @@ class ReseniProblemuView(ListView): class DetailReseniView(DetailView): model = m.Reseni template_name = 'TODO' - # To je všechno? Najde se to bude slugem... + # To je všechno? Najde se to podle pk... # Přehled všech řešení kvůli debugování From fd754394c22346a1400c75940d59678e952f61a1 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 27 Oct 2020 23:54:35 +0100 Subject: [PATCH 07/31] =?UTF-8?q?P=C5=99id=C3=A1ny=20templates=20(hodn?= =?UTF-8?q?=C4=9B=20z=C3=A1kladn=C3=AD,=20jen=20abych=20v=C4=9Bd=C4=9Bl,?= =?UTF-8?q?=20=C5=BEe=20to=20n=C4=9Bco=20d=C4=9Bl=C3=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seminar/odevzdavatko/detail.html | 7 ++++++ .../seminar/odevzdavatko/seznam.html | 11 ++++++++++ .../seminar/odevzdavatko/tabulka.html | 22 +++++++++++++++++++ seminar/views/odevzdavatko.py | 8 +++---- 4 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 seminar/templates/seminar/odevzdavatko/detail.html create mode 100644 seminar/templates/seminar/odevzdavatko/seznam.html create mode 100644 seminar/templates/seminar/odevzdavatko/tabulka.html diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html new file mode 100644 index 00000000..4238c848 --- /dev/null +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} + +{{ object }} + +{% endblock %} diff --git a/seminar/templates/seminar/odevzdavatko/seznam.html b/seminar/templates/seminar/odevzdavatko/seznam.html new file mode 100644 index 00000000..0fc26df4 --- /dev/null +++ b/seminar/templates/seminar/odevzdavatko/seznam.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} + +
    + {% for obj in object_list %} +
  • {{ obj }} + {% endfor %} +
+ +{% endblock %} diff --git a/seminar/templates/seminar/odevzdavatko/tabulka.html b/seminar/templates/seminar/odevzdavatko/tabulka.html new file mode 100644 index 00000000..893efa6d --- /dev/null +++ b/seminar/templates/seminar/odevzdavatko/tabulka.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} + +{% block content %} + + + + {# Prázdná buňka v levém horním rohu #} + {% for p in problemy %} + + {% endfor %} + + {% for resitel, vysledky in radky %} + + + {% for vysl in vysledky %} + + {% endfor %} + + {% endfor %} +
{{ p }}
{{ resitel } {{ vysl.pocet_reseni }} řešení, dohromady za {{ vysl.body }}, nejnovější z {{ vysl.posledni_odevzdani }}
+ +{% endblock %} diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index ad79f1d8..b53b1913 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -27,7 +27,7 @@ class SouhrnReseni: class TabulkaOdevzdanychReseniView(TemplateView): - template_name = 'TODO' + template_name = 'seminar/odevzdavatko/tabulka.html' def get_context_data(self, *args, **kwargs): akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi... @@ -73,7 +73,7 @@ class TabulkaOdevzdanychReseniView(TemplateView): class ReseniProblemuView(ListView): model = m.Reseni - template_name = 'TODO' + template_name = 'seminar/odevzdavatko/seznam.html' def get_queryset(self): qs = super().get_queryset() @@ -96,14 +96,14 @@ class ReseniProblemuView(ListView): class DetailReseniView(DetailView): model = m.Reseni - template_name = 'TODO' + 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 = 'TODO' + template_name = 'seminar/odevzdavatko/seznam.html' class SeznamAktualnichReseniView(SeznamReseniView): def get_queryset(self): From f07db53c27c10c02190e785f65b8fabd0d0d5869 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 28 Oct 2020 00:32:09 +0100 Subject: [PATCH 08/31] =?UTF-8?q?Kop=C3=ADrov=C3=A1n=C3=AD=20je=20=C4=8Das?= =?UTF-8?q?t=C3=BDm=20zdrojem...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index b53b1913..92b4cc99 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -85,7 +85,7 @@ class ReseniProblemuView(ListView): raise ValueError("Nemám problém! (To je problém!)") resitel = m.Resitel.objects.get(id=resitel_id) - problem = m.Resitel.objects.get(id=problem_id) + problem = m.Problem.objects.get(id=problem_id) qs = qs.filter( problem__in=[problem], resitele__in=[resitel], From 4cfe76bb3ae51b1bb71140b6cd344bbad9f9999f Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 28 Oct 2020 00:32:20 +0100 Subject: [PATCH 09/31] =?UTF-8?q?=C3=9Aprava=20koment=C3=A1=C5=99e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ono to dělá to, co jsem tam napsal... --- seminar/views/odevzdavatko.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 92b4cc99..3f715bee 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -110,5 +110,5 @@ class SeznamAktualnichReseniView(SeznamReseniView): 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) # Doufám, že tohle najde řešení, která maji alespoň jednoho řešitele řešícího v aktuálním ročníku + 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 From 5fae78f3c7c145346ffbcacd775024e61abd2d94 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 18 Nov 2020 00:35:18 +0100 Subject: [PATCH 10/31] =?UTF-8?q?P=C5=99eps=C3=A1na=20tabulka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Teď se ptá databáze jen málokrát (zdaleka ne jednou; TODO) a zbytek se zpracovává v Pythonu. Asi by to pořád šlo zlepšit pomocí agregací, ale whatever. --- .../seminar/odevzdavatko/tabulka.html | 12 ++- seminar/views/odevzdavatko.py | 77 ++++++++++--------- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/seminar/templates/seminar/odevzdavatko/tabulka.html b/seminar/templates/seminar/odevzdavatko/tabulka.html index 893efa6d..ac628be6 100644 --- a/seminar/templates/seminar/odevzdavatko/tabulka.html +++ b/seminar/templates/seminar/odevzdavatko/tabulka.html @@ -9,11 +9,15 @@ {{ p }} {% endfor %} - {% for resitel, vysledky in radky %} + {% for resitel,hodnoty in radky%} - {{ resitel } - {% for vysl in vysledky %} - {{ vysl.pocet_reseni }} řešení, dohromady za {{ vysl.body }}, nejnovější z {{ vysl.posledni_odevzdani }} + {{ resitel }} + {% for hodn in hodnoty %} + + {% if hodn %} + {{ hodn.pocet_reseni }} řešení
{{ hodn.body }} bodů
{{ hodn.posledni_odevzdani }} + {% endif %} + {% endfor %} {% endfor %} diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 3f715bee..318b7bae 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -26,49 +26,50 @@ class SouhrnReseni: body : float -class TabulkaOdevzdanychReseniView(TemplateView): +class TabulkaOdevzdanychReseniView(ListView): template_name = 'seminar/odevzdavatko/tabulka.html' + model = m.Hodnoceni + akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi... + resitele = resi_v_rocniku(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. + zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() + + def get_queryset(self): + 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): - akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi... - resitele = resi_v_rocniku(akt_rocnik) - zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY) - - ctx = dict() - ctx['problemy'] = zadane_problemy - ctx['resitele'] = resitele + 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) + tabulka[problem][resitel].pocet_reseni += 1 - # Zkonstruujeme jednotlivé řádky - # Řádky budou indexované řešiteli a budou obsahovat SouhrnyReseni - # TODO: Tohle se asi nějak dá urychlit / zpřehlednit... - ctx['radky'] = dict() - for resitel in resitele: - ctx['radky'][resitel] = [] - for problem in zadane_problemy: - reseni_k_tomuto_problemu = m.Reseni.objects.filter( - resitele__in=[resitel], # Snad funguje i takhle - hodnoceni__problem__in=[problem], # ditto - ).order_by('-cas_doruceni') - pocet_reseni = reseni_k_tomuto_problemu.count() - if pocet_reseni > 0: - nejnovejsi = reseni_k_tomuto_problemu.first().cas_doruceni - pocet_bodu = max( - [h.body for h in m.Hodnoceni.objects.filter( - reseni__in=reseni_k_tomuto_problemu, - problem=problem, - ) - ] - ) + 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: - nejnovejsi = None - pocet_bodu = None - ctx['radky'][resitel].append( - SouhrnReseni( - pocet_reseni=pocet_reseni, - posledni_odevzdani=nejnovejsi, - body=pocet_bodu, - ) - ) + resiteluv_radek.append(None) + hodnoty.append(resiteluv_radek) + ctx['radky'] = list(zip(self.resitele, hodnoty)) + return ctx class ReseniProblemuView(ListView): From 50bc5f393177a4b60fda93a9c2512b6ac5242246 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 18 Nov 2020 03:41:05 +0100 Subject: [PATCH 11/31] =?UTF-8?q?=C5=98azen=C3=AD=20Non=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 318b7bae..55a12f67 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -52,7 +52,10 @@ class TabulkaOdevzdanychReseniView(ListView): 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) + 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 for hodnoceni in self.get_queryset(): From 67144d30342ce5a325a4436667083b9baafe0914 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Fri, 27 Nov 2020 04:16:28 +0100 Subject: [PATCH 12/31] =?UTF-8?q?Oprava=20pr=C3=A1v=20upload=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bez toho soubory dostávaly ACL masku '---', takže požadavky pak končily HTTP 403. (Cherry-pick z masteru) --- mamweb/settings_common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index bec16f7f..7a2bf85b 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -295,6 +295,9 @@ LOGGING = { }, } +# Permissions for uploads +FILE_UPLOAD_PERMISSIONS = 0o0644 + # MaM specific SEMINAR_RESENI_DIR = os.path.join('reseni') From 440f40fc8240fcc1f4a6b69aace7669ca2ce3b6a Mon Sep 17 00:00:00 2001 From: Jonas Havelka Date: Tue, 1 Dec 2020 23:05:20 +0100 Subject: [PATCH 13/31] =?UTF-8?q?Fix=20sql=20dotazu=20na=20=C5=99e=C5=A1it?= =?UTF-8?q?ele=20v=20aktu=C3=A1ln=C3=ADm=20ro=C4=8Dn=C3=ADku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/utils.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) 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): From 3fd3838e771e522881deded77520f9a3b9ba81da Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 1 Dec 2020 23:51:26 +0100 Subject: [PATCH 14/31] =?UTF-8?q?Pojmenovan=C3=A9=20URLs=20odevzd=C3=A1v?= =?UTF-8?q?=C3=A1tka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/urls.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seminar/urls.py b/seminar/urls.py index fde4cadb..7050241f 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -157,9 +157,9 @@ urlpatterns = [ # org_member_required(views.OrganizatorAutocomplete.as_view()), # name='seminar_autocomplete_organizator') - path('temp/reseni/', views.TabulkaOdevzdanychReseniView.as_view()), - path('temp/reseni///', views.ReseniProblemuView.as_view()), - path('temp/reseni/', views.DetailReseniView.as_view()), + path('temp/reseni/', views.TabulkaOdevzdanychReseniView.as_view(), name='odevzdavatko_tabulka'), + path('temp/reseni///', views.ReseniProblemuView.as_view(), name='odevzdavatko_reseni_resitele_k_problemu'), + path('temp/reseni/', views.DetailReseniView.as_view(), name='odevzdavatko_detail_reseni'), path('temp/reseni/all', views.SeznamReseniView.as_view()), path('temp/reseni/akt', views.SeznamAktualnichReseniView.as_view()), From 0ebc9b5f32586413dfe4605dfe9864b7fff353a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Pokorn=C3=A1?= Date: Tue, 1 Dec 2020 23:52:03 +0100 Subject: [PATCH 15/31] =?UTF-8?q?views=5Fall=20|=20filtrov=C3=A1n=C3=AD=20?= =?UTF-8?q?json-u=20podle=20pr=C3=A1v=20u=C5=BEivatele?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models.py | 11 +++-- seminar/views/views_all.py | 90 ++++++++++++++++++++++++++++---------- seminar/viewsets.py | 25 ----------- 3 files changed, 74 insertions(+), 52 deletions(-) diff --git a/seminar/models.py b/seminar/models.py index 57a44404..7b4ce05d 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -745,15 +745,18 @@ class Problem(SeminarModelBase,PolymorphicModel): def verejne(self): # 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 + #cislo_verejne = False + #if (self.cislo_zadani and self.cislo_zadani.verejne()): + # cislo_verejne = True - return (stav_verejny and cislo_verejne) + #return (stav_verejny and cislo_verejne) verejne.boolean = True def verejne_url(self): diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index a550c40a..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,15 +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)): - # FIXME přidat filtrování na veřejnost - 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 @@ -195,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): @@ -203,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) @@ -332,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: @@ -339,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 @@ -385,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 cc59f7d7..087d07d6 100644 --- a/seminar/viewsets.py +++ b/seminar/viewsets.py @@ -18,31 +18,6 @@ class PermissionMixin(object): # návštěvník nemusí být zalogován, aby si prohlížel obsah return [permission() for permission in permission_classes] - def verejne_nad(self, node): - """ Returns output of verejne for closest Rocnik, Cislo or Problem above. - (All of them have method verejne.)""" - parent = get_parent(node) - while True: - rocnik = isinstance(parent, RocnikNode) - cislo = isinstance(parent, CisloNode) - problem = isinstance(parent, ProblemNode) - - if (rocnik or cislo or problem): - break - else: - parent = get_parent(parent) - if rocnik: - return parent.rocnik.verejne() - elif cislo: - return parent.cislo.verejne() - elif problem: - return parent.problem.verjne() - - def has_object_permission(self, request, view, obj): - # test that obj is Node - assert isinstance(obj, Node) - return verejne_nad(node) - class ReadWriteSerializerMixin(object): """ Overrides get_serializer_class to choose the read serializer From 96a73c05d4ec0e66a93629fe6be5b64a12c083dc Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 1 Dec 2020 23:52:15 +0100 Subject: [PATCH 16/31] =?UTF-8?q?Odevzd=C3=A1v=C3=A1tko:=20Odkazy=20z=20ta?= =?UTF-8?q?bulky=20na=20seznam=20=C5=99e=C5=A1en=C3=AD=20dan=C3=A9ho=20?= =?UTF-8?q?=C5=99e=C5=A1itele?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Zkrácení tabulky --- .../seminar/odevzdavatko/tabulka.html | 16 ++++++++--- seminar/templatetags/utils.py | 27 +++++++++++++++++++ seminar/views/odevzdavatko.py | 3 +++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 seminar/templatetags/utils.py diff --git a/seminar/templates/seminar/odevzdavatko/tabulka.html b/seminar/templates/seminar/odevzdavatko/tabulka.html index ac628be6..ff396ce4 100644 --- a/seminar/templates/seminar/odevzdavatko/tabulka.html +++ b/seminar/templates/seminar/odevzdavatko/tabulka.html @@ -1,21 +1,31 @@ {% extends "base.html" %} +{% load utils %} {# Možná by mohlo být někde výš v hierarchii templatů... #} + {% block content %} {# Prázdná buňka v levém horním rohu #} {% for p in problemy %} - + {% endfor %} {% for resitel,hodnoty in radky%} - + {% for hodn in hodnoty %} {% endfor %} diff --git a/seminar/templatetags/utils.py b/seminar/templatetags/utils.py new file mode 100644 index 00000000..2a520d6a --- /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 = dt - now + if delta <= timedelta(days=1): + return dt.strftime("%k:%M") + if delta <= timedelta(years=1): + return dt.strftime("%d. %m.") + return dt.strftime("%d. %m. %Y") + diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 55a12f67..ea30c543 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -57,6 +57,9 @@ class TabulkaOdevzdanychReseniView(ListView): # 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(): From dd4cdfa494370ed31256d733d2e661b33df31f49 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 00:01:34 +0100 Subject: [PATCH 17/31] =?UTF-8?q?Odevzd=C3=A1v=C3=A1tko:=20odkazy=20ze=20s?= =?UTF-8?q?eznamu=20=C5=99e=C5=A1en=C3=AD=20na=20konkr=C3=A9tn=C3=AD=20?= =?UTF-8?q?=C5=99e=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templates/seminar/odevzdavatko/seznam.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/templates/seminar/odevzdavatko/seznam.html b/seminar/templates/seminar/odevzdavatko/seznam.html index 0fc26df4..8ceb0ac6 100644 --- a/seminar/templates/seminar/odevzdavatko/seznam.html +++ b/seminar/templates/seminar/odevzdavatko/seznam.html @@ -4,7 +4,7 @@
    {% for obj in object_list %} -
  • {{ obj }} +
  • {{ obj }} {% endfor %}
From 71a2e98dda729c6b62a78522c80ce8fab0710a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aneta=20Pokorn=C3=A1?= Date: Wed, 2 Dec 2020 00:39:19 +0100 Subject: [PATCH 18/31] =?UTF-8?q?treenode=20|=20UlohaVzorakNode=20se=20v?= =?UTF-8?q?=20treenodeeditoru=20zobrazuje=20jen=20org=C5=AFm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/viewsets.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/seminar/viewsets.py b/seminar/viewsets.py index 087d07d6..163d2d5a 100644 --- a/seminar/viewsets.py +++ b/seminar/viewsets.py @@ -90,4 +90,7 @@ class UlohaVzorakNodeViewSet(PermissionMixin, 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) From cea3eee7b59e2c32818b6b5d46466092c2cd4eeb Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 00:54:31 +0100 Subject: [PATCH 19/31] =?UTF-8?q?Pr=C3=A1va=20k=20odevzd=C3=A1v=C3=A1tku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/urls.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/seminar/urls.py b/seminar/urls.py index 7050241f..b4993eca 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -157,10 +157,10 @@ urlpatterns = [ # org_member_required(views.OrganizatorAutocomplete.as_view()), # name='seminar_autocomplete_organizator') - path('temp/reseni/', views.TabulkaOdevzdanychReseniView.as_view(), name='odevzdavatko_tabulka'), - path('temp/reseni///', views.ReseniProblemuView.as_view(), name='odevzdavatko_reseni_resitele_k_problemu'), - path('temp/reseni/', views.DetailReseniView.as_view(), name='odevzdavatko_detail_reseni'), - path('temp/reseni/all', views.SeznamReseniView.as_view()), - path('temp/reseni/akt', views.SeznamAktualnichReseniView.as_view()), + 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())), ] From 86311461c629e09bb58e629b4c8bff16486d2030 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 00:56:15 +0100 Subject: [PATCH 20/31] =?UTF-8?q?Zm=C4=9Bna=20jmen=20uploadovan=C3=BDch=20?= =?UTF-8?q?soubor=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/models.py b/seminar/models.py index 310ce573..4a249154 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -988,7 +988,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) From 8b5f9437e54c1414879717de3329240c0a6948ee Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 00:56:36 +0100 Subject: [PATCH 21/31] =?UTF-8?q?Pomocn=C3=A1=20metoda=20v=20p=C5=99=C3=AD?= =?UTF-8?q?loze=20=C5=99e=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hodí se třeba odevzdávátku, aby se nepoužila celá cesta --- seminar/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/seminar/models.py b/seminar/models.py index 4a249154..43090d21 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -1041,6 +1041,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""" From 6ff0c7cd03897c59639ecfc7517c73ccfba3855f Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 01:12:50 +0100 Subject: [PATCH 22/31] =?UTF-8?q?Str=C3=A1nka=20s=20detailem=20=C5=99e?= =?UTF-8?q?=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seminar/odevzdavatko/detail.html | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index 4238c848..8c3c2d24 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -2,6 +2,46 @@ {% block content %} -{{ object }} +

Ř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 %} +
{{ p }} + {# TODO: Přehled řešení k problému, odkázaný odsud? #} + {{ p }} +
{{ resitel }} + {# TODO: Chceme mít view i na řešení konkrétního řešitele ke všem problémům? #} + {{ resitel }} + {% if hodn %} - {{ hodn.pocet_reseni }} řešení
{{ hodn.body }} bodů
{{ hodn.posledni_odevzdani }} + + {{ hodn.pocet_reseni }} řeš.
{{ hodn.body }} b
{{ hodn.posledni_odevzdani|kratke_datum|default_if_none:"Nikdy"|default:"???"}} +
{% endif %}
+ +{% for priloha in object.prilohy.all %} + + + + + {# TODO: Orgo-poznámka, ideálně jako formulář #} +{% endfor %} +
SouborŘešitelova poznámkaDatum
{{ priloha.split | last }}{{ priloha.res_poznamka }}{{ priloha.vytvoreno }}
+{% else %} +

Žádné přílohy

+{% endif %} + +{# Hodnocení: #} +{# FIXME: Udělat jako formulář #} +

Hodnocení:

+{% if object.hodnoceni.all %} + + +{% for h in object.hodnoceni.all %} + + + + +{% endfor %} +
ProblémBodyČíslo pro body
{{ h.problem }}{{ h.body }}{{ h.cislo_body }}
+{% else %} +

Ještě nebylo hodnoceno

+{% endif %} + {% endblock %} From b667900672d13ad8a6ab63090076e85da45dab38 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 01:17:38 +0100 Subject: [PATCH 23/31] =?UTF-8?q?Detail=20v=20seznamu=20=C5=99e=C5=A1en?= =?UTF-8?q?=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templates/seminar/odevzdavatko/seznam.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/templates/seminar/odevzdavatko/seznam.html b/seminar/templates/seminar/odevzdavatko/seznam.html index 8ceb0ac6..b58dcb54 100644 --- a/seminar/templates/seminar/odevzdavatko/seznam.html +++ b/seminar/templates/seminar/odevzdavatko/seznam.html @@ -4,7 +4,7 @@
    {% for obj in object_list %} -
  • {{ obj }} +
  • {{ obj }} ({{ obj.get_forma_display }} {{ obj.cas_doruceni }}) {% endfor %}
From 88af1e6752f5fa2f53a71d8374bfd747bb926ca0 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 02:30:34 +0100 Subject: [PATCH 24/31] =?UTF-8?q?Fix:=20=C5=98e=C5=A1en=C3=AD=20nem=C3=A1?= =?UTF-8?q?=20hodnocen=C3=AD,=20ale=20hodnocen=C3=AD=5Fset.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templates/seminar/odevzdavatko/detail.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index 8c3c2d24..6cee990d 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -29,10 +29,10 @@ {# Hodnocení: #} {# FIXME: Udělat jako formulář #}

Hodnocení:

-{% if object.hodnoceni.all %} +{% if object.hodnoceni_set.all %} -{% for h in object.hodnoceni.all %} +{% for h in object.hodnoceni_set.all %} From 8e17ad9f46572384d7ec01bf768a0350fdd47959 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 17:57:06 +0100 Subject: [PATCH 25/31] =?UTF-8?q?Chyba=20ve=20znam=C3=A9nku=20p=C5=99i=20p?= =?UTF-8?q?o=C4=8D=C3=ADt=C3=A1n=C3=AD=20=C4=8Das=C5=AF=20:-D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templatetags/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/templatetags/utils.py b/seminar/templatetags/utils.py index 2a520d6a..4d5de06d 100644 --- a/seminar/templatetags/utils.py +++ b/seminar/templatetags/utils.py @@ -18,7 +18,7 @@ def kratke_datum(dt): naive_now = datetime.now() tz = timezone(TIME_ZONE) now = tz.localize(naive_now) - delta = dt - now + delta = now - dt if delta <= timedelta(days=1): return dt.strftime("%k:%M") if delta <= timedelta(years=1): From 7b4366fdafec51135e12881800acf3338319139c Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 18:06:12 +0100 Subject: [PATCH 26/31] Fix timedelta 1 roku --- seminar/templatetags/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/templatetags/utils.py b/seminar/templatetags/utils.py index 4d5de06d..1cb92d6a 100644 --- a/seminar/templatetags/utils.py +++ b/seminar/templatetags/utils.py @@ -21,7 +21,7 @@ def kratke_datum(dt): delta = now - dt if delta <= timedelta(days=1): return dt.strftime("%k:%M") - if delta <= timedelta(years=1): + if delta <= timedelta(days=365): # Timedelta neumí vyjádřit 1 rok return dt.strftime("%d. %m.") return dt.strftime("%d. %m. %Y") From 47b78c1b2a563ac725cc3b9a297b05160f5cdad5 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 23:33:12 +0100 Subject: [PATCH 27/31] =?UTF-8?q?Odevzd=C3=A1v=C3=A1tko:=20P=C5=99esun=20s?= =?UTF-8?q?pole=C4=8Dn=C3=A9ho=20k=C3=B3du=20ze=20t=C5=99=C3=ADdy=20do=20m?= =?UTF-8?q?etod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Není to hezké, ale mělo by to fungovat --- seminar/views/odevzdavatko.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index ea30c543..b44068b2 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -29,17 +29,25 @@ class SouhrnReseni: class TabulkaOdevzdanychReseniView(ListView): template_name = 'seminar/odevzdavatko/tabulka.html' model = m.Hodnoceni - akt_rocnik = m.Nastaveni.get_solo().aktualni_rocnik # .get_solo() vrátí tu jedinou instanci, asi... - resitele = resi_v_rocniku(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. - zadane_problemy = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY).non_polymorphic() 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(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(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 From cc8df34d663bdf401124b4236e49ca758c726c69 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 23:52:09 +0100 Subject: [PATCH 28/31] =?UTF-8?q?P=C5=99eform=C3=A1tov=C3=A1n=C3=AD=20men?= =?UTF-8?q?=C3=AD=C4=8Dkov=C3=A9ho=20JSONu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/sitetree_new.json | 791 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 790 insertions(+), 1 deletion(-) diff --git a/data/sitetree_new.json b/data/sitetree_new.json index f0eb3a9c..a6d33fc7 100644 --- a/data/sitetree_new.json +++ b/data/sitetree_new.json @@ -1 +1,790 @@ -[{"model": "sitetree.tree", "pk": 1, "fields": {"title": "Hlavn\u00ed menu", "alias": "main_menu"}}, {"model": "sitetree.treeitem", "pk": 1, "fields": {"title": "Co je M&M", "hint": "", "url": "/co-je-MaM/uvod/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 1, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 2, "fields": {"title": "Jak \u0159e\u0161it", "hint": "", "url": "/jak-resit/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 2, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 3, "fields": {"title": "Aktu\u00e1ln\u00ed
ro\u010dn\u00edk", "hint": "", "url": "/zadani/aktualni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 3, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 4, "fields": {"title": "Soust\u0159ed\u011bn\u00ed", "hint": "", "url": "/soustredeni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 4, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 5, "fields": {"title": "Archiv", "hint": "", "url": "/archiv/rocniky/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 5, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 6, "fields": {"title": "P\u0159ihl\u00e1sit", "hint": "", "url": "/login/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": true, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 6, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 7, "fields": {"title": "\u00davod", "hint": "", "url": "/co-je-MaM/uvod/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 7, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 8, "fields": {"title": "Organiz\u00e1to\u0159i", "hint": "", "url": "/co-je-MaM/organizatori/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 8, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 9, "fields": {"title": "FAQ", "hint": "", "url": "/co-je-MaM/FAQ/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 9, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 10, "fields": {"title": "Kontakt", "hint": "", "url": "/co-je-MaM/kontakt/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 1, "sort_order": 10, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 11, "fields": {"title": "T\u00e9mata", "hint": "", "url": "/jak-resit/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 11, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 12, "fields": {"title": "Jak ps\u00e1t p\u0159\u00edsp\u011bvek", "hint": "", "url": "/jak-resit/jak-psat-prispevek/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 12, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 13, "fields": {"title": "Odm\u011bny", "hint": "", "url": "/co-je-MaM/odmeny/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 2, "sort_order": 13, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 16, "fields": {"title": "V\u00fdsledkov\u00e1 listina", "hint": "", "url": "zadani/vysledkova-listina/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 33, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 17, "fields": {"title": "\u010cl\u00e1nky", "hint": "", "url": "/clanky/resitel/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 34, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 18, "fields": {"title": "\u00davod", "hint": "", "url": "/soustredeni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 18, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 19, "fields": {"title": "P\u0159ipravujeme", "hint": "", "url": "/soustredeni/pripravujeme/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 19, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 20, "fields": {"title": "Prob\u011bhlo", "hint": "", "url": "/soustredeni/probehlo/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 4, "sort_order": 20, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 21, "fields": {"title": "Profil", "hint": "", "url": "/profil/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": true, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": null, "sort_order": 21, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 22, "fields": {"title": "Osobn\u00ed \u00fadaje", "hint": "", "url": "/profil/osobni-udaje", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 23, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 23, "fields": {"title": "Poslat \u0159e\u0161en\u00ed", "hint": "", "url": "/odeslat-reseni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 36, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 24, "fields": {"title": "T\u00e9mata", "hint": "", "url": "/archiv/temata/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 5, "sort_order": 35, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 28, "fields": {"title": "HIDDEN", "hint": "", "url": "/korektury/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": true, "access_perm_type": 1, "parent": null, "sort_order": 28, "access_permissions": [1]}}, {"model": "sitetree.treeitem", "pk": 30, "fields": {"title": "Aktu\u00e1ln\u00ed", "hint": "", "url": "/korektury/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 28, "sort_order": 30, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 31, "fields": {"title": "Zastaral\u00e9", "hint": "", "url": "/korektury/zastarale/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 28, "sort_order": 31, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 32, "fields": {"title": "N\u00e1pov\u011bda", "hint": "", "url": "/korektury/help/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 28, "sort_order": 32, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 33, "fields": {"title": "Aktu\u00e1ln\u00ed \u010d\u00edslo", "hint": "", "url": "/zadani/aktualni/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 15, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 34, "fields": {"title": "T\u00e9mata", "hint": "", "url": "/zadani/temata/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 3, "sort_order": 17, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 35, "fields": {"title": "\u010c\u00edsla", "hint": "", "url": "/archiv/rocniky/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 5, "sort_order": 24, "access_permissions": []}}, {"model": "sitetree.treeitem", "pk": 36, "fields": {"title": "\u00davod", "hint": "", "url": "/profil/", "urlaspattern": false, "tree": 1, "hidden": false, "alias": null, "description": "", "inmenu": true, "inbreadcrumbs": true, "insitetree": true, "access_loggedin": false, "access_guest": false, "access_restricted": false, "access_perm_type": 1, "parent": 21, "sort_order": 22, "access_permissions": []}}] \ No newline at end of file +[ + { + "model": "sitetree.tree", + "pk": 1, + "fields": { + "title": "Hlavní menu", + "alias": "main_menu" + } + }, + { + "model": "sitetree.treeitem", + "pk": 1, + "fields": { + "title": "Co je M&M", + "hint": "", + "url": "/co-je-MaM/uvod/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": null, + "sort_order": 1, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 2, + "fields": { + "title": "Jak řešit", + "hint": "", + "url": "/jak-resit/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": null, + "sort_order": 2, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 3, + "fields": { + "title": "Aktuální
ročník", + "hint": "", + "url": "/zadani/aktualni/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": null, + "sort_order": 3, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 4, + "fields": { + "title": "Soustředění", + "hint": "", + "url": "/soustredeni/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": null, + "sort_order": 4, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 5, + "fields": { + "title": "Archiv", + "hint": "", + "url": "/archiv/rocniky/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": null, + "sort_order": 5, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 6, + "fields": { + "title": "Přihlásit", + "hint": "", + "url": "/login/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": true, + "access_restricted": false, + "access_perm_type": 1, + "parent": null, + "sort_order": 6, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 7, + "fields": { + "title": "Úvod", + "hint": "", + "url": "/co-je-MaM/uvod/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 1, + "sort_order": 7, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 8, + "fields": { + "title": "Organizátoři", + "hint": "", + "url": "/co-je-MaM/organizatori/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 1, + "sort_order": 8, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 9, + "fields": { + "title": "FAQ", + "hint": "", + "url": "/co-je-MaM/FAQ/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 1, + "sort_order": 9, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 10, + "fields": { + "title": "Kontakt", + "hint": "", + "url": "/co-je-MaM/kontakt/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 1, + "sort_order": 10, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 11, + "fields": { + "title": "Témata", + "hint": "", + "url": "/jak-resit/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 2, + "sort_order": 11, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 12, + "fields": { + "title": "Jak psát příspěvek", + "hint": "", + "url": "/jak-resit/jak-psat-prispevek/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 2, + "sort_order": 12, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 13, + "fields": { + "title": "Odměny", + "hint": "", + "url": "/co-je-MaM/odmeny/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 2, + "sort_order": 13, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 16, + "fields": { + "title": "Výsledková listina", + "hint": "", + "url": "zadani/vysledkova-listina/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 3, + "sort_order": 33, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 17, + "fields": { + "title": "Články", + "hint": "", + "url": "/clanky/resitel/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 3, + "sort_order": 34, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 18, + "fields": { + "title": "Úvod", + "hint": "", + "url": "/soustredeni/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 4, + "sort_order": 18, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 19, + "fields": { + "title": "Připravujeme", + "hint": "", + "url": "/soustredeni/pripravujeme/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 4, + "sort_order": 19, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 20, + "fields": { + "title": "Proběhlo", + "hint": "", + "url": "/soustredeni/probehlo/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 4, + "sort_order": 20, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 21, + "fields": { + "title": "Profil", + "hint": "", + "url": "/profil/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": true, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": null, + "sort_order": 21, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 22, + "fields": { + "title": "Osobní údaje", + "hint": "", + "url": "/profil/osobni-udaje", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 21, + "sort_order": 23, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 23, + "fields": { + "title": "Poslat řešení", + "hint": "", + "url": "/odeslat-reseni/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 21, + "sort_order": 36, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 24, + "fields": { + "title": "Témata", + "hint": "", + "url": "/archiv/temata/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 5, + "sort_order": 35, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 28, + "fields": { + "title": "HIDDEN", + "hint": "", + "url": "/korektury/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": true, + "access_perm_type": 1, + "parent": null, + "sort_order": 28, + "access_permissions": [ + 1 + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 30, + "fields": { + "title": "Aktuální", + "hint": "", + "url": "/korektury/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 28, + "sort_order": 30, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 31, + "fields": { + "title": "Zastaralé", + "hint": "", + "url": "/korektury/zastarale/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 28, + "sort_order": 31, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 32, + "fields": { + "title": "Nápověda", + "hint": "", + "url": "/korektury/help/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 28, + "sort_order": 32, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 33, + "fields": { + "title": "Aktuální číslo", + "hint": "", + "url": "/zadani/aktualni/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 3, + "sort_order": 15, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 34, + "fields": { + "title": "Témata", + "hint": "", + "url": "/zadani/temata/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 3, + "sort_order": 17, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 35, + "fields": { + "title": "Čísla", + "hint": "", + "url": "/archiv/rocniky/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 5, + "sort_order": 24, + "access_permissions": [ + + ] + } + }, + { + "model": "sitetree.treeitem", + "pk": 36, + "fields": { + "title": "Úvod", + "hint": "", + "url": "/profil/", + "urlaspattern": false, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": false, + "access_perm_type": 1, + "parent": 21, + "sort_order": 22, + "access_permissions": [ + + ] + } + } +] From a9bfea7dfa7a6e54ce3b5d04b92dedd6fc6129d7 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 23:52:52 +0100 Subject: [PATCH 29/31] =?UTF-8?q?P=C5=99id=C3=A1no=20odevzd=C3=A1v=C3=A1tk?= =?UTF-8?q?o=20do=20men=C3=AD=C4=8Dka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/sitetree_new.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/data/sitetree_new.json b/data/sitetree_new.json index a6d33fc7..82fc8245 100644 --- a/data/sitetree_new.json +++ b/data/sitetree_new.json @@ -786,5 +786,31 @@ ] } + }, + { + "model": "sitetree.treeitem", + "pk": 37, + "fields": { + "title": "Odevzdaná řešení", + "hint": "", + "url": "odevzdavatko_tabulka", + "urlaspattern": true, + "tree": 1, + "hidden": false, + "alias": null, + "description": "", + "inmenu": true, + "inbreadcrumbs": true, + "insitetree": true, + "access_loggedin": false, + "access_guest": false, + "access_restricted": true, + "access_perm_type": 1, + "parent": 21, + "sort_order": 37, + "access_permissions": [ + 1 + ] + } } ] From e870a9e6494308f1f305db53cbc84d912279d9a9 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 2 Dec 2020 23:54:45 +0100 Subject: [PATCH 30/31] =?UTF-8?q?Fix:=20zapomenut=C3=BD=20self?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/views/odevzdavatko.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index b44068b2..de8ceec3 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -33,7 +33,7 @@ class TabulkaOdevzdanychReseniView(ListView): 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(akt_rocnik) + 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() @@ -44,7 +44,7 @@ class TabulkaOdevzdanychReseniView(ListView): 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(akt_rocnik) + 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() From 994b2fcdda9b98db4cada0a2ec5070bd7b230a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kate=C5=99ina=20=C4=8C?= Date: Tue, 22 Dec 2020 22:07:08 +0100 Subject: [PATCH 31/31] =?UTF-8?q?node=20s=20testovac=C3=ADmi=20daty=20(v?= =?UTF-8?q?=C3=ADc=20textu)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vue_frontend/src/router/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vue_frontend/src/router/index.js b/vue_frontend/src/router/index.js index aead18ba..ccb6c8c0 100644 --- a/vue_frontend/src/router/index.js +++ b/vue_frontend/src/router/index.js @@ -20,7 +20,7 @@ export default new Router({ }, { path: '/zadani/aktualni', name: 'treenode_zadani', - props: {'tnid': 23}, + props: {'tnid': 1655}, component: TreeNodeRoot }, { path: '/cislo/:cislo',
ProblémBodyČíslo pro body
{{ h.problem }} {{ h.body }}