WIP: Přednášky #87

Draft
zelvuska wants to merge 13 commits from prednasky into master
12 changed files with 421 additions and 213 deletions

View file

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

View file

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

View file

@ -503,5 +503,10 @@ label[for=id_skola] {
font-weight: bold;
}
/* Přednášky */
.textznalosti, .textprednasky {
font-style: italic;
}
/*******************/

View file

@ -4,7 +4,7 @@ from reversion.admin import VersionAdmin
from django.utils.safestring import mark_safe
from django.utils.html import escape
from .models import Prednaska, Seznam, STAV_NAVRH
from .models import Prednaska, Seznam, Znalost
from soustredeni.models import Soustredeni
@ -64,14 +64,14 @@ admin.site.register(Seznam, SeznamAdmin)
class PrednaskaAdmin(VersionAdmin):
list_display = ['nazev', 'org', 'obor']
list_filter = ['org', 'obor']
search_fields = []
search_fields = ['nazev']
filter_horizontal = ('seznamy', )
actions = ['move_to_soustredeni']
def move_to_soustredeni(self, request, queryset):
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:
self.message_user(
request,
@ -97,3 +97,10 @@ class PrednaskaAdmin(VersionAdmin):
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
class NewPrednaskyForm(forms.Form):
ucastnik = forms.CharField(label = 'Tvoje jméno', max_length = 100)
from .models import Hlasovani, HlasovaniOZnalostech
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

@ -0,0 +1,18 @@
# Generated by Django 4.2.16 on 2025-01-24 20:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('prednasky', '0019_znalost_hlasovanioznalostech'),
]
operations = [
migrations.AlterField(
model_name='hlasovani',
name='body',
field=models.IntegerField(choices=[(-1, 'rozhodně nechci'), (0, 'je mi to jedno'), (1, 'rozhodně chci')], default=0, verbose_name='Body'),
),
]

View file

@ -1,81 +1,105 @@
from django.db import models
from soustredeni.models import Soustredeni
from personalni.models import Organizator
STAV_NAVRH = 1
STAV_BUDE = 2
STAV_CHOICES = (
(STAV_NAVRH, 'Návrh'),
(STAV_BUDE, 'Bude')
)
from personalni.models import Organizator, Osoba
class Seznam(models.Model):
class Meta:
db_table = 'prednasky_seznam'
verbose_name = 'Seznam přednášek'
verbose_name_plural = 'Seznamy přednášek'
ordering = ['soustredeni', 'stav']
db_table = "prednasky_seznam"
verbose_name = "Seznam přednášek"
verbose_name_plural = "Seznamy přednášek"
ordering = ["soustredeni", "stav"]
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)
class Stav(models.IntegerChoices):
NAVRH = 1, "Návrh"
BUDE = 2, "Bude"
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):
return "Seznam {}přednášek na {}".format("návrhů "
if self.stav == STAV_NAVRH else "", self.soustredeni)
return f"Seznam {'návrhů ' if self.stav == Seznam.Stav.NAVRH else ''}přednášek na {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 Meta:
db_table = 'prednasky_prednaska'
verbose_name = 'Přednáška'
verbose_name_plural = 'Přednášky'
ordering = ['org', 'nazev']
db_table = "prednasky_prednaska"
verbose_name = "Přednáška"
verbose_name_plural = "Přednášky"
ordering = ["org", "nazev"]
id = models.AutoField(primary_key = True)
nazev = models.CharField('Název', max_length = 300)
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=CHOICES_OBTIZNOST)
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)
class Obtiznost(models.IntegerChoices):
LEHKA = 1, "Lehká"
STREDNI = 2, "Střední"
TEZKA = 3, "Těžká"
id = models.AutoField(primary_key=True)
nazev = models.CharField("Název", max_length=300)
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)
def __str__(self):
return "{} ({})".format(self.nazev, self.org)
return f"{self.nazev} ({self.org})"
class Hlasovani(models.Model):
class Meta:
db_table = 'prednasky_hlasovani'
verbose_name = 'Hlasování'
verbose_name_plural = 'Hlasování'
ordering = ['ucastnik', 'prednaska']
id = models.AutoField(primary_key = True)
db_table = "prednasky_hlasovani"
verbose_name = "Hlasování"
verbose_name_plural = "Hlasování"
ordering = ["ucastnik", "prednaska"]
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)
body = models.IntegerField('Body', default = 0, choices = CHOICES_BODY)
ucastnik = models.CharField('Účastník', max_length = 100)
seznam = models.ForeignKey(Seznam,null=True,on_delete=models.SET_NULL)
body = models.IntegerField("Body", default=Body.JEDNO, choices=Body.choices)
# (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):
return "{} dal {} bodů {} v seznamu {}".format(self.ucastnik,
self.body, self.prednaska, self.seznam)
return f"{self.ucastnik} dal {self.body} bodů {self.prednaska} v seznamu {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 %}
<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>
<h1>{% block nadpis1a %}Hlasování o přednáškách{% endblock %}</h1>
<form enctype="multipart/form-data" action="." method="post">
{% csrf_token %}
<table>
{% for p, h in prednasky %}
<tr><td><label>{{p.org}}: <span style="font-size: 175%">{{p.nazev}}</span></label></td></tr>
<tr><td><p><i>{{p.anotace}}</i></p></td></tr>
<tr><td><label>Obor: </label> {{p.obor}}</td></tr>
<tr><td><label>Obtížnost: </label> {{p.obtiznost}}</td> </tr>
{% if p.klicova %}<tr><td><label>Klíčová slova: </label> {{p.klicova}}</td></tr>{% endif%}
<tr><td>Hodnocení:
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="-1" {% if h == -1 %} CHECKED="checked" {% endif %} > rozhodně nechci
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="0" {% if h == 0 %} CHECKED="checked" {% endif %}> je mi to jedno
<INPUT TYPE="radio" NAME="q{{p.pk}}" VALUE="1" {% if h == 1 %} CHECKED="checked" {% endif %}> rozhodně chci
</td></tr>
<tr><td>&nbsp;</td></tr>
{% empty %}
Nejsou žádné přednášky o kterých by šlo hlasovat.
{% endfor %}
<tr><td><input name="odeslat" type="submit" value="Odeslat"></td><tr>
</table>
<h3>Jak moc by ses chtěl(a) zúčastnit následujících přednášek?</h3>
<p>Obtížnost 1 je nejlehčí, 3 nejtěžší.</p>
{{ form_set_prednasky.management_form }}
{% for f, p in formy_a_prednasky %}
<h4>{{p.nazev}} ({{p.org}})</h4>
<p class="textprednasky">{{p.anotace}}</p>
<label>Obor: </label> {{p.obor}}<br>
<label>Obtížnost: </label> {{p.obtiznost}}<br>
{% if p.klicova %}<label>Klíčová slova: </label> {{p.klicova}}<br>{% endif%}
<br>
{{ f }}
<br>
{% empty %}
Nejsou žádné přednášky o kterých by šlo hlasovat.
{% endfor %}
{{ 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>
{% endblock %}

View file

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

View file

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

View file

@ -1,65 +1,112 @@
import csv
import http
import logging
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.views import generic
from django.shortcuts import HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Sum
from django.forms import Form
from django.db import transaction
from various.views.pomocne import formularOKView
from .forms import HlasovaniPrednaskaFormSet, HlasovaniZnalostiFormSet
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 personalni.models import Osoba
PREDNASKY_PREFIX = "prednasky"
ZNALOSTI_PREFIX = "znalosti"
logger = logging.getLogger(__name__)
def newPrednaska(request):
# hlasovani se vztahuje k nejnovejsimu soustredeni
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:
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()
ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id)
# obsluha formulare
ucastnik = osoba.plne_jmeno() + ' ' + str(osoba.id) # id, kvůli kolizi jmen
if request.method == 'POST':
form = Form(request.POST, request.FILES)
if form.is_valid():
# 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
form_set_prednasky = HlasovaniPrednaskaFormSet(request.POST, prefix=PREDNASKY_PREFIX)
form_set_znalosti = HlasovaniZnalostiFormSet(request.POST, prefix=ZNALOSTI_PREFIX)
# TODO v následujících řádcích je zbytečně mnoho dotazů na QuerySet (pokud účastník hlasoval, hlasoval u všech)
for i in request.POST:
if i[0] == 'q':
prednaska = Prednaska.objects.filter(pk=int(i[1:]))[0]
hlasovani = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if not hlasovani:
hlasovani = Hlasovani()
hlasovani.prednaska = prednaska
hlasovani.ucastnik = ucastnik
hlasovani.seznam = seznam
hlasovani.body = int(request.POST[i])
hlasovani.save()
if form_set_prednasky.is_valid() and form_set_znalosti.is_valid():
with transaction.atomic():
seznam.hlasovani_set.filter(ucastnik=ucastnik).delete()
seznam.hlasovanioznalostech_set.filter(ucastnik=osoba).delete()
for form in form_set_prednasky:
prednaska_id = form.cleaned_data['prednaska_id']
prednaska = Prednaska.objects.filter(id=prednaska_id).first()
if prednaska is None:
logger.error(f"Účastník {ucastnik} hodnotil neexistující přednášku {prednaska_id} číslem {form.cleaned_data['body']}")
continue
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')
def prednaska_hodnoceni(prednaska):
h = Hlasovani.objects.filter(ucastnik=ucastnik, prednaska=prednaska).first()
if h:
return prednaska, h.body
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(
request,
'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
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:
hlasovani_set = obj.hlasovani_set.filter(seznam=seznam).only('body')
@ -96,32 +143,76 @@ class SeznamListView(generic.ListView):
return context
def SeznamExportView(request, seznam):
"""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
# lidi?
hlasovani = Hlasovani.objects.filter(seznam=seznam)
prednasky = Prednaska.objects.filter(seznamy=seznam)
orgove = set(p.org for p in prednasky)
ucastnici = set(h.ucastnik for h in hlasovani)
# def SeznamExportView(request, seznam):
# """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
# # lidi?
# hlasovani = Hlasovani.objects.filter(seznam=seznam)
# prednasky = Prednaska.objects.filter(seznamy=seznam)
# orgove = set(p.org for p in prednasky)
# 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 = []
for u in ucastnici:
try:
p.body.append(hlasovani.get(ucastnik=u, prednaska=p).body)
except ObjectDoesNotExist:
# účastník nehlasoval
p.body.append("?")
def PrednaskyExportView(request, seznam: int, **kwargs):
hlasovani = Hlasovani.objects.filter(seznam=seznam).select_related("prednaska")
hlasovani_o_znalostech = HlasovaniOZnalostech.objects.filter(seznam=seznam).select_related('ucastnik', 'znalost')
prednasky = list(Prednaska.objects.filter(seznamy=seznam))
znalosti = list(Znalost.objects.filter(seznamy=seznam))
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:
h.ucastnik = hash(h.ucastnik)
if h.ucastnik not in table:
table[h.ucastnik] = [h.ucastnik] + ([""] * width)
return render(
request,
'prednasky/seznam_prednasek_export.txt',
{"hlasovani": hlasovani, "prednasky": prednasky, "orgove": orgove},
content_type="text/plain"
)
if h.prednaska.id in prednasky_map:
table[h.ucastnik][prednasky_map[h.prednaska.id]] = h.body
else:
pass # Padat hlasitě?
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