From c17afece9deea9c21eada821f91f5d299d15f290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 21 Nov 2022 22:09:24 +0100 Subject: [PATCH 01/15] Fix: #1427 --- .../static/odevzdavatko/check_for_detail.js | 22 ++++ .../dynamic_formsets_for_detail.js | 56 ++++++++++ .../templates/odevzdavatko/detail.html | 101 ++++-------------- odevzdavatko/urls.py | 4 +- odevzdavatko/views.py | 63 ++++++----- 5 files changed, 131 insertions(+), 115 deletions(-) create mode 100644 odevzdavatko/static/odevzdavatko/check_for_detail.js create mode 100644 odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js diff --git a/odevzdavatko/static/odevzdavatko/check_for_detail.js b/odevzdavatko/static/odevzdavatko/check_for_detail.js new file mode 100644 index 00000000..3be7e1e9 --- /dev/null +++ b/odevzdavatko/static/odevzdavatko/check_for_detail.js @@ -0,0 +1,22 @@ +// Kontrola, že org neposílá nějakou blbost v detail.html + +function zkontroluj_hodnoceni() { + const pocet = $('.hodnoceni').length; + if (pocet === 1) { // vydím pouze plusko + const vysledek = confirm("Odstranil jsi všechny problémy tohoto řešení. Nepůjde tedy dohledat přes problémy, co řeší, tj. například v došlých řešeních. Přesto odeslat?"); + if (!vysledek) { + event.preventDefault(); + return false; + } + } + + function problem_is_empty(elem, index, array) {return elem.firstElementChild.children.length !== 1 && elem.firstElementChild.children[1].textContent === "";} + + if ($('.hodnoceni').toArray().some(problem_is_empty)) { + alert("Neuloženo! Nezadal jsi problém, ke kterému posíláš hodnocení. Pokud je toto hodnocení navíc, smaž ho prosím křížkem a znovu odešli.") + event.preventDefault() + return false; + } + + return true; +} diff --git a/odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js b/odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js new file mode 100644 index 00000000..a14c9f8f --- /dev/null +++ b/odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js @@ -0,0 +1,56 @@ +// FIXME: Necopypastovat! Tohle je zkopírované ze static/odevzdavatko/dynamic_formsets.js + + +// Credit https://medium.com/all-about-django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0 +function updateElementIndex(el, prefix, ndx) { + var id_regex = new RegExp('(' + prefix + '-\\d+)'); + var replacement = prefix + '-' + ndx; + if ($(el).attr("for")) { + $(el).attr("for", $(el).attr("for").replace(id_regex, replacement)); + } + if (el.id) { + el.id = el.id.replace(id_regex, replacement); + } + if (el.name) { + el.name = el.name.replace(id_regex, replacement); + } +} + +// Credit https://medium.com/all-about-django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0 +function deleteForm(prefix, btn) { + var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val()); + if (total >= 1){ + btn.closest('tr').remove(); + var forms = $('.hodnoceni'); + var formCount = forms.length - 1; // There is one extra such form hidden as template! + $('#id_' + prefix + '-TOTAL_FORMS').val(formCount); + for (var i=0; i -// Credit https://medium.com/all-about-django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0 -function updateElementIndex(el, prefix, ndx) { - var id_regex = new RegExp('(' + prefix + '-\\d+)'); - var replacement = prefix + '-' + ndx; - if ($(el).attr("for")) { - $(el).attr("for", $(el).attr("for").replace(id_regex, replacement)); - } - if (el.id) { - el.id = el.id.replace(id_regex, replacement); - } - if (el.name) { - el.name = el.name.replace(id_regex, replacement); - } -} - -// Credit https://medium.com/all-about-django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0 -function deleteForm(prefix, btn) { - var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val()); - if (total >= 1){ - btn.closest('tr').remove(); - var forms = $('.hodnoceni'); - var formCount = forms.length - 1; // There is one extra such form hidden as template! - $('#id_' + prefix + '-TOTAL_FORMS').val(formCount); - for (var i=0; i + {% if edit %} + + + {% endif %}

Řešené problémy: {{ object.problem.all | join:", " }}

-

Řešitelé: {% for r in object.resitele.all %} {{ r }} ({{ r.osoba.email }}) +

Řešitelé: {% for r in object.resitele.all %} {{ r }} {% if edit %}({{ r.osoba.email }}){% endif %} {% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}

{# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #} @@ -82,13 +30,13 @@ $(document).ready(function(){ {{ priloha.split | last }} {{ priloha.res_poznamka }} {{ priloha.vytvoreno }} - {# TODO: Orgo-poznámka, ideálně jako formulář #} {% endfor %} {% else %}

Žádné přílohy

{% endif %} + {% if edit %}
{# Poznámka #}

Neveřejná poznámka:

@@ -116,7 +64,7 @@ $(document).ready(function(){ - Přidat hodnocení
+ Přidat hodnocení
@@ -129,28 +77,19 @@ $(document).ready(function(){ + {% else %} +

Hodnocení:

+ + +{% for h in hodnoceni %} + + + + + +{% endfor %} +
ProblémBodyZpětná vazba od opravovatele
{{ h.problem }}{{ h.body }}{{ h.feedback }}
+ {% endif %} - {% endblock %} diff --git a/odevzdavatko/urls.py b/odevzdavatko/urls.py index e15b3807..8c53de6b 100644 --- a/odevzdavatko/urls.py +++ b/odevzdavatko/urls.py @@ -26,9 +26,9 @@ urlpatterns = [ path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), path('org/reseni/rocnik//', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), path('org/reseni///', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'), - path('org/reseni/', org_required(viewMethodSwitch(get=views.DetailReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'), + path('org/reseni/', org_required(viewMethodSwitch(get=views.EditReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'), path('org/reseni/all', org_required(views.SeznamReseniView.as_view())), path('org/reseni/akt', org_required(views.SeznamAktualnichReseniView.as_view())), - path('resitel/reseni/', resitel_or_org_required(views.ResitelReseniView.as_view()), name='odevzdavatko_resitel_reseni'), + path('resitel/reseni/', resitel_or_org_required(views.DetailReseniView.as_view()), name='odevzdavatko_resitel_reseni'), ] diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 6c232172..2927838b 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -211,6 +211,7 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi ## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex class DetailReseniView(DetailView): + """ Náhled na řešení. Editace je v :py:class:`EditReseniView`. """ model = m.Reseni template_name = 'odevzdavatko/detail.html' @@ -227,18 +228,43 @@ class DetailReseniView(DetailView): return result def get_context_data(self, **kw): + self.check_access() ctx = super().get_context_data(**kw) - ctx['form'] = f.OhodnoceniReseniFormSet( - initial = self.aktualni_hodnoceni() - ) + hodnoceni = self.aktualni_hodnoceni() + ctx["hodnoceni"] = hodnoceni + return ctx + + def get(self, request, *args, **kwargs): + """ + Oproti :py:class:`django.views.generic.detail.BaseDetailView` + kontroluje přístup pomocí :py:meth:`check_access` + """ + response = super().get(self, request, *args, **kwargs) + self.check_access() + return response + + def check_access(self): + """ Řešitel musí být součástí řešení, jinak se na něj nemá co dívat. """ + if not self.object.resitele.filter(osoba__user=self.request.user).exists(): + raise PermissionDenied() + + +class EditReseniView(DetailReseniView): + """ Editace (hlavně hodnocení) řešení. """ + def get_context_data(self, **kw): + ctx = super().get_context_data(**kw) + ctx['form'] = f.OhodnoceniReseniFormSet(initial=ctx["hodnoceni"]) ctx['poznamka_form'] = f.PoznamkaReseniForm(instance=self.reseni) + ctx['edit'] = True return ctx + def check_access(self): + """ Na orga máme nároky už v urls.py """ + pass + def hodnoceniReseniView(request, pk, *args, **kwargs): reseni = get_object_or_404(m.Reseni, pk=pk) - template_name = 'odevzdavatko/detail.html' - form_class = f.OhodnoceniReseniFormSet success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk}) # FIXME: Použit initial i tady a nebastlit hodnocení tak nízkoúrovňově @@ -270,33 +296,6 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): return redirect(success_url) -class ResitelReseniView(DetailView): - model = m.Reseni - template_name = 'odevzdavatko/detail_resitele.html' - - def aktualni_hodnoceni(self): - self.reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk']) - result = [] - for hodn in m.Hodnoceni.objects.filter(reseni=self.reseni): - result.append( - { - "problem": hodn.problem, - "body": hodn.body, - "feedback": hodn.feedback, - # "deadline_body": hodn.deadline_body, - } - ) - return result - - def get_context_data(self, **kw): - ctx = super().get_context_data(**kw) - hodnoceni = self.aktualni_hodnoceni() - if not self.reseni.resitele.filter(osoba__user=self.request.user).exists(): - raise PermissionDenied() - # ctx['poznamka'] = f.PoznamkaReseniForm(instance=self.reseni) - ctx["hodnoceni"] = hodnoceni - return ctx - class PrehledOdevzdanychReseni(ListView): From 0d17b450112fcababb8cb944dcae2cdbf504d55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 21 Nov 2022 23:27:44 +0100 Subject: [PATCH 02/15] =?UTF-8?q?Fix:=200.5=20=C2=B7=20#1237?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personalni/forms.py | 25 +++++++++++++++++++ .../templates/personalni/udaje/edit.html | 1 + .../templates/personalni/udaje/gdpr.html | 2 +- .../templates/personalni/udaje/prihlaska.html | 1 + personalni/views.py | 2 ++ seminar/migrations/0110_resitel_prezdivka.py | 18 +++++++++++++ seminar/models/personalni.py | 2 ++ 7 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 seminar/migrations/0110_resitel_prezdivka.py diff --git a/personalni/forms.py b/personalni/forms.py index ea200267..5f0d27f6 100644 --- a/personalni/forms.py +++ b/personalni/forms.py @@ -32,6 +32,7 @@ class PrihlaskaForm(PasswordResetForm): help_text='Tímto jménem se následně budeš přihlašovat pro odevzdání řešení a další činnosti v semináři') jmeno = forms.CharField(label='Jméno', max_length=256, required=True) + prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) pohlavi_muz = forms.ChoiceField(label='Pohlaví', choices = ((True,'muž'),(False,'žena')), required=True) @@ -105,6 +106,17 @@ class PrihlaskaForm(PasswordResetForm): pass return email + def clean_prezdivka_resitele(self): + prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele') + if prezdivka_resitele == '': + return prezdivka_resitele + try: + Resitel.objects.get(prezdivka_resitele=prezdivka_resitele) + raise forms.ValidationError('Přezdívka je již použita') + except ObjectDoesNotExist: + pass + return prezdivka_resitele + def clean_zasilat(self): zasilat = self.cleaned_data.get('zasilat') ulice = self.cleaned_data.get('ulice') @@ -138,6 +150,7 @@ class ProfileEditForm(forms.Form): disabled=True) jmeno = forms.CharField(label='Jméno', max_length=256, required=True) + prezdivka_resitele = forms.CharField(label='Přezdívka (veřejná)', max_length=256, required=False) prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True) pohlavi_muz = forms.ChoiceField(label='Pohlaví', choices = ((True,'muž'),(False,'žena')), required=True) @@ -190,6 +203,18 @@ class ProfileEditForm(forms.Form): # pass # return username # + + def clean_prezdivka_resitele(self): + prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele') + if prezdivka_resitele == '': + return prezdivka_resitele + try: + Resitel.objects.get(prezdivka_resitele=prezdivka_resitele) + raise forms.ValidationError('Přezdívka je již použita') + except ObjectDoesNotExist: + pass + return prezdivka_resitele + def clean_email(self): err_logger = logging.getLogger('seminar.prihlaska.problem') email = self.cleaned_data.get('email') diff --git a/personalni/templates/personalni/udaje/edit.html b/personalni/templates/personalni/udaje/edit.html index 5ec690d9..9091925d 100644 --- a/personalni/templates/personalni/udaje/edit.html +++ b/personalni/templates/personalni/udaje/edit.html @@ -44,6 +44,7 @@ {% include "personalni/udaje/prihlaska_field.html" with field=form.jmeno %} + {% include "personalni/udaje/prihlaska_field.html" with field=form.prezdivka_resitele %} {% include "personalni/udaje/prihlaska_field.html" with field=form.prijmeni %} {% include "personalni/udaje/prihlaska_field.html" with field=form.pohlavi_muz%} {% include "personalni/udaje/prihlaska_field.html" with field=form.email %} diff --git a/personalni/templates/personalni/udaje/gdpr.html b/personalni/templates/personalni/udaje/gdpr.html index 3e85de78..5d9af535 100644 --- a/personalni/templates/personalni/udaje/gdpr.html +++ b/personalni/templates/personalni/udaje/gdpr.html @@ -11,7 +11,7 @@ Získáváme od Tebe údaje vyplněné v přihlášce do semináře (jméno, př Slibujeme Ti, že Tvá osobní data nezneužijeme k ničemu, co by nesouviselo s M&M nebo s dalšími aktivitami Matfyzu, a nikdy je nepředáme nikomu cizímu. Údaje využíváme k zajištění chodu semináře a také je sdílíme s ostatními propagačními akcemi Matfyzu, abychom mohli vyhodnocovat úspěšnost akcí. Pokud budeš mít zájem, budeme Ti také posílat zajímavé zprávy a novinky týkajíci se Matfyzu.

-Veřejně vystavujeme pouze výsledkové listiny, které také uchováváme pro archivní účely. Pokud ale z nějakého důvodu nebudeš chtít mít své jméno či školu uvedené ve výsledkové listině, není problém to zařídit, napiš nám. Z tištěných materiálů samozřejmě údaje už odstranit nemůžeme. +Veřejně vystavujeme pouze seznam přezdívek (pro výběr spoluřešitelů k řešení) a výsledkové listiny, které také uchováváme pro archivní účely. Pokud ale z nějakého důvodu nebudeš chtít mít své jméno či školu uvedené ve výsledkové listině, není problém to zařídit, napiš nám. Z tištěných materiálů samozřejmě údaje už odstranit nemůžeme.

Na soustředěních a dalších akcích semináře navíc pořizujeme fotografie a videozáznamy a používáme je ke zpravodajským a propagačním účelům. Pro propagační účely si od Tebe vyžádáme samostatný souhlas na začátku akce. diff --git a/personalni/templates/personalni/udaje/prihlaska.html b/personalni/templates/personalni/udaje/prihlaska.html index 5e6434bf..33adba03 100644 --- a/personalni/templates/personalni/udaje/prihlaska.html +++ b/personalni/templates/personalni/udaje/prihlaska.html @@ -46,6 +46,7 @@

{% include "personalni/udaje/prihlaska_field.html" with field=form.jmeno %} + {% include "personalni/udaje/prihlaska_field.html" with field=form.prezdivka_resitele %} {% include "personalni/udaje/prihlaska_field.html" with field=form.prijmeni %} {% include "personalni/udaje/prihlaska_field.html" with field=form.pohlavi_muz%} {% include "personalni/udaje/prihlaska_field.html" with field=form.email %} diff --git a/personalni/views.py b/personalni/views.py index 94b90dea..d7d52540 100644 --- a/personalni/views.py +++ b/personalni/views.py @@ -160,6 +160,7 @@ def resitelEditView(request): if resitel_edit: ## Změny v řešiteli + resitel_edit.prezdivka_resitele = fcd['prezdivka_resitele'] resitel_edit.skola = fcd['skola'] resitel_edit.rok_maturity = fcd['rok_maturity'] resitel_edit.zasilat = fcd['zasilat'] @@ -263,6 +264,7 @@ def prihlaskaView(request): err_logger.warning(f'Zaregistrovala se osoba s kolizním jménem. ID osob: {[o.id for o in kolize]}') r = s.Resitel( + prezdivka_resitele=fcd['prezdivka_resitele'], rok_maturity = fcd['rok_maturity'], zasilat = fcd['zasilat'], zasilat_cislo_emailem = fcd['zasilat_cislo_emailem'] diff --git a/seminar/migrations/0110_resitel_prezdivka.py b/seminar/migrations/0110_resitel_prezdivka.py new file mode 100644 index 00000000..51d25822 --- /dev/null +++ b/seminar/migrations/0110_resitel_prezdivka.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2022-11-21 22:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0109_hodnoceni_feedback'), + ] + + operations = [ + migrations.AddField( + model_name='resitel', + name='prezdivka_resitele', + field=models.CharField(blank=True, max_length=256, null=True, unique=True, verbose_name='přezdívka řešitele'), + ), + ] diff --git a/seminar/models/personalni.py b/seminar/models/personalni.py index 28deec4d..3e64af45 100644 --- a/seminar/models/personalni.py +++ b/seminar/models/personalni.py @@ -211,6 +211,8 @@ class Resitel(SeminarModelBase): # Interní ID id = models.AutoField(primary_key = True) + prezdivka_resitele = models.CharField('přezdívka řešitele', blank=True, null=True, max_length=256, unique=True) + osoba = models.OneToOneField(Osoba, blank=False, null=False, verbose_name='osoba', on_delete=models.PROTECT) From 062653e70856998af7231a3eff17f35d99b685d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 22 Nov 2022 00:15:20 +0100 Subject: [PATCH 03/15] =?UTF-8?q?Fix:=200.5=20=C2=B7=20#1237?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/urls.py | 1 + api/views/autocomplete.py | 20 +++++++++++++++++++ odevzdavatko/forms.py | 9 ++++++++- .../templates/odevzdavatko/nahraj_reseni.html | 2 ++ odevzdavatko/views.py | 1 + 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/api/urls.py b/api/urls.py index 23aafe36..76d82b25 100644 --- a/api/urls.py +++ b/api/urls.py @@ -22,6 +22,7 @@ urlpatterns = [ # Autocomplete path('api/autocomplete/skola/', views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), path('api/autocomplete/resitel/', org_required(views.ResitelAutocomplete.as_view()), name='autocomplete_resitel'), + path('api/autocomplete/resitel_public/', views.PublicResitelAutocomplete.as_view(), name='autocomplete_resitel_public'), path('api/autocomplete/problem/odevzdatelny', views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), # Ceka na autocomplete v3 diff --git a/api/views/autocomplete.py b/api/views/autocomplete.py index 217df008..c706b126 100644 --- a/api/views/autocomplete.py +++ b/api/views/autocomplete.py @@ -44,6 +44,26 @@ class ResitelAutocomplete(LoginRequiredAjaxMixin,autocomplete.Select2QuerySetVie qs = qs.filter(query) return qs + +class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2QuerySetView): + """ + View k :mod:`dal.autocomplete` pro vyhledávání řešitelů podle přezdívky + především v odevzdávátku. + """ + def get_queryset(self): + qs = m.Resitel.objects.filter( + prezdivka_resitele__isnull=False + ).exclude( + prezdivka_resitele="" + ).filter( + prezdivka_resitele__startswith=self.q + ).all() + return qs + + def get_result_label(self, result): + return result.prezdivka_resitele + + class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView): """ View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """ def get_queryset(self): diff --git a/odevzdavatko/forms.py b/odevzdavatko/forms.py index a8538668..b52c30f4 100644 --- a/odevzdavatko/forms.py +++ b/odevzdavatko/forms.py @@ -63,7 +63,7 @@ class PosliReseniForm(forms.Form): class NahrajReseniForm(forms.ModelForm): class Meta: model = m.Reseni - fields = ('problem',) + fields = ('problem', 'resitele') help_texts = {'problem':''} # Nezobrazovat help text ve formuláři widgets = {'problem': @@ -72,6 +72,13 @@ class NahrajReseniForm(forms.ModelForm): attrs = {'data-placeholder--id': '-1', 'data-placeholder--text' : '---', 'data-allow-clear': 'true'}, + ), + 'resitele': + autocomplete.ModelSelect2Multiple( + url='autocomplete_resitel_public', + attrs = {'data-placeholder--id': '-1', + 'data-placeholder--text' : '---', + 'data-allow-clear': 'true'}, ) } diff --git a/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html b/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html index 64ef92c1..07529720 100644 --- a/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html +++ b/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html @@ -13,6 +13,8 @@

Když řešení různých témátek vložíš každé zvlášť, lépe se v nich vyznáme a třeba ti je i rychleji opravíme.

+

Pokud řešíte ve více lidech, je nutné přidat tyto lidi jako „Autory řešení“! V tomto poli se vyhledává podle přezdívek, které si lze nastavit v „Osobní údaje“. Sebe vyplňovat nemusíte a za skupinu odevzdávejte pouze jednou (ne každý sám)!

+
{% csrf_token %}
diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 2927838b..3b29d397 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -407,6 +407,7 @@ class NahrajReseniView(LoginRequiredMixin, CreateView): with transaction.atomic(): self.object = form.save() self.object.resitele.add(m.Resitel.objects.get(osoba__user = self.request.user)) + self.object.resitele.add(*form.cleaned_data["resitele"]) self.object.cas_doruceni = timezone.now() self.object.forma = m.Reseni.FORMA_UPLOAD self.object.save() From ad45b0a23b5fca93794d024cc3bc9cfb7d6184ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 22 Nov 2022 00:24:57 +0100 Subject: [PATCH 04/15] =?UTF-8?q?Fix:=20=C4=8D=C3=A1rky=20v=20detailu=20?= =?UTF-8?q?=C5=99e=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index 7448f71e..2e4ad53a 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -12,8 +12,7 @@

Řešené problémy: {{ object.problem.all | join:", " }}

-

Řešitelé: {% for r in object.resitele.all %} {{ r }} {% if edit %}({{ r.osoba.email }}){% endif %} -{% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}

+

Řešitelé: {% for r in object.resitele.all %}{{ r }}{% if edit %}({{ r.osoba.email }}){% endif %}{% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}

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

Forma: {{ object.get_forma_display }}

From e325d41f76e07f8bb1024a0b9074007e22dd9c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 22 Nov 2022 00:26:35 +0100 Subject: [PATCH 05/15] =?UTF-8?q?Fix:=20zapomn=C4=9Bl=20jsem=20je=C5=A1t?= =?UTF-8?q?=C4=9B=20po=20sjednocen=C3=AD=20odstranit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../odevzdavatko/detail_resitele.html | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 odevzdavatko/templates/odevzdavatko/detail_resitele.html diff --git a/odevzdavatko/templates/odevzdavatko/detail_resitele.html b/odevzdavatko/templates/odevzdavatko/detail_resitele.html deleted file mode 100644 index fb0cb5fb..00000000 --- a/odevzdavatko/templates/odevzdavatko/detail_resitele.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "base.html" %} -{% load static %} -{% load deadliny %} - -{% block content %} - -

Řešené problémy: {{ object.problem.all | join:", " }}

- -

Řešitelé: {% for r in object.resitele.all %} {{ r }} - {% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}

- -{# 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 }}, deadline: {{object.deadline_reseni | deadline_html }}

- -{# Soubory: #} -

Přílohy:

-{% if object.prilohy.all %} -
- -{% for priloha in object.prilohy.all %} - - - - - {# TODO: Orgo-poznámka, ideálně jako formulář #} -{% endfor %} -
SouborŘešitelova poznámkaDatum
{{ priloha.split | last }}{{ priloha.res_poznamka }}{{ priloha.vytvoreno }}
-{% else %} -

Žádné přílohy

-{% endif %} - -{#

Poznámka:

#} -{#

{{ poznamka }}

#} - -{# Hodnocení: #} -

Hodnocení:

- -{# #} -{% for h in hodnoceni %} - - - - -{# #} - -{% endfor %} -
ProblémBodyZpětná vazba od opravovateleDeadline pro body
{{ h.problem }}{{ h.body }}{{ h.feedback }}{{ h.deadline_body }}
- -{% endblock %} From 3b6e238323806b309f25cc3fe20767d6043df917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 19 Dec 2022 20:43:05 +0100 Subject: [PATCH 06/15] =?UTF-8?q?Fix:=20lep=C5=A1=C3=AD=20hled=C3=A1n?= =?UTF-8?q?=C3=AD=20podle=20p=C5=99ezd=C3=ADvky?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/views/autocomplete.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/views/autocomplete.py b/api/views/autocomplete.py index ab0114b3..10e0bca9 100644 --- a/api/views/autocomplete.py +++ b/api/views/autocomplete.py @@ -56,7 +56,7 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer ).exclude( prezdivka_resitele="" ).filter( - prezdivka_resitele__startswith=self.q + prezdivka_resitele__icontains=self.q ).all() return qs From 9bb0bcf3ca9699af6288f17c7ee239a0ab3351cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 19 Dec 2022 22:51:49 +0100 Subject: [PATCH 07/15] =?UTF-8?q?fix:=20p=C5=99eklep?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/static/odevzdavatko/check_for_detail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odevzdavatko/static/odevzdavatko/check_for_detail.js b/odevzdavatko/static/odevzdavatko/check_for_detail.js index 3be7e1e9..b694dc88 100644 --- a/odevzdavatko/static/odevzdavatko/check_for_detail.js +++ b/odevzdavatko/static/odevzdavatko/check_for_detail.js @@ -2,7 +2,7 @@ function zkontroluj_hodnoceni() { const pocet = $('.hodnoceni').length; - if (pocet === 1) { // vydím pouze plusko + if (pocet === 1) { // vidím pouze plusko const vysledek = confirm("Odstranil jsi všechny problémy tohoto řešení. Nepůjde tedy dohledat přes problémy, co řeší, tj. například v došlých řešeních. Přesto odeslat?"); if (!vysledek) { event.preventDefault(); From 1f16f194f7c6ea669ffc12512473f387f0f7930a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 19 Dec 2022 23:12:23 +0100 Subject: [PATCH 08/15] add: Pro jistotu v DetailView i kontrola u orga --- odevzdavatko/views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 3b29d397..834b7624 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -259,8 +259,9 @@ class EditReseniView(DetailReseniView): return ctx def check_access(self): - """ Na orga máme nároky už v urls.py """ - pass + # Na orga máme nároky už v urls.py ale better safe then sorry + if not self.request.user.je_org: + raise PermissionDenied() def hodnoceniReseniView(request, pk, *args, **kwargs): From abcfa996bd5473dff9ea069fc03cb835ca042ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 19 Dec 2022 23:38:41 +0100 Subject: [PATCH 09/15] =?UTF-8?q?fix:=20=20->=20=20a=20zbaven?= =?UTF-8?q?=C3=AD=20se=20vyk=C5=99i=C4=8Dn=C3=ADk=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/nahraj_reseni.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html b/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html index 07529720..739340c3 100644 --- a/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html +++ b/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html @@ -13,7 +13,7 @@

Když řešení různých témátek vložíš každé zvlášť, lépe se v nich vyznáme a třeba ti je i rychleji opravíme.

-

Pokud řešíte ve více lidech, je nutné přidat tyto lidi jako „Autory řešení“! V tomto poli se vyhledává podle přezdívek, které si lze nastavit v „Osobní údaje“. Sebe vyplňovat nemusíte a za skupinu odevzdávejte pouze jednou (ne každý sám)!

+

Pokud řešíte ve více lidech, je nutné přidat tyto lidi jako „Autory řešení“. V tomto poli se vyhledává podle přezdívek, které si lze nastavit v „Osobní údaje“. Sebe vyplňovat nemusíte a za skupinu odevzdávejte pouze jednou (ne každý sám).

{% csrf_token %} From 98ac3f63bf274b9ff65d0aef1b294d446cb40b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 19 Dec 2022 23:52:11 +0100 Subject: [PATCH 10/15] =?UTF-8?q?fix:=20kontrola=20duplicitn=C3=AD=20p?= =?UTF-8?q?=C5=99ezd=C3=ADvky=20p=C5=99i=20editaci=20osobn=C3=ADch=20?= =?UTF-8?q?=C3=BAdaj=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personalni/forms.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/personalni/forms.py b/personalni/forms.py index 5f0d27f6..2946745d 100644 --- a/personalni/forms.py +++ b/personalni/forms.py @@ -208,11 +208,8 @@ class ProfileEditForm(forms.Form): prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele') if prezdivka_resitele == '': return prezdivka_resitele - try: - Resitel.objects.get(prezdivka_resitele=prezdivka_resitele) + if Resitel.objects.filter(prezdivka_resitele=prezdivka_resitele).exclude(osoba__user__username=self.username).count() > 0: raise forms.ValidationError('Přezdívka je již použita') - except ObjectDoesNotExist: - pass return prezdivka_resitele def clean_email(self): From 932ea700f38924b4eb24cb51d1d13a041cd3a010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 19 Dec 2022 23:55:24 +0100 Subject: [PATCH 11/15] =?UTF-8?q?fix:=20lep=C5=A1=C3=AD=20count=20ne=C5=BE?= =?UTF-8?q?=20try-catch=20p=C5=99i=20kontrole=20duplicitn=C3=AD=20p=C5=99e?= =?UTF-8?q?zd=C3=ADvky=20v=20p=C5=99ihl=C3=A1=C5=A1ce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- personalni/forms.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/personalni/forms.py b/personalni/forms.py index 2946745d..f9d90182 100644 --- a/personalni/forms.py +++ b/personalni/forms.py @@ -110,11 +110,8 @@ class PrihlaskaForm(PasswordResetForm): prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele') if prezdivka_resitele == '': return prezdivka_resitele - try: - Resitel.objects.get(prezdivka_resitele=prezdivka_resitele) + if Resitel.objects.filter(prezdivka_resitele=prezdivka_resitele).count() > 0: raise forms.ValidationError('Přezdívka je již použita') - except ObjectDoesNotExist: - pass return prezdivka_resitele def clean_zasilat(self): From 5dedba2937510b3896b8a8a011c4ea885fe440e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 20 Dec 2022 12:29:19 +0100 Subject: [PATCH 12/15] =?UTF-8?q?fix:=20=E2=80=9Erozl=C3=A1m=C3=A1n=C3=AD?= =?UTF-8?q?=E2=80=9C=20dlouh=C3=A9ho=20=C5=99=C3=A1dku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index b16a5a28..a024fa07 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -12,7 +12,7 @@

Řešené problémy: {{ object.problem.all | join:", " }}

-

Řešitelé: {% for r in object.resitele.all %}{{ r }}{% if edit %}({{ r.osoba.email }}){% endif %}{% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}

+

Řešitelé: {% for r in object.resitele.all %}{{ r }}{# mailto -> #}{% if edit %} ({{ r.osoba.email }}){% endif %}{# <- mailto #}{# čárky -> #}{% if forloop.revcounter0 != 0 %}, {% endif %}{# <- čárky #}{% endfor %}

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

Forma: {{ object.get_forma_display }}

From 0b835ef9d496991b070bd795efc748a848ab473f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 20 Dec 2022 12:40:55 +0100 Subject: [PATCH 13/15] =?UTF-8?q?fix:=20=C5=99e=C5=A1itel=C3=A9=20maj?= =?UTF-8?q?=C3=AD=20b=C3=BDt=20vid=C4=9Bt=20jen=20ti,=20kte=C5=99=C3=AD=20?= =?UTF-8?q?neodmaturovali?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/views/autocomplete.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/views/autocomplete.py b/api/views/autocomplete.py index 10e0bca9..601f4e35 100644 --- a/api/views/autocomplete.py +++ b/api/views/autocomplete.py @@ -51,7 +51,10 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer především v odevzdávátku. """ def get_queryset(self): + letos = m.Nastaveni.get_solo().aktualni_rocnik qs = m.Resitel.objects.filter( + rok_maturity__gte=letos.druhy_rok() + ).filter( prezdivka_resitele__isnull=False ).exclude( prezdivka_resitele="" From f2764a26f399a88bc0d91133e77f03dacd72a9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 20 Dec 2022 14:26:43 +0100 Subject: [PATCH 14/15] =?UTF-8?q?fix:=20je=C5=A1t=C4=9B=20jeden=20n=C3=A1v?= =?UTF-8?q?rh=20na=20zal=C3=A1m=C3=A1n=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index a024fa07..324de443 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -12,7 +12,13 @@

Řešené problémy: {{ object.problem.all | join:", " }}

-

Řešitelé: {% for r in object.resitele.all %}{{ r }}{# mailto -> #}{% if edit %} ({{ r.osoba.email }}){% endif %}{# <- mailto #}{# čárky -> #}{% if forloop.revcounter0 != 0 %}, {% endif %}{# <- čárky #}{% endfor %}

+{% if edit %} +

Řešitelé: + {% for r in object.resitele.all %}{{ r }}({{ r.osoba.email }}){% if forloop.revcounter0 != 0 %}, {% endif %}{% endfor %} +

+{% else %} +

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

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

Forma: {{ object.get_forma_display }}

From 09e2df75ce20de22894fd5b3c3dc9af541400b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 20 Dec 2022 14:29:04 +0100 Subject: [PATCH 15/15] =?UTF-8?q?fix:=20mezera=20p=C5=99ed=20z=C3=A1vorkou?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index 324de443..06f69609 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -14,7 +14,7 @@ {% if edit %}

Řešitelé: - {% for r in object.resitele.all %}{{ r }}({{ r.osoba.email }}){% if forloop.revcounter0 != 0 %}, {% endif %}{% endfor %} + {% for r in object.resitele.all %}{{ r }} ({{ r.osoba.email }}){% if forloop.revcounter0 != 0 %}, {% endif %}{% endfor %}

{% else %}

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