Vítejte na stránce semináře MaM!
") - print(s) - f.sites.add(s[0]) - f.save() - - # users - admin = User.objects.create_superuser(username='admin', email='', password='admin') - os_admin = Osoba.objects.create( - user=admin, jmeno='admin', prijmeni='admin', - prezdivka='admin', osloveni='', email='admin@admin.admin', - telefon='123 456 789', datum_narozeni=datetime.date(2000, 1, 1), - ulice='admin', mesto='admin', psc='100 00', - datum_registrace=datetime.date(2020, 9, 6) - ) - or_admin = Organizator.objects.create( - osoba=os_admin, organizuje_od=None, organizuje_do=None, - strucny_popis_organizatora="Organizátor k uživateli Admin" - ) - - usernames = ['anet', 'bara', 'cyril', 'david', 'eva', 'filip'] - users = [] - for usr in usernames[:size]: - u = User.objects.create_user(username=usr, password=usr) - u.first_name = usr.capitalize() - u.save() - users.append(u) - print(users) - - # skoly - skoly = gen_skoly() - - # osoby - osoby = gen_osoby(rnd, size) - - # resitele a organizatori - last_rocnik = 25 - organizatori = gen_organizatori(rnd, osoby, last_rocnik) - resitele = gen_resitele(rnd, osoby, skoly) - - #generování novinek - novinky = gen_novinky(rnd, organizatori) - - # prijemci - prijemci = gen_prijemci(rnd, osoby) - - global zlinska - zlinska.kontaktni_osoba=rnd.choice(osoby) - zlinska.save() - - # rocniky - rocniky = gen_rocniky(last_rocnik, size) - - # cisla - # rocnik_cisla je pole polí čísel (typ Cislo), vnitřní pole odpovídají jednotlivým ročníkům. - rocnik_cisla = gen_cisla(rnd, rocniky) - - # generování obyčejných úloh do čísel - gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size) - - # generování témat, zatím v prvních třech číslech po jednom - # FIXME: více témat - # rocnik_temata je pole polí trojic (první číslo :int, poslední číslo :int, téma:Tema), přičemž každé vnitřní pole odpovídá ročníku a FIXME: je to takhle fuj a když to někdo vidí poprvé, tak je z toho smutný, protože vůbec neví, co se děje a co má čekat. - rocnik_temata = gen_temata(rnd, rocniky, rocnik_cisla, organizatori) - - rocnik = Rocnik.objects.filter(rocnik = 23).first() - dlouhe_tema = gen_dlouhe_tema(rnd, organizatori, rocnik, "Strašně dlouhé téma", - "MFI", 8) - - # generování úloh k tématům ve všech číslech - gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori, resitele) - - #generování soustředění - soustredeni = gen_soustredeni(rnd, resitele, organizatori) - - #generování konfer - konfery = gen_konfery(size, rnd, organizatori, resitele, soustredeni) - - # vytvoreni pdf ke korekturam - create_test_pdf(rnd, organizatori) - - # TODO: nastavi správně, kolik se čeho generuje, aby rozsahy přibližně odpovídaly - # FIXME: misto typu ruzne typy objektu a vnoreni do sebe (Tom nechápe, co je tímto fixme míněno) - # TODO: vytvorit temata s ruznymi vlakny - # TODO: nagenerovat starsim rocnikum pohadku - # TODO: nagenerovat články - # TODO: vecpat obrázky všude, kde to jde - # TODO: mezičíslo node - # TODO: přidat ke konferám řešení a dát je do čísel - - # Dohackované vytvoření jednoho článku - gen_clanek(rnd, organizatori, resitele) - - # TODO: přidat články včetně zařazení do struktury treenodů, - # a následně otestovat konsistency check databáze z utils.py - # pomocí stránky /stav - - # obecné nastavení semináře, musí být už přidané ročníky a čísla, jinak se nastaví divně - nastaveni = Nastaveni.objects.create( - aktualni_cislo = Cislo.objects.all()[1]) diff --git a/seminar/utils.py b/seminar/utils.py deleted file mode 100644 index c826bf0b..00000000 --- a/seminar/utils.py +++ /dev/null @@ -1,387 +0,0 @@ -import datetime -import decimal - -from django.contrib.auth import get_user_model -from django.contrib.auth.decorators import permission_required, \ - user_passes_test -from django import views as DjangoViews - -from django.db import transaction - -from django.contrib.auth.models import AnonymousUser -from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist - -import logging - -import seminar.models as m -import treenode.treelib as t - -logger = logging.getLogger(__name__) - -org_required = permission_required('auth.org') -resitel_required = permission_required('auth.resitel') - - -# inspirováno django.contrib.auth.decorators permission_required -def check_perms(user): - if user.has_perms(('auth.resitel',)): - return True - if user.has_perms(('auth.org',)): - return True - return False - - -resitel_or_org_required = user_passes_test(check_perms) - -User = get_user_model() -# Není to úplně hezké, ale budeme doufat, že to je funkční... -User.je_org = property(lambda self: self.has_perm('auth.org')) -User.je_resitel = property(lambda self: self.has_perm('auth.resitel')) -AnonymousUser.je_org = False -AnonymousUser.je_resitel = False - - -def vzorecek_na_prepocet(body, resitelu): - """ Vzoreček na přepočet plných bodů na parciálni, když má řešení více řešitelů. """ - return body * 3 / (resitelu + 2) - - -def inverze_vzorecku_na_prepocet(body: decimal.Decimal, resitelu) -> decimal.Decimal: - """ Vzoreček na přepočet parciálních bodů na plné, když má řešení více řešitelů. """ - return round(body * (resitelu + 2) / 3, 1) - - -def histogram(seznam): - d = {} - for i in seznam: - if i not in d: - d[i] = 0 - d[i] += 1 - return d - -# Pozor: zarovnáno velmi netradičně pro přehlednost -roman_numerals = zip((1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1), - ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I')) - - -def roman(num): - res = "" - for i, n in roman_numerals: - res += n * (num // i) - num %= i - return res - - -def from_roman(rom): - if not rom: - return 0 - for i, n in roman_numerals: - if rom.upper().startswith(n): - return i + from_roman(rom[len(n):]) - raise Exception('Invalid roman numeral: "%s"', rom) - - -def seznam_problemu(): - """Funkce pro hledání nekonzistencí v databázi a dalších nežádoucích stavů webu/databáze. - - Nijak nesouvisí s Problémy zadanými řešitelům.""" - # FIXME: přejmenovat funkci? - # FIXME: Tak, jak je napsaná, asi spíš patří někam k views a ne do utils (?) - problemy = [] - - # Pomocna fce k formatovani problemovych hlasek - def prb(cls, msg, objs=None): - s = '%s: %s' % (cls.__name__, msg) - if objs: - s += ' [' - for o in objs: - try: - url = o.admin_url() - except: - url = None - if url: - s += '%s, ' % (url, o.pk,) - else: - s += '%s, ' % (o.pk,) - s = s[:-2] + ']' - problemy.append(s) - - # Duplicita jmen - jmena = {} - for r in m.Resitel.objects.all(): - j = r.osoba.plne_jmeno() - if j not in jmena: - jmena[j] = [] - jmena[j].append(r) - for j in jmena: - if len(jmena[j]) > 1: - prb(m.Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j]) - - # Data maturity a narození - for r in m.Resitel.objects.all(): - if not r.rok_maturity: - prb(m.Resitel, 'Neznámý rok maturity', [r]) - if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): - prb(m.Resitel, 'Podezřelé datum maturity', [r]) - if r.osoba.datum_narozeni and ( - r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12): - prb(m.Resitel, 'Podezřelé datum narození', [r]) -# if not r.email: -# prb(Resitel, u'Neznámý email', [r]) - - ## Kontroly konzistence databáze a TreeNodů - - # Články - for clanek in m.Clanek.objects.all(): - # získáme řešení svázané se článkem a z něj node ve stromě - reseni = clanek.reseni_set - if (reseni.count() != 1): - raise ValueError("Článek k sobě má nejedno řešení!") - r = reseni.first() - clanek_node = r.text_cely # vazba na ReseniNode z Reseni - # content type je věc pomáhající rozeznávat různé typy objektů v django-polymorphic - # protože isinstance vrátí vždy jen TreeNode - # https://django-polymorphic.readthedocs.io/en/stable/migrating.html - cislonode_ct = ContentType.objects.get_for_model(m.CisloNode) - node = clanek_node - while node is not None: - node_ct = node.polymorphic_ctype - if node_ct == cislonode_ct: # dostali jsme se k CisloNode - # zkontrolujeme, že stromové číslo odpovídá atributu - # .cislonode je opačná vazba k treenode_ptr, abychom z TreeNode dostali - # CisloNode - if clanek.cislo != node.cislonode.cislo: - prb(m.Clanek, "Číslo otištění uložené u článku nesedí s " - "číslem otištění podle struktury treenodů.", [clanek]) - break - node = t.get_parent(node) - - return problemy - - -### Generovani obalek -def resi_v_rocniku(rocnik, cislo=None): - """ Vrátí seznam řešitelů, co vyřešili nějaký problém v daném ročníku, do daného čísla. - Parametry: - rocnik (typu Rocnik) ročník, ze kterého chci řešitele, co něco odevzdali - cislo (typu Cislo) číslo, do kterého včetně se počítá, že v daném - ročníku řešitel něco poslal. - Pokud není zadané, počítají se všechna řešení z daného ročníku. - Výstup: - QuerySet objektů typu Resitel """ - - if cislo is None: - # filtrujeme pouze podle ročníku - return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(), - reseni__hodnoceni__deadline_body__cislo__rocnik=rocnik).distinct() - else: # filtrujeme podle ročníku i čísla - return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(), - reseni__hodnoceni__deadline_body__cislo__rocnik=rocnik, - reseni__hodnoceni__deadline_body__cislo__poradi__lte=cislo.poradi).distinct() - - -def aktivniResitele(cislo, pouze_letosni=False): - """ Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali - a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla). - Parametry: - cislo (typu Cislo) číslo, o které se jedná - pouze_letosni jen řešitelé, kteří tento rok něco poslali - - """ - letos = cislo.rocnik - - # detekujeme, zda jde o první tři čísla či nikoli (tj. zda spamovat řešitele z minulého roku) - zacatek_rocniku = True - try: - if int(cislo.poradi) > 3: - zacatek_rocniku = False - except ValueError: - # if cislo.poradi != '7-8': - # raise ValueError(f'{cislo} je neplatné číslo čísla (není int a není 7-8)') - zacatek_rocniku = False - - # nehledě na číslo chceme jen řešitele, kteří letos něco odevzdali - if pouze_letosni: - zacatek_rocniku = False - - try: - loni = m.Rocnik.objects.get(rocnik=letos.rocnik - 1) - except ObjectDoesNotExist: - # Pro první ročník neexistuje ročník předchozí - zacatek_rocniku = False - - if not zacatek_rocniku: - return resi_v_rocniku(letos, cislo).filter(rok_maturity__gte=letos.druhy_rok()) - else: - # spojíme querysety s řešiteli loni a letos do daného čísla - return (resi_v_rocniku(loni) | resi_v_rocniku(letos, cislo)).distinct().filter(rok_maturity__gte=letos.druhy_rok()) - -def viewMethodSwitch(get, post): - """ - Vrátí view, který zavolá různé jiné views podle toho, kterou metodou je zavolán. - - Inspirováno https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#an-alternative-better-solution, jen jsem to udělal genericky. - - Parametry: - post view pro metodu POST - get view pro metodu GET - - V obou případech se míní už view jakožto funkce, takže u class-based views se už má použít .as_view() - - TODO: Podpora i pro metodu HEAD? A možná i pro FILES? - """ - - theGetView = get - thePostView = post - - class NewView(DjangoViews.View): - def get(self, request, *args, **kwargs): - return theGetView(request, *args, **kwargs) - def post(self, request, *args, **kwargs): - return thePostView(request, *args, **kwargs) - - return NewView.as_view() - - -def sync_skoly(base_url): - """Stáhne všechny školy z mamwebu na adreseVítejte na stránce semináře MaM!
", + ) + print(s) + f.sites.add(s[0]) + f.save() + + # users + admin = User.objects.create_superuser( + username='admin', email='', password='admin', + ) + os_admin = Osoba.objects.create( + user=admin, jmeno='admin', prijmeni='admin', + prezdivka='admin', osloveni='', email='admin@admin.admin', + telefon='123 456 789', datum_narozeni=datetime.date(2000, 1, 1), + ulice='admin', mesto='admin', psc='100 00', + datum_registrace=datetime.date(2020, 9, 6), + ) + or_admin = Organizator.objects.create( + osoba=os_admin, organizuje_od=None, organizuje_do=None, + strucny_popis_organizatora="Organizátor k uživateli Admin", + ) + + usernames = ['anet', 'bara', 'cyril', 'david', 'eva', 'filip'] + users = [] + for usr in usernames[:size]: + u = User.objects.create_user(username=usr, password=usr) + u.first_name = usr.capitalize() + u.save() + users.append(u) + print(users) + + # skoly + skoly = gen_skoly() + + # osoby + osoby = gen_osoby(rnd, size) + + # resitele a organizatori + last_rocnik = 25 + organizatori = gen_organizatori(rnd, osoby, last_rocnik) + resitele = gen_resitele(rnd, osoby, skoly) + + # generování novinek + novinky = gen_novinky(rnd, organizatori) + + # prijemci + prijemci = gen_prijemci(rnd, osoby) + + # rocniky + rocniky = gen_rocniky(last_rocnik, size) + + # cisla + # rocnik_cisla je pole polí čísel (typ Cislo), vnitřní pole odpovídají jednotlivým ročníkům. + rocnik_cisla = gen_cisla(rnd, rocniky) + + # generování obyčejných úloh do čísel + gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size) + + # generování témat, zatím v prvních třech číslech po jednom + # FIXME: více témat + # rocnik_temata je pole polí trojic (první číslo :int, poslední číslo :int, téma:Tema), přičemž každé vnitřní pole odpovídá ročníku a FIXME: je to takhle fuj a když to někdo vidí poprvé, tak je z toho smutný, protože vůbec neví, co se děje a co má čekat. + rocnik_temata = gen_temata(rnd, rocniky, rocnik_cisla, organizatori) + + rocnik = Rocnik.objects.filter(rocnik=23).first() + dlouhe_tema = gen_dlouhe_tema( + rnd, organizatori, rocnik, "Strašně dlouhé téma", + "MFI", 8, + ) + + # generování úloh k tématům ve všech číslech + gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori, resitele) + + # generování soustředění + soustredeni = gen_soustredeni(size, resitele, organizatori, rnd=rnd) + + # generování konfer + konfery = gen_konfery(size, organizatori, soustredeni, rnd=rnd) + + # vytvoreni pdf ke korekturam + create_test_pdf(rnd, organizatori) + + # TODO: nastavi správně, kolik se čeho generuje, aby rozsahy přibližně odpovídaly + # FIXME: misto typu ruzne typy objektu a vnoreni do sebe (Tom nechápe, co je tímto fixme míněno) + # TODO: vytvorit temata s ruznymi vlakny + # TODO: nagenerovat starsim rocnikum pohadku + # TODO: nagenerovat články + # TODO: vecpat obrázky všude, kde to jde + # TODO: mezičíslo node + # TODO: přidat ke konferám řešení a dát je do čísel + + # Dohackované vytvoření jednoho článku + gen_clanek(rnd, organizatori, resitele) + + # TODO: přidat články včetně zařazení do struktury treenodů, + # a následně otestovat konsistency check databáze z utils.py + # pomocí stránky /stav + + # obecné nastavení semináře, musí být už přidané ročníky a čísla, jinak se nastaví divně + nastaveni = Nastaveni.objects.create( + aktualni_cislo=Cislo.objects.all()[1]) diff --git a/various/urls.py b/various/urls.py new file mode 100644 index 00000000..a3f03ade --- /dev/null +++ b/various/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from .views.final import TitulniStranaView, JakResitView, StavDatabazeView +from personalni.utils import org_required + +urlpatterns = [ + path('', TitulniStranaView.as_view(), name='titulni_strana'), + path('jak-resit/', JakResitView.as_view(), name='jak_resit'), + path('stav', org_required(StavDatabazeView), name='stav_databaze'), +] diff --git a/various/views/__init__.py b/various/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/various/views.py b/various/views/csrf.py similarity index 100% rename from various/views.py rename to various/views/csrf.py diff --git a/various/views/final.py b/various/views/final.py new file mode 100644 index 00000000..de23a718 --- /dev/null +++ b/various/views/final.py @@ -0,0 +1,160 @@ +""" +Stránky, které se mi nepovedlo lépe zařadit. + +Oproti `./pomocne.py` se tyto views používají přímo ve various +a naopak importují spoustu věcí odjinud +""" +import datetime + +from django.contrib.contenttypes.models import ContentType +from django.shortcuts import get_object_or_404, render +from django.utils import timezone +from django.views import generic + +import novinky.views +import treenode.treelib as t +import tvorba.views +from personalni.models import Resitel +from seminar import models as m + +from ..models import Nastaveni + + +class TitulniStranaView(generic.ListView): + template_name = 'various/titulnistrana/titulnistrana.html' + + def get_queryset(self): + return novinky.views.spravne_novinky(self.request)[:3] + + def get_context_data(self, **kwargs): + context = super(TitulniStranaView, self).get_context_data(**kwargs) + nastaveni = get_object_or_404(Nastaveni) + + deadline = m.Deadline.objects.filter( + deadline__gte=timezone.now()).order_by("deadline").first() + context['nejblizsi_deadline'] = deadline + + # Aktuální témata + nazvy_a_odkazy_na_aktualni_temata = [] + akt_temata = tvorba.views.aktualni_temata(nastaveni.aktualni_rocnik) + + for tema in akt_temata: + # FIXME: netuším, jestli funguje tema.verejne_url(), nemáme testdata na témátka - je to asi url vzhledem k ročníku + nazvy_a_odkazy_na_aktualni_temata.append({ + 'nazev': tema.nazev, + 'url': tema.verejne_url() + }) + + context['aktualni_temata'] = nazvy_a_odkazy_na_aktualni_temata + + return context + + +class JakResitView(generic.ListView): + template_name = 'various/jakresit/jak-resit.html' + + def get_queryset(self): + return None + + +### Status +def histogram(seznam): + d = {} + for i in seznam: + if i not in d: + d[i] = 0 + d[i] += 1 + return d + + +def seznam_problemu(): + """Funkce pro hledání nekonzistencí v databázi a dalších nežádoucích stavů webu/databáze. + + Nijak nesouvisí s Problémy zadanými řešitelům.""" + # FIXME: přejmenovat funkci? + problemy = [] + + # Pomocna fce k formatovani problemovych hlasek + def prb(cls, msg, objs=None): + s = '%s: %s' % (cls.__name__, msg) + if objs: + s += ' [' + for o in objs: + try: + url = o.admin_url() + except: + url = None + if url: + s += '%s, ' % (url, o.pk,) + else: + s += '%s, ' % (o.pk,) + s = s[:-2] + ']' + problemy.append(s) + + # Duplicita jmen + jmena = {} + for r in m.Resitel.objects.all(): + j = r.osoba.plne_jmeno() + if j not in jmena: + jmena[j] = [] + jmena[j].append(r) + for j in jmena: + if len(jmena[j]) > 1: + prb(m.Resitel, 'Duplicitní jméno "%s"' % (j,), jmena[j]) + + # Data maturity a narození + for r in m.Resitel.objects.all(): + if not r.rok_maturity: + prb(m.Resitel, 'Neznámý rok maturity', [r]) + if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): + prb(m.Resitel, 'Podezřelé datum maturity', [r]) + if r.osoba.datum_narozeni and ( + r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12): + prb(m.Resitel, 'Podezřelé datum narození', [r]) + # if not r.email: + # prb(Resitel, u'Neznámý email', [r]) + + ## Kontroly konzistence databáze a TreeNodů + + # Články + for clanek in m.Clanek.objects.all(): + # získáme řešení svázané se článkem a z něj node ve stromě + reseni = clanek.reseni_set + if (reseni.count() != 1): + raise ValueError("Článek k sobě má nejedno řešení!") + r = reseni.first() + clanek_node = r.text_cely # vazba na ReseniNode z Reseni + # content type je věc pomáhající rozeznávat různé typy objektů v django-polymorphic + # protože isinstance vrátí vždy jen TreeNode + # https://django-polymorphic.readthedocs.io/en/stable/migrating.html + cislonode_ct = ContentType.objects.get_for_model(m.CisloNode) + node = clanek_node + while node is not None: + node_ct = node.polymorphic_ctype + if node_ct == cislonode_ct: # dostali jsme se k CisloNode + # zkontrolujeme, že stromové číslo odpovídá atributu + # .cislonode je opačná vazba k treenode_ptr, abychom z TreeNode dostali + # CisloNode + if clanek.cislo != node.cislonode.cislo: + prb(m.Clanek, "Číslo otištění uložené u článku nesedí s " + "číslem otištění podle struktury treenodů.", [clanek]) + break + node = t.get_parent(node) + + return problemy + +def StavDatabazeView(request): + # nastaveni = Nastaveni.objects.get() + problemy = seznam_problemu() + muzi = Resitel.objects.filter(osoba__osloveni=m.Osoba.OSLOVENI_MUZSKE) + zeny = Resitel.objects.filter(osoba__osloveni=m.Osoba.OSLOVENI_ZENSKE) + return render(request, 'various/stav_databaze.html', { + # 'nastaveni': nastaveni, + 'problemy': problemy, + + 'resitele': Resitel.objects.all(), + 'muzi': muzi, + 'zeny': zeny, + 'jmena_muzu': histogram([r.osoba.jmeno for r in muzi]), + 'jmena_zen': histogram([r.osoba.jmeno for r in zeny]), + }) diff --git a/various/views/generic.py b/various/views/generic.py new file mode 100644 index 00000000..b18178fb --- /dev/null +++ b/various/views/generic.py @@ -0,0 +1,29 @@ +import django.views + + +def viewMethodSwitch(get, post): + """ + Vrátí view, který zavolá různé jiné views podle toho, kterou metodou je zavolán. + + Inspirováno https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#an-alternative-better-solution, jen jsem to udělal genericky. + + Parametry: + post view pro metodu POST + get view pro metodu GET + + V obou případech se míní už view jakožto funkce, takže u class-based views se už má použít .as_view() + + TODO: Podpora i pro metodu HEAD? A možná i pro FILES? + """ + + theGetView = get + thePostView = post + + class NewView(django.views.View): + def get(self, request, *args, **kwargs): + return theGetView(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + return thePostView(request, *args, **kwargs) + + return NewView.as_view() diff --git a/various/views/pomocne.py b/various/views/pomocne.py new file mode 100644 index 00000000..42547467 --- /dev/null +++ b/various/views/pomocne.py @@ -0,0 +1,26 @@ +""" +Stránky, které se mi nepovedlo lépe zařadit. + +Oproti `./final.py` se tyto views importují odjinud +tedy ideálně neimportovat sem nic od jinud +""" + +from typing import Sequence + +from django.shortcuts import render +from django.urls import reverse + + +# Interní, nemá se nikdy objevit v urls (jinak to účastníci vytrolí) +def formularOKView(request, text='', dalsi_odkazy: Sequence[tuple[str, str]] = ()): + template_name = 'seminar/formular_ok.html' + odkazy = list(dalsi_odkazy) + [ + # (Text, odkaz) + ('Vrátit se na titulní stránku', reverse('titulni_strana')), + ('Zobrazit aktuální zadání', reverse('seminar_aktualni_zadani')), + ] + context = { + 'odkazy': odkazy, + 'text': text, + } + return render(request, template_name, context) diff --git a/vyroci/urls.py b/vyroci/urls.py index 69132f45..44215a46 100644 --- a/vyroci/urls.py +++ b/vyroci/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from seminar.utils import org_required +from personalni.utils import org_required from .views import VyrociView, VyrociListView urlpatterns = [ diff --git a/vyroci/views.py b/vyroci/views.py index 207ed619..455d6e25 100644 --- a/vyroci/views.py +++ b/vyroci/views.py @@ -1,7 +1,7 @@ from django.views.generic import FormView, ListView from seminar.models import Osoba -from seminar.views import formularOKView +from various.views.pomocne import formularOKView from .forms import UcastnikVyrociForm from .models import UcastnikVyroci diff --git a/vysledkovky/utils.py b/vysledkovky/utils.py index 2036b9d3..7cd914f4 100644 --- a/vysledkovky/utils.py +++ b/vysledkovky/utils.py @@ -4,7 +4,7 @@ from typing import Union, Iterable # TODO: s pythonem 3.10 přepsat na '|' import seminar.models as m from django.db.models import Q, Sum -from seminar.utils import resi_v_rocniku +from tvorba.utils import resi_v_rocniku ROCNIK_ZRUSENI_TEMAT = 25