From dd5d8886ee064553b26a12512ddda6493eef1d7f Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 21:27:04 +0200 Subject: [PATCH 01/54] =?UTF-8?q?Trocha=20popisu=20TabulkaOdevzdanychResen?= =?UTF-8?q?iView,=20a=C5=A5=20se=20v=20tom=20d=C3=A1=20vyznat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index d3c74812..684b790b 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -125,7 +125,7 @@ class TabulkaOdevzdanychReseniView(ListView): ctx = super().get_context_data(*args, **kwargs) ctx['problemy'] = self.problemy ctx['resitele'] = self.resitele - tabulka = dict() + tabulka: dict[m.Problem, dict[m.Resitel, SouhrnReseni]] = dict() def pridej_reseni(problem, resitel, body, cas): if problem not in tabulka: @@ -145,11 +145,11 @@ class TabulkaOdevzdanychReseniView(ListView): for resitel in hodnoceni.reseni.resitele.all(): pridej_reseni(hodnoceni.problem, resitel, hodnoceni.body, hodnoceni.reseni.cas_doruceni) - hodnoty = [] - resitele_do_tabulky = [] + hodnoty: list[list[SouhrnReseni]] = [] + resitele_do_tabulky: list[m.Resitel] = [] for resitel in self.resitele: dostal_body = False - resiteluv_radek = [] + resiteluv_radek: list[SourhnReseni] = [] # podle pořadí v self.problemy, pokud daný problém neřešil, pak None for problem in self.problemy: if problem in tabulka and resitel in tabulka[problem]: resiteluv_radek.append(tabulka[problem][resitel]) From dd49c0e1ba65a51cc8da54f35e52ed0ed476f850 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 21:47:27 +0200 Subject: [PATCH 02/54] =?UTF-8?q?Mal=C3=A1=20=C3=BAprava=20TabulkaOdevzdan?= =?UTF-8?q?ychReseniView.get=5Fcontext=5Fdata.pridej=5Freseni?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 684b790b..6d8013ca 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -127,7 +127,10 @@ class TabulkaOdevzdanychReseniView(ListView): ctx['resitele'] = self.resitele tabulka: dict[m.Problem, dict[m.Resitel, SouhrnReseni]] = dict() - def pridej_reseni(problem, resitel, body, cas): + def pridej_reseni(resitel, hodnoceni): + problem = hodnoceni.problem + body = hodnoceni.body + cas = hodnoceni.reseni.cas_doruceni if problem not in tabulka: tabulka[problem] = dict() if resitel not in tabulka[problem]: @@ -143,7 +146,7 @@ class TabulkaOdevzdanychReseniView(ListView): for hodnoceni in self.get_queryset(): for resitel in hodnoceni.reseni.resitele.all(): - pridej_reseni(hodnoceni.problem, resitel, hodnoceni.body, hodnoceni.reseni.cas_doruceni) + pridej_reseni(resitel, hodnoceni) hodnoty: list[list[SouhrnReseni]] = [] resitele_do_tabulky: list[m.Resitel] = [] From 659ad62b52a522f658df4b0e9cdb6329612d5756 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 22:15:07 +0200 Subject: [PATCH 03/54] =?UTF-8?q?Je=C5=A1t=C4=9B=20docstring=20k=20ReseniP?= =?UTF-8?q?roblemuView?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/views.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 6d8013ca..e3715891 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -177,6 +177,11 @@ class TabulkaOdevzdanychReseniView(ListView): # Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji? class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View): + """Rozskok mezi více řešeními téhož problému od téhož řešitele. + + Asi už bude zastaralý v okamžiku, kdy se tenhle komentář nasadí na produkci :-) + + V případě, že takové řešení existuje jen jedno, tak na něj přesměruje.""" model = m.Reseni template_name = 'odevzdavatko/seznam.html' From 96bc21a727f78c1f1e5943e1b7bc63b56629f9e9 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 22:15:27 +0200 Subject: [PATCH 04/54] =?UTF-8?q?Zru=C5=A1en=20SourhnReseni?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Už není potřeba, v tabulce stejně jsou už přímo řešení. --- odevzdavatko/views.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index e3715891..e9bedcbd 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -37,14 +37,6 @@ logger = logging.getLogger(__name__) # 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 = 'odevzdavatko/tabulka.html' model = m.Hodnoceni @@ -120,26 +112,25 @@ class TabulkaOdevzdanychReseniView(ListView): return qs def get_context_data(self, *args, **kwargs): + # TODO: refactor asi. Přepisoval jsem to jen syntakticky, nejspíš půlka kódu přestala dávat smysl… # self.resitele, self.reseni a self.problemy jsou již nastavené ctx = super().get_context_data(*args, **kwargs) ctx['problemy'] = self.problemy ctx['resitele'] = self.resitele - tabulka: dict[m.Problem, dict[m.Resitel, SouhrnReseni]] = dict() + tabulka: dict[m.Problem, dict[m.Resitel, list[m.Reseni]]] = dict() def pridej_reseni(resitel, hodnoceni): problem = hodnoceni.problem body = hodnoceni.body cas = hodnoceni.reseni.cas_doruceni + reseni = hodnoceni.reseni 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) + tabulka[problem][resitel] = [reseni] else: - tabulka[problem][resitel].posledni_odevzdani = max(tabulka[problem][resitel].posledni_odevzdani, cas) - # Zvětšení počtu bodů o aktuální počet, pokud se tam někde nevyskytuje None – pak je součet taky None ("Pozor, nezadané body") - tabulka[problem][resitel].body = tabulka[problem][resitel].body + body if body is not None and tabulka[problem][resitel].body is not None else None - tabulka[problem][resitel].pocet_reseni += 1 + tabulka[problem][resitel].append(reseni) # 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 @@ -148,17 +139,17 @@ class TabulkaOdevzdanychReseniView(ListView): for resitel in hodnoceni.reseni.resitele.all(): pridej_reseni(resitel, hodnoceni) - hodnoty: list[list[SouhrnReseni]] = [] + hodnoty: list[list[list[m.Reseni]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy, v každé buňce seznam řešení k danému řešiteli a problému. resitele_do_tabulky: list[m.Resitel] = [] for resitel in self.resitele: dostal_body = False - resiteluv_radek: list[SourhnReseni] = [] # podle pořadí v self.problemy, pokud daný problém neřešil, pak None + resiteluv_radek: list[list[m.Resitel]] = [] # podle pořadí v self.problemy for problem in self.problemy: if problem in tabulka and resitel in tabulka[problem]: resiteluv_radek.append(tabulka[problem][resitel]) dostal_body = True else: - resiteluv_radek.append(None) + resiteluv_radek.append([]) if self.chteni_resitele != FiltrForm.RESITELE_RELEVANTNI or dostal_body: hodnoty.append(resiteluv_radek) resitele_do_tabulky.append(resitel) From ed5e7a1d9f33c27e383644e000d5992a39786ab6 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 22:16:02 +0200 Subject: [PATCH 05/54] =?UTF-8?q?Template=20pro=20zobrazen=C3=AD=20=C5=99e?= =?UTF-8?q?=C5=A1en=C3=AD=20p=C5=99=C3=ADmo=20v=20tabulce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Snad, ještě jsem to netestoval :-) --- odevzdavatko/templates/odevzdavatko/tabulka.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html index 6d1232d2..b751b9a5 100644 --- a/odevzdavatko/templates/odevzdavatko/tabulka.html +++ b/odevzdavatko/templates/odevzdavatko/tabulka.html @@ -36,13 +36,13 @@ Do data (včetně): {{ filtr.reseni_do }} {# TODO: Chceme mít view i na řešení konkrétního řešitele ke všem problémům? #} {{ resitel }} - {% for hodn in hodnoty %} + {% for bunka in hodnoty %} - {% if hodn %} - - {{ hodn.pocet_reseni }} řeš.
{{ hodn.body }} b
{{ hodn.posledni_odevzdani|kratke_datum|default_if_none:"Nikdy"|default:"???"}} -
- {% endif %} + {% for reseni in bunka %} + + {{reseni.datum_doruceni | date 'j. n.'}}({{ hodn.body }}b) + + {% endfor %} {% endfor %} From 8f2aa72f6d64f8a7f338da0891bae7d3ba3f2795 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 22:21:42 +0200 Subject: [PATCH 06/54] =?UTF-8?q?Fix=20zapomenut=C3=A9=20fieldy=20v=20tabu?= =?UTF-8?q?lce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: rebase squash --- odevzdavatko/views.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index e9bedcbd..d5c4f3a1 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -131,9 +131,6 @@ class TabulkaOdevzdanychReseniView(ListView): tabulka[problem][resitel] = [reseni] else: tabulka[problem][resitel].append(reseni) - # 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 53032a49d8c9aed533fd925fff9050e5944b8a71 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 22:23:15 +0200 Subject: [PATCH 07/54] =?UTF-8?q?Neum=C3=ADm=20ps=C3=A1t=20filtry.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit todo squash --- odevzdavatko/templates/odevzdavatko/tabulka.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html index b751b9a5..0dad11e1 100644 --- a/odevzdavatko/templates/odevzdavatko/tabulka.html +++ b/odevzdavatko/templates/odevzdavatko/tabulka.html @@ -40,7 +40,7 @@ Do data (včetně): {{ filtr.reseni_do }} {% for reseni in bunka %} - {{reseni.datum_doruceni | date 'j. n.'}}({{ hodn.body }}b) + {{reseni.datum_doruceni | date:"j. n."}}({{ hodn.body }}b) {% endfor %} From 468443e0621cfcd1eebaa909c48f470017ccd73d Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 22:46:47 +0200 Subject: [PATCH 08/54] =?UTF-8?q?V=20tabulce=20pot=C5=99ebujeme=20zn=C3=A1?= =?UTF-8?q?t=20i=20Hodnocen=C3=AD,=20kv=C5=AFli=20bod=C5=AFm=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/tabulka.html | 6 +++--- odevzdavatko/views.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html index 0dad11e1..f318789a 100644 --- a/odevzdavatko/templates/odevzdavatko/tabulka.html +++ b/odevzdavatko/templates/odevzdavatko/tabulka.html @@ -38,10 +38,10 @@ Do data (včetně): {{ filtr.reseni_do }} {% for bunka in hodnoty %} - {% for reseni in bunka %} + {% for reseni,hodnoceni in bunka %} - {{reseni.datum_doruceni | date:"j. n."}}({{ hodn.body }}b) - + {{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body }}b) +
{% endfor %} {% endfor %} diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index d5c4f3a1..9fda18a8 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -118,7 +118,7 @@ class TabulkaOdevzdanychReseniView(ListView): ctx = super().get_context_data(*args, **kwargs) ctx['problemy'] = self.problemy ctx['resitele'] = self.resitele - tabulka: dict[m.Problem, dict[m.Resitel, list[m.Reseni]]] = dict() + tabulka: dict[m.Problem, dict[m.Resitel, list[tuple[m.Reseni, m.Hodnoceni]]]] = dict() def pridej_reseni(resitel, hodnoceni): problem = hodnoceni.problem @@ -128,19 +128,19 @@ class TabulkaOdevzdanychReseniView(ListView): if problem not in tabulka: tabulka[problem] = dict() if resitel not in tabulka[problem]: - tabulka[problem][resitel] = [reseni] + tabulka[problem][resitel] = [(reseni, hodnoceni)] else: - tabulka[problem][resitel].append(reseni) + tabulka[problem][resitel].append((reseni, hodnoceni)) for hodnoceni in self.get_queryset(): for resitel in hodnoceni.reseni.resitele.all(): pridej_reseni(resitel, hodnoceni) - hodnoty: list[list[list[m.Reseni]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy, v každé buňce seznam řešení k danému řešiteli a problému. + hodnoty: list[list[list[tuple[m.Reseni, m.Hodnoceni]]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy, v každé buňce seznam řešení k danému řešiteli a problému. resitele_do_tabulky: list[m.Resitel] = [] for resitel in self.resitele: dostal_body = False - resiteluv_radek: list[list[m.Resitel]] = [] # podle pořadí v self.problemy + resiteluv_radek: list[list[tuple[m.Resitel, m.Hodnoceni]]] = [] # podle pořadí v self.problemy for problem in self.problemy: if problem in tabulka and resitel in tabulka[problem]: resiteluv_radek.append(tabulka[problem][resitel]) From bef932345c676fe73ba034b93254dd582f8fab28 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 22:47:13 +0200 Subject: [PATCH 09/54] Kladivoo! --- odevzdavatko/templates/odevzdavatko/tabulka.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html index f318789a..c108c7d8 100644 --- a/odevzdavatko/templates/odevzdavatko/tabulka.html +++ b/odevzdavatko/templates/odevzdavatko/tabulka.html @@ -40,7 +40,7 @@ Do data (včetně): {{ filtr.reseni_do }} {% for reseni,hodnoceni in bunka %} - {{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body }}b) + {{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body|default:"🔨"}}b)
{% endfor %} From 86f6d47f1019a289702b72f2a477ccad17d5e945 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 23:30:57 +0200 Subject: [PATCH 10/54] =?UTF-8?q?Sou=C4=8Dty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hnusně, ale přece… --- odevzdavatko/templates/odevzdavatko/tabulka.html | 7 +++++-- odevzdavatko/views.py | 13 +++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html index c108c7d8..6f3a0540 100644 --- a/odevzdavatko/templates/odevzdavatko/tabulka.html +++ b/odevzdavatko/templates/odevzdavatko/tabulka.html @@ -36,13 +36,16 @@ Do data (včetně): {{ filtr.reseni_do }} {# TODO: Chceme mít view i na řešení konkrétního řešitele ke všem problémům? #} {{ resitel }} - {% for bunka in hodnoty %} + {% for soucet,bunka in hodnoty %} {% for reseni,hodnoceni in bunka %} - {{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body|default:"🔨"}}b) + {{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body|default_if_none:"🔨"}} b)
{% endfor %} + {% if bunka|length > 1 %} + Σ: {{soucet}} b + {% endif %} {% endfor %} diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 9fda18a8..d5c7e4bc 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -13,6 +13,7 @@ from django.db.models import Q from dataclasses import dataclass import datetime +from decimal import Decimal from itertools import groupby import logging @@ -119,6 +120,7 @@ class TabulkaOdevzdanychReseniView(ListView): ctx['problemy'] = self.problemy ctx['resitele'] = self.resitele tabulka: dict[m.Problem, dict[m.Resitel, list[tuple[m.Reseni, m.Hodnoceni]]]] = dict() + soucty: dict[m.Problem, dict[m.Resitel, Decimal]] = dict() def pridej_reseni(resitel, hodnoceni): problem = hodnoceni.problem @@ -127,26 +129,29 @@ class TabulkaOdevzdanychReseniView(ListView): reseni = hodnoceni.reseni if problem not in tabulka: tabulka[problem] = dict() + soucty[problem] = dict() if resitel not in tabulka[problem]: tabulka[problem][resitel] = [(reseni, hodnoceni)] + soucty[problem][resitel] = hodnoceni.body or 0 # Neobodované neřešíme else: tabulka[problem][resitel].append((reseni, hodnoceni)) + soucty[problem][resitel] += hodnoceni.body or 0 # Neobodované neřešíme for hodnoceni in self.get_queryset(): for resitel in hodnoceni.reseni.resitele.all(): pridej_reseni(resitel, hodnoceni) - hodnoty: list[list[list[tuple[m.Reseni, m.Hodnoceni]]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy, v každé buňce seznam řešení k danému řešiteli a problému. + hodnoty: list[list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy + jejich součty, v každé buňce seznam řešení k danému řešiteli a problému. resitele_do_tabulky: list[m.Resitel] = [] for resitel in self.resitele: dostal_body = False - resiteluv_radek: list[list[tuple[m.Resitel, m.Hodnoceni]]] = [] # podle pořadí v self.problemy + resiteluv_radek: list[tuple[Decimal,list[tuple[m.Resitel, m.Hodnoceni]]]] = [] # podle pořadí v self.problemy for problem in self.problemy: if problem in tabulka and resitel in tabulka[problem]: - resiteluv_radek.append(tabulka[problem][resitel]) + resiteluv_radek.append((soucty[problem][resitel], tabulka[problem][resitel])) dostal_body = True else: - resiteluv_radek.append([]) + resiteluv_radek.append((Decimal(0),[])) if self.chteni_resitele != FiltrForm.RESITELE_RELEVANTNI or dostal_body: hodnoty.append(resiteluv_radek) resitele_do_tabulky.append(resitel) From fe144e6de77440b8c58dd1f7e818ffd5111998fe Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 22 May 2023 23:58:04 +0200 Subject: [PATCH 11/54] =?UTF-8?q?Barvi=C4=8Dkyyy!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/static/css/mamweb.css | 1 + odevzdavatko/templates/odevzdavatko/tabulka.html | 3 ++- odevzdavatko/templatetags/barvy_reseni.py | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 odevzdavatko/templatetags/barvy_reseni.py diff --git a/mamweb/static/css/mamweb.css b/mamweb/static/css/mamweb.css index 63c5f527..b1b192d6 100644 --- a/mamweb/static/css/mamweb.css +++ b/mamweb/static/css/mamweb.css @@ -1233,6 +1233,7 @@ div.gdpr { .dosla_reseni tr th, .dosla_reseni tr td { padding: 1px 10px 1px 10px; border-collapse: collapse; + min-width: 8em; /*Nastřeleno, aby se řádky s řešeními nezalamovaly. Teoreticky není potřeba pro th, ale whatever.*/ } .dosla_reseni tr:nth-child(even) { diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html index 6f3a0540..5fd3b8db 100644 --- a/odevzdavatko/templates/odevzdavatko/tabulka.html +++ b/odevzdavatko/templates/odevzdavatko/tabulka.html @@ -1,6 +1,7 @@ {% extends "base.html" %} {% load utils %} {# Možná by mohlo být někde výš v hierarchii templatů... #} +{% load barvy_reseni %} {% block content %} @@ -39,7 +40,7 @@ Do data (včetně): {{ filtr.reseni_do }} {% for soucet,bunka in hodnoty %} {% for reseni,hodnoceni in bunka %} - + {{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body|default_if_none:"🔨"}} b)
{% endfor %} diff --git a/odevzdavatko/templatetags/barvy_reseni.py b/odevzdavatko/templatetags/barvy_reseni.py new file mode 100644 index 00000000..5a3791fd --- /dev/null +++ b/odevzdavatko/templatetags/barvy_reseni.py @@ -0,0 +1,15 @@ +from django import template +register = template.Library() + +from functools import cache +import seminar.models as m + +@register.filter +@cache +def barva_reseni(r: m.Reseni): + """Vrátí nějakou barvu pro daný problém, ve tvaru '#RRGGBB' + + Efektivně hešujeme do barev.""" + + #TODO: ne všechny barvy jsou dobře rozlišitelné a vidět… + return f'#{hash(str(r.id)) & 0xffffff:06x}' From d304e46ceb3499aed5e62b7f6a53aa4f41522ce8 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 23 May 2023 00:28:13 +0200 Subject: [PATCH 12/54] =?UTF-8?q?Barvi=C4=8Dky=20jdou=20vypnout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/forms.py | 2 ++ odevzdavatko/templates/odevzdavatko/tabulka.html | 3 ++- odevzdavatko/views.py | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/odevzdavatko/forms.py b/odevzdavatko/forms.py index 223d807f..8fdd1e21 100644 --- a/odevzdavatko/forms.py +++ b/odevzdavatko/forms.py @@ -196,6 +196,7 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form): 'reseni_od': terminy[-2] if rocnik is None else terminy[0], 'reseni_do': terminy[-1], 'neobodovane': False, + 'barvicky': True, } return initial @@ -220,3 +221,4 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form): reseni_od = forms.DateField(input_formats=[DATE_FORMAT]) reseni_do = forms.DateField(input_formats=[DATE_FORMAT]) neobodovane = forms.BooleanField(required=False) + barvicky = forms.BooleanField(required=False) diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html index 5fd3b8db..7cd317e5 100644 --- a/odevzdavatko/templates/odevzdavatko/tabulka.html +++ b/odevzdavatko/templates/odevzdavatko/tabulka.html @@ -12,6 +12,7 @@ Od data (vyjma): {{ filtr.reseni_od }} Do data (včetně): {{ filtr.reseni_do }} 🔨? {{ filtr.neobodovane }} +🎨? {{ filtr.barvicky }} @@ -40,7 +41,7 @@ Do data (včetně): {{ filtr.reseni_do }} {% for soucet,bunka in hodnoty %} {% for reseni,hodnoceni in bunka %} - + {{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body|default_if_none:"🔨"}} b)
{% endfor %} diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index d5c7e4bc..a3838285 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -63,6 +63,7 @@ class TabulkaOdevzdanychReseniView(ListView): reseni_od = fcd["reseni_od"] reseni_do = fcd["reseni_do"] jen_neobodovane = fcd["neobodovane"] + self.barvicky = fcd["barvicky"] else: initial = FiltrForm.gen_initial(self.aktualni_rocnik) resitele = initial['resitele'] @@ -70,6 +71,7 @@ class TabulkaOdevzdanychReseniView(ListView): reseni_od = initial['reseni_od'][0] reseni_do = initial['reseni_do'][0] jen_neobodovane = initial["neobodovane"] + self.barvicky = initial["barvicky"] # Chceme jen letošní problémy @@ -161,6 +163,7 @@ class TabulkaOdevzdanychReseniView(ListView): ctx['form'] = ctx['filtr'] # Pro maximum v přesměrovátku ročníků ctx['aktualni_rocnik'] = m.Nastaveni.get_solo().aktualni_rocnik + ctx['barvicky'] = self.barvicky if 'rocnik' in self.kwargs: ctx['rocnik'] = self.kwargs['rocnik'] else: From feffa99d793e76a78c4dca8d0633e56d27613bb2 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Tue, 20 Jun 2023 00:26:40 +0200 Subject: [PATCH 13/54] =?UTF-8?q?Fix=20typu=20v=20hodnot=C3=ADtku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index a3838285..781ff8bc 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -147,7 +147,7 @@ class TabulkaOdevzdanychReseniView(ListView): resitele_do_tabulky: list[m.Resitel] = [] for resitel in self.resitele: dostal_body = False - resiteluv_radek: list[tuple[Decimal,list[tuple[m.Resitel, m.Hodnoceni]]]] = [] # podle pořadí v self.problemy + resiteluv_radek: list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]] = [] # podle pořadí v self.problemy for problem in self.problemy: if problem in tabulka and resitel in tabulka[problem]: resiteluv_radek.append((soucty[problem][resitel], tabulka[problem][resitel])) From 2cf4d87c6b9dd16b89a6f92d08ca22cc14204664 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 21 Jun 2023 14:45:46 +0200 Subject: [PATCH 14/54] =?UTF-8?q?Margin=C3=A1ln=C3=AD=20zlep=C5=A1en=C3=AD?= =?UTF-8?q?=20vyr=C3=A1b=C3=ADtka=20org=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Podle diskuse na Matrixu --- personalni/admin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/personalni/admin.py b/personalni/admin.py index fc3cadd4..a00fc6ac 100644 --- a/personalni/admin.py +++ b/personalni/admin.py @@ -2,6 +2,7 @@ from django.contrib import admin from django.contrib.auth.models import Group from django_reverse_admin import ReverseModelAdmin import seminar.models as m +from datetime import datetime @admin.register(m.Osoba) @@ -22,12 +23,12 @@ class OsobaAdmin(admin.ModelAdmin): org_group = Group.objects.get(name='org') print(queryset) for o in queryset: + if m.Organizator.objects.filter(osoba=o).exists(): continue user = o.user - print(user) user.groups.add(org_group) user.is_staff = True user.save() - org = m.Organizator.objects.create(osoba=o) + org = m.Organizator.objects.create(osoba=o, organizuje_od=datetime.now()) org.save() udelej_orgem.short_description = "Udělej vybraných osob organizátory" From 844c55d5a7260e2ebec5e678c44342fdbb345147 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 21 Jun 2023 15:41:17 +0200 Subject: [PATCH 15/54] =?UTF-8?q?Oprava=20drobnost=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personalni/admin.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/personalni/admin.py b/personalni/admin.py index a00fc6ac..29741888 100644 --- a/personalni/admin.py +++ b/personalni/admin.py @@ -21,7 +21,6 @@ class OsobaAdmin(admin.ModelAdmin): def udelej_orgem(self,request,queryset): org_group = Group.objects.get(name='org') - print(queryset) for o in queryset: if m.Organizator.objects.filter(osoba=o).exists(): continue user = o.user @@ -30,7 +29,7 @@ class OsobaAdmin(admin.ModelAdmin): user.save() org = m.Organizator.objects.create(osoba=o, organizuje_od=datetime.now()) org.save() - udelej_orgem.short_description = "Udělej vybraných osob organizátory" + udelej_orgem.short_description = "Udělej z vybraných osob organizátory" class OsobaInline(admin.TabularInline): model = m.Osoba From 36a7a5af5dee6b2f930ce491ea15d82d43d12393 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 21 Jun 2023 15:41:36 +0200 Subject: [PATCH 16/54] =?UTF-8?q?Test=20pro=20d=C4=9Bl=C3=A1n=C3=AD=20org?= =?UTF-8?q?=C5=AF.=20Nefunguje=20:-/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personalni/tests.py | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 personalni/tests.py diff --git a/personalni/tests.py b/personalni/tests.py new file mode 100644 index 00000000..633ff1d4 --- /dev/null +++ b/personalni/tests.py @@ -0,0 +1,53 @@ +from django.test import TestCase + +from django.contrib.auth.models import User, Group +# Tohle bude peklo, až jednou ty modely fakt rozstřelíme… Možná vyrobit various.all_models, které půjdou importovat jako m? :-) +import seminar.models as m + +import logging +logger = logging.getLogger(__name__) + +class DelaniOrguTest(TestCase): + def setUp(self): + self.org_group = Group.objects.get(name='org') + + novy_user = User.objects.create(username='osoba') + self.nova_osoba = m.Osoba.objects.create( + jmeno='Milada', + prijmeni='Von Kolej', + user = novy_user, + # Snad nic dalšího nepotřebujeme, kdyžtak se doplní… + ) + stary_user = User.objects.create(username='stary_user') + stara_osoba = m.Osoba.objects.create(user=stary_user) + self.stary_org = m.Organizator.objects.create(osoba=stara_osoba) + + def test_pridani_orga(self): + # Nejdřív to není org… + self.assertFalse(m.Organizator.objects.filter(osoba=self.nova_osoba).exists()) + self.assertNotIn(self.org_group, self.nova_osoba.user.groups.all()) + self.assertFalse(self.nova_osoba.user.has_perm('auth.org')) + self.assertFalse(self.nova_osoba.user.is_staff) + breakpoint + + # Pak orga uděláme… + from personalni.admin import OsobaAdmin + qs = m.Osoba.objects.filter(id=self.nova_osoba.id) + OsobaAdmin.udelej_orgem(None, None, qs) + + # A pak už to org má být. + logger.info(f'Nová osoba je staff: {self.nova_osoba.user.is_staff}') + self.assertTrue(self.nova_osoba.user.is_staff) + self.assertTrue(self.nova_osoba.user.has_perm('auth.org')) + self.assertIn(self.org_group, self.nova_osoba.user.groups.all()) + self.assertTrue(m.Organizator.objects.filter(osoba=self.nova_osoba).exists()) + novy_org = m.Organizator.objects.get(osoba=self.nova_osoba) + self.assertIsNotNone(novy_org.organizuje_od) + + def test_pridani_stareho_orga(self): + from personalni.admin import OsobaAdmin + OsobaAdmin.udelej_orgem(None, None, m.Osoba.objects.filter(id=self.stary_org.osoba.id)) # Ugly + # Když to spadne, tak jsem se to dozvěděl, takže už nepotřebuju nic kontrolovat. + # Jestli to funguje správně má řešit jiný test. + + From 3eb9c7998d984dd78757b8a012f54921d8041a8a Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Wed, 21 Jun 2023 15:51:08 +0200 Subject: [PATCH 17/54] =?UTF-8?q?Zpr=C3=A1vy=20do=20admina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personalni/admin.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/personalni/admin.py b/personalni/admin.py index 29741888..14af2c2c 100644 --- a/personalni/admin.py +++ b/personalni/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.contrib.auth.models import Group from django_reverse_admin import ReverseModelAdmin +from django.contrib.messages import WARNING, ERROR, SUCCESS import seminar.models as m from datetime import datetime @@ -21,14 +22,23 @@ class OsobaAdmin(admin.ModelAdmin): def udelej_orgem(self,request,queryset): org_group = Group.objects.get(name='org') + uspesne_vytvoreni_orgove = 0 for o in queryset: - if m.Organizator.objects.filter(osoba=o).exists(): continue + if m.Organizator.objects.filter(osoba=o).exists(): + # Ref: https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.message_user + self.message_user(request, f"Osoba {o} už je org, přeskakuji.", level=WARNING) + continue user = o.user + if user is None: + self.message_user(request, f"Osoba {o} nemá uživatele! Přeskakuji.", level=ERROR) + continue user.groups.add(org_group) user.is_staff = True user.save() org = m.Organizator.objects.create(osoba=o, organizuje_od=datetime.now()) org.save() + uspesne_vytvoreni_orgove += 1 + self.message_user(request, f'Úspěšně vytvořeno {uspesne_vytvoreni_orgove} orgů.', level=SUCCESS) udelej_orgem.short_description = "Udělej z vybraných osob organizátory" class OsobaInline(admin.TabularInline): From e182785e48625b670978e13b5b82ca90e750de3b Mon Sep 17 00:00:00 2001 From: MaM Web user Date: Wed, 20 Sep 2023 01:11:03 +0200 Subject: [PATCH 18/54] =?UTF-8?q?P=C5=99id=C3=A1ny=20akce=20pro=20p=C5=99e?= =?UTF-8?q?generov=C3=A1n=C3=AD=20deadlin=C5=AF=20do=20Admina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nikdo o tom neví, a když se o tom dozví, tak se buď nic nezmění, nebo to bylo tak dávno, že si toho nikdo nevšimne :-D Ale na testování se to hodí… Also: někde jsem přepsal mezery na taby. --- seminar/admin.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/seminar/admin.py b/seminar/admin.py index e88af140..2ce7b2f5 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -12,16 +12,22 @@ from django.utils.safestring import mark_safe import seminar.models as m admin.site.register(m.Rocnik) - -admin.site.register(m.Deadline) admin.site.register(m.ZmrazenaVysledkovka) +@admin.register(m.Deadline) +class DeadlineAdmin(admin.ModelAdmin): + actions = ['pregeneruj_vysledkovku'] -class DeadlineAdminInline(admin.TabularInline): - model = m.Deadline - extra = 0 + def pregeneruj_vysledkovku(self, req, qs): + for deadline in qs: + deadline.vygeneruj_vysledkovku() + pregeneruj_vysledkovku.short_description = 'Přegeneruj výsledkovky vybraných deadlinů' +class DeadlineAdminInline(admin.TabularInline): + model = m.Deadline + extra = 0 + class CisloForm(ModelForm): class Meta: model = m.Cislo @@ -71,7 +77,7 @@ class CisloForm(ModelForm): @admin.register(m.Cislo) class CisloAdmin(admin.ModelAdmin): form = CisloForm - actions = ['force_publish'] + actions = ['force_publish', 'pregeneruj_vysledkovky'] inlines = (DeadlineAdminInline,) def force_publish(self,request,queryset): @@ -111,6 +117,12 @@ class CisloAdmin(admin.ModelAdmin): force_publish.short_description = 'Zveřejnit vybraná čísla a všechny návrhy úloh v nich učinit zadanými' + def pregeneruj_vysledkovky(self, req, qs): + for cislo in qs: + for deadline in cislo.deadline_v_cisle.all(): + deadline.vygeneruj_vysledkovku() + pregeneruj_vysledkovky.short_description = 'Přegenerovat výsledkovky všech deadlinů vybraných čísel' + @admin.register(m.Problem) class ProblemAdmin(PolymorphicParentModelAdmin): From f14df7b579161740342fd708ad659c8dc169f574 Mon Sep 17 00:00:00 2001 From: MaM Web user Date: Wed, 20 Sep 2023 10:47:11 +0200 Subject: [PATCH 19/54] =?UTF-8?q?Nov=C3=A9=20k=C3=B3dy=20=C3=BAloh=20ve=20?= =?UTF-8?q?v=C3=BDsledkovce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Zprasený commit, má být na jiné větvi, já vím :-D) --- seminar/models/tvorba.py | 17 +++++++---------- vysledkovky/utils.py | 8 ++++---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/seminar/models/tvorba.py b/seminar/models/tvorba.py index 54e769c8..1c1a3285 100644 --- a/seminar/models/tvorba.py +++ b/seminar/models/tvorba.py @@ -491,7 +491,7 @@ class Problem(SeminarModelBase,PolymorphicModel): return self.nadproblem.kod_v_rocniku+".{}".format(self.kod) return str(self.kod) logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") - return '' + return f'' # def verejne(self): # # aktuálně podle stavu problému @@ -571,9 +571,9 @@ class Tema(Problem): if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY: if self.nadproblem: return self.nadproblem.kod_v_rocniku+".t{}".format(self.kod) - return "t{}".format(self.kod) + return 't'+self.kod logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") - return '' + return f'' def save(self, *args, **kwargs): super().save(*args, **kwargs) @@ -607,9 +607,9 @@ class Clanek(Problem): # Nemělo by být potřeba # if self.nadproblem: # return self.nadproblem.kod_v_rocniku+".c{}".format(self.kod) - return "c{}".format(self.kod) + return "c" + self.kod logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") - return '' + return f'' def node(self): return None @@ -642,12 +642,9 @@ class Uloha(Problem): @cached_property def kod_v_rocniku(self): if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY: - name="{}.u{}".format(self.cislo_zadani.poradi,self.kod) - if self.nadproblem: - return self.nadproblem.kod_v_rocniku+name - return name + return f"{self.cislo_zadani.poradi}.{self.kod}" logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") - return '' + return f'' def save(self, *args, **kwargs): super().save(*args, **kwargs) diff --git a/vysledkovky/utils.py b/vysledkovky/utils.py index 56d05c31..2036b9d3 100644 --- a/vysledkovky/utils.py +++ b/vysledkovky/utils.py @@ -257,7 +257,7 @@ class VysledkovkaCisla(Vysledkovka): # (mají vlastní sloupeček ve výsledkovce, nemají nadproblém) hlavni_problemy = set() for p in self.problemy: - hlavni_problemy.add(p.hlavni_problem) + hlavni_problemy.add(p.hlavni_problem) # FIXME: proč tohle nemůže obsahovat reálné instance? Ve výsledkovce by se pak zobrazovaly správné kódy… # zunikátnění hlavni_problemy = list(hlavni_problemy) @@ -313,7 +313,7 @@ class VysledkovkaCisla(Vysledkovka): # Sečteme hodnocení for hodnoceni in self.hodnoceni_do_cisla: - prob = hodnoceni.problem + prob = hodnoceni.problem.get_real_instance() nadproblem = prob.hlavni_problem.id # Když nadproblém není "téma", pak je "Ostatní" @@ -366,9 +366,9 @@ class VysledkovkaCisla(Vysledkovka): for problem in self.problemy: h_problem = problem.hlavni_problem if h_problem in temata_a_spol: - podproblemy[h_problem.id].append(problem) + podproblemy[h_problem.id].append(problem.get_real_instance()) else: - podproblemy[-1].append(problem) + podproblemy[-1].append(problem.get_real_instance()) for podproblem in podproblemy.keys(): podproblemy[podproblem] = sorted(podproblemy[podproblem], key=lambda p: p.kod_v_rocniku) From 8a473a50970404a3d0aa01c6b262719a04aa8a09 Mon Sep 17 00:00:00 2001 From: MaM Web user Date: Wed, 20 Sep 2023 11:10:55 +0200 Subject: [PATCH 20/54] =?UTF-8?q?Popisky=20v=20z=C3=A1hlav=C3=AD=20v=C3=BD?= =?UTF-8?q?sledkovky?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sice to na mobilu nic moc neudělá, ale aspoň myší se to má šanci používat trochu snáz. --- vysledkovky/templates/vysledkovky/vysledkovka_cisla.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html b/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html index ac53c811..4aa62953 100644 --- a/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html +++ b/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html @@ -4,11 +4,11 @@ # Jméno {% for p in vysledkovka.temata_a_spol%} - {# #}{{ p.kod_v_rocniku }}{# #} + {# #}{{ p.kod_v_rocniku }}{# #} {# TODELETE #} {% for podproblemy in vysledkovka.podproblemy_iter.next %} - {# #}{{ podproblemy.kod_v_rocniku }}{# #} + {# #}{{ podproblemy.kod_v_rocniku }}{# #} {% endfor %} {# TODELETE #} @@ -17,7 +17,7 @@ {# TODELETE #} {% for podproblemy in vysledkovka.podproblemy_iter.next %} - {# #}{{ podproblemy.kod_v_rocniku }}{# #} + {# #}{{ podproblemy.kod_v_rocniku }}{# #} {% endfor %} {# TODELETE #} From bfb7a75b97366f16ce551984714f4f3a5eb5026f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 2 Oct 2023 09:28:23 +0200 Subject: [PATCH 21/54] =?UTF-8?q?Oprava=20vytv=C3=A1=C5=99en=C3=AD=20galer?= =?UTF-8?q?ie=20(Pillow=20odstranil=20n=C4=9Bco,=20co=20django-imagekit=20?= =?UTF-8?q?pou=C5=BE=C3=ADv=C3=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8a6a46e9..309141f5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ psycopg2 html5lib ipython -Pillow +Pillow<10 # FIXME <10 je tu kvůli nekompatibilitě s django-imagekit<=5.0.0 pytz six pexpect From d006f6ebfaea6b3a1fe12811ddc86e7bb02cc757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 2 Oct 2023 10:08:49 +0200 Subject: [PATCH 22/54] =?UTF-8?q?Oprava=20vytv=C3=A1=C5=99en=C3=AD=20galer?= =?UTF-8?q?ie=20(Pillow=20odstranil=20n=C4=9Bco,=20co=20django-imagekit=20?= =?UTF-8?q?pou=C5=BE=C3=ADv=C3=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 309141f5..84810998 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,8 @@ psycopg2 html5lib ipython -Pillow<10 # FIXME <10 je tu kvůli nekompatibilitě s django-imagekit<=5.0.0 +Pillow +pilkit>=3.0 # Kvůli kompatibilitě s Pillow>=10.0.0 pytz six pexpect From 0738aedc9ebf9549dab9aa8e09b857c910f360c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 2 Oct 2023 21:32:09 +0200 Subject: [PATCH 23/54] =?UTF-8?q?Oprava=20pipu=20instaluj=C3=ADc=C3=ADho?= =?UTF-8?q?=20prereleasy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 84810998..ff6d1ef5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ django-ckeditor django-cleanup # Uklízí media/ od smazaných „databázových“ souborů django-flat-theme django-taggit -django-autocomplete-light>=3.9.0rc1 +django-autocomplete-light>=3.9.0 django-crispy-forms django-imagekit django-polymorphic From 1f0d70b31ef625489efffe773d37f7dc60fd5351 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 2 Oct 2023 23:29:51 +0200 Subject: [PATCH 24/54] =?UTF-8?q?Dokumentace=20z=C3=A1vislost=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit podle dnešní schůzky, zatím velmi předběžná verze --- docs/index.rst | 1 + docs/tabulka_prerekvizit.rst | 25 ---------- docs/vyvoj.rst | 2 +- docs/zavislosti.rst | 97 ++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 26 deletions(-) delete mode 100644 docs/tabulka_prerekvizit.rst create mode 100644 docs/zavislosti.rst diff --git a/docs/index.rst b/docs/index.rst index 5481bb88..d06c7e4a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,6 +27,7 @@ Dokumentace (jak v ``docs/``, tak přímo v kódu) je psaná ve :titlesonly: vyvoj + zavislosti sphinx skripty modules/modules diff --git a/docs/tabulka_prerekvizit.rst b/docs/tabulka_prerekvizit.rst deleted file mode 100644 index 9dcce4c5..00000000 --- a/docs/tabulka_prerekvizit.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. Není odkázaná z menu, je to záměr - -Tabulka prerekvizit v různých distribucích -========= - -.. admonition:: Metodika - - Na čistém repozitáři (``git clean -fxd``) a čistém systému spouštíme - ``make/init_local``. Když to spadne, tak do tabulky zapíšeme, co jsme - přiinstalovali. Protože větev ``makefiles`` aktuálně není mergenutá do - masteru, nefunguje synchronizace flatpages (a stejně nemáme SSH klíč), takže - tam ``make/init_local`` sestřelíme a vyzkoušíme, že ``make/test`` spustí - testy. - -.. Grafické tabulky (grid-tables, simple-tables) jsou strašný porod vyrábět, dlabu na to a cpu to do CSV… - -.. csv-table:: Prerekvizity v jednotlivých distribucích - :header: Distribuce / OS, Repozitář s Py3.9, venv, py knihovny, PostgreSQL knihovna, poznámky - - Ubuntu 22.10, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, "Je potřeba zapnout zdroj ``universe`` a nainstalovat kompilátor C (``gcc``)?" - Linux Mint 21, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, "" - Archlinux 2022.11.01, AUR, vestavěný, vestavěné, ``postgresql-libs``, "Je potřeba céčkový kompilátor (``gcc``)" - openSUSE Leap 15.4, oficiální (``python39``), předinstalovaný?, ``python39-devel``, ??FIXME!!, "Výchozí verze pythonu je 3.6 a ta je moc stará, potřeba instalovat ``gcc``. Nevím jak sehnat pg_config." - Debian 11, "oficiální, výchozí", ??, ??, ??, "Určitě to tam rozběhat jde, protože Gimli. Nejspíš bude relativně podobné Ubuntu." - diff --git a/docs/vyvoj.rst b/docs/vyvoj.rst index 0d23972a..2df0ae64 100644 --- a/docs/vyvoj.rst +++ b/docs/vyvoj.rst @@ -37,7 +37,7 @@ Kromě toho je potřeba mít účet na `Gitee `_, kd bydlí gitový repozitář s kódem. .. tip:: Potřebné balíčky v různých distribucích jsou sepsané v :ref:`tabulce - prerekvizit `. + prerekvizit `. Doporučené ^^^^^^^^^^ diff --git a/docs/zavislosti.rst b/docs/zavislosti.rst new file mode 100644 index 00000000..c2f684bd --- /dev/null +++ b/docs/zavislosti.rst @@ -0,0 +1,97 @@ +Závislosti webu +@@@@@@@@@@@@@@@ + +Web ke svému běhu potřebuje různé další programy. Tahle stránka se snaží je pokrýt. + +Stránka je koncipována jako odrážkový seznam balíčků pro Ubuntu s případnými +komentáři, na konci stránky jsou uvedena :ref:`jména balíčků ` v různých dalších distribucích. (Seznam mj. cílí na lokální +rozchození, proto popisuji Ubuntu a ne Debian. I tak se ale snažíme popsat web +v úplnosti.) + +.. I use Arch, btw. + + +Základ webu +=========== + +- ``python3`` – Ideálně Python 3.9, jenž je na Gimlim +- ``python3-pip`` pro instalaci dalších Pythoních balíčků podle ``requirements.txt`` +- ``python3-venv`` +- ``gcc`` – kompilace Pythoních knihoven ze zdrojových distribucí (sdist), možná (neotestováno) jde jako alternativu použít ``python3-wheel`` a stahovat bdists +- ``python3-dev`` – taktéž +- ``libpq-dev`` do třetice… +- ``ghostscript`` TODO konverze PDF v korekturovátku +- ``pdflatex`` FIXME! generování obálek a stvrzenek +- ``git`` – používán :ref:`Make skripty` +- ``locales`` pro české formáty + +Nasazení na produkci / testweb +============================== + +(nejsou nutně potřeba k provozu lokální instance) + +- ``rsync`` +- ``pg_utils`` FIXME +- ``htpasswd`` FIXME – aby testweb nepoužívali náhodní kolemjdoucí +- ``postgresql-server`` TODO +- ``acl`` pro nastavování práv přes ``setfacl`` + +Pro testweb je potřeba i všechno pro :ref:`dokumentaci `, vizte níž. + +Předpokládá se nasazení v uWSGI pod Nginxem a služba běžící pod systemd, nicméně to už je spíš záležitost infrastruktury a ne specifikum mamwebu. + +Dokumentace +=========== + +- ``make`` pro zbuildění +- Pythoní balíčky podle příslušné části ``requirements.txt`` + +Vývojové nástroje +================= + +(Nejsou nezbytně nutné, ale předpokládáme jejich užitečnost. Mohou se hodit i na produkci.) + +- ``psql`` TODO pro manuální dotazy do PostgreSQL +- ``sqlite3`` TODO totéž pro SQLite3 +- ``ssh`` +- ``graphviz`` pro vygenerování schématu +- ``rsync`` +- ``ipython3`` – hezčí interaktivní shell (stačí z ``requirements.txt``) + +Potenciální usnadnění života +============================ + +(Úplně zbytečné, ale sdílíme pozitivní zkušenosti :-)) + +- ``tea`` – CLI klient pro Giteu, aby člověk nepotřeboval otevírat web pro založení PR + + +Alternativní jména balíčků +========================== + +Různé distribuce balí SW různě, takže to, co je v jedné distribuci jeden +balíček může být v jiné rozděleno do víc. Pro usnadnění nasazení je tady +přehled známých alternativních jmen. + +TODO: tabulka není úplná. Pokud na něco narazíte, tak ji prosím doplňte. + +.. admonition:: Jak se pozná, že web funguje, pro účely tabulky? + + Na čistém repozitáři (``git clean -fxd``) a čistém systému spouštíme + ``make/init_local``. Když to spadne, tak do tabulky zapíšeme, co jsme + přiinstalovali. Protože nefunguje synchronizace flatpages (nemáme SSH klíč), + ``make/init_local`` sestřelíme při pokusu o synchronizaci a vyzkoušíme, že + ``make/test`` spustí testy. + +.. Grafické tabulky (grid-tables, simple-tables) jsou strašný porod vyrábět, dlabu na to a cpu to do CSV… + +.. csv-table:: Prerekvizity v jednotlivých distribucích + :header: Distribuce / OS, Repozitář s Py3.9, venv, py knihovny, PostgreSQL knihovna, poznámky + + Ubuntu 22.10, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, "Je potřeba zapnout zdroj ``universe`` a nainstalovat kompilátor C (``gcc``)?" + Linux Mint 21, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, "" + Archlinux 2022.11.01, AUR, vestavěný, vestavěné, ``postgresql-libs``, "Je potřeba céčkový kompilátor (``gcc``)" + openSUSE Leap 15.4, oficiální (``python39``), předinstalovaný?, ``python39-devel``, ??FIXME!!, "Výchozí verze pythonu je 3.6 a ta je moc stará, potřeba instalovat ``gcc``. Nevím jak sehnat pg_config." + Debian 11, "oficiální, výchozí", ??, ??, ??, "Určitě to tam rozběhat jde, protože Gimli. Nejspíš bude relativně podobné Ubuntu." + From bb127832dc418a5c793dd1eac12440cd6a5457f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 9 Oct 2023 21:11:12 +0200 Subject: [PATCH 25/54] =?UTF-8?q?Oprava=20=E2=80=9En=C3=A1zvu=20z=C3=A1lo?= =?UTF-8?q?=C5=BEky=E2=80=9C=20p=C5=99i=20Ojojojojoj?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/templates/500.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mamweb/templates/500.html b/mamweb/templates/500.html index 7fc267fe..67085a8f 100644 --- a/mamweb/templates/500.html +++ b/mamweb/templates/500.html @@ -4,7 +4,9 @@ {% block errorheading %}
{# Meníčko nedostaneme, protože dostáváme prázdný kontext. Tak alespoň ať se O-JO-JO-JO-JOJ neschovává pod ním #} + {% block nadpis1a %} O-jo-jo-jo-joj + {% endblock %} {% endblock %} {% block errortext %} From 60346d68390bb4c5f0f7b4d01989a2ee7cb43b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 9 Oct 2023 21:50:50 +0200 Subject: [PATCH 26/54] =?UTF-8?q?Str=C3=A1nka=20pro=20CSRF=20chybu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/settings_common.py | 3 + various/static/various/img/zere_kostku.svg | 87 ++++++++++++++++++++++ various/templates/various/403_csrf.html | 19 +++++ various/views.py | 7 ++ 4 files changed, 116 insertions(+) create mode 100644 various/static/various/img/zere_kostku.svg create mode 100644 various/templates/various/403_csrf.html diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 03724d3d..36b39296 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -54,6 +54,9 @@ LOGIN_REDIRECT_URL = 'profil' SESSION_EXPIRE_AT_BROWSER_CLOSE = True DOBA_ODHLASENI_PRI_ZASKRTNUTI_NEODHLASOVAT = 365 * 24 * 3600 # rok +# View pro chybu s CSRF tokenem (např. se sušenkami) +CSRF_FAILURE_VIEW = 'various.views.csrf_error' + # Modules configuration AUTHENTICATION_BACKENDS = ( diff --git a/various/static/various/img/zere_kostku.svg b/various/static/various/img/zere_kostku.svg new file mode 100644 index 00000000..bac31662 --- /dev/null +++ b/various/static/various/img/zere_kostku.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + diff --git a/various/templates/various/403_csrf.html b/various/templates/various/403_csrf.html new file mode 100644 index 00000000..ff2f0cf9 --- /dev/null +++ b/various/templates/various/403_csrf.html @@ -0,0 +1,19 @@ +{#{% extends "error_base.html" %} Z toho nedědíme, protože se nemá přecházet na titulní stránku. #} +{% extends "base.html" %} + +{% load static %} + +{% block content %} + +

{% block nadpis1a %}O-jo-jo-jo-joj{% endblock nadpis1a %}

+ +

+ Problém se sušenkami či něčím podobným. Zkuste to prosím znovu: {{ url }}. Případně můžete přejít na titulní stránku. +

+ +

Pokud problém přetrvává obraťte se na nás přes e-mail: mailto:mam@matfyz.cz a pošlete nám následující popis chyby: {{ reason }}

+ + + + +{% endblock %} diff --git a/various/views.py b/various/views.py index 91ea44a2..3e5e1a5a 100644 --- a/various/views.py +++ b/various/views.py @@ -1,3 +1,10 @@ from django.shortcuts import render # Create your views here. + + +def csrf_error(request, reason): + return render( + request, 'various/403_csrf.html', + {"url": request.META["HTTP_REFERER"], "reason": reason}, + ) From 29b327120049d0bee64f220443939a68ebae7f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 9 Oct 2023 22:02:05 +0200 Subject: [PATCH 27/54] =?UTF-8?q?CSRF=20chyba=20m=C3=A1=20vr=C3=A1tit=2040?= =?UTF-8?q?3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- various/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/various/views.py b/various/views.py index 3e5e1a5a..9bb6b109 100644 --- a/various/views.py +++ b/various/views.py @@ -1,3 +1,4 @@ +from django.http import HttpResponseForbidden from django.shortcuts import render # Create your views here. @@ -7,4 +8,5 @@ def csrf_error(request, reason): return render( request, 'various/403_csrf.html', {"url": request.META["HTTP_REFERER"], "reason": reason}, + status=HttpResponseForbidden.status_code, ) From 0e24c1d9add98d95533d8884d5a23be7af72d10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 9 Oct 2023 22:04:01 +0200 Subject: [PATCH 28/54] =?UTF-8?q?Koment=C3=A1=C5=99=20k=20CSRF=20chyb?= =?UTF-8?q?=C3=A1m?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- various/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/various/views.py b/various/views.py index 9bb6b109..b5808f19 100644 --- a/various/views.py +++ b/various/views.py @@ -5,6 +5,7 @@ from django.shortcuts import render def csrf_error(request, reason): + """ Jednoduchý „template_view“ (třída to být nesmůže) pro CSRF chyby """ return render( request, 'various/403_csrf.html', {"url": request.META["HTTP_REFERER"], "reason": reason}, From 68d51a0bf1d02b349141ba282d61614e5d37d8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 9 Oct 2023 22:14:27 +0200 Subject: [PATCH 29/54] =?UTF-8?q?P=C5=99eklep?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- various/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/various/views.py b/various/views.py index b5808f19..7bc3fccd 100644 --- a/various/views.py +++ b/various/views.py @@ -5,7 +5,7 @@ from django.shortcuts import render def csrf_error(request, reason): - """ Jednoduchý „template_view“ (třída to být nesmůže) pro CSRF chyby """ + """ Jednoduchý „template_view“ (třída to být nemůže) pro CSRF chyby """ return render( request, 'various/403_csrf.html', {"url": request.META["HTTP_REFERER"], "reason": reason}, From 002e33002c5c1500ec10eed0881285cb521e2e6c Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 9 Oct 2023 22:25:25 +0200 Subject: [PATCH 30/54] =?UTF-8?q?P=C5=99egenerov=C3=A1vat=20v=C3=BDsledkov?= =?UTF-8?q?ky=20nem=C5=AF=C5=BEe=20b=C4=9B=C5=BEn=C3=BD=20org?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/admin.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/seminar/admin.py b/seminar/admin.py index 2ce7b2f5..59a72927 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -18,12 +18,12 @@ admin.site.register(m.ZmrazenaVysledkovka) class DeadlineAdmin(admin.ModelAdmin): actions = ['pregeneruj_vysledkovku'] + # Nikomu nezobrazovat, ale superuživatelům se může hodit :-) + @admin.action(permissions=[], description= 'Přegeneruj výsledkovky vybraných deadlinů') def pregeneruj_vysledkovku(self, req, qs): for deadline in qs: deadline.vygeneruj_vysledkovku() - pregeneruj_vysledkovku.short_description = 'Přegeneruj výsledkovky vybraných deadlinů' - - + class DeadlineAdminInline(admin.TabularInline): model = m.Deadline extra = 0 @@ -117,11 +117,12 @@ class CisloAdmin(admin.ModelAdmin): force_publish.short_description = 'Zveřejnit vybraná čísla a všechny návrhy úloh v nich učinit zadanými' + # Jen pro superuživatele + @admin.action(permissions=[], description='Přegenerovat výsledkovky všech deadlinů vybraných čísel') def pregeneruj_vysledkovky(self, req, qs): for cislo in qs: for deadline in cislo.deadline_v_cisle.all(): deadline.vygeneruj_vysledkovku() - pregeneruj_vysledkovky.short_description = 'Přegenerovat výsledkovky všech deadlinů vybraných čísel' @admin.register(m.Problem) From b69ebcd6b6942a4a04489835b127176f62c881d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 9 Oct 2023 22:29:29 +0200 Subject: [PATCH 31/54] =?UTF-8?q?U=20CSRF=20chyby=20m=C3=A1=20b=C3=BDt=20r?= =?UTF-8?q?eason=20asi=20p=C5=99edvypln=C4=9Bn=C3=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- various/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/various/views.py b/various/views.py index 7bc3fccd..c6e46ab8 100644 --- a/various/views.py +++ b/various/views.py @@ -4,8 +4,8 @@ from django.shortcuts import render # Create your views here. -def csrf_error(request, reason): - """ Jednoduchý „template_view“ (třída to být nemůže) pro CSRF chyby """ +def csrf_error(request, reason=""): + """ Jednoduchý „template view“ (třída to být nemůže) pro CSRF chyby """ return render( request, 'various/403_csrf.html', {"url": request.META["HTTP_REFERER"], "reason": reason}, From 7e1644d5c199cb23aae2afcbc5febfed1b934f72 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 9 Oct 2023 22:43:27 +0200 Subject: [PATCH 32/54] =?UTF-8?q?Parci=C3=A1ln=C3=AD=20fix=20testu=20d?= =?UTF-8?q?=C4=9Bl=C3=A1n=C3=AD=20org=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personalni/tests.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/personalni/tests.py b/personalni/tests.py index 633ff1d4..6f00cd1e 100644 --- a/personalni/tests.py +++ b/personalni/tests.py @@ -1,6 +1,8 @@ -from django.test import TestCase +from django.test import TestCase, RequestFactory from django.contrib.auth.models import User, Group +from django.contrib.admin.sites import AdminSite +from personalni.admin import OsobaAdmin # Tohle bude peklo, až jednou ty modely fakt rozstřelíme… Možná vyrobit various.all_models, které půjdou importovat jako m? :-) import seminar.models as m @@ -9,6 +11,15 @@ logger = logging.getLogger(__name__) class DelaniOrguTest(TestCase): def setUp(self): + # Admin musí mít instanci + # Ref: https://www.argpar.se/posts/programming/testing-django-admin/ + adm_site = AdminSite() + self.admin = OsobaAdmin(m.Osoba, adm_site) + + from django.contrib.messages.storage.cookie import CookieStorage + self.request = RequestFactory().get('/admin') + self.request._messages = CookieStorage(self.request) + self.org_group = Group.objects.get(name='org') novy_user = User.objects.create(username='osoba') @@ -31,9 +42,8 @@ class DelaniOrguTest(TestCase): breakpoint # Pak orga uděláme… - from personalni.admin import OsobaAdmin qs = m.Osoba.objects.filter(id=self.nova_osoba.id) - OsobaAdmin.udelej_orgem(None, None, qs) + self.admin.udelej_orgem(self.request, qs) # A pak už to org má být. logger.info(f'Nová osoba je staff: {self.nova_osoba.user.is_staff}') @@ -45,8 +55,7 @@ class DelaniOrguTest(TestCase): self.assertIsNotNone(novy_org.organizuje_od) def test_pridani_stareho_orga(self): - from personalni.admin import OsobaAdmin - OsobaAdmin.udelej_orgem(None, None, m.Osoba.objects.filter(id=self.stary_org.osoba.id)) # Ugly + self.admin.udelej_orgem(self.request, m.Osoba.objects.filter(id=self.stary_org.osoba.id)) # Ugly # Když to spadne, tak jsem se to dozvěděl, takže už nepotřebuju nic kontrolovat. # Jestli to funguje správně má řešit jiný test. From 2d416472e8b11967c4caeb9cf2cc932573dc5b8b Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 9 Oct 2023 22:50:28 +0200 Subject: [PATCH 33/54] =?UTF-8?q?Tak=20superuser=20u=C5=BE=20m=C5=AF=C5=BE?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lol… --- seminar/admin.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/seminar/admin.py b/seminar/admin.py index 59a72927..8f589a03 100644 --- a/seminar/admin.py +++ b/seminar/admin.py @@ -19,11 +19,15 @@ class DeadlineAdmin(admin.ModelAdmin): actions = ['pregeneruj_vysledkovku'] # Nikomu nezobrazovat, ale superuživatelům se může hodit :-) - @admin.action(permissions=[], description= 'Přegeneruj výsledkovky vybraných deadlinů') + @admin.action(permissions=['bazmek'], description= 'Přegeneruj výsledkovky vybraných deadlinů') def pregeneruj_vysledkovku(self, req, qs): for deadline in qs: deadline.vygeneruj_vysledkovku() + def has_bazmek_permission(self, request): + # Boilerplate: potřebujeme nějakou permission, protože nějaká haluz v Djangu… + return request.user.is_superuser + class DeadlineAdminInline(admin.TabularInline): model = m.Deadline extra = 0 @@ -118,11 +122,15 @@ class CisloAdmin(admin.ModelAdmin): force_publish.short_description = 'Zveřejnit vybraná čísla a všechny návrhy úloh v nich učinit zadanými' # Jen pro superuživatele - @admin.action(permissions=[], description='Přegenerovat výsledkovky všech deadlinů vybraných čísel') + @admin.action(permissions=['bazmek'], description='Přegenerovat výsledkovky všech deadlinů vybraných čísel') def pregeneruj_vysledkovky(self, req, qs): for cislo in qs: for deadline in cislo.deadline_v_cisle.all(): deadline.vygeneruj_vysledkovku() + + def has_bazmek_permission(self, request): + # Boilerplate: potřebujeme nějakou permission, protože nějaká haluz v Djangu… + return request.user.is_superuser @admin.register(m.Problem) From aff9a39262d5ab0acce386084ae4fba4da1ad1c2 Mon Sep 17 00:00:00 2001 From: MaM Web user Date: Mon, 9 Oct 2023 23:00:49 +0200 Subject: [PATCH 34/54] =?UTF-8?q?uwsgi=20v=20requirements.txt=20nevypad?= =?UTF-8?q?=C3=A1=20pot=C5=99ebn=C4=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit a navíc to pak Jidášovi nefunguje, zatím nevím proč. P. --- requirements.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index ff6d1ef5..d51645de 100644 --- a/requirements.txt +++ b/requirements.txt @@ -53,9 +53,6 @@ Werkzeug requests # requests-oauthlib -# uWSGI -uWSGI - # Potřeba pro test data lorem From 1aa389414d47e81280157d77e558e6f432f1985e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Sat, 14 Oct 2023 11:26:38 +0200 Subject: [PATCH 35/54] =?UTF-8?q?N=C3=A1vrh=20na=20webappku=20na=20=C5=A1i?= =?UTF-8?q?frova=C4=8Dku=20(na=20Sklen=C3=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/settings_common.py | 1 + mamweb/urls.py | 2 + sifrovacka/__init__.py | 0 sifrovacka/admin.py | 8 ++++ sifrovacka/apps.py | 5 ++ sifrovacka/forms.py | 15 ++++++ sifrovacka/migrations/0001_initial.py | 34 ++++++++++++++ sifrovacka/migrations/__init__.py | 0 sifrovacka/models.py | 18 ++++++++ .../templates/sifrovacka/odpovedi_list.html | 23 ++++++++++ .../templates/sifrovacka/sifrovacka.html | 46 +++++++++++++++++++ sifrovacka/urls.py | 17 +++++++ sifrovacka/views.py | 30 ++++++++++++ 13 files changed, 199 insertions(+) create mode 100644 sifrovacka/__init__.py create mode 100644 sifrovacka/admin.py create mode 100644 sifrovacka/apps.py create mode 100644 sifrovacka/forms.py create mode 100644 sifrovacka/migrations/0001_initial.py create mode 100644 sifrovacka/migrations/__init__.py create mode 100644 sifrovacka/models.py create mode 100644 sifrovacka/templates/sifrovacka/odpovedi_list.html create mode 100644 sifrovacka/templates/sifrovacka/sifrovacka.html create mode 100644 sifrovacka/urls.py create mode 100644 sifrovacka/views.py diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 36b39296..71bae132 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -154,6 +154,7 @@ INSTALLED_APPS = ( 'soustredeni', 'treenode', 'vyroci', + 'sifrovacka', # Admin upravy: diff --git a/mamweb/urls.py b/mamweb/urls.py index 0855b6b6..9ef2750a 100644 --- a/mamweb/urls.py +++ b/mamweb/urls.py @@ -71,6 +71,8 @@ urlpatterns = [ # Výroční sraz path('sraz/30-let/', include('vyroci.urls')), + # Miniapka na šifrovačku + path('sifrovacka/', include('sifrovacka.urls')), ] # This is only needed when using runserver. diff --git a/sifrovacka/__init__.py b/sifrovacka/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sifrovacka/admin.py b/sifrovacka/admin.py new file mode 100644 index 00000000..71d191d4 --- /dev/null +++ b/sifrovacka/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from .models import OdpovedUcastnika, SpravnaOdpoved + +# Register your models here. + +admin.site.register(OdpovedUcastnika) +admin.site.register(SpravnaOdpoved) diff --git a/sifrovacka/apps.py b/sifrovacka/apps.py new file mode 100644 index 00000000..e9f34de6 --- /dev/null +++ b/sifrovacka/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class SifrovackaConfig(AppConfig): + name = 'sifrovacka' diff --git a/sifrovacka/forms.py b/sifrovacka/forms.py new file mode 100644 index 00000000..ac547894 --- /dev/null +++ b/sifrovacka/forms.py @@ -0,0 +1,15 @@ +from django.core.exceptions import ValidationError +from django.forms import ModelForm +from .models import OdpovedUcastnika, SpravnaOdpoved + + +class SifrovackaForm(ModelForm): + class Meta: + model = OdpovedUcastnika + fields = ["sifra", "odpoved", ] + + def clean_sifra(self): + sifra = self.cleaned_data.get('sifra') + if SpravnaOdpoved.objects.filter(sifra=sifra).count() == 0: + raise ValidationError("Špatné číslo šifry") + return sifra diff --git a/sifrovacka/migrations/0001_initial.py b/sifrovacka/migrations/0001_initial.py new file mode 100644 index 00000000..742461ef --- /dev/null +++ b/sifrovacka/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 3.2.22 on 2023-10-14 09:20 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('seminar', '0113_resitel_zasilat_cislo_papirove'), + ] + + operations = [ + migrations.CreateModel( + name='SpravnaOdpoved', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('odpoved', models.TextField()), + ('sifra', models.IntegerField()), + ('skryty_text', models.TextField()), + ], + ), + migrations.CreateModel( + name='OdpovedUcastnika', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('odpoved', models.TextField(verbose_name='Tajenka')), + ('sifra', models.IntegerField(verbose_name='Číslo šifry')), + ('resitel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='seminar.resitel')), + ], + ), + ] diff --git a/sifrovacka/migrations/__init__.py b/sifrovacka/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sifrovacka/models.py b/sifrovacka/models.py new file mode 100644 index 00000000..0e2dc78e --- /dev/null +++ b/sifrovacka/models.py @@ -0,0 +1,18 @@ +from django.db import models + +from seminar.models.personalni import Resitel + + +# Create your models here. + + +class OdpovedUcastnika(models.Model): + resitel = models.ForeignKey(Resitel, blank=False, null=False, on_delete=models.CASCADE) + odpoved = models.TextField("Tajenka", blank=False, null=False,) + sifra = models.IntegerField("Číslo šifry", blank=False, null=False,) + + +class SpravnaOdpoved(models.Model): + odpoved = models.TextField(blank=False, null=False,) + sifra = models.IntegerField(blank=False, null=False,) + skryty_text = models.TextField(blank=False, null=False,) diff --git a/sifrovacka/templates/sifrovacka/odpovedi_list.html b/sifrovacka/templates/sifrovacka/odpovedi_list.html new file mode 100644 index 00000000..8e122558 --- /dev/null +++ b/sifrovacka/templates/sifrovacka/odpovedi_list.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block content %} + +

{% block nadpis1a %}Šifrovačka odpovědi{% endblock nadpis1a %}

+ + + + + + + + + {% for u in object_list %} + + + + + + {% endfor %} +
ŘešitelŠifraOdpověď
{{ u.resitel }}{{ u.sifra }}{{ u.odpoved }}
+ +{% endblock content %} diff --git a/sifrovacka/templates/sifrovacka/sifrovacka.html b/sifrovacka/templates/sifrovacka/sifrovacka.html new file mode 100644 index 00000000..4e0cc15a --- /dev/null +++ b/sifrovacka/templates/sifrovacka/sifrovacka.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} + +{% block content %} + +
+ +

{% block nadpis1a %}M&Mí šifrovačka{% endblock nadpis1a %}

+ +
+ +

Zadat tajenku šifry:

+ +
+ + {{form.non_field_errors}} + {% for field in form %} + + + + + + + + + {% if field.errors %} + + + + {% endif %} + {% endfor %} +
+ + + + {{ field }} + {{ field.help_text|safe }} +
{{ field.errors }}
+ + {% csrf_token %} + + +
+ +{% endblock content %} diff --git a/sifrovacka/urls.py b/sifrovacka/urls.py new file mode 100644 index 00000000..0f3eb669 --- /dev/null +++ b/sifrovacka/urls.py @@ -0,0 +1,17 @@ +from django.urls import path + +from seminar.utils import org_required, resitel_required +from .views import SifrovackaView, SifrovackaListView + +urlpatterns = [ + path( + '', + resitel_required(SifrovackaView.as_view()), + name='sifrovacka' + ), + path( + 'odpovedi/', + org_required(SifrovackaListView.as_view()), + name='sifrovacka_odpovedi' + ), +] diff --git a/sifrovacka/views.py b/sifrovacka/views.py new file mode 100644 index 00000000..a83e6c17 --- /dev/null +++ b/sifrovacka/views.py @@ -0,0 +1,30 @@ +from django.urls import reverse +from django.views.generic import FormView, ListView + +from seminar.views import formularOKView +from .forms import SifrovackaForm +from .models import OdpovedUcastnika, SpravnaOdpoved +from seminar.models.personalni import Resitel + + +# Create your views here. + +class SifrovackaView(FormView): + template_name = 'sifrovacka/sifrovacka.html' + form_class = SifrovackaForm + + def form_valid(self, form): + instance = form.save(commit=False) + resitel = Resitel.objects.get(osoba__user=self.request.user) + instance.resitel = resitel + instance.save() + sifra = SpravnaOdpoved.objects.filter(sifra=instance.sifra, odpoved__iexact=instance.odpoved.strip()).first() + if sifra is None: + return formularOKView(self.request, f'

Bohužel vám hvězdy nebyly nakloněny.

Zkusit znovu.




') + + return formularOKView(self.request, f'

{sifra.skryty_text}

Odevzdat další.




') + + +class SifrovackaListView(ListView): + template_name = 'sifrovacka/odpovedi_list.html' + model = OdpovedUcastnika From c635b0a2802cedafce0d95bd34361cf54dd595b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Sat, 14 Oct 2023 12:09:14 +0200 Subject: [PATCH 36/54] =?UTF-8?q?K=20formul=C3=A1=C5=99i=20maj=C3=AD=20m?= =?UTF-8?q?=C3=ADt=20p=C5=99=C3=ADstup=20i=20orgov=C3=A9=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sifrovacka/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sifrovacka/urls.py b/sifrovacka/urls.py index 0f3eb669..a7af5e54 100644 --- a/sifrovacka/urls.py +++ b/sifrovacka/urls.py @@ -1,12 +1,12 @@ from django.urls import path -from seminar.utils import org_required, resitel_required +from seminar.utils import org_required, resitel_or_org_required from .views import SifrovackaView, SifrovackaListView urlpatterns = [ path( '', - resitel_required(SifrovackaView.as_view()), + resitel_or_org_required(SifrovackaView.as_view()), name='sifrovacka' ), path( From dca7a7beddc0b0e546466c6ca3adfa8a6743699a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borek=20Po=C5=BE=C3=A1r?= Date: Sat, 14 Oct 2023 12:28:22 +0200 Subject: [PATCH 37/54] =?UTF-8?q?Trochu=20p=C5=99eps=C3=A1ny=20text=C3=ADk?= =?UTF-8?q?y.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sifrovacka/forms.py | 2 +- sifrovacka/views.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sifrovacka/forms.py b/sifrovacka/forms.py index ac547894..06edaba6 100644 --- a/sifrovacka/forms.py +++ b/sifrovacka/forms.py @@ -11,5 +11,5 @@ class SifrovackaForm(ModelForm): def clean_sifra(self): sifra = self.cleaned_data.get('sifra') if SpravnaOdpoved.objects.filter(sifra=sifra).count() == 0: - raise ValidationError("Špatné číslo šifry") + raise ValidationError("Tohle číslo šifry v databázi nemáme. Zkontrolujte si ho prosím.") return sifra diff --git a/sifrovacka/views.py b/sifrovacka/views.py index a83e6c17..20dcf49a 100644 --- a/sifrovacka/views.py +++ b/sifrovacka/views.py @@ -20,9 +20,9 @@ class SifrovackaView(FormView): instance.save() sifra = SpravnaOdpoved.objects.filter(sifra=instance.sifra, odpoved__iexact=instance.odpoved.strip()).first() if sifra is None: - return formularOKView(self.request, f'

Bohužel vám hvězdy nebyly nakloněny.

Zkusit znovu.




') + return formularOKView(self.request, f'

Bohužel vám hvězdy nebyly nakloněny. Rozumějte máte to blbě.

Zkusit znovu.




') - return formularOKView(self.request, f'

{sifra.skryty_text}

Odevzdat další.




') + return formularOKView(self.request, f'

{sifra.skryty_text}

Odevzdat další.




') class SifrovackaListView(ListView): From b8eee44ed05c5c01bd0e75ac54ee07d709f41939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borek=20Po=C5=BE=C3=A1r?= Date: Sat, 14 Oct 2023 12:37:23 +0200 Subject: [PATCH 38/54] Hrajeme si se styly. --- sifrovacka/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sifrovacka/views.py b/sifrovacka/views.py index 20dcf49a..91100e53 100644 --- a/sifrovacka/views.py +++ b/sifrovacka/views.py @@ -20,9 +20,9 @@ class SifrovackaView(FormView): instance.save() sifra = SpravnaOdpoved.objects.filter(sifra=instance.sifra, odpoved__iexact=instance.odpoved.strip()).first() if sifra is None: - return formularOKView(self.request, f'

Bohužel vám hvězdy nebyly nakloněny. Rozumějte máte to blbě.

Zkusit znovu.




') + return formularOKView(self.request, f'

Bohužel vám hvězdy nebyly nakloněny. Rozumějte máte to blbě.

Zkusit znovu.




') - return formularOKView(self.request, f'

{sifra.skryty_text}

Odevzdat další.




') + return formularOKView(self.request, f'

{sifra.skryty_text}

Odevzdat další.




') class SifrovackaListView(ListView): From 1f7b770a5c8b71593dead68d3c9beca49243e3ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Sun, 15 Oct 2023 19:52:11 +0200 Subject: [PATCH 39/54] =?UTF-8?q?Odpov=C4=9Bdi=20od=20=C3=BA=C4=8Dastn?= =?UTF-8?q?=C3=ADk=C5=AF=20maj=C3=AD=20nov=C4=9B=20i=20timestamp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0002_auto_20231015_1944.py | 28 +++++++++++++++++++ sifrovacka/models.py | 7 ++++- .../templates/sifrovacka/odpovedi_list.html | 2 ++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 sifrovacka/migrations/0002_auto_20231015_1944.py diff --git a/sifrovacka/migrations/0002_auto_20231015_1944.py b/sifrovacka/migrations/0002_auto_20231015_1944.py new file mode 100644 index 00000000..dea42891 --- /dev/null +++ b/sifrovacka/migrations/0002_auto_20231015_1944.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.22 on 2023-10-15 17:44 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('sifrovacka', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='odpoveducastnika', + options={'ordering': ['-timestamp']}, + ), + migrations.AddField( + model_name='odpoveducastnika', + name='timestamp', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Timestamp'), + ), + migrations.AlterField( + model_name='odpoveducastnika', + name='odpoved', + field=models.TextField(verbose_name='Tajenka bez diakritiky'), + ), + ] diff --git a/sifrovacka/models.py b/sifrovacka/models.py index 0e2dc78e..05dd6e4c 100644 --- a/sifrovacka/models.py +++ b/sifrovacka/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.utils import timezone from seminar.models.personalni import Resitel @@ -7,9 +8,13 @@ from seminar.models.personalni import Resitel class OdpovedUcastnika(models.Model): + class Meta: + ordering = ["-timestamp"] + resitel = models.ForeignKey(Resitel, blank=False, null=False, on_delete=models.CASCADE) - odpoved = models.TextField("Tajenka", blank=False, null=False,) + odpoved = models.TextField("Tajenka bez diakritiky", blank=False, null=False,) sifra = models.IntegerField("Číslo šifry", blank=False, null=False,) + timestamp = models.DateTimeField("Timestamp", blank=False, null=False, default=timezone.now) class SpravnaOdpoved(models.Model): diff --git a/sifrovacka/templates/sifrovacka/odpovedi_list.html b/sifrovacka/templates/sifrovacka/odpovedi_list.html index 8e122558..cc52a584 100644 --- a/sifrovacka/templates/sifrovacka/odpovedi_list.html +++ b/sifrovacka/templates/sifrovacka/odpovedi_list.html @@ -6,6 +6,7 @@ + @@ -13,6 +14,7 @@ {% for u in object_list %} + From 04e2007c3a76ff36882b2835dc5a3ed3e423fec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Sun, 15 Oct 2023 19:55:23 +0200 Subject: [PATCH 40/54] =?UTF-8?q?(sifrovacka)=20M=C3=A9n=C4=9B=20=C5=99?= =?UTF-8?q?=C3=A1dk=C5=AF=20v=20tajence=20v=20=C3=BA=C4=8Dastnick=C3=A9m?= =?UTF-8?q?=20formul=C3=A1=C5=99i=20(bez=20diakritiky=20bylo=20p=C5=99id?= =?UTF-8?q?=C3=A1no=20u=C5=BE=20v=20p=C5=99edchoz=C3=ADm=20commitu)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sifrovacka/forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sifrovacka/forms.py b/sifrovacka/forms.py index 06edaba6..e3eba7c7 100644 --- a/sifrovacka/forms.py +++ b/sifrovacka/forms.py @@ -1,5 +1,5 @@ from django.core.exceptions import ValidationError -from django.forms import ModelForm +from django.forms import ModelForm, Textarea from .models import OdpovedUcastnika, SpravnaOdpoved @@ -7,6 +7,9 @@ class SifrovackaForm(ModelForm): class Meta: model = OdpovedUcastnika fields = ["sifra", "odpoved", ] + widgets = { + "odpoved": Textarea(attrs={'rows': 1, 'cols': 30}), + } def clean_sifra(self): sifra = self.cleaned_data.get('sifra') From e58956484070109442a97c40f80ab17f20efd900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 16 Oct 2023 19:55:37 +0200 Subject: [PATCH 41/54] =?UTF-8?q?(sifrovacka)=20odli=C5=A1en=C3=AD=20p?= =?UTF-8?q?=C5=99ijmut=C3=BDch=20a=20nep=C5=99ijmut=C3=BDch=20odpov=C4=9Bd?= =?UTF-8?q?=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0003_odpoveducastnika_uspech.py | 18 ++++++++++++++++++ sifrovacka/models.py | 1 + .../templates/sifrovacka/odpovedi_list.html | 2 +- sifrovacka/views.py | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 sifrovacka/migrations/0003_odpoveducastnika_uspech.py diff --git a/sifrovacka/migrations/0003_odpoveducastnika_uspech.py b/sifrovacka/migrations/0003_odpoveducastnika_uspech.py new file mode 100644 index 00000000..1d61dd8c --- /dev/null +++ b/sifrovacka/migrations/0003_odpoveducastnika_uspech.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.22 on 2023-10-16 17:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sifrovacka', '0002_auto_20231015_1944'), + ] + + operations = [ + migrations.AddField( + model_name='odpoveducastnika', + name='uspech', + field=models.BooleanField(default=False, verbose_name='Úspěch'), + ), + ] diff --git a/sifrovacka/models.py b/sifrovacka/models.py index 05dd6e4c..26c6c008 100644 --- a/sifrovacka/models.py +++ b/sifrovacka/models.py @@ -15,6 +15,7 @@ class OdpovedUcastnika(models.Model): odpoved = models.TextField("Tajenka bez diakritiky", blank=False, null=False,) sifra = models.IntegerField("Číslo šifry", blank=False, null=False,) timestamp = models.DateTimeField("Timestamp", blank=False, null=False, default=timezone.now) + uspech = models.BooleanField("Úspěch", blank=False, null=False, default=False) class SpravnaOdpoved(models.Model): diff --git a/sifrovacka/templates/sifrovacka/odpovedi_list.html b/sifrovacka/templates/sifrovacka/odpovedi_list.html index cc52a584..0024a7c1 100644 --- a/sifrovacka/templates/sifrovacka/odpovedi_list.html +++ b/sifrovacka/templates/sifrovacka/odpovedi_list.html @@ -17,7 +17,7 @@ - + {% endfor %}
Timestamp Řešitel Šifra Odpověď
{{ u.timestamp }} {{ u.resitel }} {{ u.sifra }} {{ u.odpoved }}{{ u.timestamp }} {{ u.resitel }} {{ u.sifra }}{{ u.odpoved }}{{ u.odpoved }}
diff --git a/sifrovacka/views.py b/sifrovacka/views.py index 91100e53..9c4af3ed 100644 --- a/sifrovacka/views.py +++ b/sifrovacka/views.py @@ -22,6 +22,9 @@ class SifrovackaView(FormView): if sifra is None: return formularOKView(self.request, f'

Bohužel vám hvězdy nebyly nakloněny. Rozumějte máte to blbě.

Zkusit znovu.




') + instance.uspech = True + instance.save() + return formularOKView(self.request, f'

{sifra.skryty_text}

Odevzdat další.




') From 29b5361545415a3a7ddceff911994f4c3c811cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 16 Oct 2023 20:01:41 +0200 Subject: [PATCH 42/54] =?UTF-8?q?(sifrovacka)=20stringifikace=20spr=C3=A1v?= =?UTF-8?q?n=C3=BDch=20odpov=C4=9Bd=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sifrovacka/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sifrovacka/models.py b/sifrovacka/models.py index 26c6c008..6517c2e0 100644 --- a/sifrovacka/models.py +++ b/sifrovacka/models.py @@ -22,3 +22,6 @@ class SpravnaOdpoved(models.Model): odpoved = models.TextField(blank=False, null=False,) sifra = models.IntegerField(blank=False, null=False,) skryty_text = models.TextField(blank=False, null=False,) + + def __str__(self): + return f"{self.sifra}: {self.odpoved}" From 93cfa504a8ba5542a157b3d9aeb4c81dea06d977 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Sun, 22 Oct 2023 15:21:24 +0200 Subject: [PATCH 43/54] =?UTF-8?q?Nepadat=20pro=20hodn=C4=9B=20nevalidn?= =?UTF-8?q?=C3=AD=20CSRF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Když to nemá referer, tak je to hodně divné, ale mail o tom nechci. --- various/templates/various/403_csrf.html | 2 +- various/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/various/templates/various/403_csrf.html b/various/templates/various/403_csrf.html index ff2f0cf9..0d55fb96 100644 --- a/various/templates/various/403_csrf.html +++ b/various/templates/various/403_csrf.html @@ -8,7 +8,7 @@

{% block nadpis1a %}O-jo-jo-jo-joj{% endblock nadpis1a %}

- Problém se sušenkami či něčím podobným. Zkuste to prosím znovu: {{ url }}. Případně můžete přejít na titulní stránku. + Problém se sušenkami či něčím podobným. Zkuste {% if url %}to prosím znovu: {{ url }}. Případně {% endif %}můžete přejít na titulní stránku.

Pokud problém přetrvává obraťte se na nás přes e-mail: mailto:mam@matfyz.cz a pošlete nám následující popis chyby: {{ reason }}

diff --git a/various/views.py b/various/views.py index c6e46ab8..96d9a29d 100644 --- a/various/views.py +++ b/various/views.py @@ -8,6 +8,6 @@ def csrf_error(request, reason=""): """ Jednoduchý „template view“ (třída to být nemůže) pro CSRF chyby """ return render( request, 'various/403_csrf.html', - {"url": request.META["HTTP_REFERER"], "reason": reason}, + {"url": request.META.get("HTTP_REFERER", None), "reason": reason}, status=HttpResponseForbidden.status_code, ) From e9782c73e4040bae8a0e5cdd804e162533eaa846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 24 Oct 2023 13:16:48 +0200 Subject: [PATCH 44/54] =?UTF-8?q?V=20p=C5=99edchoz=C3=ADm=20commitu=20bylo?= =?UTF-8?q?=20=C5=A1patn=C4=9B=20trefen=C3=A9=20{%=20endif=20%}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- various/templates/various/403_csrf.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/various/templates/various/403_csrf.html b/various/templates/various/403_csrf.html index 0d55fb96..d0082550 100644 --- a/various/templates/various/403_csrf.html +++ b/various/templates/various/403_csrf.html @@ -8,7 +8,7 @@

{% block nadpis1a %}O-jo-jo-jo-joj{% endblock nadpis1a %}

- Problém se sušenkami či něčím podobným. Zkuste {% if url %}to prosím znovu: {{ url }}. Případně {% endif %}můžete přejít na titulní stránku. + Problém se sušenkami či něčím podobným. Zkuste {% if url %}to prosím znovu: {{ url }}. Případně můžete {% endif %}přejít na titulní stránku.

Pokud problém přetrvává obraťte se na nás přes e-mail: mailto:mam@matfyz.cz a pošlete nám následující popis chyby: {{ reason }}

From 668546c7205b4e9316fa586d2158038e23e82e57 Mon Sep 17 00:00:00 2001 From: "Pavel \"LEdoian\" Turinsky" Date: Mon, 30 Oct 2023 22:19:50 +0100 Subject: [PATCH 45/54] Fix testu --- personalni/tests.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/personalni/tests.py b/personalni/tests.py index 6f00cd1e..31aac8e8 100644 --- a/personalni/tests.py +++ b/personalni/tests.py @@ -39,16 +39,17 @@ class DelaniOrguTest(TestCase): self.assertNotIn(self.org_group, self.nova_osoba.user.groups.all()) self.assertFalse(self.nova_osoba.user.has_perm('auth.org')) self.assertFalse(self.nova_osoba.user.is_staff) - breakpoint # Pak orga uděláme… qs = m.Osoba.objects.filter(id=self.nova_osoba.id) self.admin.udelej_orgem(self.request, qs) # A pak už to org má být. - logger.info(f'Nová osoba je staff: {self.nova_osoba.user.is_staff}') + self.nova_osoba.refresh_from_db() self.assertTrue(self.nova_osoba.user.is_staff) - self.assertTrue(self.nova_osoba.user.has_perm('auth.org')) + # FIXME: V db nejsou práva. Nový org je sice ve skupině "org", ale ta nemá právo "auth.org" + # Očekávané řešení: dodat fixture, která to přidá. + #self.assertTrue(self.nova_osoba.user.has_perm('auth.org')) self.assertIn(self.org_group, self.nova_osoba.user.groups.all()) self.assertTrue(m.Organizator.objects.filter(osoba=self.nova_osoba).exists()) novy_org = m.Organizator.objects.get(osoba=self.nova_osoba) From f457520d7da9185122f366e8942bbea27a28f4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 30 Oct 2023 23:33:13 +0100 Subject: [PATCH 46/54] =?UTF-8?q?Takhle=20u=C5=BE=20by=20=C5=A1lo=20pustit?= =?UTF-8?q?=20(ugettext->gettext,=20force=5Ftext->force=5Fstr)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aesop/ovvpfile.py | 4 ++-- aesop/utils.py | 4 ++-- aesop/views.py | 2 +- galerie/models.py | 1 - korektury/models.py | 1 - korektury/views.py | 1 - prednasky/models.py | 1 - requirements.txt | 2 +- seminar/views/views_all.py | 2 +- 9 files changed, 7 insertions(+), 11 deletions(-) diff --git a/aesop/ovvpfile.py b/aesop/ovvpfile.py index 4d58af35..ba0873f1 100644 --- a/aesop/ovvpfile.py +++ b/aesop/ovvpfile.py @@ -1,5 +1,5 @@ from django.http import HttpResponse -from django.utils.encoding import force_text +from django.utils.encoding import force_str class OvvpFile: @@ -20,7 +20,7 @@ class OvvpFile: yield '\t'.join(self.columns) + '\n' # rows for r in self.rows: - yield '\t'.join([force_text(r[c]) for c in self.columns]) + '\n' + yield '\t'.join([force_str(r[c]) for c in self.columns]) + '\n' def to_string(self): return ''.join(self.to_lines()) diff --git a/aesop/utils.py b/aesop/utils.py index 3ea62dce..58b170ec 100644 --- a/aesop/utils.py +++ b/aesop/utils.py @@ -1,6 +1,6 @@ import datetime -from django.utils.encoding import force_text +from django.utils.encoding import force_str from aesop.ovvpfile import OvvpFile @@ -9,7 +9,7 @@ def default_ovvpfile(event, rocnik): of = OvvpFile() of.headers['version'] = '1' of.headers['event'] = event - of.headers['year'] = force_text(rocnik.prvni_rok) + of.headers['year'] = force_str(rocnik.prvni_rok) of.headers['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") of.headers['id-scope'] = 'mam' of.headers['id-generation'] = '1' diff --git a/aesop/views.py b/aesop/views.py index 4d1748b7..e4b3364b 100644 --- a/aesop/views.py +++ b/aesop/views.py @@ -8,7 +8,7 @@ from django.shortcuts import get_object_or_404 from django.http import HttpResponse from django.urls import reverse from django.views import generic -from django.utils.encoding import force_text +from django.utils.encoding import force_str from .utils import default_ovvpfile from seminar.models import Rocnik, Soustredeni diff --git a/galerie/models.py b/galerie/models.py index 8e6efdc7..78551969 100644 --- a/galerie/models.py +++ b/galerie/models.py @@ -2,7 +2,6 @@ from django.db import models #from django.db.models import Q -from django.utils.encoding import force_text from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFit, Transpose diff --git a/korektury/models.py b/korektury/models.py index 8906c00c..c9d47dfa 100644 --- a/korektury/models.py +++ b/korektury/models.py @@ -16,7 +16,6 @@ import os from django.db import models from django.utils import timezone from django.conf import settings -from django.utils.encoding import force_text from django.core.exceptions import ObjectDoesNotExist from django.utils.functional import cached_property from django.utils.text import get_valid_filename diff --git a/korektury/views.py b/korektury/views.py index 564e1331..1bdfaa92 100644 --- a/korektury/views.py +++ b/korektury/views.py @@ -5,7 +5,6 @@ třídy většinou rozšiřující nějakou třídu z :mod:`django.views.generic """ from django.shortcuts import get_object_or_404, render from django.views import generic -from django.utils.translation import ugettext as _ from django.conf import settings from django.http import HttpResponseForbidden from django.core.mail import EmailMessage diff --git a/prednasky/models.py b/prednasky/models.py index 50c71984..dcf44cbc 100644 --- a/prednasky/models.py +++ b/prednasky/models.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from django.db import models -from django.utils.encoding import force_text from seminar.models import Organizator, Soustredeni diff --git a/requirements.txt b/requirements.txt index d51645de..53c528ab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ Unidecode # Django and modules -Django<3.3 +Django<5.0 #django-bootstrap-sass django-mptt django-reversion diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 8e71fed3..318eee21 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -3,7 +3,7 @@ from django.http import HttpResponse from django.urls import reverse from django.core.exceptions import ObjectDoesNotExist from django.views import generic -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.http import Http404 from django.db.models import Q, Sum, Count from django.views.generic.base import RedirectView From 6fe9beb0f0df44a8692c916e6c6732e285c0d2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 31 Oct 2023 21:20:48 +0100 Subject: [PATCH 47/54] =?UTF-8?q?Deprecated=20v=C4=9Bci?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/settings_common.py | 1 - seminar/migrations/0006_problem_add_timestamp.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 71bae132..d6ed2852 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -28,7 +28,6 @@ APPEND_SLASH = True LANGUAGE_CODE = 'cs' TIME_ZONE = 'Europe/Prague' USE_I18N = True -USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) diff --git a/seminar/migrations/0006_problem_add_timestamp.py b/seminar/migrations/0006_problem_add_timestamp.py index 3df8bfdb..fd1509de 100644 --- a/seminar/migrations/0006_problem_add_timestamp.py +++ b/seminar/migrations/0006_problem_add_timestamp.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals from django.db import models, migrations import datetime -from django.utils.timezone import utc class Migration(migrations.Migration): @@ -16,7 +15,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='problem', name='timestamp', - field=models.DateTimeField(default=datetime.datetime(2015, 5, 15, 8, 54, 56, 319985, tzinfo=utc), verbose_name='vytvo\u0159eno', auto_now=True), + field=models.DateTimeField(default=datetime.datetime(2015, 5, 15, 8, 54, 56, 319985, tzinfo=datetime.timezone.utc), verbose_name='vytvo\u0159eno', auto_now=True), preserve_default=False, ), migrations.AlterField( From b456b8c86168332758ad1424c307043e30f72bc7 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Mon, 13 Nov 2023 20:58:39 +0100 Subject: [PATCH 48/54] =?UTF-8?q?Neodkazovat=20z=20archivu=20na=20v=C3=BDs?= =?UTF-8?q?ledkovku,=20kdy=C5=BE=20tam=20nen=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templates/seminar/archiv/cisla.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/seminar/templates/seminar/archiv/cisla.html b/seminar/templates/seminar/archiv/cisla.html index ce3b3dba..fe6f7977 100644 --- a/seminar/templates/seminar/archiv/cisla.html +++ b/seminar/templates/seminar/archiv/cisla.html @@ -40,7 +40,9 @@ {% endif %} {% endfor %} - Výsledková listina + {% if rocnik.verejne_vysledkovky_cisla %} {# Tohle jsem asi neměl tady použít, ale šlo to… #} + Výsledková listina + {% endif %} From a9a426ca916b0f0e2d016709ea8ded74baa6c6c0 Mon Sep 17 00:00:00 2001 From: Pavel 'LEdoian' Turinsky Date: Mon, 13 Nov 2023 20:59:06 +0100 Subject: [PATCH 49/54] =?UTF-8?q?Odkaz=20na=20v=C3=BDsledkovku=20a=20ne=20?= =?UTF-8?q?na=20horn=C3=AD=20=C4=8D=C3=A1st=20str=C3=A1nky?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templates/seminar/archiv/cisla.html | 2 +- seminar/templates/seminar/archiv/rocnik.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/seminar/templates/seminar/archiv/cisla.html b/seminar/templates/seminar/archiv/cisla.html index fe6f7977..830e37b4 100644 --- a/seminar/templates/seminar/archiv/cisla.html +++ b/seminar/templates/seminar/archiv/cisla.html @@ -41,7 +41,7 @@ {% endfor %} {% if rocnik.verejne_vysledkovky_cisla %} {# Tohle jsem asi neměl tady použít, ale šlo to… #} - Výsledková listina + Výsledková listina {% endif %} diff --git a/seminar/templates/seminar/archiv/rocnik.html b/seminar/templates/seminar/archiv/rocnik.html index 410b9361..66336086 100644 --- a/seminar/templates/seminar/archiv/rocnik.html +++ b/seminar/templates/seminar/archiv/rocnik.html @@ -113,7 +113,7 @@ {% if vysledkovka.radky_vysledkovky %} -

Výsledková listina

+

Výsledková listina

{% include "vysledkovky/vysledkovka_rocnik.html" %} {% endif %} From 37437b9674b744f37da392b7a426596330ff1cde Mon Sep 17 00:00:00 2001 From: MaM Web user Date: Mon, 20 Nov 2023 21:46:42 +0100 Subject: [PATCH 50/54] =?UTF-8?q?Jid=C3=A1=C5=A1:=20oprava=20pad=C3=A1n?= =?UTF-8?q?=C3=AD=20sphinxu=20(dokumentace)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/settings_prod.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mamweb/settings_prod.py b/mamweb/settings_prod.py index ebe827e4..060ba870 100644 --- a/mamweb/settings_prod.py +++ b/mamweb/settings_prod.py @@ -20,7 +20,9 @@ INSTALLED_APPS += ( ) # SECURITY WARNING: keep the secret key used in production secret! -assert not SECRET_KEY.startswith('12345') +# `'DOCUTILSCONFIG' in os.environ` kvůli sphinxu +# FIXME zjistit, zda je bezpečné a zda se to nedá udělat lépe +assert 'DOCUTILSCONFIG' in os.environ or not SECRET_KEY.startswith('12345') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False From 7a4213a61e8222a9a7ff2541177b7cc0d3a71b26 Mon Sep 17 00:00:00 2001 From: MaM Web user Date: Mon, 20 Nov 2023 22:06:42 +0100 Subject: [PATCH 51/54] =?UTF-8?q?Jid=C3=A1=C5=A1:=20django=20chce=20migrac?= =?UTF-8?q?i=20related=5Fname=20=20->=20,=20tak=20ji=20dostane?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...django_chce_migraci_tak_dostane_migraci.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 seminar/migrations/0114_related_name_se_zmenilo_a_django_chce_migraci_tak_dostane_migraci.py diff --git a/seminar/migrations/0114_related_name_se_zmenilo_a_django_chce_migraci_tak_dostane_migraci.py b/seminar/migrations/0114_related_name_se_zmenilo_a_django_chce_migraci_tak_dostane_migraci.py new file mode 100644 index 00000000..fccc850c --- /dev/null +++ b/seminar/migrations/0114_related_name_se_zmenilo_a_django_chce_migraci_tak_dostane_migraci.py @@ -0,0 +1,40 @@ +# Generated by Django 4.2.7 on 2023-11-20 21:02 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('seminar', '0113_resitel_zasilat_cislo_papirove'), + ] + + operations = [ + migrations.AlterField( + model_name='problem', + name='autor', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='autor_problemu_%(class)s', to='seminar.organizator', verbose_name='autor problému'), + ), + migrations.AlterField( + model_name='problem', + name='garant', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='garant_problemu_%(class)s', to='seminar.organizator', verbose_name='garant zadaného problému'), + ), + migrations.AlterField( + model_name='problem', + name='opravovatele', + field=models.ManyToManyField(blank=True, related_name='opravovatele_%(class)s', to='seminar.organizator', verbose_name='opravovatelé'), + ), + migrations.AlterField( + model_name='problem', + name='polymorphic_ctype', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='treenode', + name='polymorphic_ctype', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'), + ), + ] From c55fbb9dca53c392a9808edceb21a0c6079f1679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Wed, 22 Nov 2023 13:42:15 +0100 Subject: [PATCH 52/54] =?UTF-8?q?WTF=20(fix=20admin=20soust=C5=99ed=C4=9Bn?= =?UTF-8?q?=C3=AD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- soustredeni/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soustredeni/admin.py b/soustredeni/admin.py index 091f9c59..c6f048db 100644 --- a/soustredeni/admin.py +++ b/soustredeni/admin.py @@ -25,7 +25,7 @@ class SoustredeniOrganizatoriInline(admin.TabularInline): extra = 1 fields = ['organizator','poznamka'] autocomplete_fields = ['organizator'] - ordering = ['organizator__osoba__jmeno','organizator__prijmeni'] + ordering = ['organizator__osoba__jmeno','organizator__osoba__prijmeni'] formfield_overrides = { models.TextField: {'widget': widgets.TextInput} } From 0fbfb1e3cd9e14dd715b5d73409bdfe62a7ab382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 4 Dec 2023 10:51:28 +0100 Subject: [PATCH 53/54] =?UTF-8?q?Fix=20=E2=80=9Eget=5Fapp=5Flist()=20takes?= =?UTF-8?q?=202=20positional=20arguments=20but=203=20were=20given=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mamweb/admin.py b/mamweb/admin.py index b6924468..5d0351df 100644 --- a/mamweb/admin.py +++ b/mamweb/admin.py @@ -35,13 +35,13 @@ locale.setlocale(locale.LC_COLLATE, 'cs_CZ.UTF-8') # https://books.agiliq.com/projects/django-admin-cookbook/en/latest/set_ordering.html # FIXME zpraseno pomocí toho, že Python umí bez problému přepisovat funkce -def get_app_list(self, request): +def get_app_list(self, request, app_label=None): """ Return a sorted list of all the installed apps that have been registered in this site. """ - app_dict = self._build_app_dict(request) + app_dict = self._build_app_dict(request, label=app_label) # Sort the apps alphabetically. app_list = sorted(app_dict.values(), key=lambda x: locale.strxfrm('!') if (x['name'] == "Seminar") else locale.strxfrm(x['name'].lower())) From ffa0c682f425427a275556c11386a3c500580780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 11 Dec 2023 20:16:04 +0100 Subject: [PATCH 54/54] =?UTF-8?q?Pokus=20o=20=C5=99e=C5=A1en=C3=AD=20probl?= =?UTF-8?q?=C3=A9m=C5=AF=20s=20v=C3=BDsledkovkou=20posledn=C3=ADho=20?= =?UTF-8?q?=C4=8D=C3=ADsla?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/templates/seminar/archiv/cislo.html | 6 ++++-- seminar/templates/seminar/archiv/rocnik.html | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/seminar/templates/seminar/archiv/cislo.html b/seminar/templates/seminar/archiv/cislo.html index b8edce90..fa34e965 100644 --- a/seminar/templates/seminar/archiv/cislo.html +++ b/seminar/templates/seminar/archiv/cislo.html @@ -38,9 +38,11 @@

Orgovské odkazy

{% endif %} diff --git a/seminar/templates/seminar/archiv/rocnik.html b/seminar/templates/seminar/archiv/rocnik.html index 66336086..fd2a99b6 100644 --- a/seminar/templates/seminar/archiv/rocnik.html +++ b/seminar/templates/seminar/archiv/rocnik.html @@ -120,8 +120,7 @@ {% if user.je_org %}