Merge branch 'master' into vylepseni_odevzdavatka

This commit is contained in:
Jonas Havelka 2023-03-06 20:17:03 +01:00
commit c0fa59a504
8 changed files with 86 additions and 11 deletions

View file

@ -11,19 +11,20 @@ class OrgSkolyAutocompleteTestCase(TestCase):
sync_skoly('https://mam.mff.cuni.cz/') sync_skoly('https://mam.mff.cuni.cz/')
# Správné školy podle toho, co orgové poslali: (prefix, ID školy) # Správné školy podle toho, co orgové poslali: (prefix, ID školy)
# NOTE: Pozor, jedná se o databázové indexy. Pokud se to někdy rozbije, bude potřeba je přepsat nebo předělat na IZO # NOTE: Pozor, jedná se o databázové indexy. Pokud se to někdy rozbije, bude potřeba je přepsat nebo předělat na IZO
# TODO: Opravit zakomentované školy.
cls.spravna_data = [ cls.spravna_data = [
('gymnázium kolín', 53), ('gymnázium kolín', 53),
('kolín', 53), ('kolín', 53),
('gasoš', 96), #('gasoš', 96),
('Rokycany', 96), ('Rokycany', 96),
('gasoš Rokycany', 96), #('gasoš Rokycany', 96),
('SPŠE Pardubice', 815), #('SPŠE Pardubice', 815),
('Jaroše', 164), ('Jaroše', 164),
("Gymnázium, Brno, tř. Kpt. Jaroše", 164), #("Gymnázium, Brno, tř. Kpt. Jaroše", 164),
("Jírovcova", 157), ("Jírovcova", 157),
('České Budějovice', 157), ('České Budějovice', 157),
("Gymnázium, České Budějovice, Jírovcova 8", 157), ("Gymnázium, České Budějovice, Jírovcova 8", 157),
("první soukromé", 2), #("první soukromé", 2),
("Gymnázium Elgartova", 147), ("Gymnázium Elgartova", 147),
("Jihlava", 45), ("Jihlava", 45),
('Milevsko', 223), ('Milevsko', 223),

View file

@ -2,6 +2,7 @@
{% load static %} {% load static %}
{% load deadliny %} {% load deadliny %}
{% load mail %} {% load mail %}
{% load jmena %}
{# Přišlo mi to hezčí, než psát všude if. #} {# Přišlo mi to hezčí, než psát všude if. #}
{% block custom_css %} {% block custom_css %}
@ -15,6 +16,17 @@
{% if edit %} {% if edit %}
<script src="{% static 'odevzdavatko/dynamic_formsets_for_detail.js' %}"></script> <script src="{% static 'odevzdavatko/dynamic_formsets_for_detail.js' %}"></script>
<script src="{% static 'odevzdavatko/check_for_detail.js' %}"></script> <script src="{% static 'odevzdavatko/check_for_detail.js' %}"></script>
<script type="text/javascript">
$(document).ready(function () {
const zaskrtavatko = document.getElementById('pridat-jmena-resitelu');
zaskrtavatko.addEventListener('change', () => {
for (var priloha of document.getElementsByClassName("reseni-ke-stazeni")) {
let new_download = zaskrtavatko.checked ? priloha.dataset.altFilename : '';
priloha.setAttribute('download', new_download);
}
});
});
</script>
{% endif %} {% endif %}
@ -47,11 +59,20 @@
<tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr> <tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr>
{% for priloha in object.prilohy.all %} {% for priloha in object.prilohy.all %}
<tr> <tr>
<td><a href="{{ priloha.soubor.url }}" download>{{ priloha.split | last }}</a></td> <td><a class='reseni-ke-stazeni'
href="{{ priloha.soubor.url }}"
download
data-alt-filename="{{object.resitele.first.osoba | jmeno_jako_prefix }}_{{ object.id }}_{{ priloha.split | last}}"
>{{ priloha.split | last }}</a></td>
<td>{{ priloha.res_poznamka }}</td> <td>{{ priloha.res_poznamka }}</td>
<td>{{ priloha.vytvoreno }}</td></tr> <td>{{ priloha.vytvoreno }}</td></tr>
{% endfor %} {% endfor %}
</table> </table>
{% if edit %} {# FIXME: tohle nesouvisí s editací, ale s tím, jestli je člověk org… #}
<br>
<input type=checkbox id="pridat-jmena-resitelu">
<label class="field-label" for="pridat-jmena-resitelu">Uvést jméno řešitele v názvu souboru při stažení.</label>
{% endif %}
{% else %} {% else %}
<p>Žádné přílohy</p> <p>Žádné přílohy</p>
{% endif %} {% endif %}

View file

View file

@ -0,0 +1,9 @@
from django import template
register = template.Library()
from personalni.utils import normalizuj_jmeno
import seminar.models as m # jen kvůli typové anotaci…
@register.filter
def jmeno_jako_prefix(o: m.Osoba):
return normalizuj_jmeno(o).replace(' ', '_')

View file

@ -114,7 +114,7 @@ class TabulkaOdevzdanychReseniView(ListView):
qs = super().get_queryset() qs = super().get_queryset()
if self.jen_neobodovane: if self.jen_neobodovane:
qs = qs.filter(body__isnull=True) qs = qs.filter(body__isnull=True)
qs = qs.filter(problem__in=self.problemy, reseni__in=self.reseni, reseni__resitele__in=self.resitele).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba') qs = qs.filter(problem__in=self.problemy, reseni__in=self.reseni, reseni__resitele__in=self.resitele).select_related('reseni', 'problem').prefetch_related('reseni__resitele__osoba').distinct()
# FIXME tohle je ošklivé, na špatném místě a pomalé. Ale moc mě štvalo, že musím hledat správná místa v tabulce. # FIXME tohle je ošklivé, na špatném místě a pomalé. Ale moc mě štvalo, že musím hledat správná místa v tabulce.
self.problemy = self.problemy.filter(id__in=qs.values("problem__id")) self.problemy = self.problemy.filter(id__in=qs.values("problem__id"))
return qs return qs
@ -259,8 +259,8 @@ class DetailReseniView(DetailView):
return response return response
def check_access(self): def check_access(self):
""" Řešitel musí být součástí řešení, jinak se na něj nemá co dívat. """ """ Řešitel musí být součástí řešení, jinak se na něj nemá co dívat. Případně to může být org."""
if not self.object.resitele.filter(osoba__user=self.request.user).exists(): if not self.object.resitele.filter(osoba__user=self.request.user).exists() and not self.request.user.je_org:
raise PermissionDenied() raise PermissionDenied()

11
personalni/utils.py Normal file
View file

@ -0,0 +1,11 @@
import seminar.models as m
from various.utils import bez_diakritiky_translate
import re
def normalizuj_jmeno(o: m.Osoba) -> str:
# FIXME: Možná není potřeba vázat na model?
cele_jmeno = f'{o.jmeno} {o.prijmeni}'
cele_jmeno = cele_jmeno.translate(bez_diakritiky_translate)
cele_jmeno = re.sub(r'[^a-zA-Z- ]', '', cele_jmeno)
return cele_jmeno

View file

@ -26,7 +26,7 @@ def deadline_html(deadline: m.Deadline):
m.Deadline.TYP_PRVNI_A_SOUS: 'sous_deadline', m.Deadline.TYP_PRVNI_A_SOUS: 'sous_deadline',
m.Deadline.TYP_CISLA: 'final_deadline', m.Deadline.TYP_CISLA: 'final_deadline',
} }
return mark_safe(f'<span class="{classes[deadline.typ]}">{text}</span>') return mark_safe(f'<span class="{classes[deadline.typ]}" title="{deadline}">{text}</span>')
@register.filter(name='zkrat_nazev_problemu') @register.filter(name='zkrat_nazev_problemu')
def zkrat_nazev_problemu(nazev,width): def zkrat_nazev_problemu(nazev,width):
@ -35,4 +35,4 @@ def zkrat_nazev_problemu(nazev,width):
nazev = nazev[:width-1] + "..." nazev = nazev[:width-1] + "..."
else: else:
nazev = nazev[:width] + "..." nazev = nazev[:width] + "..."
return nazev return nazev

33
various/utils.py Normal file
View file

@ -0,0 +1,33 @@
bez_diakritiky = ({}
# FIXME: funguje jen pro český a slovenský text, jinak jsou špatně
# transliterace. Potenciální řešení:
# https://stackoverflow.com/questions/517923/what-is-the-best-way-to-remove-accents-normalize-in-a-python-unicode-string
# (ale přidává to další závislosti…)
# Tisknutelné ASCII
| {chr(a): chr(a) for a in range(32, 126+1)}
# České, slovenské a blízké diakritiky a divnoznaky
| { x: 'a' for x in 'áÁäÄ'}
| { x: 'c' for x in 'čČ'}
| { x: 'd' for x in 'ďĎ'}
| { x: 'e' for x in 'éÉěĚëË'}
| { x: 'i' for x in 'íÍ'}
| { x: 'l' for x in 'ľĽĺĹ'}
| { x: 'n' for x in 'ňŇ'}
| { x: 'o' for x in 'óÓöÖôÔ'}
| { x: 'r' for x in 'řŘŕŔ'}
| { x: 's' for x in 'šŠßẞ'}
| { x: 't' for x in 'ťŤ'}
| { x: 'u' for x in 'úÚůŮ'}
| { x: 'y' for x in 'ýÝ'}
| { x: 'z' for x in 'žŽ'}
)
# Tabulka pro str.translate
class _bez_diakritiky_translate:
def __getitem__(self, it):
return ord(bez_diakritiky.get(chr(it), None))
bez_diakritiky_translate = _bez_diakritiky_translate()
# TODO: testy?