Compare commits
17 commits
stahnout_r
...
master
Author | SHA1 | Date | |
---|---|---|---|
ef9d51d922 | |||
ca5e6728dd | |||
7563dd728c | |||
174087edc7 | |||
4906f82365 | |||
41032be9eb | |||
422caadb9e | |||
aa997bfcd8 | |||
1a2bef328b | |||
a84df1909b | |||
0724030bef | |||
833893f233 | |||
a7746cddda | |||
0d67b5ff83 | |||
071c66ee10 | |||
1bee36d9b6 | |||
6ea212cdf8 |
Before Width: | Height: | Size: 697 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 617 B After Width: | Height: | Size: 1.1 KiB |
|
@ -95,7 +95,7 @@ function safe_checkout_branch {
|
||||||
echo >&2 "Změna v $SCRIPT, prosím pullni manuálně"
|
echo >&2 "Změna v $SCRIPT, prosím pullni manuálně"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
git checkout "$BRANCH"
|
git checkout "$BRANCH" --
|
||||||
git pull
|
git pull
|
||||||
git clean -f
|
git clean -f
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Tento soubor slouží pouze pro shell a podobné. Nikde neimportovat v kódu!
|
# Tento soubor slouží pouze pro shell a podobné. Nikde neimportovat v kódu!
|
||||||
|
|
||||||
print("Naimportoval jsi `seminar.models`. Pevně věřím, že to nebylo nikde v kódu. Díky.")
|
print("Naimportoval jsi `mamweb.vsechno`. Pevně věřím, že to nebylo nikde v kódu. Díky.")
|
||||||
|
|
||||||
from galerie.models import *
|
from galerie.models import *
|
||||||
from header_fotky.models import *
|
from header_fotky.models import *
|
||||||
|
|
|
@ -65,6 +65,9 @@ class Reseni(SeminarModelBase):
|
||||||
def absolute_url(self):
|
def absolute_url(self):
|
||||||
return "https://" + str(get_current_site(None)) + self.verejne_url()
|
return "https://" + str(get_current_site(None)) + self.verejne_url()
|
||||||
|
|
||||||
|
def resitel_url(self):
|
||||||
|
return f'https://{get_current_site(None)}{reverse_lazy("odevzdavatko_resitel_reseni", args=[self.id])}'
|
||||||
|
|
||||||
# má OneToOneField s:
|
# má OneToOneField s:
|
||||||
# Konfera
|
# Konfera
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,7 @@ Sloupce:
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>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í).</li>
|
<li>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í).</li>
|
||||||
<li>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 <a href="{% url 'odevzdavatko_resitel_reseni' reseni.id %}">zde</a>. Pokud chcete z nějakého důvodu napsat řešitelům e-mail, klikněte na „Poslat mail všem řešitelům“.</li>
|
<li>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é. Změníte-li u nějakého hodnocení toto políčko, řešitel bude upozorněn emailem, pokud si tuto možnost nevypl ve svém profilu. Pohled řešitele si můžete prohlédnout <a href="{% url 'odevzdavatko_resitel_reseni' reseni.id %}">zde</a>. Pokud chcete z nějakého důvodu napsat řešitelům e-mail, klikněte na „Poslat mail všem řešitelům“.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
Další poznámky
|
Další poznámky
|
||||||
|
|
|
@ -222,6 +222,17 @@ class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixi
|
||||||
ctx["problem_id"] = self.kwargs['problem']
|
ctx["problem_id"] = self.kwargs['problem']
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
HODNOCENI_INITIAL_DATA = [
|
||||||
|
"problem",
|
||||||
|
"body",
|
||||||
|
"body_celkem",
|
||||||
|
"body_neprepocitane",
|
||||||
|
"body_neprepocitane_celkem",
|
||||||
|
"body_max",
|
||||||
|
"body_neprepocitane_max",
|
||||||
|
"deadline_body",
|
||||||
|
"feedback",
|
||||||
|
]
|
||||||
## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex
|
## XXX: https://docs.djangoproject.com/en/3.1/topics/class-based-views/mixins/#avoid-anything-more-complex
|
||||||
class DetailReseniView(DetailView):
|
class DetailReseniView(DetailView):
|
||||||
""" Náhled na řešení. Editace je v :py:class:`EditReseniView`. """
|
""" Náhled na řešení. Editace je v :py:class:`EditReseniView`. """
|
||||||
|
@ -232,18 +243,7 @@ class DetailReseniView(DetailView):
|
||||||
self.reseni = get_object_or_404(Reseni, id=self.kwargs['pk'])
|
self.reseni = get_object_or_404(Reseni, id=self.kwargs['pk'])
|
||||||
result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet
|
result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet
|
||||||
for hodn in Hodnoceni.objects.filter(reseni=self.reseni):
|
for hodn in Hodnoceni.objects.filter(reseni=self.reseni):
|
||||||
seznam_atributu = [
|
result.append({attr: getattr(hodn, attr) for attr in HODNOCENI_INITIAL_DATA})
|
||||||
"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
|
return result
|
||||||
|
|
||||||
def get_context_data(self, **kw):
|
def get_context_data(self, **kw):
|
||||||
|
@ -291,9 +291,9 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
|
||||||
reseni = get_object_or_404(Reseni, pk=pk)
|
reseni = get_object_or_404(Reseni, pk=pk)
|
||||||
success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk})
|
success_url = reverse('odevzdavatko_detail_reseni', kwargs={'pk': pk})
|
||||||
|
|
||||||
# FIXME: Použit initial i tady a nebastlit hodnocení tak nízkoúrovňově
|
formset = f.OhodnoceniReseniFormSet(request.POST, initial=[
|
||||||
# Also: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#django.forms.ModelForm
|
{k: getattr(h, k) for k in HODNOCENI_INITIAL_DATA} for h in Hodnoceni.objects.filter(reseni=reseni)
|
||||||
formset = f.OhodnoceniReseniFormSet(request.POST)
|
])
|
||||||
poznamka_form = f.PoznamkaReseniForm(request.POST, instance=reseni)
|
poznamka_form = f.PoznamkaReseniForm(request.POST, instance=reseni)
|
||||||
# TODO: Napsat validaci formuláře a formsetu
|
# TODO: Napsat validaci formuláře a formsetu
|
||||||
if not (formset.is_valid() and poznamka_form.is_valid()):
|
if not (formset.is_valid() and poznamka_form.is_valid()):
|
||||||
|
@ -309,7 +309,9 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
|
||||||
qs.delete()
|
qs.delete()
|
||||||
|
|
||||||
# Vyrobíme nová podle formsetu
|
# Vyrobíme nová podle formsetu
|
||||||
|
notifikace = False
|
||||||
for form in formset:
|
for form in formset:
|
||||||
|
notifikace |= 'feedback' in form.changed_data
|
||||||
data_for_hodnoceni = form.cleaned_data
|
data_for_hodnoceni = form.cleaned_data
|
||||||
data_for_body = data_for_hodnoceni.copy()
|
data_for_body = data_for_hodnoceni.copy()
|
||||||
del(data_for_hodnoceni["body_celkem"])
|
del(data_for_hodnoceni["body_celkem"])
|
||||||
|
@ -320,16 +322,44 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
|
||||||
**form.cleaned_data,
|
**form.cleaned_data,
|
||||||
)
|
)
|
||||||
logger.info(f"Creating Hodnoceni: {hodnoceni}")
|
logger.info(f"Creating Hodnoceni: {hodnoceni}")
|
||||||
|
# FIXME následující kód má velmi vysokou šanci se rozbít, vymyslet, jak to udělat jinak
|
||||||
zmeny_bodu = [it for it in form.changed_data if it.startswith("body")]
|
zmeny_bodu = [it for it in form.changed_data if it.startswith("body")]
|
||||||
if len(zmeny_bodu) == 1:
|
if len(zmeny_bodu) != 0:
|
||||||
hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]])
|
body_nastaveny: None | tuple[str, object] = None
|
||||||
# > jedna změna je špatně, ale 4 "změny" znamenají že nebylo nic zadáno
|
def nastav_body(jake, na_kolik):
|
||||||
if len(zmeny_bodu) > 1 and len(zmeny_bodu) != 4 and len(zmeny_bodu) != 2:
|
nonlocal body_nastaveny
|
||||||
# 4 znamená vše už vyplněno a nic nezměněno, 2 znamená předvyplnili se součty a nic se nezměnilo
|
if body_nastaveny is not None:
|
||||||
logger.warning(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.")
|
logger.warning(f"Hodnocení {hodnoceni} s id {hodnoceni.id} k řešení {reseni.id} mělo mít nastavené kromě {body_nastaveny[0]} na {body_nastaveny[1]} ještě další body: {jake} na {na_kolik}. Nastavuji -0.1.")
|
||||||
hodnoceni.body = -0.1
|
hodnoceni.body = -0.1
|
||||||
|
else:
|
||||||
|
body_nastaveny = (jake, na_kolik)
|
||||||
|
hodnoceni.__setattr__(jake, na_kolik)
|
||||||
|
|
||||||
|
for key, value in data_for_body.items():
|
||||||
|
if key.startswith("body") and value is not None:
|
||||||
|
nastav_body(key, value)
|
||||||
|
|
||||||
|
# Něco se změnilo, ale nic není nastavené = něco bylo smazáno
|
||||||
|
if body_nastaveny is None:
|
||||||
|
hodnoceni.body = None
|
||||||
hodnoceni.save()
|
hodnoceni.save()
|
||||||
|
|
||||||
|
adresati = reseni.resitele.filter(upozornovat_na_opravy_reseni=True).values_list('osoba__email', flat=True)
|
||||||
|
if notifikace and adresati:
|
||||||
|
email = EmailMessage(
|
||||||
|
subject='Změna hodnocení odevzdaného řešení',
|
||||||
|
body=f"""Milá řešitelko, milý řešiteli,
|
||||||
|
|
||||||
|
došlo ke změně zpětné vazby k Tebou odevzdanému řešení. Zobrazit si ji můžeš na {reseni.resitel_url()}.
|
||||||
|
|
||||||
|
Tvoji organizátoři M&M
|
||||||
|
---
|
||||||
|
Nechceš-li tato upozornění dostávat, můžeš si to nastavit ve svém profilu.""",
|
||||||
|
from_email='odevzdavatko@mam.mff.cuni.cz',
|
||||||
|
bcc=adresati,
|
||||||
|
)
|
||||||
|
email.send()
|
||||||
|
|
||||||
return redirect(success_url)
|
return redirect(success_url)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,8 @@ class UdajeForm(forms.Form):
|
||||||
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat e-mailem upozornění na vydání nového čísla', required=False, initial=True)
|
zasilat_cislo_emailem = forms.BooleanField(label='Chci dostávat e-mailem upozornění na vydání nového čísla', required=False, initial=True)
|
||||||
spam = forms.BooleanField(label='Souhlasím se zasíláním propagačních materiálů od MFF UK', required=False)
|
spam = forms.BooleanField(label='Souhlasím se zasíláním propagačních materiálů od MFF UK', required=False)
|
||||||
|
|
||||||
|
upozornovat_na_opravy_reseni = forms.BooleanField(label='Chci dostávat emailová upozornění na změnu zpětné vazby k mým řešením', required=False, initial=True)
|
||||||
|
|
||||||
def clean_prezdivka_resitele(self):
|
def clean_prezdivka_resitele(self):
|
||||||
prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele')
|
prezdivka_resitele = self.cleaned_data.get('prezdivka_resitele')
|
||||||
if prezdivka_resitele == '':
|
if prezdivka_resitele == '':
|
||||||
|
|
22
personalni/migrations/0018_resitel_upozorneni.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 4.2.16 on 2024-12-03 19:08
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
def vypnuti_upozorneni_na_opravy_reseni(apps, schema_editor):
|
||||||
|
Resitel = apps.get_model('personalni', 'Resitel')
|
||||||
|
Resitel.objects.update(upozorneni=False)
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalni', '0017_odstrel_treenode_post'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='resitel',
|
||||||
|
name='upozorneni',
|
||||||
|
field=models.BooleanField(default=True, verbose_name='zasílat upozornění na změnu zpětné vazby k řešení emailem'),
|
||||||
|
),
|
||||||
|
migrations.RunPython(vypnuti_upozorneni_na_opravy_reseni),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.2.18 on 2025-01-14 19:48
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalni', '0018_resitel_upozorneni'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='resitel',
|
||||||
|
old_name='upozorneni',
|
||||||
|
new_name='upozornovat_na_opravy_reseni',
|
||||||
|
),
|
||||||
|
]
|
|
@ -250,6 +250,8 @@ class Resitel(SeminarModelBase):
|
||||||
poznamka = models.TextField('neveřejná poznámka', blank=True,
|
poznamka = models.TextField('neveřejná poznámka', blank=True,
|
||||||
help_text='Neveřejná poznámka k řešiteli (plain text)')
|
help_text='Neveřejná poznámka k řešiteli (plain text)')
|
||||||
|
|
||||||
|
upozornovat_na_opravy_reseni = models.BooleanField('zasílat upozornění na změnu zpětné vazby k řešení emailem', default=True)
|
||||||
|
|
||||||
|
|
||||||
def export_row(self):
|
def export_row(self):
|
||||||
"Slovnik pro pouziti v AESOP exportu"
|
"Slovnik pro pouziti v AESOP exportu"
|
||||||
|
|
34
personalni/static/personalni/jak_se_dozvedeli.css
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
.seznam {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 0.3em 1em;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.osoba {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
.uno {
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dos {
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tres {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grey {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
28
personalni/templates/personalni/jak_se_dozvedeli.html
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block custom_css %}
|
||||||
|
{% load static %}
|
||||||
|
<link href="{% static 'personalni/jak_se_dozvedeli.css' %}" rel="stylesheet">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="seznam">
|
||||||
|
<div class="osoba hint">
|
||||||
|
<div class="uno">Jméno</div>
|
||||||
|
<div class="dos">Jak se dozvěděli</div>
|
||||||
|
<div class="tres">Datum registrace</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for osoba in object_list %}
|
||||||
|
<div class="osoba">
|
||||||
|
<div class="uno">{{ osoba.jmeno }} {{ osoba.prijmeni }}</div>
|
||||||
|
<div class="dos {% if not osoba.jak_se_dozvedeli %}grey{% endif %}">{% if osoba.jak_se_dozvedeli %} {{osoba.jak_se_dozvedeli}} {% else %} NEZADÁNO {% endif %}</div>
|
||||||
|
<div class="tres">{{ osoba.datum_registrace }}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock%}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
</h4>
|
</h4>
|
||||||
<table class="form">
|
<table class="form">
|
||||||
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_emailem %}
|
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_emailem %}
|
||||||
|
{% include "personalni/udaje/prihlaska_field.html" with field=form.upozornovat_na_opravy_reseni %}
|
||||||
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_papirove %}
|
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat_cislo_papirove %}
|
||||||
{% include "personalni/udaje/prihlaska_field.html" with field=form.spam %}
|
{% include "personalni/udaje/prihlaska_field.html" with field=form.spam %}
|
||||||
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat %}
|
{% include "personalni/udaje/prihlaska_field.html" with field=form.zasilat %}
|
||||||
|
|
|
@ -33,4 +33,11 @@ urlpatterns = [
|
||||||
name='stari_organizatori'
|
name='stari_organizatori'
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# Zpřístupnění dat z "jak jste se o nás dozvěděli" pro orgy propagace
|
||||||
|
path(
|
||||||
|
'org/propagace/jak-se-dozvedeli/',
|
||||||
|
org_required(views.JakSeDozvedeliView.as_view()),
|
||||||
|
name='jak_se_dozvedeli'
|
||||||
|
)
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -34,7 +34,7 @@ from various.autentizace.utils import posli_reset_hesla
|
||||||
|
|
||||||
from django.forms.models import model_to_dict
|
from django.forms.models import model_to_dict
|
||||||
|
|
||||||
from .models import Organizator
|
from .models import Organizator, Osoba
|
||||||
|
|
||||||
|
|
||||||
def aktivniOrganizatori(datum=timezone.now()):
|
def aktivniOrganizatori(datum=timezone.now()):
|
||||||
|
@ -62,6 +62,11 @@ class CojemamOrganizatoriStariView(generic.ListView):
|
||||||
id__in=aktivniOrganizatori()
|
id__in=aktivniOrganizatori()
|
||||||
).order_by('-organizuje_do')
|
).order_by('-organizuje_do')
|
||||||
|
|
||||||
|
class JakSeDozvedeliView(generic.ListView):
|
||||||
|
model = Osoba
|
||||||
|
template_name = 'personalni/jak_se_dozvedeli.html'
|
||||||
|
queryset = Osoba.objects.order_by('-datum_registrace')
|
||||||
|
|
||||||
|
|
||||||
def obalkyView(request, resitele):
|
def obalkyView(request, resitele):
|
||||||
if len(resitele) == 0:
|
if len(resitele) == 0:
|
||||||
|
@ -230,6 +235,7 @@ def resitelEditView(request):
|
||||||
resitel_edit.zasilat = fcd['zasilat']
|
resitel_edit.zasilat = fcd['zasilat']
|
||||||
resitel_edit.zasilat_cislo_emailem = fcd['zasilat_cislo_emailem']
|
resitel_edit.zasilat_cislo_emailem = fcd['zasilat_cislo_emailem']
|
||||||
resitel_edit.zasilat_cislo_papirove = fcd['zasilat_cislo_papirove']
|
resitel_edit.zasilat_cislo_papirove = fcd['zasilat_cislo_papirove']
|
||||||
|
resitel_edit.upozornovat_na_opravy_reseni = fcd['upozornovat_na_opravy_reseni']
|
||||||
if fcd.get('skola'):
|
if fcd.get('skola'):
|
||||||
resitel_edit.skola = fcd['skola']
|
resitel_edit.skola = fcd['skola']
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -30,6 +30,8 @@ Jak moc by ses chtěl(a) zúčastnit následujících přednášek?
|
||||||
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci
|
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr><td> </td></tr>
|
<tr><td> </td></tr>
|
||||||
|
{% empty %}
|
||||||
|
Nejsou žádné přednášky o kterých by šlo hlasovat.
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr><td><input name="odeslat" type="submit" value="Odeslat"></td><tr>
|
<tr><td><input name="odeslat" type="submit" value="Odeslat"></td><tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% load humanize %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1> Děkujeme. </h1>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import http
|
||||||
|
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.shortcuts import HttpResponseRedirect
|
from django.shortcuts import HttpResponseRedirect
|
||||||
|
@ -5,14 +7,22 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
from django.forms import Form
|
from django.forms import Form
|
||||||
|
|
||||||
|
from various.views.pomocne import formularOKView
|
||||||
|
|
||||||
|
from various.models import Nastaveni
|
||||||
from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH
|
from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH
|
||||||
from soustredeni.models import Soustredeni
|
from soustredeni.models import Soustredeni
|
||||||
from personalni.models import Osoba
|
from personalni.models import Osoba
|
||||||
|
|
||||||
def newPrednaska(request):
|
def newPrednaska(request):
|
||||||
# hlasovani se vztahuje k nejnovejsimu soustredeni
|
# hlasovani se vztahuje k nejnovejsimu soustredeni
|
||||||
sous = Soustredeni.objects.first()
|
sous = Nastaveni.get_solo().aktualni_sous
|
||||||
seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first()
|
seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first()
|
||||||
|
if sous is None or seznam is None:
|
||||||
|
return render(request, 'universal.html', {
|
||||||
|
'title': "Nelze hlasovat",
|
||||||
|
'text': "Není žádný seznam přednášek, o kterém by se dalo hlasovat.",
|
||||||
|
}, status=http.HTTPStatus.NOT_FOUND)
|
||||||
osoba = Osoba.objects.filter(user=request.user).first()
|
osoba = Osoba.objects.filter(user=request.user).first()
|
||||||
ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id)
|
ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id)
|
||||||
# obsluha formulare
|
# obsluha formulare
|
||||||
|
@ -54,7 +64,7 @@ def newPrednaska(request):
|
||||||
|
|
||||||
|
|
||||||
def Prednaska_hotovo(request):
|
def Prednaska_hotovo(request):
|
||||||
return render(request, 'prednasky/hotovo.html')
|
return formularOKView(request, "Děkujeme za vyplnění hlasování o přednáškách a těšíme se na soustředění.")
|
||||||
|
|
||||||
class MetaSeznamListView(generic.ListView):
|
class MetaSeznamListView(generic.ListView):
|
||||||
model = Seznam
|
model = Seznam
|
||||||
|
|
|
@ -17,7 +17,7 @@ django-solo # Singleton model (speciálně Nastavení)
|
||||||
django-ckeditor-5 # Editor htmlka (hlavně v adminu u flatpages)
|
django-ckeditor-5 # Editor htmlka (hlavně v adminu u flatpages)
|
||||||
django-cleanup # Uklízí media/ od smazaných „databázových“ souborů
|
django-cleanup # Uklízí media/ od smazaných „databázových“ souborů
|
||||||
django-taggit # Taggy v djangu (speciálně zaměření problémů)
|
django-taggit # Taggy v djangu (speciálně zaměření problémů)
|
||||||
django-autocomplete-light>=3.9.0 # Automatické doplňování (problémů, účastníků, …) ve formulářích
|
django-autocomplete-light>=3.9.0,<3.12.0 # Automatické doplňování (problémů, účastníků, …) ve formulářích
|
||||||
django-imagekit # Všechny možné obrázky v Djangu
|
django-imagekit # Všechny možné obrázky v Djangu
|
||||||
django-polymorphic # Polymorfismus na django modelech (hlavně Problém nebo treenode)
|
django-polymorphic # Polymorfismus na django modelech (hlavně Problém nebo treenode)
|
||||||
django-sitetree # Struktura stránek, hlavně pro meníčko
|
django-sitetree # Struktura stránek, hlavně pro meníčko
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 4.2.16 on 2025-01-21 20:54
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalni', '0019_rename_upozorneni_resitel_upozornovat_na_opravy_reseni'),
|
||||||
|
('tvorba', '0007_alter_deadline_typ'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.SeparateDatabaseAndState(
|
||||||
|
database_operations=[],
|
||||||
|
state_operations=[
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='problem',
|
||||||
|
name='opravovatele',
|
||||||
|
field=models.ManyToManyField(blank=True, db_table='seminar_problemy_opravovatele', related_name='opravovatele_%(class)s', to='personalni.organizator', verbose_name='opravovatelé'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Problemy_Opravovatele',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
|
@ -393,20 +393,6 @@ class ZmrazenaVysledkovka(SeminarModelBase):
|
||||||
|
|
||||||
html = models.TextField(null=False, blank=False)
|
html = models.TextField(null=False, blank=False)
|
||||||
|
|
||||||
class Problemy_Opravovatele(SeminarModelBase):
|
|
||||||
"""Jen vazebná tabulka pro opravovatele.
|
|
||||||
|
|
||||||
Ona stejně existovala, při přesunu mezi aplikacemi jen potřebujeme zajistit nepřejmenování DB tabulky.
|
|
||||||
Proto taky nepotřebuje žádná specifika, ze :py:class:SeminarModelBase: dědí ze zvyku než že by to k něčemu kdy měo být.
|
|
||||||
"""
|
|
||||||
class Meta:
|
|
||||||
db_table = 'seminar_problemy_opravovatele'
|
|
||||||
|
|
||||||
id = models.AutoField(primary_key = True)
|
|
||||||
|
|
||||||
problem = models.ForeignKey('Problem', on_delete=models.CASCADE)
|
|
||||||
organizator = models.ForeignKey(Organizator, on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
@reversion.register(ignore_duplicates=True)
|
@reversion.register(ignore_duplicates=True)
|
||||||
# Pozor na následující řádek. *Nekrmit, asi kouše!*
|
# Pozor na následující řádek. *Nekrmit, asi kouše!*
|
||||||
class Problem(SeminarModelBase,PolymorphicModel):
|
class Problem(SeminarModelBase,PolymorphicModel):
|
||||||
|
@ -462,7 +448,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
|
||||||
on_delete=models.SET_NULL)
|
on_delete=models.SET_NULL)
|
||||||
|
|
||||||
opravovatele = models.ManyToManyField(Organizator, verbose_name='opravovatelé',
|
opravovatele = models.ManyToManyField(Organizator, verbose_name='opravovatelé',
|
||||||
blank=True, related_name='opravovatele_%(class)s', through=Problemy_Opravovatele)
|
blank=True, related_name='opravovatele_%(class)s', db_table='seminar_problemy_opravovatele')
|
||||||
|
|
||||||
kod = models.CharField('lokální kód', max_length=32, blank=True, default='',
|
kod = models.CharField('lokální kód', max_length=32, blank=True, default='',
|
||||||
help_text='Číslo/kód úlohy v čísle nebo kód tématu/článku/seriálu v ročníku')
|
help_text='Číslo/kód úlohy v čísle nebo kód tématu/článku/seriálu v ročníku')
|
||||||
|
|
20
various/migrations/0007_nastaveni_aktualni_sous.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 4.2.16 on 2025-01-21 20:34
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('soustredeni', '0013_alter_soustredeni_kontaktnicek_pdf_and_more'),
|
||||||
|
('various', '0006_tvorba_post'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='nastaveni',
|
||||||
|
name='aktualni_sous',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='soustredeni.soustredeni', verbose_name='Aktuálně připravovaný sous'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -26,6 +26,11 @@ class Nastaveni(SingletonModel):
|
||||||
verbose_name="Účastnický poplatek za soustředění",
|
verbose_name="Účastnický poplatek za soustředění",
|
||||||
default=1000)
|
default=1000)
|
||||||
|
|
||||||
|
aktualni_sous = models.ForeignKey(
|
||||||
|
"soustredeni.Soustredeni", verbose_name='Aktuálně připravovaný sous',
|
||||||
|
null=True, blank=True, on_delete=models.PROTECT,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def aktualni_rocnik(self):
|
def aktualni_rocnik(self):
|
||||||
return self.aktualni_cislo.rocnik
|
return self.aktualni_cislo.rocnik
|
||||||
|
|