Merge pull request 'Vylepšení odevzdávátka' (!13) from vylepseni_odevzdavatka into master
Reviewed-on: #13
This commit is contained in:
commit
3110eb92a5
17 changed files with 218 additions and 170 deletions
|
@ -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'),
|
||||
path('api/autocomplete/problem/vsechny', views.ProblemAutocomplete.as_view(), name='autocomplete_problem'),
|
||||
|
||||
|
|
|
@ -44,6 +44,29 @@ 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):
|
||||
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=""
|
||||
).filter(
|
||||
prezdivka_resitele__icontains=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):
|
||||
|
|
|
@ -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'},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
22
odevzdavatko/static/odevzdavatko/check_for_detail.js
Normal file
22
odevzdavatko/static/odevzdavatko/check_for_detail.js
Normal file
|
@ -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) { // 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();
|
||||
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;
|
||||
}
|
|
@ -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<formCount; i++) {
|
||||
$(forms.get(i)).find(':input').each(function() {
|
||||
updateElementIndex(this, prefix, i);
|
||||
});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Credit: https://simpleit.rocks/python/django/dynamic-add-form-with-add-button-in-django-modelformset-template/
|
||||
$(document).ready(function(){
|
||||
$('#pridat_hodnoceni').click(function() {
|
||||
var form_idx = $('#id_form-TOTAL_FORMS').val();
|
||||
var new_form = $('#empty_form').html().replace(/__prefix__/g, form_idx);
|
||||
$('#form_set').append(new_form);
|
||||
// Newly created form has not the binding between remove button and remove function
|
||||
// We need to add it manually
|
||||
$('.smazat_hodnoceni').click(function(){
|
||||
deleteForm("form",this);
|
||||
});
|
||||
// Copy deadline
|
||||
if (form_idx !== "0") {
|
||||
$('#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);
|
||||
});
|
||||
$('.smazat_hodnoceni').click(function(){
|
||||
deleteForm("form",this);
|
||||
});
|
||||
});
|
|
@ -4,68 +4,21 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
{# FIXME: Necopypastovat! Tohle je zkopírované ze static/odevzdavatko/dynamic_formsets.js #}
|
||||
<script type='text/javascript'>
|
||||
// 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<formCount; i++) {
|
||||
$(forms.get(i)).find(':input').each(function() {
|
||||
updateElementIndex(this, prefix, i);
|
||||
});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Credit: https://simpleit.rocks/python/django/dynamic-add-form-with-add-button-in-django-modelformset-template/
|
||||
$(document).ready(function(){
|
||||
$('#pridat_hodnoceni').click(function() {
|
||||
var form_idx = $('#id_form-TOTAL_FORMS').val();
|
||||
var new_form = $('#empty_form').html().replace(/__prefix__/g, form_idx);
|
||||
$('#form_set').append(new_form);
|
||||
// Newly created form has not the binding between remove button and remove function
|
||||
// We need to add it manually
|
||||
$('.smazat_hodnoceni').click(function(){
|
||||
deleteForm("form",this);
|
||||
});
|
||||
// Copy deadline
|
||||
if (form_idx !== "0") {
|
||||
$('#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);
|
||||
});
|
||||
$('.smazat_hodnoceni').click(function(){
|
||||
deleteForm("form",this);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% if edit %}
|
||||
<script src="{% static 'odevzdavatko/dynamic_formsets_for_detail.js' %}"></script>
|
||||
<script src="{% static 'odevzdavatko/check_for_detail.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p>Řešené problémy: {{ object.problem.all | join:", " }}</p>
|
||||
|
||||
<p>Řešitelé: {% for r in object.resitele.all %} {{ r }} (<a href="mailto:{{ r.osoba.email }}?subject={{ "Oprava řešení M&M " | urlencode }}{{ object.problem.all.0.hlavni_problem | urlencode }}">{{ r.osoba.email }}</a>)
|
||||
{% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}</p>
|
||||
{% if edit %}
|
||||
<p>Řešitelé:
|
||||
{% for r in object.resitele.all %}{{ r }} (<a href="mailto:{{ r.osoba.email }}?subject={{ "Oprava řešení M&M " | urlencode }}{{ object.problem.all.0.hlavni_problem | urlencode }}">{{ r.osoba.email }}</a>){% if forloop.revcounter0 != 0 %}, {% endif %}{% endfor %}
|
||||
</p>
|
||||
{% else %}
|
||||
<p>Řešitelé: {{ object.resitele.all | join:", " }}</p>
|
||||
{% endif %}
|
||||
|
||||
{# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #}
|
||||
<p>Forma: {{ object.get_forma_display }}</p>
|
||||
|
@ -82,13 +35,13 @@ $(document).ready(function(){
|
|||
<td><a href="{{ priloha.soubor.url }}" download>{{ priloha.split | last }}</a></td>
|
||||
<td>{{ priloha.res_poznamka }}</td>
|
||||
<td>{{ priloha.vytvoreno }}</td></tr>
|
||||
{# TODO: Orgo-poznámka, ideálně jako formulář #}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Žádné přílohy</p>
|
||||
{% endif %}
|
||||
|
||||
{% if edit %}
|
||||
<form method=post onsubmit="return zkontroluj_hodnoceni();">
|
||||
{# Poznámka #}
|
||||
<h3>Neveřejná poznámka:</h3>
|
||||
|
@ -116,7 +69,7 @@ $(document).ready(function(){
|
|||
</table>
|
||||
|
||||
|
||||
<a href="#" title="Přidat hodnocení"> <img src="{% static "odevzdavatko/plus.png" %}" id="pridat_hodnoceni" alt="Přidat hodnocení"></a> </br>
|
||||
<a href="#" title="Přidat hodnocení"> <img src="{% static "odevzdavatko/plus.png" %}" id="pridat_hodnoceni" alt="Přidat hodnocení"></a> <br/>
|
||||
<input type=submit value="Uložit"></form>
|
||||
|
||||
<table id="empty_form" style="display: none;">
|
||||
|
@ -129,28 +82,19 @@ $(document).ready(function(){
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
{% else %}
|
||||
<h3>Hodnocení:</h3>
|
||||
<table class="dosla_reseni">
|
||||
<tr><th>Problém</th><th>Body</th><th>Zpětná vazba od opravovatele</th></tr>
|
||||
{% for h in hodnoceni %}
|
||||
<tr class="hodnoceni">
|
||||
<td>{{ h.problem }}</td>
|
||||
<td>{{ h.body }}</td>
|
||||
<td>{{ h.feedback }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
<script type="text/javascript">
|
||||
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;
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load deadliny %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p>Řešené problémy: {{ object.problem.all | join:", " }}</p>
|
||||
|
||||
<p>Řešitelé: {% for r in object.resitele.all %} {{ r }}
|
||||
{% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}</p>
|
||||
|
||||
{# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #}
|
||||
<p>Forma: {{ object.get_forma_display }}</p>
|
||||
|
||||
<p>Doručeno {{ object.cas_doruceni }}, deadline: {{object.deadline_reseni | deadline_html }}</p>
|
||||
|
||||
{# Soubory: #}
|
||||
<h3>Přílohy:</h3>
|
||||
{% if object.prilohy.all %}
|
||||
<table class="dosla_reseni">
|
||||
<tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr>
|
||||
{% for priloha in object.prilohy.all %}
|
||||
<tr>
|
||||
<td><a href="{{ priloha.soubor.url }}" download>{{ priloha.split | last }}</a></td>
|
||||
<td>{{ priloha.res_poznamka }}</td>
|
||||
<td>{{ priloha.vytvoreno }}</td></tr>
|
||||
{# TODO: Orgo-poznámka, ideálně jako formulář #}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Žádné přílohy</p>
|
||||
{% endif %}
|
||||
|
||||
{#<h3>Poznámka:</h3>#}
|
||||
{#<p>{{ poznamka }}</p>#}
|
||||
|
||||
{# Hodnocení: #}
|
||||
<h3>Hodnocení:</h3>
|
||||
<table id="form_set" class="dosla_reseni">
|
||||
<tr><th>Problém</th><th>Body</th><th>Zpětná vazba od opravovatele</th>{# <th>Deadline pro body</th> #}</tr>
|
||||
{% for h in hodnoceni %}
|
||||
<tr class="hodnoceni">
|
||||
<td>{{ h.problem }}</td>
|
||||
<td>{{ h.body }}</td>
|
||||
<td>{{ h.feedback }}</td>
|
||||
{# <td>{{ h.deadline_body }}</td>#}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
<p style="text-align: justify">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.</p>
|
||||
|
||||
<p>Pokud řešíte ve více lidech, je <strong>nutné</strong> 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 <strong>jednou</strong> (ne každý sám).</p>
|
||||
|
||||
<form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' %}" method="post" onsubmit="return zkontroluj_prilohy();">
|
||||
{% csrf_token %}
|
||||
<table class='form' id="reseni">
|
||||
|
|
|
@ -26,9 +26,9 @@ urlpatterns = [
|
|||
path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
||||
path('org/reseni/rocnik/<int:rocnik>/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
|
||||
path('org/reseni/<int:problem>/<int:resitel>/', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'),
|
||||
path('org/reseni/<int:pk>', org_required(viewMethodSwitch(get=views.DetailReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'),
|
||||
path('org/reseni/<int:pk>', 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/<int:pk>', resitel_or_org_required(views.ResitelReseniView.as_view()), name='odevzdavatko_resitel_reseni'),
|
||||
path('resitel/reseni/<int:pk>', resitel_or_org_required(views.DetailReseniView.as_view()), name='odevzdavatko_resitel_reseni'),
|
||||
]
|
||||
|
|
|
@ -216,6 +216,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'
|
||||
|
||||
|
@ -232,18 +233,44 @@ 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()
|
||||
)
|
||||
ctx['poznamka_form'] = f.PoznamkaReseniForm(instance=self.reseni)
|
||||
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 ale better safe then sorry
|
||||
if not self.request.user.je_org:
|
||||
raise PermissionDenied()
|
||||
|
||||
|
||||
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ě
|
||||
|
@ -275,33 +302,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):
|
||||
|
@ -413,6 +413,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()
|
||||
|
|
|
@ -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,14 @@ 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
|
||||
if Resitel.objects.filter(prezdivka_resitele=prezdivka_resitele).count() > 0:
|
||||
raise forms.ValidationError('Přezdívka je již použita')
|
||||
return prezdivka_resitele
|
||||
|
||||
def clean_zasilat(self):
|
||||
zasilat = self.cleaned_data.get('zasilat')
|
||||
ulice = self.cleaned_data.get('ulice')
|
||||
|
@ -138,6 +147,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 +200,15 @@ 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
|
||||
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')
|
||||
return prezdivka_resitele
|
||||
|
||||
def clean_email(self):
|
||||
err_logger = logging.getLogger('seminar.prihlaska.problem')
|
||||
email = self.cleaned_data.get('email')
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
</h4>
|
||||
<table class="form">
|
||||
{% 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 %}
|
||||
|
|
|
@ -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.
|
||||
</p>
|
||||
<p class="gdpr">
|
||||
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.
|
||||
</p>
|
||||
<p class="gdpr">
|
||||
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.
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
</h4>
|
||||
<table class="form">
|
||||
{% 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 %}
|
||||
|
|
|
@ -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']
|
||||
|
|
18
seminar/migrations/0110_resitel_prezdivka.py
Normal file
18
seminar/migrations/0110_resitel_prezdivka.py
Normal file
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue