diff --git a/data/sitetree.json b/data/sitetree.json index 26c70ca3..b910e5be 100644 --- a/data/sitetree.json +++ b/data/sitetree.json @@ -695,13 +695,13 @@ "alias": null, "description": "", "hidden": false, - "hint": "", + "hint": "To, co ŘEŠITELÉ poslali", "inbreadcrumbs": true, "inmenu": true, "insitetree": true, "parent": 21, - "sort_order": 37, - "title": "Odevzdaná řešení", + "sort_order": 38, + "title": "Došlá řešení", "tree": 1, "url": "odevzdavatko_tabulka", "urlaspattern": true @@ -724,7 +724,7 @@ "inmenu": true, "insitetree": true, "parent": 21, - "sort_order": 38, + "sort_order": 42, "title": "Odhlásit se", "tree": 1, "url": "logout", @@ -806,5 +806,31 @@ }, "model": "sitetree.treeitem", "pk": 41 + }, + { + "fields": { + "access_guest": false, + "access_loggedin": false, + "access_perm_type": 1, + "access_permissions": [ + 2 + ], + "access_restricted": true, + "alias": null, + "description": "", + "hidden": false, + "hint": "To, co jsem JÁ odevzdal", + "inbreadcrumbs": true, + "inmenu": true, + "insitetree": true, + "parent": 21, + "sort_order": 37, + "title": "Odevzdaná řešení", + "tree": 1, + "url": "seminar_resitel_odevzdana_reseni", + "urlaspattern": true + }, + "model": "sitetree.treeitem", + "pk": 42 } ] \ No newline at end of file diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py index 75a5493c..925d5961 100644 --- a/mamweb/settings_common.py +++ b/mamweb/settings_common.py @@ -78,6 +78,7 @@ TEMPLATES = [ 'django.contrib.messages.context_processors.messages', 'sekizai.context_processors.sekizai', 'header_fotky.context_processors.vzhled', + 'various.context_processors.april', ) }, }, @@ -132,6 +133,7 @@ INSTALLED_APPS = ( 'korektury', 'prednasky', 'header_fotky', + 'various', # Admin upravy: diff --git a/mamweb/templates/base.html b/mamweb/templates/base.html index b79060b5..8f2b7a7d 100644 --- a/mamweb/templates/base.html +++ b/mamweb/templates/base.html @@ -131,6 +131,48 @@ $("a[rel^='gallery-image']").prettyPhoto(prettyparams); }); + {% if april == 2021 %} + + {% endif %} {% render_block "js" %} diff --git a/seminar/forms.py b/seminar/forms.py index 8f6950fa..7aaa78b4 100644 --- a/seminar/forms.py +++ b/seminar/forms.py @@ -142,6 +142,28 @@ class PrihlaskaForm(forms.Form): elif data.get('skola_adresa')=='': self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy')) +# Editační formulář bez řešitele. +class ProfileEditFormPoMaturite(forms.Form): + username = forms.CharField(label='Přihlašovací jméno', + max_length=256, + required=True) + + jmeno = forms.CharField(label='Jméno', max_length=256, required=True) + prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) + pohlavi_muz = forms.ChoiceField(label='Pohlaví', + choices = ((True,'muž'),(False,'žena')), required=True) + email = forms.EmailField(label='E-mail',max_length=256, required=True) + telefon = forms.CharField(widget=TelInput(),label='Telefon',max_length=256, required=False) + datum_narozeni = forms.DateField(widget=DateInput(),label='Datum narození', required=False) + ulice = forms.CharField(label='Ulice', max_length=256, required=False) + mesto = forms.CharField(label='Město', max_length=256, required=False) + psc = forms.CharField(label='PSČ', max_length=32, required=False) + stat = forms.ChoiceField(label='Stát', + choices = (('CZ', 'Česká Republika'), + ('SK', 'Slovenská Republika'), + ('other', 'Jiné')), + required=False) + stat_text = forms.CharField(label='Stát', max_length=256, required=False) class ProfileEditForm(forms.Form): username = forms.CharField(label='Přihlašovací jméno', @@ -181,7 +203,7 @@ class ProfileEditForm(forms.Form): rok_maturity = forms.IntegerField( label='Rok maturity', - min_value=date.today().year, + min_value=date.today().year, max_value=date.today().year+8, required=True) zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True) diff --git a/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py b/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py index f819f047..eb2d950f 100644 --- a/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py +++ b/seminar/migrations/0001_squashed_0067_auto_20190814_0805.py @@ -107,22 +107,50 @@ def spoj_k_organizatorum_osoby(apps, scema_editor): for org in Organizator.objects.all(): # Spárování organizátora s osobou + # Myšlenka: Když najdeme řešitele pro daného uživatele, tak se vezme Osoba příslušná uživateli, + # Pokud nenajdeme uživatele, tak ještě zkusíme dohledat Osobu podle e-mailu user = org.user - resitele = Resitel.objects.filter(user=user) - if resitele.count() != 0: - osoba = resitele.first().osoba - else: + if user is None: + logger.error(f'Org {org} nemá uživatele!') + # Je to podezřelé, ale prostě vyrobíme novou osobu. osoba = Osoba(user=user) - - # Přesun informací z usera do osoby - # pro řešitele již v minule migraci - osoba.jmeno = user.first_name - osoba.prijmeni = user.last_name - osoba.email = user.email - user.jmeno = "Použij osobu!" - user.prijmeni = "Použij osobu!" - user.email = "Použij osobu!" - user.save() + # Téhle osobě nejdou nastavit detaily, protože žádné nemáme. + else: + logger.info(f'Org {org.user.email}(ID: {org.id}) má uživatele {user}') + # 💢💢💢 Python nemá goto, ale prý má výjimky… 💢💢💢 + class EndException(Exception): pass + try: + # Hledáme podle uživatele + resitele = Resitel.objects.filter(user=user) + if resitele.count() != 0 and user is not None: + osoba = resitele.first().osoba + logger.info(f'Našel jsem řešitele {resitele.first().email} podle uživatele, používám jeho Osobu') + raise EndException + + # Hledáme podle e-mailu + osoby = Osoba.objects.filter(email__iexact=user.email) + if osoby.count() != 0 and user.email != '': + osoba = osoby.first() + if osoba.user is None: + osoba.user = user + logger.info(f'Našel jsem Osobu {osoby.first().email} podle e-mailu') + raise EndException + + # Fallback + logger.warning(f'Org neměl řešitele, zakládám novou Osobu.') + osoba = Osoba(user=user) + + # Přesun informací z usera do osoby + # pro osoby z řešitelů (jediné dosud existující osoby) již v minule migraci + osoba.jmeno = user.first_name + osoba.prijmeni = user.last_name + osoba.email = user.email + user.jmeno = "Použij osobu!" + user.prijmeni = "Použij osobu!" + user.email = "Použij osobu!" + user.save() + + except EndException: pass # Přesun informací z organizátora do jeho osoby osoba.prezdivka = org.prezdivka if org.prezdivka is not None else '' @@ -142,7 +170,10 @@ def fix_problem(apps, schema_editor): else: pr.autor = None if pr.opravovatel is not None: - pr.opravovatele.add(Organizator.objects.filter(osoba__user=pr.opravovatel).first()) + if Organizator.objects.filter(osoba__user=pr.opravovatel).first() is not None: + pr.opravovatele.add(Organizator.objects.filter(osoba__user=pr.opravovatel).first()) + else: + logger.error(f'WTF, nespárovaný opravovatel {pr.opravovatel} problému {pr}') pr.save() def fix_pohadka(apps, schema_editor): diff --git a/seminar/migrations/0051_resitel_to_osoba.py b/seminar/migrations/0051_resitel_to_osoba.py index 17237bd0..04220896 100644 --- a/seminar/migrations/0051_resitel_to_osoba.py +++ b/seminar/migrations/0051_resitel_to_osoba.py @@ -28,26 +28,23 @@ def resitel_to_osoba(apps,schema_editor): if u.first_name: if not o.jmeno: o.jmeno = u.first_name - u.first_name = 'Použij osobu!' + u.first_name += ' (Uživatel!)' elif o.jmeno == u.first_name: - u.first_name = 'Použij osobu!' + u.first_name += ' (Uživatel!)' else: raise ValueError('jmeno a first_name rozdílné: "{}" vs. "{}"'.format(o.jmeno, u.first_name)) if u.last_name: if not o.prijmeni: o.prijmeni = u.last_name - u.last_name = 'Použij osobu!' + u.last_name += ' (Uživatel!)' elif o.prijmeni == u.last_name: - u.last_name = 'Použij osobu!' + u.last_name += ' (Uživatel!)' else: raise ValueError('prijmeni a last_name rozdílné: "{}" vs. "{}"'.format(o.prijmeni, u.last_name)) if u.email: if not o.email: o.email = u.email - u.email = 'Použij osobu!' - elif o.email == u.email: - u.email = 'Použij osobu!' - else: + elif o.email != u.email: raise ValueError('o.email a u.email rozdílné: "{}" vs. "{}"'.format(o.email, u.email)) u.save() diff --git a/seminar/migrations/0052_user_to_organizator.py b/seminar/migrations/0052_user_to_organizator.py index db3827ce..fec3c2af 100644 --- a/seminar/migrations/0052_user_to_organizator.py +++ b/seminar/migrations/0052_user_to_organizator.py @@ -4,6 +4,10 @@ from __future__ import unicode_literals from django.db import migrations +import logging + +logger = logging.getLogger(__name__) + def spoj_k_organizatorum_osoby(apps, scema_editor): Organizator = apps.get_model('seminar', 'Organizator') Resitel = apps.get_model('seminar', 'Resitel') @@ -11,22 +15,49 @@ def spoj_k_organizatorum_osoby(apps, scema_editor): for org in Organizator.objects.all(): # Spárování organizátora s osobou + # Myšlenka: Když najdeme řešitele pro daného uživatele, tak se vezme Osoba příslušná uživateli, + # Pokud nenajdeme uživatele, tak ještě zkusíme dohledat Osobu podle e-mailu user = org.user - resitele = Resitel.objects.filter(user=user) - if resitele.count() != 0: - osoba = resitele.first().osoba - else: + if user is None: + logger.error(f'Org {org} nemá uživatele!') + # Je to podezřelé, ale prostě vyrobíme novou osobu. osoba = Osoba(user=user) + # Téhle osobě nejdou nastavit detaily, protože žádné nemáme. + else: + logger.info(f'Org {org.user.email}(ID: {org.id}) má uživatele {user}') + # 💢💢💢 Python nemá goto, ale prý má výjimky… 💢💢💢 + class EndException(Exception): pass + try: + # Hledáme podle uživatele + resitele = Resitel.objects.filter(user=user) + if resitele.count() != 0 and user is not None: + osoba = resitele.first().osoba + logger.info(f'Našel jsem řešitele {resitele.first().email} podle uživatele, používám jeho Osobu') + raise EndException + + # Hledáme podle e-mailu + osoby = Osoba.objects.filter(email__iexact=user.email) + if osoby.count() != 0 and user.email != '': + osoba = osoby.first() + if osoba.user is None: + osoba.user = user + logger.info(f'Našel jsem Osobu {osoby.first().email} podle e-mailu') + raise EndException + + # Fallback + logger.warning(f'Org neměl řešitele, zakládám novou Osobu.') + osoba = Osoba(user=user) + + # Přesun informací z usera do osoby + # pro osoby z řešitelů (jediné dosud existující osoby) již v minule migraci + osoba.jmeno = user.first_name + osoba.prijmeni = user.last_name + osoba.email = user.email + user.jmeno += " (Uživatel!)" + user.prijmeni += " (Uživatel!)" + user.save() - # Přesun informací z usera do osoby - # pro řešitele již v minule migraci - osoba.jmeno = user.first_name - osoba.prijmeni = user.last_name - osoba.email = user.email - user.jmeno = "Použij osobu!" - user.prijmeni = "Použij osobu!" - user.email = "Použij osobu!" - user.save() + except EndException: pass # Přesun informací z organizátora do jeho osoby osoba.prezdivka = org.prezdivka if org.prezdivka is not None else '' @@ -46,7 +77,10 @@ def fix_problem(apps, schema_editor): else: pr.autor = None if pr.opravovatel is not None: - pr.opravovatele.add(Organizator.objects.filter(osoba__user=pr.opravovatel).first()) + if Organizator.objects.filter(osoba__user=pr.opravovatel).first() is not None: + pr.opravovatele.add(Organizator.objects.filter(osoba__user=pr.opravovatel).first()) + else: + logger.error(f'WTF, nespárovaný opravovatel {pr.opravovatel} problému {pr}') pr.save() def fix_pohadka(apps, schema_editor): diff --git a/seminar/models.py b/seminar/models.py index 63c9bdfa..afa54367 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -602,13 +602,18 @@ class Cislo(SeminarModelBase): png_filename = pathlib.Path(tempfile.mkdtemp(), 'nahled.png') subprocess.run([ - "convert", - "-density", "300x300", - "-geometry", "{}x{}".format(VYSKA, sirka), - "-background", "white", - "-flatten", - "{}[0]".format(self.pdf.path), # titulní strana - png_filename + "gs", + "-sstdout=%stderr", + "-dSAFER", + "-dNOPAUSE", + "-dBATCH", + "-dNOPROMPT", + "-sDEVICE=pngalpha", + "-r{}x{}".format(VYSKA, sirka), + "-dFirstPage=1d", + "-dLastPage=1d", + "-sOutputFile=" + str(png_filename), + "-f%s" % self.pdf.path ], check=True, capture_output=True diff --git a/seminar/templates/seminar/odevzdavatko/detail.html b/seminar/templates/seminar/odevzdavatko/detail.html index dadeff41..14094fb8 100644 --- a/seminar/templates/seminar/odevzdavatko/detail.html +++ b/seminar/templates/seminar/odevzdavatko/detail.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% load static %} +{% load deadliny %} {% block content %} @@ -62,7 +63,9 @@ $(document).ready(function(){

Řešitelé: {{ object.resitele.all | join:", " }}

{# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #} -

Forma: {{ object.get_forma_display }}, doručeno {{ object.cas_doruceni }}

+

Forma: {{ object.get_forma_display }}

+ +

Doručeno {{ object.cas_doruceni }}, deadline: {{object.cas_doruceni | deadline_html }}

{# Soubory: #}

Přílohy:

diff --git a/seminar/templates/seminar/odevzdavatko/resitel_prehled.html b/seminar/templates/seminar/odevzdavatko/resitel_prehled.html new file mode 100644 index 00000000..be2e94bd --- /dev/null +++ b/seminar/templates/seminar/odevzdavatko/resitel_prehled.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} +{% load static %} +{% load deadliny %} + +{% block custom_css %} + +{% endblock custom_css %} + +{% block content %} +{% for rocnik, hodnoceni in podle_rocniku %} +

Ročník {{ rocnik }}

+ + + + + + + + {% for hodn in hodnoceni %} + + + + + + + {% endfor %} +
DoručenoProblémBodyDeadline
{{ hodn.reseni.cas_doruceni }}{{ hodn.problem }}{{ hodn.body|default_if_none:"---" }}{{ hodn.reseni.cas_doruceni | deadline_html }}
+{% endfor %} +{% endblock %} diff --git a/seminar/templates/seminar/odevzdavatko/seznam.html b/seminar/templates/seminar/odevzdavatko/seznam.html index b58dcb54..2b3f332a 100644 --- a/seminar/templates/seminar/odevzdavatko/seznam.html +++ b/seminar/templates/seminar/odevzdavatko/seznam.html @@ -1,11 +1,15 @@ {% extends "base.html" %} +{% load deadliny %} {% block content %} +{% for dl, mnozina_reseni in reseni_podle_deadlinu.items %} +

{{ dl.2 | deadline_html }}

+{% endfor %} {% endblock %} diff --git a/seminar/templates/seminar/profil/edit.html b/seminar/templates/seminar/profil/edit.html index 9f94090e..a5aacd0e 100644 --- a/seminar/templates/seminar/profil/edit.html +++ b/seminar/templates/seminar/profil/edit.html @@ -61,6 +61,7 @@ {% include "seminar/profil/prihlaska_field.html" with field=form.stat_text id="id_li_stat_text"%} +{% if not po_maturite %} {# Vysloužilým účastníkům skrýt editaci školy apod. #}

@@ -95,6 +96,7 @@
+{% endif %} diff --git a/seminar/templates/seminar/profil/resitel.html b/seminar/templates/seminar/profil/resitel.html index 8f29d246..364bd541 100644 --- a/seminar/templates/seminar/profil/resitel.html +++ b/seminar/templates/seminar/profil/resitel.html @@ -11,6 +11,7 @@ Odhlásit se
Upravit údaje
+Odevzdaná řešení
{% endblock %} diff --git a/seminar/templatetags/deadliny.py b/seminar/templatetags/deadliny.py new file mode 100644 index 00000000..81500d73 --- /dev/null +++ b/seminar/templatetags/deadliny.py @@ -0,0 +1,35 @@ +from django import template +from django.utils.safestring import mark_safe +from seminar.utils import TypDeadline, deadline +register = template.Library() + +@register.filter(name='deadline') +def deadline_text(datum): + typ, cislo, dl = deadline(datum) + strings = { + TypDeadline.PredDeadline: f"1. deadline čísla {cislo} ({dl})", + TypDeadline.SousDeadline: f"Soustřeďkový deadline čísla {cislo} ({dl})", + TypDeadline.FinalDeadline: f"Finální deadline čísla {cislo} ({dl})", + } + return strings[typ] + +@register.filter(name='deadline_kratseji') +def deadline_kratsi_text(datum): + typ, cislo, dl = deadline(datum) + strings = { + TypDeadline.PredDeadline: f"1. deadline {cislo}", + TypDeadline.SousDeadline: f"Soustřeďkový deadline {cislo}", + TypDeadline.FinalDeadline: f"Finální deadline {cislo}", + } + return strings[typ] + +@register.filter(name='deadline_html') +def deadline_html(datum): + typ, _, _ = deadline(datum) + text = deadline_kratsi_text(datum) + classes = { + TypDeadline.PredDeadline: 'preddeadline', + TypDeadline.SousDeadline: 'sous_deadline', + TypDeadline.FinalDeadline: 'final_deadline', + } + return mark_safe(f'{text}') diff --git a/seminar/urls.py b/seminar/urls.py index d76bd790..14973445 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -135,6 +135,7 @@ urlpatterns = [ path('prihlasit/', views.LoginView.as_view(), name='login'), path('odhlasit/', views.LogoutView.as_view(), name='logout'), path('resitel/', resitel_required(views.ResitelView.as_view()), name='seminar_resitel'), + path('resitel/odevzdana_reseni/', resitel_required(views.PrehledOdevzdanychReseni.as_view()), name='seminar_resitel_odevzdana_reseni'), path('reset-hesla/', views.PasswordResetView.as_view(), name='reset_password'), path('zmena-hesla/', views.PasswordChangeView.as_view(), name='change_password'), path('reset-hesla/2/', views.PasswordResetDoneView.as_view(), name='reset_password_done'), diff --git a/seminar/utils.py b/seminar/utils.py index a41b4111..68bce110 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -309,7 +309,7 @@ def deadline_v_rocniku(datum, rocnik): deadliny.append((TypDeadline.FinalDeadline, c, c.datum_deadline)) deadliny = sorted(deadliny, key=lambda x: x[2]) # podle data for dl in deadliny: - if datum <= dl: + if datum <= dl[2]: # První takový deadline je ten nejtěsnější return dl @@ -319,20 +319,22 @@ def deadline(datum): Vrací trojici (TypDeadline, Cislo, datumDeadline: date). """ + if isinstance(datum, datetime.datetime): + datum = datum.date() rok = datum.year # Dva ročníky podezřelé z obsahování dat - pozdejsi_rocnik = m.Rocnik.filter(prvni_rok=rok) - drivejsi_rocnik = m.Rocnik.filter(druhy_rok=rok) - if any( + pozdejsi_rocnik = m.Rocnik.objects.filter(prvni_rok=rok) + drivejsi_rocnik = m.Rocnik.objects.filter(prvni_rok=rok-1) + if any([ pozdejsi_rocnik.count() > 1, drivejsi_rocnik.count() > 1, - ): + ]): raise ValueError(f"Více ročníků začíná/končí stejným rokem: {rok}") pozdejsi_rocnik = pozdejsi_rocnik.first() if pozdejsi_rocnik.count() > 0 else None drivejsi_rocnik = drivejsi_rocnik.first() if drivejsi_rocnik.count() > 0 else None # Předpokládáme, že neexistuje číslo, které má deadline ale nemá finální deadline. - posledni_deadline_drivejsiho_rocniku = m.Cislo.objects.get(rocnik=drivejsi_rocnik, datum_deadline__isnull=False).datum_deadline + posledni_deadline_drivejsiho_rocniku = m.Cislo.objects.filter(rocnik=drivejsi_rocnik, datum_deadline__isnull=False).last().datum_deadline if datum <= posledni_deadline_drivejsiho_rocniku: return deadline_v_rocniku(datum, drivejsi_rocnik) diff --git a/seminar/views/odevzdavatko.py b/seminar/views/odevzdavatko.py index 5c64bc11..585727a5 100644 --- a/seminar/views/odevzdavatko.py +++ b/seminar/views/odevzdavatko.py @@ -8,12 +8,13 @@ from django.db import transaction from dataclasses import dataclass import datetime +from itertools import groupby import logging import seminar.models as m import seminar.forms as f from seminar.forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm -from seminar.utils import aktivniResitele, resi_v_rocniku +from seminar.utils import aktivniResitele, resi_v_rocniku, deadline logger = logging.getLogger(__name__) @@ -24,6 +25,8 @@ logger = logging.getLogger(__name__) # - ReseniProblemuView # - Detail konkrétního řešení -- všechny soubory, datum, ... # - DetailReseniView +# - Pro řešitele: přehled jejich odevzdaných řešení +# - PrehledOdevzdanychReseni # # Taky se může hodit: # - Tabulka všech řešitelů x všech problémů? @@ -169,7 +172,14 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi return redirect(reverse("odevzdavatko_detail_reseni", kwargs={"pk": jedine_reseni.id})) context = self.get_context_data() return self.render_to_response(context) - # Kontext automaticky? + + def get_context_data(self, *args, **kwargs): + ctx = super().get_context_data(*args, **kwargs) + # XXX: Předat groupby do template nejde: https://stackoverflow.com/questions/6906593/itertools-groupby-in-a-django-template + # Django má {% regroup %}, ale ten potřebuje, aby klíč byl atribut položky: https://docs.djangoproject.com/en/3.2/ref/templates/builtins/#regroup + # Takže rozbalíme groupby do slovníku klíč → seznam sami (dictionary comphrehension) + ctx['reseni_podle_deadlinu'] = {k: list(v) for k,v in groupby(ctx['object_list'], lambda r: deadline(r.cas_doruceni))} + return ctx ## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex class DetailReseniView(DetailView): @@ -230,6 +240,29 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): return redirect(success_url) +class PrehledOdevzdanychReseni(ListView): + model = m.Hodnoceni + template_name = 'seminar/odevzdavatko/resitel_prehled.html' + + def get_queryset(self): + if not self.request.user.is_authenticated: + raise RuntimeError("Uživatel měl být přihlášený!") + resitel = m.Resitel.objects.get(osoba__user=self.request.user) + qs = super().get_queryset() + qs = qs.filter(reseni__resitele__in=[resitel]) + return qs + + def get_context_data(self, *args, **kwargs): + ctx = super().get_context_data(*args, **kwargs) + # Ročník určujeme podle čísla, do jehož deadlinu došlo řešení. + # Chceme to mít seřazené, takže místo comphrerehsion ručně postavíme pole polí. Django templates neumí použít OrderedDict :-/ + podle_rocniku = [] + for rocnik, hodnoceni in groupby(ctx['object_list'], lambda ho: deadline(ho.reseni.cas_doruceni)[1].rocnik): + podle_rocniku.append((rocnik, list(hodnoceni))) + ctx['podle_rocniku'] = reversed(podle_rocniku) # Od nejnovějšího ročníku + # TODO: Umožnit stažení / zobrazení řešení + return ctx + # Přehled všech řešení kvůli debugování class SeznamReseniView(ListView): diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index 49180550..3ba73886 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -26,7 +26,7 @@ import seminar.models as m from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva from seminar import utils, treelib -from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm +from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm, ProfileEditFormPoMaturite import seminar.forms as f import seminar.templatetags.treenodes as tnltt import seminar.views.views_rest as vr @@ -1095,15 +1095,23 @@ def resitelEditView(request): user_edit = osoba_edit.user ## Vytvoření slovníku, kterým předvyplním formulář prefill_1=model_to_dict(user_edit) - if resitel_edit: + if resitel_edit and resitel_edit.rok_maturity >= date.today().year: prefill_2=model_to_dict(resitel_edit) prefill_1.update(prefill_2) prefill_3=model_to_dict(osoba_edit) prefill_1.update(prefill_3) - form = ProfileEditForm(initial=prefill_1) + if 'datum_narozeni' in prefill_1: + prefill_1['datum_narozeni'] = str(prefill_1['datum_narozeni']) + if resitel_edit and resitel_edit.rok_maturity < date.today().year: + form = ProfileEditFormPoMaturite(initial=prefill_1) + else: + form = ProfileEditForm(initial=prefill_1) ## Změna údajů a jejich uložení if request.method == 'POST': - form = ProfileEditForm(request.POST) + if resitel_edit and resitel_edit.rok_maturity < date.today().year: + form = ProfileEditFormPoMaturite(request.POST) + else: + form = ProfileEditForm(request.POST) if form.is_valid(): ## Změny v osobě fcd = form.cleaned_data @@ -1115,6 +1123,7 @@ def resitelEditView(request): osoba_edit.ulice = fcd['ulice'] osoba_edit.mesto = fcd['mesto'] osoba_edit.psc = fcd['psc'] + osoba_edit.datum_narozeni = fcd['datum_narozeni'] ## Změny v osobě s podmínkami if fcd.get('spam',False): osoba_edit.datum_souhlasu_zasilani = date.today() @@ -1124,7 +1133,7 @@ def resitelEditView(request): ## Neznámá země msg = "Unknown country {}".format(fcd['stat_text']) - if resitel_edit: + if resitel_edit and resitel_edit.rok_maturity >= date.today().year: ## Změny v řešiteli resitel_edit.skola = fcd['skola'] resitel_edit.rok_maturity = fcd['rok_maturity'] @@ -1140,7 +1149,7 @@ def resitelEditView(request): return formularOKView(request) else: ## Stránka před odeslaním formuláře = předvyplněný formulář - return render(request, 'seminar/profil/edit.html', {'form': form}) + return render(request, 'seminar/profil/edit.html', {'form': form, 'po_maturite': resitel_edit and resitel_edit.rok_maturity < date.today().year}) def prihlaskaView(request): generic_logger = logging.getLogger('seminar.prihlaska') diff --git a/various/__init__.py b/various/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/various/admin.py b/various/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/various/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/various/apps.py b/various/apps.py new file mode 100644 index 00000000..c24a4428 --- /dev/null +++ b/various/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class VariousConfig(AppConfig): + name = 'various' diff --git a/various/context_processors.py b/various/context_processors.py new file mode 100644 index 00000000..c0be2975 --- /dev/null +++ b/various/context_processors.py @@ -0,0 +1,14 @@ +def april(req): + if 'X-April' in req.headers: + try: + year = int(req.headers['X-April']) + return {'april': year} + except: + pass # Fall-back to regular behaviour + + import datetime + today = datetime.date.today() + if today.day == 1 and today.month == 4: + return {'april': today.year} + return {} + diff --git a/various/migrations/__init__.py b/various/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/various/models.py b/various/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/various/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/various/tests.py b/various/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/various/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/various/views.py b/various/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/various/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.