Compare commits

...

10 commits

10 changed files with 398 additions and 213 deletions

View file

@ -14,12 +14,12 @@
"flatpage" "flatpage"
], ],
[ [
"delete_flatpage", "change_flatpage",
"flatpages", "flatpages",
"flatpage" "flatpage"
], ],
[ [
"change_flatpage", "delete_flatpage",
"flatpages", "flatpages",
"flatpage" "flatpage"
], ],
@ -34,12 +34,12 @@
"galerie" "galerie"
], ],
[ [
"delete_galerie", "change_galerie",
"galerie", "galerie",
"galerie" "galerie"
], ],
[ [
"change_galerie", "delete_galerie",
"galerie", "galerie",
"galerie" "galerie"
], ],
@ -54,12 +54,12 @@
"obrazek" "obrazek"
], ],
[ [
"delete_obrazek", "change_obrazek",
"galerie", "galerie",
"obrazek" "obrazek"
], ],
[ [
"change_obrazek", "delete_obrazek",
"galerie", "galerie",
"obrazek" "obrazek"
], ],
@ -104,12 +104,12 @@
"komentar" "komentar"
], ],
[ [
"delete_komentar", "change_komentar",
"korektury", "korektury",
"komentar" "komentar"
], ],
[ [
"change_komentar", "delete_komentar",
"korektury", "korektury",
"komentar" "komentar"
], ],
@ -124,12 +124,12 @@
"korekturovanepdf" "korekturovanepdf"
], ],
[ [
"delete_korekturovanepdf", "change_korekturovanepdf",
"korektury", "korektury",
"korekturovanepdf" "korekturovanepdf"
], ],
[ [
"change_korekturovanepdf", "delete_korekturovanepdf",
"korektury", "korektury",
"korekturovanepdf" "korekturovanepdf"
], ],
@ -144,12 +144,12 @@
"oprava" "oprava"
], ],
[ [
"delete_oprava", "change_oprava",
"korektury", "korektury",
"oprava" "oprava"
], ],
[ [
"change_oprava", "delete_oprava",
"korektury", "korektury",
"oprava" "oprava"
], ],
@ -164,12 +164,12 @@
"novinky" "novinky"
], ],
[ [
"delete_novinky", "change_novinky",
"novinky", "novinky",
"novinky" "novinky"
], ],
[ [
"change_novinky", "delete_novinky",
"novinky", "novinky",
"novinky" "novinky"
], ],
@ -204,12 +204,12 @@
"prijemce" "prijemce"
], ],
[ [
"delete_prijemce", "change_prijemce",
"personalni", "personalni",
"prijemce" "prijemce"
], ],
[ [
"change_prijemce", "delete_prijemce",
"personalni", "personalni",
"prijemce" "prijemce"
], ],
@ -234,12 +234,12 @@
"skola" "skola"
], ],
[ [
"delete_skola", "change_skola",
"personalni", "personalni",
"skola" "skola"
], ],
[ [
"change_skola", "delete_skola",
"personalni", "personalni",
"skola" "skola"
], ],
@ -248,38 +248,28 @@
"personalni", "personalni",
"skola" "skola"
], ],
[
"add_hlasovani",
"prednasky",
"hlasovani"
],
[
"delete_hlasovani",
"prednasky",
"hlasovani"
],
[
"change_hlasovani",
"prednasky",
"hlasovani"
],
[ [
"view_hlasovani", "view_hlasovani",
"prednasky", "prednasky",
"hlasovani" "hlasovani"
], ],
[
"view_hlasovanioznalostech",
"prednasky",
"hlasovanioznalostech"
],
[ [
"add_prednaska", "add_prednaska",
"prednasky", "prednasky",
"prednaska" "prednaska"
], ],
[ [
"delete_prednaska", "change_prednaska",
"prednasky", "prednasky",
"prednaska" "prednaska"
], ],
[ [
"change_prednaska", "delete_prednaska",
"prednasky", "prednasky",
"prednaska" "prednaska"
], ],
@ -294,12 +284,12 @@
"seznam" "seznam"
], ],
[ [
"delete_seznam", "change_seznam",
"prednasky", "prednasky",
"seznam" "seznam"
], ],
[ [
"change_seznam", "delete_seznam",
"prednasky", "prednasky",
"seznam" "seznam"
], ],
@ -308,18 +298,38 @@
"prednasky", "prednasky",
"seznam" "seznam"
], ],
[
"add_znalost",
"prednasky",
"znalost"
],
[
"change_znalost",
"prednasky",
"znalost"
],
[
"delete_znalost",
"prednasky",
"znalost"
],
[
"view_znalost",
"prednasky",
"znalost"
],
[ [
"add_konfera", "add_konfera",
"soustredeni", "soustredeni",
"konfera" "konfera"
], ],
[ [
"delete_konfera", "change_konfera",
"soustredeni", "soustredeni",
"konfera" "konfera"
], ],
[ [
"change_konfera", "delete_konfera",
"soustredeni", "soustredeni",
"konfera" "konfera"
], ],
@ -334,12 +344,12 @@
"konfery_ucastnici" "konfery_ucastnici"
], ],
[ [
"delete_konfery_ucastnici", "change_konfery_ucastnici",
"soustredeni", "soustredeni",
"konfery_ucastnici" "konfery_ucastnici"
], ],
[ [
"change_konfery_ucastnici", "delete_konfery_ucastnici",
"soustredeni", "soustredeni",
"konfery_ucastnici" "konfery_ucastnici"
], ],
@ -354,12 +364,12 @@
"soustredeni" "soustredeni"
], ],
[ [
"delete_soustredeni", "change_soustredeni",
"soustredeni", "soustredeni",
"soustredeni" "soustredeni"
], ],
[ [
"change_soustredeni", "delete_soustredeni",
"soustredeni", "soustredeni",
"soustredeni" "soustredeni"
], ],
@ -374,12 +384,12 @@
"soustredeni_organizatori" "soustredeni_organizatori"
], ],
[ [
"delete_soustredeni_organizatori", "change_soustredeni_organizatori",
"soustredeni", "soustredeni",
"soustredeni_organizatori" "soustredeni_organizatori"
], ],
[ [
"change_soustredeni_organizatori", "delete_soustredeni_organizatori",
"soustredeni", "soustredeni",
"soustredeni_organizatori" "soustredeni_organizatori"
], ],
@ -394,12 +404,12 @@
"soustredeni_ucastnici" "soustredeni_ucastnici"
], ],
[ [
"delete_soustredeni_ucastnici", "change_soustredeni_ucastnici",
"soustredeni", "soustredeni",
"soustredeni_ucastnici" "soustredeni_ucastnici"
], ],
[ [
"change_soustredeni_ucastnici", "delete_soustredeni_ucastnici",
"soustredeni", "soustredeni",
"soustredeni_ucastnici" "soustredeni_ucastnici"
], ],
@ -414,12 +424,12 @@
"tag" "tag"
], ],
[ [
"delete_tag", "change_tag",
"taggit", "taggit",
"tag" "tag"
], ],
[ [
"change_tag", "delete_tag",
"taggit", "taggit",
"tag" "tag"
], ],
@ -434,12 +444,12 @@
"taggeditem" "taggeditem"
], ],
[ [
"delete_taggeditem", "change_taggeditem",
"taggit", "taggit",
"taggeditem" "taggeditem"
], ],
[ [
"change_taggeditem", "delete_taggeditem",
"taggit", "taggit",
"taggeditem" "taggeditem"
], ],
@ -454,12 +464,12 @@
"cislo" "cislo"
], ],
[ [
"delete_cislo", "change_cislo",
"tvorba", "tvorba",
"cislo" "cislo"
], ],
[ [
"change_cislo", "delete_cislo",
"tvorba", "tvorba",
"cislo" "cislo"
], ],
@ -474,12 +484,12 @@
"clanek" "clanek"
], ],
[ [
"delete_clanek", "change_clanek",
"tvorba", "tvorba",
"clanek" "clanek"
], ],
[ [
"change_clanek", "delete_clanek",
"tvorba", "tvorba",
"clanek" "clanek"
], ],
@ -509,12 +519,12 @@
"pohadka" "pohadka"
], ],
[ [
"delete_pohadka", "change_pohadka",
"tvorba", "tvorba",
"pohadka" "pohadka"
], ],
[ [
"change_pohadka", "delete_pohadka",
"tvorba", "tvorba",
"pohadka" "pohadka"
], ],
@ -529,12 +539,12 @@
"problem" "problem"
], ],
[ [
"delete_problem", "change_problem",
"tvorba", "tvorba",
"problem" "problem"
], ],
[ [
"change_problem", "delete_problem",
"tvorba", "tvorba",
"problem" "problem"
], ],
@ -549,12 +559,12 @@
"rocnik" "rocnik"
], ],
[ [
"delete_rocnik", "change_rocnik",
"tvorba", "tvorba",
"rocnik" "rocnik"
], ],
[ [
"change_rocnik", "delete_rocnik",
"tvorba", "tvorba",
"rocnik" "rocnik"
], ],
@ -569,12 +579,12 @@
"tema" "tema"
], ],
[ [
"delete_tema", "change_tema",
"tvorba", "tvorba",
"tema" "tema"
], ],
[ [
"change_tema", "delete_tema",
"tvorba", "tvorba",
"tema" "tema"
], ],
@ -589,12 +599,12 @@
"uloha" "uloha"
], ],
[ [
"delete_uloha", "change_uloha",
"tvorba", "tvorba",
"uloha" "uloha"
], ],
[ [
"change_uloha", "delete_uloha",
"tvorba", "tvorba",
"uloha" "uloha"
], ],
@ -609,12 +619,12 @@
"nastaveni" "nastaveni"
], ],
[ [
"delete_nastaveni", "change_nastaveni",
"various", "various",
"nastaveni" "nastaveni"
], ],
[ [
"change_nastaveni", "delete_nastaveni",
"various", "various",
"nastaveni" "nastaveni"
], ],

View file

@ -57,6 +57,7 @@ DOBA_ODHLASENI_PRI_ZASKRTNUTI_NEODHLASOVAT = 365 * 24 * 3600 # rok
CSRF_FAILURE_VIEW = 'various.views.csrf.csrf_error' CSRF_FAILURE_VIEW = 'various.views.csrf.csrf_error'
# Modules configuration # Modules configuration
FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',

View file

@ -4,7 +4,7 @@ from reversion.admin import VersionAdmin
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.html import escape from django.utils.html import escape
from .models import Prednaska, Seznam, STAV_NAVRH from .models import Prednaska, Seznam, Znalost
from soustredeni.models import Soustredeni from soustredeni.models import Soustredeni
@ -64,14 +64,14 @@ admin.site.register(Seznam, SeznamAdmin)
class PrednaskaAdmin(VersionAdmin): class PrednaskaAdmin(VersionAdmin):
list_display = ['nazev', 'org', 'obor'] list_display = ['nazev', 'org', 'obor']
list_filter = ['org', 'obor'] list_filter = ['org', 'obor']
search_fields = [] search_fields = ['nazev']
filter_horizontal = ('seznamy', ) filter_horizontal = ('seznamy', )
actions = ['move_to_soustredeni'] actions = ['move_to_soustredeni']
def move_to_soustredeni(self, request, queryset): def move_to_soustredeni(self, request, queryset):
sous = Soustredeni.objects.first() sous = Soustredeni.objects.first()
seznam = Seznam.objects.filter(soustredeni=sous, stav=STAV_NAVRH) seznam = Seznam.objects.filter(soustredeni=sous, stav=Seznam.Stav.NAVRH)
if len(seznam) == 0: if len(seznam) == 0:
self.message_user( self.message_user(
request, request,
@ -97,3 +97,10 @@ class PrednaskaAdmin(VersionAdmin):
admin.site.register(Prednaska, PrednaskaAdmin) admin.site.register(Prednaska, PrednaskaAdmin)
class ZnalostAdmin(PrednaskaAdmin): # Trochu hack, ať nemusím vypisovat všechno znovu
list_display = ("__str__",)
list_filter = ()
admin.site.register(Znalost, ZnalostAdmin)

View file

@ -1,7 +1,15 @@
from django import forms from django import forms
class NewPrednaskyForm(forms.Form): from .models import Hlasovani, HlasovaniOZnalostech
ucastnik = forms.CharField(label = 'Tvoje jméno', max_length = 100)
class HlasovaniPrednaskaForm(forms.Form):
prednaska_id = forms.IntegerField(widget=forms.HiddenInput)
body = forms.ChoiceField(label=False, widget=forms.RadioSelect, choices=Hlasovani.Body.choices, initial=Hlasovani.Body.JEDNO)
HlasovaniPrednaskaFormSet = forms.formset_factory(HlasovaniPrednaskaForm, extra=0)
class HlasovaniZnalostiForm(forms.Form):
znalost_id = forms.IntegerField(widget=forms.HiddenInput)
odpoved = forms.ChoiceField(label=False, widget=forms.RadioSelect, choices=HlasovaniOZnalostech.Odpoved.choices)
HlasovaniZnalostiFormSet = forms.formset_factory(HlasovaniZnalostiForm, extra=0)

View file

@ -0,0 +1,39 @@
# Generated by Django 4.2.16 on 2025-01-24 13:41
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('personalni', '0019_rename_upozorneni_resitel_upozornovat_na_opravy_reseni'),
('prednasky', '0018_post_split_soustredeni'),
]
operations = [
migrations.CreateModel(
name='Znalost',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nazev', models.CharField(help_text='Např. Neuronové sítě', max_length=200, verbose_name='Nadpis')),
('text', models.TextField(blank=True, help_text='Např. Perceptron, vrstevnatá síť, forward a backward propagation', null=True, verbose_name='Detailní popis')),
('seznamy', models.ManyToManyField(to='prednasky.seznam')),
],
options={
'verbose_name': 'Znalost k přednáškám',
'verbose_name_plural': 'Znalosti k přednáškám',
'db_table': 'prednasky_znalost',
},
),
migrations.CreateModel(
name='HlasovaniOZnalostech',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('odpoved', models.CharField(choices=[(-1, 'Tohle celkem umím'), (0, 'Už jsem o tom slyšel, ale neřekl bychm, že to úplně umím'), (1, 'Tohle vůbec neznám')], max_length=16, verbose_name='odpověď')),
('seznam', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='prednasky.seznam')),
('ucastnik', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='personalni.osoba')),
('znalost', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='prednasky.znalost')),
],
),
]

View file

@ -1,81 +1,105 @@
from django.db import models from django.db import models
from soustredeni.models import Soustredeni from soustredeni.models import Soustredeni
from personalni.models import Organizator from personalni.models import Organizator, Osoba
STAV_NAVRH = 1
STAV_BUDE = 2
STAV_CHOICES = (
(STAV_NAVRH, 'Návrh'),
(STAV_BUDE, 'Bude')
)
class Seznam(models.Model): class Seznam(models.Model):
class Meta: class Meta:
db_table = 'prednasky_seznam' db_table = "prednasky_seznam"
verbose_name = 'Seznam přednášek' verbose_name = "Seznam přednášek"
verbose_name_plural = 'Seznamy přednášek' verbose_name_plural = "Seznamy přednášek"
ordering = ['soustredeni', 'stav'] ordering = ["soustredeni", "stav"]
id = models.AutoField(primary_key = True) class Stav(models.IntegerChoices):
soustredeni = models.ForeignKey(Soustredeni,null = True, default = None, NAVRH = 1, "Návrh"
on_delete=models.PROTECT) BUDE = 2, "Bude"
stav = models.IntegerField('Stav',choices=STAV_CHOICES,default = STAV_NAVRH)
id = models.AutoField(primary_key=True)
soustredeni = models.ForeignKey(Soustredeni, null=True, default=None, on_delete=models.PROTECT)
stav = models.IntegerField("Stav", choices=Stav.choices, default=Stav.NAVRH)
def __str__(self): def __str__(self):
return "Seznam {}přednášek na {}".format("návrhů " return f"Seznam {"návrhů " if self.stav == Seznam.Stav.NAVRH else ""}přednášek na {self.soustredeni}"
if self.stav == STAV_NAVRH else "", self.soustredeni)
CHOICES_OBTIZNOST = (
(1, 'Lehká'),
(2, 'Střední'),
(3, 'Těžká'),
)
CHOICES_BODY = (
(-1, '-1'),
(0, '0'),
(1, '1'),
)
class Prednaska(models.Model): class Prednaska(models.Model):
class Meta: class Meta:
db_table = 'prednasky_prednaska' db_table = "prednasky_prednaska"
verbose_name = 'Přednáška' verbose_name = "Přednáška"
verbose_name_plural = 'Přednášky' verbose_name_plural = "Přednášky"
ordering = ['org', 'nazev'] ordering = ["org", "nazev"]
id = models.AutoField(primary_key = True) class Obtiznost(models.IntegerChoices):
nazev = models.CharField('Název', max_length = 300) LEHKA = 1, "Lehká"
org = models.ForeignKey(Organizator, on_delete=models.PROTECT) STREDNI = 2, "Střední"
popis = models.TextField('Popis pro orgy',null = True, blank = True,help_text = 'Neveřejný popis pro ostatní orgy') TEZKA = 3, "Těžká"
anotace = models.TextField('Anotace',null = True, blank = True, help_text = 'Veřejná anotace v hlasování')
obtiznost = models.IntegerField('Obtížnost', choices=CHOICES_OBTIZNOST) id = models.AutoField(primary_key=True)
obor = models.CharField('Obor', max_length = 5, help_text = 'Podmnožina MFIOB') nazev = models.CharField("Název", max_length=300)
klicova = models.CharField('Klíčová slova', max_length = 200, null = True, blank = True) org = models.ForeignKey(Organizator, on_delete=models.PROTECT)
popis = models.TextField("Popis pro orgy", null=True, blank=True, help_text="Neveřejný popis pro ostatní orgy")
anotace = models.TextField("Anotace", null=True, blank=True, help_text="Veřejná anotace v hlasování")
obtiznost = models.IntegerField("Obtížnost", choices=Obtiznost.choices)
obor = models.CharField("Obor", max_length=5, help_text="Podmnožina MFIOB")
klicova = models.CharField("Klíčová slova", max_length=200, null=True, blank=True)
seznamy = models.ManyToManyField(Seznam) seznamy = models.ManyToManyField(Seznam)
def __str__(self): def __str__(self):
return "{} ({})".format(self.nazev, self.org) return f"{self.nazev} ({self.org})"
class Hlasovani(models.Model): class Hlasovani(models.Model):
class Meta: class Meta:
db_table = 'prednasky_hlasovani' db_table = "prednasky_hlasovani"
verbose_name = 'Hlasování' verbose_name = "Hlasování"
verbose_name_plural = 'Hlasování' verbose_name_plural = "Hlasování"
ordering = ['ucastnik', 'prednaska'] ordering = ["ucastnik", "prednaska"]
id = models.AutoField(primary_key = True)
class Body(models.IntegerChoices):
NECHCI = -1, "rozhodně nechci"
JEDNO = 0, "je mi to jedno"
CHCI = 1, "rozhodně chci"
id = models.AutoField(primary_key=True)
prednaska = models.ForeignKey(Prednaska, on_delete=models.CASCADE) prednaska = models.ForeignKey(Prednaska, on_delete=models.CASCADE)
body = models.IntegerField('Body', default = 0, choices = CHOICES_BODY) body = models.IntegerField("Body", default=Body.JEDNO, choices=Body.choices)
ucastnik = models.CharField('Účastník', max_length = 100)
seznam = models.ForeignKey(Seznam,null=True,on_delete=models.SET_NULL) # (přechod z jména na objekt Osoby nějak kape na tom,
# že všechna předchozí hlasování zde mají náhodný string…)
# TODO Změnit to na Osobu
ucastnik = models.CharField("Účastník", max_length=100)
seznam = models.ForeignKey(Seznam, null=True, on_delete=models.SET_NULL)
def __str__(self): def __str__(self):
return "{} dal {} bodů {} v seznamu {}".format(self.ucastnik, return f"{self.ucastnik} dal {self.body} bodů {self.prednaska} v seznamu {self.seznam}"
self.body, self.prednaska, self.seznam)
class Znalost(models.Model):
class Meta:
db_table = "prednasky_znalost"
verbose_name = "Znalost k přednáškám"
verbose_name_plural = "Znalosti k přednáškám"
nazev = models.CharField("Nadpis", max_length=200, blank=False, null=False, help_text="Např. Neuronové sítě")
text = models.TextField("Detailní popis", blank=True, null=True, help_text="Např. Perceptron, vrstevnatá síť, forward a backward propagation")
seznamy = models.ManyToManyField(Seznam)
def __str__(self):
return self.nazev
class HlasovaniOZnalostech(models.Model):
class Odpoved(models.IntegerChoices):
UMIM = -1, "Tohle celkem umím"
CIRCA = 0, "Už jsem o tom slyšel, ale neřekl bychm, že to úplně umím"
NEUMIM = 1, "Tohle vůbec neznám"
odpoved = models.CharField(u"odpověď", max_length=16, choices=Odpoved.choices, blank=False, null=False)
znalost = models.ForeignKey(Znalost, on_delete=models.CASCADE, blank=False, null=False)
ucastnik = models.ForeignKey(Osoba, on_delete=models.CASCADE, blank=False, null=False)
seznam = models.ForeignKey(Seznam, on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return f"{self.ucastnik} dal {self.znalost} bodů {self.znalost} v seznamu {self.seznam}"

View file

@ -5,36 +5,36 @@
{% block content %} {% block content %}
<h1> <h1>{% block nadpis1a %}Hlasování o přednáškách{% endblock %}</h1>
{% block nadpis1a %}Hlasování o přednáškách{% endblock %}
</h1>
<p>
Jak moc by ses chtěl(a) zúčastnit následujících přednášek?
<br>
<span style="font-size: 75%">Obtížnost 1 je nejlehčí, 3 nejtěžší.</span>
</p>
<form enctype="multipart/form-data" action="." method="post"> <form enctype="multipart/form-data" action="." method="post">
{% csrf_token %} {% csrf_token %}
<table>
{% for p, h in prednasky %} <h3>Jak moc by ses chtěl(a) zúčastnit následujících přednášek?</h3>
<tr><td><label>{{p.org}}: <span style="font-size: 175%">{{p.nazev}}</span></label></td></tr> <p>Obtížnost 1 je nejlehčí, 3 nejtěžší.</p>
<tr><td><p><i>{{p.anotace}}</i></p></td></tr> {{ form_set_prednasky.management_form }}
<tr><td><label>Obor: </label> {{p.obor}}</td></tr> {% for f, p in formy_a_prednasky %}
<tr><td><label>Obtížnost: </label> {{p.obtiznost}}</td> </tr> <h4>{{p.nazev}} ({{p.org}})</h4>
{% if p.klicova %}<tr><td><label>Klíčová slova: </label> {{p.klicova}}</td></tr>{% endif%} <p class="textprednasky">{{p.anotace}}</p>
<tr><td>Hodnocení: <label>Obor: </label> {{p.obor}}<br>
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="-1" {% if h == -1 %} CHECKED="checked" {% endif %} > rozhodně nechci <label>Obtížnost: </label> {{p.obtiznost}}<br>
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="0" {% if h == 0 %} CHECKED="checked" {% endif %}> je mi to jedno {% if p.klicova %}<label>Klíčová slova: </label> {{p.klicova}}<br>{% endif%}
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci <br>
</td></tr> {{ f }}
<tr><td>&nbsp;</td></tr> <br>
{% empty %} {% empty %}
Nejsou žádné přednášky o kterých by šlo hlasovat. Nejsou žádné přednášky o kterých by šlo hlasovat.
{% endfor %} {% endfor %}
<tr><td><input name="odeslat" type="submit" value="Odeslat"></td><tr>
</table> {{ form_set_znalosti.management_form }}
{% for f, z in formy_a_znalosti %}
{% if forloop.first %}<hr/><h3>Jak moc znáš následující?</h3>{% endif %}
<h4>{{z.nazev}}</h4>
<p class="textznalosti">{{z.text}}</p>
{{ f }}
<br>
{% endfor %}
<input type="submit" value="Odeslat"/>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -14,7 +14,7 @@
{% else %} {% else %}
<a href="/prednasky/seznam_prednasek/{{seznam.id}}">Seznam přednášek na soustředění {{seznam.soustredeni.misto}} </a> <a href="/prednasky/seznam_prednasek/{{seznam.id}}">Seznam přednášek na soustředění {{seznam.soustredeni.misto}} </a>
{% endif %} {% endif %}
<a href="/prednasky/seznam_prednasek/{{seznam.id}}/export">Export</a> <a href="/prednasky/seznam_prednasek/{{seznam.id}}/hlasovani.csv">Export</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View file

@ -12,10 +12,15 @@ urlpatterns = [
'prednasky/metaseznam_prednasek', 'prednasky/metaseznam_prednasek',
org_required(views.MetaSeznamListView.as_view()), org_required(views.MetaSeznamListView.as_view()),
name='metaseznam-list'), name='metaseznam-list'),
# path(
# 'prednasky/seznam_prednasek/<int:seznam>/export',
# org_required(views.SeznamExportView),
# name='seznam-export'
# ),
path( path(
'prednasky/seznam_prednasek/<int:seznam>/export', 'prednasky/seznam_prednasek/<int:seznam>/hlasovani.csv',
org_required(views.SeznamExportView), org_required(views.PrednaskyExportView),
name='seznam-export' name='seznam-export-csv'
), ),
path( path(
'prednasky/seznam_prednasek/<int:seznam>/', 'prednasky/seznam_prednasek/<int:seznam>/',

View file

@ -1,65 +1,112 @@
import csv
import http import http
import logging
from django.http import HttpResponse
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
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Sum from django.db import transaction
from django.forms import Form
from various.views.pomocne import formularOKView from various.views.pomocne import formularOKView
from .forms import HlasovaniPrednaskaFormSet, HlasovaniZnalostiFormSet
from various.models import Nastaveni from various.models import Nastaveni
from prednasky.models import Prednaska, Hlasovani, Seznam, STAV_NAVRH from prednasky.models import Prednaska, Hlasovani, Znalost, HlasovaniOZnalostech, Seznam
from soustredeni.models import Soustredeni from soustredeni.models import Soustredeni
from personalni.models import Osoba from personalni.models import Osoba
PREDNASKY_PREFIX = "prednasky"
ZNALOSTI_PREFIX = "znalosti"
logger = logging.getLogger(__name__)
def newPrednaska(request): def newPrednaska(request):
# hlasovani se vztahuje k nejnovejsimu soustredeni # hlasovani se vztahuje k nejnovejsimu soustredeni
sous = Nastaveni.get_solo().aktualni_sous sous = Nastaveni.get_solo().aktualni_sous
seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() seznam = Seznam.objects.filter(soustredeni = sous, stav=Seznam.Stav.NAVRH).first()
if sous is None or seznam is None: if sous is None or seznam is None:
return render(request, 'universal.html', { return render(request, 'universal.html', {
'title': "Nelze hlasovat", 'title': "Nelze hlasovat",
'text': "Není žádný seznam přednášek, o kterém by se dalo hlasovat.", 'text': "Není žádný seznam přednášek, o kterém by se dalo hlasovat.",
}, status=http.HTTPStatus.NOT_FOUND) }, 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) # id, kvůli kolizi jmen
# obsluha formulare
if request.method == 'POST': if request.method == 'POST':
form = Form(request.POST, request.FILES) form_set_prednasky = HlasovaniPrednaskaFormSet(request.POST, prefix=PREDNASKY_PREFIX)
if form.is_valid(): form_set_znalosti = HlasovaniZnalostiFormSet(request.POST, prefix=ZNALOSTI_PREFIX)
# id z důvodu duplicitních jmen (přechod z jména na objekt Osoby nějak kape na tom,
# že všechna předchozí hlasování zde mají náhodný string…)
# TODO Změnit to na Osobu
# TODO v následujících řádcích je zbytečně mnoho dotazů na QuerySet (pokud účastník hlasoval, hlasoval u všech) if form_set_prednasky.is_valid() and form_set_znalosti.is_valid():
for i in request.POST: with transaction.atomic():
if i[0] == 'q': seznam.hlasovani_set.filter(ucastnik=ucastnik).delete()
prednaska = Prednaska.objects.filter(pk=int(i[1:]))[0] seznam.hlasovanioznalostech_set.filter(ucastnik=osoba).delete()
hlasovani = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if not hlasovani: for form in form_set_prednasky:
hlasovani = Hlasovani() prednaska_id = form.cleaned_data['prednaska_id']
hlasovani.prednaska = prednaska prednaska = Prednaska.objects.filter(id=prednaska_id).first()
hlasovani.ucastnik = ucastnik if prednaska is None:
hlasovani.seznam = seznam logger.error(f"Účastník {ucastnik} hodnotil neexistující přednášku {prednaska_id} číslem {form.cleaned_data['body']}")
hlasovani.body = int(request.POST[i]) continue
hlasovani.save()
Hlasovani.objects.create(
prednaska=prednaska,
body=form.cleaned_data['body'],
ucastnik=ucastnik,
seznam=seznam,
)
for form in form_set_znalosti:
znalost_id = form.cleaned_data['znalost_id']
znalost = Znalost.objects.filter(id=znalost_id).first()
if znalost is None:
logger.error(f"Účastník {ucastnik} hodnotil neexistující znalost {znalost_id} číslem {form.cleaned_data['odpoved']}")
continue
HlasovaniOZnalostech.objects.create(
odpoved=form.cleaned_data['odpoved'],
znalost=znalost,
ucastnik=osoba,
seznam=seznam,
)
# presmerovani na prave vzniklou galerii
return HttpResponseRedirect('./hotovo') return HttpResponseRedirect('./hotovo')
def prednaska_hodnoceni(prednaska):
h = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if h:
return prednaska, h.body
else: else:
return prednaska, 0 prednasky = seznam.prednaska_set.all()
znalosti = seznam.znalost_set.all()
# Spadnout, pokud nesedí přednáška/znalost s formulářem. (Nějak se mi to nepovedlo.)
else:
def odpoved_prednasky(p):
hlasovani = p.hlasovani_set.filter(ucastnik=ucastnik).first()
return hlasovani.body if hlasovani else Hlasovani.Body.JEDNO
def odpoved_znalosti(z):
hlasovani = z.hlasovanioznalostech_set.filter(ucastnik=osoba).first()
return hlasovani.odpoved if hlasovani else Hlasovani.Body.JEDNO
prednasky = seznam.prednaska_set.all()
znalosti = seznam.znalost_set.all()
form_set_prednasky = HlasovaniPrednaskaFormSet(initial=[
{"prednaska_id": p.id, "body": odpoved_prednasky(p)} for p in prednasky
], prefix=PREDNASKY_PREFIX)
form_set_znalosti = HlasovaniZnalostiFormSet(initial=[
{"znalost_id": z.id, "odpoved": odpoved_znalosti(z)} for z in znalosti
], prefix=ZNALOSTI_PREFIX)
return render( return render(
request, request,
'prednasky/base.html', 'prednasky/base.html',
{'prednasky': map(prednaska_hodnoceni, seznam.prednaska_set.all())} {
'form_set_prednasky': form_set_prednasky, 'form_set_znalosti': form_set_znalosti,
'formy_a_prednasky': zip(form_set_prednasky, prednasky),
'formy_a_znalosti': zip(form_set_znalosti, znalosti),
}
) )
@ -87,7 +134,7 @@ class SeznamListView(generic.ListView):
# hlasovani se vztahuje k nejnovejsimu soustredeni # hlasovani se vztahuje k nejnovejsimu soustredeni
sous = Soustredeni.objects.first() sous = Soustredeni.objects.first()
seznam = Seznam.objects.filter(soustredeni = sous, stav = STAV_NAVRH).first() seznam = Seznam.objects.filter(soustredeni = sous, stav=Seznam.Stav.NAVRH).first()
for obj in self.object_list: for obj in self.object_list:
hlasovani_set = obj.hlasovani_set.filter(seznam=seznam).only('body') hlasovani_set = obj.hlasovani_set.filter(seznam=seznam).only('body')
@ -96,32 +143,76 @@ class SeznamListView(generic.ListView):
return context return context
def SeznamExportView(request, seznam): # def SeznamExportView(request, seznam):
"""Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor""" # """Vypíše výsledky hlasování ve formátu pro prologovský optimalizátor"""
# TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro # # TODO zřejmě se nepoužívá, časem vyřadit? nahradit tabulkou vhodnější pro
# lidi? # # lidi?
hlasovani = Hlasovani.objects.filter(seznam=seznam) # hlasovani = Hlasovani.objects.filter(seznam=seznam)
prednasky = Prednaska.objects.filter(seznamy=seznam) # prednasky = Prednaska.objects.filter(seznamy=seznam)
orgove = set(p.org for p in prednasky) # orgove = set(p.org for p in prednasky)
ucastnici = set(h.ucastnik for h in hlasovani) # ucastnici = set(h.ucastnik for h in hlasovani)
#
# for p in prednasky:
# p.body = []
# for u in ucastnici:
# try:
# p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body)
# except ObjectDoesNotExist:
# # účastník nehlasoval
# p.body.append("?")
#
# for h in hlasovani:
# h.ucastnik = hash(h.ucastnik)
#
# return render(
# request,
# 'prednasky/seznam_prednasek_export.txt',
# {"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove},
# content_type="text/plain"
# )
for p in prednasky:
p.body = [] def PrednaskyExportView(request, seznam: int, **kwargs):
for u in ucastnici: hlasovani = Hlasovani.objects.filter(seznam=seznam).select_related("prednaska")
try: hlasovani_o_znalostech = HlasovaniOZnalostech.objects.filter(seznam=seznam).select_related('ucastnik', 'znalost')
p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body)
except ObjectDoesNotExist: prednasky = list(Prednaska.objects.filter(seznamy=seznam))
# účastník nehlasoval znalosti = list(Znalost.objects.filter(seznamy=seznam))
p.body.append("?")
prednasky_map: dict[int, int] = {p.id: i for i, p in enumerate(prednasky, 1)}
offset = len(prednasky_map)
znalosti_map: dict[int, int] = {z.id: i for i, z in enumerate(znalosti, offset + 1)}
width = offset + len(znalosti_map)
table: [str, list[str|Prednaska|Znalost,]] = {}
for h in hlasovani: for h in hlasovani:
h.ucastnik = hash(h.ucastnik) if h.ucastnik not in table:
table[h.ucastnik] = [h.ucastnik] + ([""] * width)
return render( if h.prednaska.id in prednasky_map:
request, table[h.ucastnik][prednasky_map[h.prednaska.id]] = h.body
'prednasky/seznam_prednasek_export.txt', else:
{"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove}, pass # Padat hlasitě?
content_type="text/plain"
) for h in hlasovani_o_znalostech:
ucastnik = str(h.ucastnik) + ' ' + str(h.ucastnik.id) # id, kvůli kolizi jmen
if ucastnik not in table:
table[ucastnik] = [ucastnik] + ([""] * width)
if h.znalost.id in znalosti_map:
table[ucastnik][znalosti_map[h.znalost.id]] = h.odpoved
else:
pass # Padat hlasitě?
response = HttpResponse(content_type="text/csv", charset="utf-8")
response["Content-Disposition"] = 'attachment; filename="hlasovani.csv"'
writer = csv.writer(response)
writer.writerow(["jména \\ přednáška|znalost"] + list(map(str, prednasky + znalosti)))
for row in table.values():
writer.writerow(list(map(str, row)))
return response