From 57b7c6372d7d9b194dce9c8d7d373b4e16da8926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 2 Jan 2023 23:42:53 +0100 Subject: [PATCH 01/21] =?UTF-8?q?add:=20r=C5=AFzn=C3=A9=20druhy=20bod?= =?UTF-8?q?=C5=AF=20u=20hodnocen=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models/odevzdavatko.py | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/seminar/models/odevzdavatko.py b/seminar/models/odevzdavatko.py index c286558c..2611b334 100644 --- a/seminar/models/odevzdavatko.py +++ b/seminar/models/odevzdavatko.py @@ -115,6 +115,71 @@ class Hodnoceni(bm.SeminarModelBase): feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)') + # TODO najít správné místo + @staticmethod + def vzorecek_na_prepocet(body, resitelu): + return body * 3 / (resitelu + 2) + + # TODO najít správné místo + @staticmethod + def inverze_vzorecku_na_prepocet(body, resitelu): + return body * (resitelu + 2) / 3 + + @property + def body_celkem(self): + # FIXME řeším jen prvního řešitele. + return Hodnoceni.objects.filter(problem=self.problem, reseni__resitele=self.reseni.resitele.first(), body__isnull=False).aggregate(Sum("body"))["body__sum"] + + @body_celkem.setter + def body_celkem(self, value): + if value is None: + self.body = None + else: + if self.body is None: + self.body = 0 + if self.body_celkem is None: + self.body += value + else: + self.body += value - self.body_celkem + + @property + def body_neprepocitane(self): + if self.body is None: + return None + return self.inverze_vzorecku_na_prepocet(self.body, self.reseni.resitele.count()) + + @body_neprepocitane.setter + def body_neprepocitane(self, value): + if value is None: + self.body = None + else: + self.body = self.vzorecek_na_prepocet(value, self.reseni.resitele.count()) + + @property + def body_neprepocitane_celkem(self): + if self.body_celkem is None: + return None + return self.inverze_vzorecku_na_prepocet(self.body_celkem, self.reseni.resitele.count()) + + @body_neprepocitane_celkem.setter + def body_neprepocitane_celkem(self, value): + if value is None: + self.body = None + else: + self.body_celkem = self.vzorecek_na_prepocet(value, self.reseni.resitele.count()) + + @property + def body_max(self): + if not isinstance(Hodnoceni.objects.first().problem, am.Uloha): + return None + return self.problem.uloha.max_body + + @property + def body_neprepocitane_max(self): + if self.body_max is None: + return None + return self.inverze_vzorecku_na_prepocet(self.body_max, self.reseni.resitele.count()) + def __str__(self): return "{}, {}, {}".format(self.problem, self.reseni, self.body) From 39da362586d99aeb08a86b280b0c215f0f654212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 2 Jan 2023 23:44:04 +0100 Subject: [PATCH 02/21] =?UTF-8?q?add:=20frontend=20k=20bod=C5=AFm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mamweb/static/css/mamweb.css | 5 +++ odevzdavatko/forms.py | 16 +++++++++ .../templates/odevzdavatko/detail.html | 35 ++++++++++++++++--- odevzdavatko/views.py | 23 ++++++++---- 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/mamweb/static/css/mamweb.css b/mamweb/static/css/mamweb.css index 63c5f527..3833ff92 100644 --- a/mamweb/static/css/mamweb.css +++ b/mamweb/static/css/mamweb.css @@ -1255,3 +1255,8 @@ div.gdpr { label[for=id_skola] { font-weight: bold; } + +/* detail řešení */ +.bodovani>input { + width: 4em; +} diff --git a/odevzdavatko/forms.py b/odevzdavatko/forms.py index a31122dd..8b71cff4 100644 --- a/odevzdavatko/forms.py +++ b/odevzdavatko/forms.py @@ -103,6 +103,22 @@ class JednoHodnoceniForm(forms.ModelForm): 'feedback': forms.Textarea(attrs={'rows': 1, 'cols': 30, 'class': 'feedback'}), } + body_celkem = forms.DecimalField(required=False, decimal_places=1) + body_neprepocitane = forms.DecimalField(required=False, decimal_places=1) + body_neprepocitane_celkem = forms.DecimalField(required=False, decimal_places=1) + + def __init__(self, *args, initial=None, **kwargs): + if initial is not None: + body_max = initial["body_max"] + body_neprepocitane_max = initial["body_neprepocitane_max"] + del(initial["body_max"]) + del(initial["body_neprepocitane_max"]) + super().__init__(*args, initial=initial, **kwargs) + if initial is not None: + self.fields['body_celkem'].widget.attrs['placeholder'] = body_max + self.fields['body_neprepocitane_celkem'].widget.attrs['placeholder'] = body_neprepocitane_max + + OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm, extra = 0, ) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index 06f69609..c605b701 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -54,12 +54,15 @@ {{ form.management_form }} - + {% for subform in form %} - + + + + @@ -72,10 +75,15 @@ Přidat hodnocení
+{# FIXME Zablokovat ostatni při změně #} +
ProblémBodyDeadline pro bodyZpětná vazba pro řešitele
Problém{# 📖 #}🧍{# 🔵 #}🧍∑{# 💪 #}🧑‍🤝‍🧑{# ❤ #}🧑‍🤝‍🧑∑Deadline pro bodyZpětná vazba pro řešitele
{{ subform.problem }}{{ subform.body }}{{ subform.body }}{{ subform.body_celkem }}{{ subform.body_neprepocitane }}{{ subform.body_neprepocitane_celkem }} {{ subform.deadline_body }} {{ subform.feedback }} Smazat
- + + + + @@ -85,16 +93,33 @@ {% else %}

Hodnocení:

- + {% for h in hodnoceni %} - + + + + {% endfor %}
ProblémBodyZpětná vazba od opravovatele
Problém{# 📖 #}🧍{# 🔵 #}🧍∑{# 💪 #}🧑‍🤝‍🧑{# ❤ #}🧑‍🤝‍🧑∑Zpětná vazba od opravovatele
{{ h.problem }}{{ h.body }}{{ h.body }}{{ h.body_celkem }}{{ h.body_neprepocitane }}{{ h.body_neprepocitane_celkem }} {{ h.feedback }}
{% endif %} +
+
{# 📖 #}🧍
+
Body, které dostává jeden řešitel za toto řešení.
+ +
{# 🔵 #}🧍∑
+
Body, které dostává jeden řešitel za tento problém (součet za všechna řešení).
+ +
{# 💪 #}🧑‍🤝‍🧑
+
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za toto řešení.
+ +
{# ❤ #}🧑‍🤝‍🧑∑
+
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za tento problém (součet za všechna řešení).
+
+ {% endblock %} diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 0100ef24..d24e495a 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -224,12 +224,18 @@ class DetailReseniView(DetailView): self.reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk']) result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet for hodn in m.Hodnoceni.objects.filter(reseni=self.reseni): - result.append({ - "problem": hodn.problem, - "body": hodn.body, - "deadline_body": hodn.deadline_body, - "feedback": hodn.feedback, - }) + seznam_atributu = [ + "problem", + "body", + "body_celkem", + "body_neprepocitane", + "body_neprepocitane_celkem", + "body_max", + "body_neprepocitane_max", + "deadline_body", + "feedback", + ] + result.append({attr: getattr(hodn, attr) for attr in seznam_atributu}) return result def get_context_data(self, **kw): @@ -292,6 +298,11 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): # Vyrobíme nová podle formsetu for form in formset: + data_for_hodnoceni = form.cleaned_data + data_for_body = data_for_hodnoceni.copy() + del(data_for_hodnoceni["body_celkem"]) + del(data_for_hodnoceni["body_neprepocitane"]) + del(data_for_hodnoceni["body_neprepocitane_celkem"]) hodnoceni = m.Hodnoceni( reseni=reseni, **form.cleaned_data, From d9756d5f6019053ab35a826de1eb168bd6e9a53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 2 Jan 2023 23:44:36 +0100 Subject: [PATCH 03/21] =?UTF-8?q?add:=20ukl=C3=A1d=C3=A1n=C3=AD=20r=C5=AFz?= =?UTF-8?q?n=C3=BDch=20bod=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../static/odevzdavatko/dynamic_formsets_for_detail.js | 10 ++++++++++ odevzdavatko/views.py | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js b/odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js index a14c9f8f..1c9bf2f9 100644 --- a/odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js +++ b/odevzdavatko/static/odevzdavatko/dynamic_formsets_for_detail.js @@ -49,8 +49,18 @@ $(document).ready(function(){ $('#id_form-' + form_idx + '-deadline_body')[0].value = $('#id_form-' + (form_idx - 1) + '-deadline_body')[0].value } $('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1); + + $('.bodovani').children().change(function(){ + $(this).parent().parent().children(".bodovani").children().attr("disabled", true); + $(this).attr("disabled", false); + }) }); $('.smazat_hodnoceni').click(function(){ deleteForm("form",this); }); + + $('.bodovani').children().change(function(){ + $(this).parent().parent().children(".bodovani").children().attr("disabled", true); + $(this).attr("disabled", false); + }) }); diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index d24e495a..746335fc 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -308,6 +308,10 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): **form.cleaned_data, ) logger.info(f"Creating Hodnoceni: {hodnoceni}") + zmeny_bodu = [it for it in form.changed_data if it.startswith("body")] + if len(zmeny_bodu) == 1: + hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]]) + hodnoceni.save() hodnoceni.save() return redirect(success_url) From 87a209bf2a8b71a701f7f954bfd2738ac62ea70c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 3 Jan 2023 00:13:29 +0100 Subject: [PATCH 04/21] =?UTF-8?q?fix:=20nekone=C4=8Dn=C3=A9=20desetin?= =?UTF-8?q?=C3=A9=20rozvoje?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models/odevzdavatko.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seminar/models/odevzdavatko.py b/seminar/models/odevzdavatko.py index 2611b334..82a75bc6 100644 --- a/seminar/models/odevzdavatko.py +++ b/seminar/models/odevzdavatko.py @@ -1,3 +1,4 @@ +import decimal import os import reversion @@ -123,7 +124,7 @@ class Hodnoceni(bm.SeminarModelBase): # TODO najít správné místo @staticmethod def inverze_vzorecku_na_prepocet(body, resitelu): - return body * (resitelu + 2) / 3 + return decimal.Context(prec=1).create_decimal_from_float(body * (resitelu + 2) / 3) @property def body_celkem(self): From 0c7a411c1f08f297e80fb43c4fbf630c057d2bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Tue, 3 Jan 2023 00:21:12 +0100 Subject: [PATCH 05/21] =?UTF-8?q?fix:=20nekone=C4=8Dn=C3=A9=20desetin?= =?UTF-8?q?=C3=A9=20rozvoje?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models/odevzdavatko.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seminar/models/odevzdavatko.py b/seminar/models/odevzdavatko.py index 82a75bc6..2d937a41 100644 --- a/seminar/models/odevzdavatko.py +++ b/seminar/models/odevzdavatko.py @@ -123,8 +123,8 @@ class Hodnoceni(bm.SeminarModelBase): # TODO najít správné místo @staticmethod - def inverze_vzorecku_na_prepocet(body, resitelu): - return decimal.Context(prec=1).create_decimal_from_float(body * (resitelu + 2) / 3) + def inverze_vzorecku_na_prepocet(body: decimal.Decimal, resitelu) -> decimal.Decimal: + return round(body * (resitelu + 2) / 3, 1) @property def body_celkem(self): From fa688ec8f33d5b8710b8ae1413ef2eeb6d156a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 20:34:46 +0100 Subject: [PATCH 06/21] =?UTF-8?q?add:=20skr=C3=BDt=20teamovou=20=C4=8D?= =?UTF-8?q?=C3=A1st=20p=C5=99i=20jednom=20=C5=99e=C5=A1iteli=20v=20=C5=99e?= =?UTF-8?q?=C5=A1en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../templates/odevzdavatko/detail.html | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index c605b701..4314c9b7 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -2,6 +2,13 @@ {% load static %} {% load deadliny %} +{# Přišlo mi to hezčí, než psát všude if. #} +{% block custom_css %} + {% if object.resitele.count == 1 %} + + {% endif %} +{% endblock %} + {% block content %} {% if edit %} @@ -54,15 +61,15 @@ {{ form.management_form }} - + {% for subform in form %} - - + + @@ -82,8 +89,8 @@ - - + + @@ -93,14 +100,14 @@ {% else %}

Hodnocení:

Problém{# 📖 #}🧍{# 🔵 #}🧍∑{# 💪 #}🧑‍🤝‍🧑{# ❤ #}🧑‍🤝‍🧑∑Deadline pro bodyZpětná vazba pro řešitele
Problém{# 📖 #}🧍{# 🔵 #}🧍∑{# 💪 #}🧑‍🤝‍🧑{# ❤ #}🧑‍🤝‍🧑∑Deadline pro bodyZpětná vazba pro řešitele
{{ subform.problem }} {{ subform.body }} {{ subform.body_celkem }}{{ subform.body_neprepocitane }}{{ subform.body_neprepocitane_celkem }}{{ subform.body_neprepocitane }}{{ subform.body_neprepocitane_celkem }} {{ subform.deadline_body }} {{ subform.feedback }} Smazat{{ form.empty_form.problem }} {{ form.empty_form.body }} {{ form.empty_form.body_celkem }}{{ form.empty_form.body_neprepocitane }}{{ form.empty_form.body_neprepocitane_celkem }}{{ form.empty_form.body_neprepocitane }}{{ form.empty_form.body_neprepocitane_celkem }} {{ form.empty_form.deadline_body }} {{ form.empty_form.feedback }} Smazat
- + {% for h in hodnoceni %} - - + + {% endfor %} @@ -114,11 +121,11 @@
{# 🔵 #}🧍∑
Body, které dostává jeden řešitel za tento problém (součet za všechna řešení).
-
{# 💪 #}🧑‍🤝‍🧑
-
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za toto řešení.
+
{# 💪 #}🧑‍🤝‍🧑
+
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za toto řešení.
-
{# ❤ #}🧑‍🤝‍🧑∑
-
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za tento problém (součet za všechna řešení).
+
{# ❤ #}🧑‍🤝‍🧑∑
+
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za tento problém (součet za všechna řešení).
From 02fe280d4aaa992b59afdf9802af56182c8c5047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 21:10:32 +0100 Subject: [PATCH 07/21] =?UTF-8?q?neum=C3=ADm=20css,=20z=20toho=20si=20nic?= =?UTF-8?q?=20ned=C4=9Blejte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index 4314c9b7..6e6c337b 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -68,8 +68,8 @@ - - + + @@ -89,8 +89,8 @@ - - + + @@ -106,8 +106,8 @@ - - + + {% endfor %} From 50bdb19e1455df465af5dfaa38cbbc99da7659cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 21:20:01 +0100 Subject: [PATCH 08/21] =?UTF-8?q?smaz=C3=A1no=20FIXME=20(to=20u=C5=BE=20js?= =?UTF-8?q?em=20ud=C4=9Blal)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index 20cc4842..f325811a 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -82,8 +82,6 @@ Přidat hodnocení
-{# FIXME Zablokovat ostatni při změně #} -
Problém{# 📖 #}🧍{# 🔵 #}🧍∑{# 💪 #}🧑‍🤝‍🧑{# ❤ #}🧑‍🤝‍🧑∑Zpětná vazba od opravovatele
Problém{# 📖 #}🧍{# 🔵 #}🧍∑{# 💪 #}🧑‍🤝‍🧑{# ❤ #}🧑‍🤝‍🧑∑Zpětná vazba od opravovatele
{{ h.problem }} {{ h.body }} {{ h.body_celkem }}{{ h.body_neprepocitane }}{{ h.body_neprepocitane_celkem }}{{ h.body_neprepocitane }}{{ h.body_neprepocitane_celkem }} {{ h.feedback }}
{{ subform.problem }} {{ subform.body }} {{ subform.body_celkem }}{{ subform.body_neprepocitane }}{{ subform.body_neprepocitane_celkem }}{{ subform.body_neprepocitane }}{{ subform.body_neprepocitane_celkem }} {{ subform.deadline_body }} {{ subform.feedback }} Smazat{{ form.empty_form.problem }} {{ form.empty_form.body }} {{ form.empty_form.body_celkem }}{{ form.empty_form.body_neprepocitane }}{{ form.empty_form.body_neprepocitane_celkem }}{{ form.empty_form.body_neprepocitane }}{{ form.empty_form.body_neprepocitane_celkem }} {{ form.empty_form.deadline_body }} {{ form.empty_form.feedback }} Smazat{{ h.problem }} {{ h.body }} {{ h.body_celkem }}{{ h.body_neprepocitane }}{{ h.body_neprepocitane_celkem }}{{ h.body_neprepocitane }}{{ h.body_neprepocitane_celkem }} {{ h.feedback }}
From 648084d1f96691b4e87ce53b1a0180887aa7c734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 22:09:57 +0100 Subject: [PATCH 09/21] =?UTF-8?q?add:=20zobrazov=C3=A1n=C3=AD=20max.=20po?= =?UTF-8?q?=C4=8Dtu=20bod=C5=AF=20i=20v=20necelkem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/odevzdavatko/forms.py b/odevzdavatko/forms.py index ebed2698..58d7768d 100644 --- a/odevzdavatko/forms.py +++ b/odevzdavatko/forms.py @@ -122,7 +122,9 @@ class JednoHodnoceniForm(forms.ModelForm): del(initial["body_neprepocitane_max"]) super().__init__(*args, initial=initial, **kwargs) if initial is not None: + self.fields['body'].widget.attrs['placeholder'] = body_max self.fields['body_celkem'].widget.attrs['placeholder'] = body_max + self.fields['body_neprepocitane'].widget.attrs['placeholder'] = body_neprepocitane_max self.fields['body_neprepocitane_celkem'].widget.attrs['placeholder'] = body_neprepocitane_max From 6f49ab3cfa507582e13112e5bcd4189ed0861cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 22:11:36 +0100 Subject: [PATCH 10/21] =?UTF-8?q?Jemn=C3=A9=20textov=C3=A9=20=C3=BApravy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index f325811a..db2b1630 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -112,12 +112,13 @@ {% endif %} +

Vysvětlivky:

{# 📖 #}🧍
-
Body, které dostává jeden řešitel za toto řešení.
+
Body za toto řešení.
{# 🔵 #}🧍∑
-
Body, které dostává jeden řešitel za tento problém (součet za všechna řešení).
+
Body za tento problém (součet za všechna řešení).
{# 💪 #}🧑‍🤝‍🧑
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za toto řešení.
From 4f7b64fae2f5bdcfcadfb63c4f7bfbab2471f514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 23:16:17 +0100 Subject: [PATCH 11/21] =?UTF-8?q?fix:=20maximum=20bod=C5=AF=20pro=20hodnoc?= =?UTF-8?q?en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models/odevzdavatko.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/models/odevzdavatko.py b/seminar/models/odevzdavatko.py index 2d937a41..71b6fb51 100644 --- a/seminar/models/odevzdavatko.py +++ b/seminar/models/odevzdavatko.py @@ -171,7 +171,7 @@ class Hodnoceni(bm.SeminarModelBase): @property def body_max(self): - if not isinstance(Hodnoceni.objects.first().problem, am.Uloha): + if not isinstance(self.problem, am.Uloha): return None return self.problem.uloha.max_body From db16df391bffb35828abc96a37f73cc80fdef3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 23:17:55 +0100 Subject: [PATCH 12/21] =?UTF-8?q?fix:=20maximum=20bod=C5=AF=20pro=20hodnoc?= =?UTF-8?q?en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models/odevzdavatko.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/seminar/models/odevzdavatko.py b/seminar/models/odevzdavatko.py index 71b6fb51..ac6c097c 100644 --- a/seminar/models/odevzdavatko.py +++ b/seminar/models/odevzdavatko.py @@ -171,15 +171,15 @@ class Hodnoceni(bm.SeminarModelBase): @property def body_max(self): - if not isinstance(self.problem, am.Uloha): + if self.body_neprepocitane_max is None: return None - return self.problem.uloha.max_body + return self.vzorecek_na_prepocet(self.body_neprepocitane_max, self.reseni.resitele.count()) @property def body_neprepocitane_max(self): - if self.body_max is None: + if not isinstance(self.problem, am.Uloha): return None - return self.inverze_vzorecku_na_prepocet(self.body_max, self.reseni.resitele.count()) + return self.problem.uloha.max_body def __str__(self): return "{}, {}, {}".format(self.problem, self.reseni, self.body) From 2b1c5e4e6ed1a11b354510b3d44dd9ec34fdafd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Feb 2023 23:26:11 +0100 Subject: [PATCH 13/21] =?UTF-8?q?fix:=20maximum=20bod=C5=AF=20pro=20hodnoc?= =?UTF-8?q?en=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models/odevzdavatko.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seminar/models/odevzdavatko.py b/seminar/models/odevzdavatko.py index ac6c097c..0fad97f8 100644 --- a/seminar/models/odevzdavatko.py +++ b/seminar/models/odevzdavatko.py @@ -177,7 +177,7 @@ class Hodnoceni(bm.SeminarModelBase): @property def body_neprepocitane_max(self): - if not isinstance(self.problem, am.Uloha): + if not isinstance(self.problem.get_real_instance(), am.Uloha): return None return self.problem.uloha.max_body From c8516d6eda5eeea448ed529808b79ab27051a9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 13 Feb 2023 22:32:14 +0100 Subject: [PATCH 14/21] =?UTF-8?q?add:=20checky=20v=20hodnot=C3=ADtku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 2 ++ odevzdavatko/views.py | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index 87e52632..f30d52c7 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -62,6 +62,8 @@

Neveřejná poznámka:

{{ poznamka_form.poznamka }}

+ +{% for h in hodnoceni %}{% if h.body < 0.0 %} {% endif %}{% endfor %} {# Hodnocení: #}

Hodnocení:

diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 9f1c45c0..322b4d69 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -315,7 +315,10 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): zmeny_bodu = [it for it in form.changed_data if it.startswith("body")] if len(zmeny_bodu) == 1: hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]]) - hodnoceni.save() + if len(zmeny_bodu) != 1 and len(zmeny_bodu) != 4: + print(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.") + logger.warning(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.") + hodnoceni.body = -0.1 hodnoceni.save() return redirect(success_url) From d66effcd461ec87c944eefb09bda26333b1ad2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 13 Feb 2023 22:46:54 +0100 Subject: [PATCH 15/21] =?UTF-8?q?move:=20p=C5=99esunuty=20vzore=C4=8Dky=20?= =?UTF-8?q?na=20p=C5=99epo=C4=8Det=20bod=C5=AF=20do=20seminar.utils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/models/odevzdavatko.py | 23 +++++++---------------- seminar/utils.py | 9 +++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/seminar/models/odevzdavatko.py b/seminar/models/odevzdavatko.py index 0fad97f8..744fe38c 100644 --- a/seminar/models/odevzdavatko.py +++ b/seminar/models/odevzdavatko.py @@ -1,4 +1,3 @@ -import decimal import os import reversion @@ -15,6 +14,8 @@ from seminar.models import personalni as pm from seminar.models import treenode as tm from seminar.models import base as bm +from seminar.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet + @reversion.register(ignore_duplicates=True) class Reseni(bm.SeminarModelBase): @@ -116,16 +117,6 @@ class Hodnoceni(bm.SeminarModelBase): feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)') - # TODO najít správné místo - @staticmethod - def vzorecek_na_prepocet(body, resitelu): - return body * 3 / (resitelu + 2) - - # TODO najít správné místo - @staticmethod - def inverze_vzorecku_na_prepocet(body: decimal.Decimal, resitelu) -> decimal.Decimal: - return round(body * (resitelu + 2) / 3, 1) - @property def body_celkem(self): # FIXME řeším jen prvního řešitele. @@ -147,33 +138,33 @@ class Hodnoceni(bm.SeminarModelBase): def body_neprepocitane(self): if self.body is None: return None - return self.inverze_vzorecku_na_prepocet(self.body, self.reseni.resitele.count()) + return inverze_vzorecku_na_prepocet(self.body, self.reseni.resitele.count()) @body_neprepocitane.setter def body_neprepocitane(self, value): if value is None: self.body = None else: - self.body = self.vzorecek_na_prepocet(value, self.reseni.resitele.count()) + self.body = vzorecek_na_prepocet(value, self.reseni.resitele.count()) @property def body_neprepocitane_celkem(self): if self.body_celkem is None: return None - return self.inverze_vzorecku_na_prepocet(self.body_celkem, self.reseni.resitele.count()) + return inverze_vzorecku_na_prepocet(self.body_celkem, self.reseni.resitele.count()) @body_neprepocitane_celkem.setter def body_neprepocitane_celkem(self, value): if value is None: self.body = None else: - self.body_celkem = self.vzorecek_na_prepocet(value, self.reseni.resitele.count()) + self.body_celkem = vzorecek_na_prepocet(value, self.reseni.resitele.count()) @property def body_max(self): if self.body_neprepocitane_max is None: return None - return self.vzorecek_na_prepocet(self.body_neprepocitane_max, self.reseni.resitele.count()) + return vzorecek_na_prepocet(self.body_neprepocitane_max, self.reseni.resitele.count()) @property def body_neprepocitane_max(self): diff --git a/seminar/utils.py b/seminar/utils.py index e7d52529..4ab547ab 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import datetime +import decimal from django.contrib.auth import get_user_model from django.contrib.auth.decorators import permission_required, \ @@ -44,6 +45,14 @@ AnonymousUser.je_org = False AnonymousUser.je_resitel = False +def vzorecek_na_prepocet(body, resitelu): + return body * 3 / (resitelu + 2) + + +def inverze_vzorecku_na_prepocet(body: decimal.Decimal, resitelu) -> decimal.Decimal: + return round(body * (resitelu + 2) / 3, 1) + + class FirstTagParser(HTMLParser): def __init__(self, *args, **kwargs): self.firstTag = None From 6742ecdb8b45a1769d30abe9a568bb71f7df2673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 13 Feb 2023 22:48:25 +0100 Subject: [PATCH 16/21] =?UTF-8?q?add:=20okomentov=C3=A1ny=20vzore=C4=8Dky?= =?UTF-8?q?=20na=20p=C5=99epo=C4=8Det=20bod=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seminar/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/seminar/utils.py b/seminar/utils.py index 4ab547ab..a4197d28 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -46,10 +46,12 @@ 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) From a70d32a4adc0ab56e7da49ae1e4adf29331bd9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Mar 2023 20:10:44 +0100 Subject: [PATCH 17/21] =?UTF-8?q?zal=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 | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index f30d52c7..03452781 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -62,8 +62,22 @@

Neveřejná poznámka:

{{ poznamka_form.poznamka }}

+ -{% for h in hodnoceni %}{% if h.body < 0.0 %} {% endif %}{% endfor %} +{% for h in hodnoceni %}{% if h.body < 0.0 %} + +{% endif %}{% endfor %} + + {# Hodnocení: #}

Hodnocení:

From 9868bff3293414224712803e6c8242d44dca154b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Mar 2023 20:11:50 +0100 Subject: [PATCH 18/21] fuj, print --- odevzdavatko/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 322b4d69..75de1192 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -316,7 +316,6 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): if len(zmeny_bodu) == 1: hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]]) if len(zmeny_bodu) != 1 and len(zmeny_bodu) != 4: - print(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.") logger.warning(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.") hodnoceni.body = -0.1 hodnoceni.save() From 6e1b1ef4e8303c699321f58f5f7666bf5957dc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Mar 2023 20:16:36 +0100 Subject: [PATCH 19/21] =?UTF-8?q?Koment=C3=A1=C5=99=204=20zm=C4=9Bny=20=3D?= =?UTF-8?q?=20beze=20zm=C4=9Bny?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py index 75de1192..eb4dca0e 100644 --- a/odevzdavatko/views.py +++ b/odevzdavatko/views.py @@ -315,7 +315,8 @@ def hodnoceniReseniView(request, pk, *args, **kwargs): zmeny_bodu = [it for it in form.changed_data if it.startswith("body")] if len(zmeny_bodu) == 1: hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]]) - if len(zmeny_bodu) != 1 and len(zmeny_bodu) != 4: + # > jedna změna je špatně, ale 4 "změny" znamenají že nebylo nic zadáno + if len(zmeny_bodu) > 1 and len(zmeny_bodu) != 4: logger.warning(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.") hodnoceni.body = -0.1 hodnoceni.save() From d63b5286a46c75eb2afe3e7252239255c03f04fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Mar 2023 21:14:58 +0100 Subject: [PATCH 20/21] =?UTF-8?q?N=C3=A1st=C5=99el=20n=C3=A1vodu=20v=20hod?= =?UTF-8?q?not=C3=ADtku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../templates/odevzdavatko/detail.html | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index c4e109e4..131c3de0 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -163,14 +163,39 @@
Body za toto řešení.
{# 🔵 #}🧍∑
-
Body za tento problém (součet za všechna řešení).
+
Body za tento problém/úlohu (součet za všechna řešení).
{# 💪 #}🧑‍🤝‍🧑
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za toto řešení.
{# ❤ #}🧑‍🤝‍🧑∑
-
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za tento problém (součet za všechna řešení).
+
Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za tento problém/úlohu (součet za všechna řešení).
+{% if edit %} +

Návod pro hodnocení:

+Sloupce: +
    +
  1. Pokud to neudělal řešitel, je třeba pomocí pluska přidat řádky (případně křížkem smazat) a vyplnit problémy tak, aby zde byly všechny, které řešení řeší (body zadáváme přímo k úlohám, ne k témátku samotnému).
  2. +
  3. Pak je třeba do jednoho ze 2 nebo 4 sloupců vyplnit body (lze udělovat desetiny, setiny už udělovat nejde): +
      +
    • TLDR: pokud si počítáš a kontroluješ vše sám, vyplňuj do nejlevějšího. Pokud naopak vždy vyplňuješ to, kolik řešení má dostat bodů (bez ohledu na počet řešitelů a předchozí odevzdání), vyplňuj nejpravější
    • +
    • Zaprvé je třeba dávat pozor, že řešitel už mohl dostat body za danou úlohu (to je rozdíl mezi lichými a sudými sloupci).
    • +
    • Zadruhé řešení na kterém se spolupracovalo dostává body přepočítané podle vzorečku zde dole. To dělá rozdíl mezi prvními a druhými dvěma sloupci, pokud se oboje zobrazují.
    • +
    +
  4. +
  5. Pokud nemáš důvod, deadline neměň. Sloupeček s deadlinem znamená, do kterého deadlinu se započítají body (nemusí se shodovat s deadlinem řešení).
  6. +
  7. Poslední sloupec je na zpětnou vazbu řešiteli, tedy (na rozdíl od Neveřejné poznámky, která je určena pro synchronizaci orgů) ji uvidí řešitelé. Zatím jen pasivně (nechodí e-mail). Pohled řešitele si můžete prohlédnout zde. Pokud chcete z nějakého důvodu napsat řešitelům e-mail, klikněte na „Poslat mail všem řešitelům“.
  8. +
+ +Další poznámky +
    +
  • Ne, soubory si zatím nejde stáhnout lépe, než proklikáním všech řešeních. Stejně tak nejde hromadně bodovat. Třeba někdy půjde.
  • +
  • Pokud řešitel odevzdal něco nesouvisejícího, nebo něco duplicitně, tak mu za to dejte nulu a jako problém nastavte něco, co odevzdal (ať se mu ve výsledkovce nezobrazuje 0 na špatném místě). A upozorni ho.
  • +
  • Ano, lze zadávat záporné body (např. za podvádění), web na vás bude silně upozorňovat, ale jinak mu to nevadí.
  • +
  • Libovolné problémy s hodnotítkem řeš s {% maillink 'webaři' to='web@mam.mff.cuni.cz' subject='Hodnotítko' %}.
  • +
+{% endif %} + {% endblock %} From 27b38e6b4da82c549a7dc9eb4b0d75f51911654f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= Date: Mon, 6 Mar 2023 21:38:16 +0100 Subject: [PATCH 21/21] =?UTF-8?q?Korektury=20n=C3=A1vodu=20na=20hodnot?= =?UTF-8?q?=C3=ADtko.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- odevzdavatko/templates/odevzdavatko/detail.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/odevzdavatko/templates/odevzdavatko/detail.html b/odevzdavatko/templates/odevzdavatko/detail.html index 131c3de0..5a43c4b5 100644 --- a/odevzdavatko/templates/odevzdavatko/detail.html +++ b/odevzdavatko/templates/odevzdavatko/detail.html @@ -180,9 +180,10 @@ Sloupce:
  • Pokud to neudělal řešitel, je třeba pomocí pluska přidat řádky (případně křížkem smazat) a vyplnit problémy tak, aby zde byly všechny, které řešení řeší (body zadáváme přímo k úlohám, ne k témátku samotnému).
  • Pak je třeba do jednoho ze 2 nebo 4 sloupců vyplnit body (lze udělovat desetiny, setiny už udělovat nejde):
      -
    • TLDR: pokud si počítáš a kontroluješ vše sám, vyplňuj do nejlevějšího. Pokud naopak vždy vyplňuješ to, kolik řešení má dostat bodů (bez ohledu na počet řešitelů a předchozí odevzdání), vyplňuj nejpravější
    • +
    • TLDR: pokud si počítáš a kontroluješ vše sám, vyplňuj do nejlevějšího. Pokud naopak vždy vyplňuješ to, kolik řešení má dostat bodů (bez ohledu na počet řešitelů a předchozí odevzdání), vyplňuj nejpravější.
    • Zaprvé je třeba dávat pozor, že řešitel už mohl dostat body za danou úlohu (to je rozdíl mezi lichými a sudými sloupci).
    • -
    • Zadruhé řešení na kterém se spolupracovalo dostává body přepočítané podle vzorečku zde dole. To dělá rozdíl mezi prvními a druhými dvěma sloupci, pokud se oboje zobrazují.
    • +
    • Zadruhé řešení, na kterém se spolupracovalo, dostává body přepočítané podle vzorečku zde dole. To dělá rozdíl mezi prvními a druhými dvěma sloupci, pokud se oboje zobrazují.
    • +
    • Co který sloupec znamená, je napsáno výše ve vysvětlivkách.
  • Pokud nemáš důvod, deadline neměň. Sloupeček s deadlinem znamená, do kterého deadlinu se započítají body (nemusí se shodovat s deadlinem řešení).
  • @@ -191,9 +192,10 @@ Sloupce: Další poznámky
      -
    • Ne, soubory si zatím nejde stáhnout lépe, než proklikáním všech řešeních. Stejně tak nejde hromadně bodovat. Třeba někdy půjde.
    • +
    • Pokud chceš zadané body smazat (rozmyslel sis to a ohodnotíš to později), smaž body v libovolném sloupeci.
    • +
    • Ne, soubory si zatím nejde stáhnout lépe než proklikáním všech řešeních. Stejně tak nejde hromadně bodovat. Třeba někdy půjde.
    • Pokud řešitel odevzdal něco nesouvisejícího, nebo něco duplicitně, tak mu za to dejte nulu a jako problém nastavte něco, co odevzdal (ať se mu ve výsledkovce nezobrazuje 0 na špatném místě). A upozorni ho.
    • -
    • Ano, lze zadávat záporné body (např. za podvádění), web na vás bude silně upozorňovat, ale jinak mu to nevadí.
    • +
    • Ano, lze zadávat záporné body (např. za podvádění), web vás bude silně upozorňovat, ale jinak mu to nevadí.
    • Libovolné problémy s hodnotítkem řeš s {% maillink 'webaři' to='web@mam.mff.cuni.cz' subject='Hodnotítko' %}.
    {% endif %}