Merge branch 'develop' into test
This commit is contained in:
commit
74a2fdceec
13 changed files with 218 additions and 19 deletions
|
@ -13,7 +13,9 @@ class SkolaAutocomplete(autocomplete.Select2QuerySetView):
|
|||
if self.q:
|
||||
words = self.q.split(' ') #TODO re split podle bileho znaku
|
||||
partq = Q()
|
||||
for w in words: # Hledej po slovech, zahoď čárky a tečky z konců.
|
||||
for w in words: # Hledej po slovech, zahoď čárky a tečky z konců.
|
||||
if len(w) == 0:
|
||||
continue
|
||||
if w[-1] in (".",","):
|
||||
w = w[:-1]
|
||||
|
||||
|
@ -26,11 +28,15 @@ class ResitelAutocomplete(LoginRequiredAjaxMixin,autocomplete.Select2QuerySetVie
|
|||
def get_queryset(self):
|
||||
qs = m.Resitel.objects.all()
|
||||
if self.q:
|
||||
qs = qs.filter(
|
||||
Q(osoba__jmeno__istartswith=self.q)|
|
||||
Q(osoba__prijmeni__istartswith=self.q)|
|
||||
Q(osoba__prezdivka__istartswith=self.q)
|
||||
parts = self.q.split()
|
||||
query = Q()
|
||||
for part in parts:
|
||||
query &= (
|
||||
Q(osoba__jmeno__istartswith=self.q)|
|
||||
Q(osoba__prijmeni__istartswith=self.q)|
|
||||
Q(osoba__prezdivka__istartswith=self.q)
|
||||
)
|
||||
qs = qs.filter(query)
|
||||
return qs
|
||||
|
||||
class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView):
|
||||
|
|
|
@ -977,5 +977,29 @@
|
|||
},
|
||||
"model": "sitetree.treeitem",
|
||||
"pk": 50
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"access_guest": false,
|
||||
"access_loggedin": false,
|
||||
"access_perm_type": 1,
|
||||
"access_permissions": [],
|
||||
"access_restricted": true,
|
||||
"alias": null,
|
||||
"description": "",
|
||||
"hidden": false,
|
||||
"hint": "",
|
||||
"inbreadcrumbs": true,
|
||||
"inmenu": true,
|
||||
"insitetree": true,
|
||||
"parent": 42,
|
||||
"sort_order": 51,
|
||||
"title": "Detail řešení {{ reseni.id }}",
|
||||
"tree": 1,
|
||||
"url": "odevzdavatko_resitel_reseni reseni.id",
|
||||
"urlaspattern": true
|
||||
},
|
||||
"model": "sitetree.treeitem",
|
||||
"pk": 51
|
||||
}
|
||||
]
|
||||
]
|
|
@ -1,4 +1,6 @@
|
|||
import locale
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin import AdminSite
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
|
||||
# Note: we are renaming the original Admin and Form as we import them!
|
||||
|
@ -24,3 +26,24 @@ class FlatPageAdmin(FlatPageAdminOld):
|
|||
admin.site.unregister(FlatPage)
|
||||
admin.site.register(FlatPage, FlatPageAdmin)
|
||||
|
||||
locale.setlocale(locale.LC_COLLATE, 'cs_CZ.UTF-8')
|
||||
|
||||
# https://books.agiliq.com/projects/django-admin-cookbook/en/latest/set_ordering.html
|
||||
# FIXME zpraseno pomocí toho, že Python umí bez problému přepisovat funkce
|
||||
def get_app_list(self, request):
|
||||
"""
|
||||
Return a sorted list of all the installed apps that have been
|
||||
registered in this site.
|
||||
"""
|
||||
|
||||
app_dict = self._build_app_dict(request)
|
||||
# Sort the apps alphabetically.
|
||||
app_list = sorted(app_dict.values(), key=lambda x: locale.strxfrm('!') if (x['name'] == "Seminar") else locale.strxfrm(x['name'].lower()))
|
||||
|
||||
# Sort the models alphabetically within each app.
|
||||
for app in app_list:
|
||||
app['models'].sort(key=lambda x: locale.strxfrm('žž' + x['name'].lower()) if (x['name'].endswith("(Node)")) else locale.strxfrm(x['name'].lower()))
|
||||
|
||||
return app_list
|
||||
|
||||
AdminSite.get_app_list = get_app_list
|
||||
|
|
|
@ -466,6 +466,11 @@ class Rocnik(SeminarModelBase):
|
|||
vc.sort(key=lambda c: c.poradi)
|
||||
return vc
|
||||
|
||||
def neverejna_cisla(self):
|
||||
vc = [c for c in self.cisla.all() if not c.verejne()]
|
||||
vc.sort(key=lambda c: c.poradi)
|
||||
return vc
|
||||
|
||||
def posledni_verejne_cislo(self):
|
||||
vc = self.verejna_cisla()
|
||||
return vc[-1] if vc else None
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
Jednotlivá čísla:
|
||||
<ul>
|
||||
{% for cislo in rocnik.cisla.all reversed %}
|
||||
<li><a href='{{ cislo.verejne_url }}'>{{ cislo.poradi }}. číslo</a> {% if cislo.pdf %}(<a href='{{ cislo.pdf.url }}'>pdf</a>) {% endif %}
|
||||
{% empty %}
|
||||
Žádná čísla k zobrazení
|
||||
{% if cislo.verejne or user.je_org %}
|
||||
<li><a href='{{ cislo.verejne_url }}'>{{ cislo.poradi }}. číslo</a> {% if cislo.pdf %}(<a href='{{ cislo.pdf.url }}'>pdf</a>) {% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<a href='{{ rocnik.verejne_url }}'>Výsledková listina</a> <!-- FIXME: url výsledkovky-->
|
||||
|
|
|
@ -63,20 +63,63 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if user.je_org and rocnik.neverejna_cisla %}
|
||||
<div class="mam-org-only">
|
||||
<div class="cisla-v-rocniku">
|
||||
{% for c in rocnik.neverejna_cisla %}
|
||||
<div class="cislo_pole">
|
||||
|
||||
<h6> Číslo {{ c.kod }}</h6>
|
||||
|
||||
<div class="flip-card" id="archiv-rocnik">
|
||||
|
||||
<div class="flip-card-inner">
|
||||
<div class="flip-card-front">
|
||||
|
||||
<div class="flip-card-foto">
|
||||
{% if c.titulka_nahled %}
|
||||
<img src="{{ c.titulka_nahled.url }}" alt="{{ c.kod }}" height=180px>
|
||||
{% else %}
|
||||
{% load static %} <img src="{% static 'images/no-picture.png' %}" height=180px alt="no-picture">
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flip-card-back">
|
||||
|
||||
<div class="cislo_odkazy">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="{{ c.verejne_url }}">archiv čísla</a>
|
||||
</li>
|
||||
{% if c.pdf %}
|
||||
<li>
|
||||
<a href='{{ c.pdf.url }}'>pdf</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if vysledkovka %}
|
||||
{% if user.je_org %}
|
||||
<div class='mam-org-only'>
|
||||
<a href='vysledkovka.tex' download>Výsledkovka ročníku (LaTeX)</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2>Výsledková listina</h2>
|
||||
{% include "seminar/vysledkovka_rocnik.html" %}
|
||||
{% endif %}
|
||||
|
||||
{% if user.je_org %}
|
||||
<div class='mam-org-only'>
|
||||
<a href='vysledkovka.tex' download>Výsledkovka ročníku (LaTeX, včetně neveřejných)</a>
|
||||
<h2>Výsledková listina včetně neveřejných bodů</h2>
|
||||
{% with radky_vysledkovky_s_neverejnymi as radky_vysledkovky %}
|
||||
{% with cisla_s_neverejnymi as cisla %}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{% with lb="{" %}
|
||||
{% with rb="}" %}
|
||||
{% with radky_vysledkovky=radky_vysledkovky_s_neverejnymi cisla=cisla_s_neverejnymi %}
|
||||
\setlength{\tabcolsep}{3pt}
|
||||
\begin{longtable}{|r|l|c|r|{% for cislo in cisla %}c{% if not forloop.last %}@{\hskip.5em}{% endif %}{% endfor %}|r|}\hline
|
||||
& & & & \multicolumn{{ lb }}{{ cisla|length }}}{c|}{\textbf{Číslo}} & \\\textbf{Poř.} & \textbf{Jméno} & \textbf{R.} & \raisebox{0.7mm}{$\sum_{-1}$} & {% for cislo in cisla %}\textbf{{ lb }}{{ cislo.poradi }}{{ rb }} & {% endfor %}\raisebox{0.7mm}{$\sum_1$} \\\hline
|
||||
|
@ -10,3 +11,4 @@
|
|||
{% endfor %}\end{longtable}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
|
|
|
@ -134,6 +134,15 @@ $(document).ready(function(){
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function problem_is_empty(elem, index, array) {return elem.firstElementChild.children.length !== 1 && elem.firstElementChild.children[1].textContent === "";}
|
||||
|
||||
if ($('.hodnoceni').toArray().some(problem_is_empty)) {
|
||||
alert("Neuloženo! Nezadal jsi problém, ke kterému posíláš hodnocení. Pokud je toto hodnocení navíc, smaž ho prosím křížkem a znovu odešli.")
|
||||
event.preventDefault()
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
|
|
50
seminar/templates/seminar/odevzdavatko/detail_resitele.html
Normal file
50
seminar/templates/seminar/odevzdavatko/detail_resitele.html
Normal file
|
@ -0,0 +1,50 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load deadliny %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p>Řešené problémy: {{ object.problem.all | join:", " }}</p>
|
||||
|
||||
<p>Řešitelé: {% for r in object.resitele.all %} {{ r }}
|
||||
{% if forloop.revcounter0 != 0 %}, {% endif %} {% endfor %}</p>
|
||||
|
||||
{# https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.get_FOO_display #}
|
||||
<p>Forma: {{ object.get_forma_display }}</p>
|
||||
|
||||
<p>Doručeno {{ object.cas_doruceni }}, deadline: {{object.cas_doruceni | deadline_html }}</p>
|
||||
|
||||
{# Soubory: #}
|
||||
<h3>Přílohy:</h3>
|
||||
{% if object.prilohy.all %}
|
||||
<table class="dosla_reseni">
|
||||
<tr><th>Soubor</th><th>Řešitelova poznámka</th><th>Datum</th></tr>
|
||||
{% for priloha in object.prilohy.all %}
|
||||
<tr>
|
||||
<td><a href="{{ priloha.soubor.url }}" download>{{ priloha.split | last }}</a></td>
|
||||
<td>{{ priloha.res_poznamka }}</td>
|
||||
<td>{{ priloha.vytvoreno }}</td></tr>
|
||||
{# TODO: Orgo-poznámka, ideálně jako formulář #}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Žádné přílohy</p>
|
||||
{% endif %}
|
||||
|
||||
{#<h3>Poznámka:</h3>#}
|
||||
{#<p>{{ poznamka }}</p>#}
|
||||
|
||||
{# Hodnocení: #}
|
||||
<h3>Hodnocení:</h3>
|
||||
<table id="form_set" class="dosla_reseni">
|
||||
<tr><th>Problém</th><th>Body</th>{# <th>Číslo pro body</th> #}</tr>
|
||||
{% for h in hodnoceni %}
|
||||
<tr class="hodnoceni">
|
||||
<td>{{ h.problem }}</td>
|
||||
<td>{{ h.body }}</td>
|
||||
{# <td>{{ h.cislo_body }}</td>#}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
|
@ -25,7 +25,7 @@
|
|||
<tr>
|
||||
<td>{{ hodn.reseni.cas_doruceni | date:"d.m.Y H:i"}}</td>
|
||||
<td id="problem"><span title="{{ hodn.problem.nazev }}">{{ hodn.problem.nazev | zkrat_nazev_problemu }}</span></td>
|
||||
<td>{{ hodn.body|default_if_none:"---" }}</td>
|
||||
<td><a href="{% url 'odevzdavatko_resitel_reseni' hodn.reseni.id %}">{{ hodn.body|default_if_none:"---" }}</a></td>
|
||||
<td>{{ hodn.reseni.cas_doruceni | deadline_html }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -142,4 +142,6 @@ urlpatterns = [
|
|||
path('org/reseni/<int:pk>', org_required(viewMethodSwitch(get=views.DetailReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'),
|
||||
path('org/reseni/all', org_required(views.SeznamReseniView.as_view())),
|
||||
path('org/reseni/akt', org_required(views.SeznamAktualnichReseniView.as_view())),
|
||||
|
||||
path('resitel/reseni/<int:pk>', resitel_or_org_required(views.ResitelReseniView.as_view()), name='odevzdavatko_resitel_reseni'),
|
||||
]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from django.core.exceptions import PermissionDenied
|
||||
from django.views.generic import ListView, DetailView, FormView
|
||||
from django.views.generic.list import MultipleObjectTemplateResponseMixin,MultipleObjectMixin
|
||||
from django.views.generic.base import View
|
||||
|
@ -75,7 +76,6 @@ class TabulkaOdevzdanychReseniView(ListView):
|
|||
|
||||
|
||||
# Chceme jen letošní problémy
|
||||
# FIXME: Neexistuje metoda, jak dostat starší problémy…
|
||||
self.problemy = self.problemy.filter(Q(Tema___rocnik=self.aktualni_rocnik) | Q(Uloha___cislo_zadani__rocnik = self.aktualni_rocnik) | Q(Clanek___cislo__rocnik = self.aktualni_rocnik) | Q(Konfera___soustredeni__rocnik = self.aktualni_rocnik))
|
||||
|
||||
self.chteni_resitele = resitele # Zapamatování pro get_context_data
|
||||
|
@ -88,9 +88,14 @@ class TabulkaOdevzdanychReseniView(ListView):
|
|||
|
||||
if problemy == FiltrForm.PROBLEMY_MOJE:
|
||||
org = m.Organizator.objects.get(osoba__user=self.request.user)
|
||||
self.problemy = self.problemy.filter(Q(autor=org)|Q(garant=org)|Q(opravovatele=org), stav=m.Problem.STAV_ZADANY)
|
||||
self.problemy = self.problemy.filter(
|
||||
Q(autor=org)|Q(garant=org)|Q(opravovatele=org),
|
||||
Q(stav=m.Problem.STAV_ZADANY)|Q(stav=m.Problem.STAV_VYRESENY),
|
||||
)
|
||||
elif problemy == FiltrForm.PROBLEMY_LETOSNI:
|
||||
self.problemy = self.problemy.filter(stav=m.Problem.STAV_ZADANY)
|
||||
self.problemy = self.problemy.filter(
|
||||
Q(stav=m.Problem.STAV_ZADANY)|Q(stav=m.Problem.STAV_VYRESENY),
|
||||
)
|
||||
#self.problemy = list(filter(lambda problem: problem.rocnik() == self.aktualni_rocnik, self.problemy)) # DB HOG? # FIXME: některé problémy nemají ročník....
|
||||
# NOTE: Protože řešení odkazuje přímo na Problém a QuerySet na Hodnocení je nepolymorfní, musíme porovnávat taky s nepolymorfními Problémy.
|
||||
self.problemy = self.problemy.non_polymorphic()
|
||||
|
@ -264,6 +269,34 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
|
|||
return redirect(success_url)
|
||||
|
||||
|
||||
class ResitelReseniView(DetailView):
|
||||
model = m.Reseni
|
||||
template_name = 'seminar/odevzdavatko/detail_resitele.html'
|
||||
|
||||
def aktualni_hodnoceni(self):
|
||||
self.reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk'])
|
||||
result = []
|
||||
for hodn in m.Hodnoceni.objects.filter(reseni=self.reseni):
|
||||
result.append(
|
||||
{
|
||||
"problem": hodn.problem,
|
||||
"body": hodn.body,
|
||||
# "cislo_body": hodn.cislo_body,
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
def get_context_data(self, **kw):
|
||||
ctx = super().get_context_data(**kw)
|
||||
hodnoceni = self.aktualni_hodnoceni()
|
||||
if not self.reseni.resitele.filter(osoba__user=self.request.user).exists():
|
||||
raise PermissionDenied()
|
||||
# ctx['poznamka'] = f.PoznamkaReseniForm(instance=self.reseni)
|
||||
ctx["hodnoceni"] = hodnoceni
|
||||
return ctx
|
||||
|
||||
|
||||
|
||||
class PrehledOdevzdanychReseni(ListView):
|
||||
model = m.Hodnoceni
|
||||
template_name = 'seminar/odevzdavatko/resitel_prehled.html'
|
||||
|
|
|
@ -630,6 +630,8 @@ class ArchivView(generic.ListView):
|
|||
context = super(ArchivView, self).get_context_data(**kwargs)
|
||||
|
||||
cisla = Cislo.objects.filter(poradi=1)
|
||||
if not self.request.user.je_org:
|
||||
cisla = cisla.filter(verejne_db=True)
|
||||
urls ={}
|
||||
|
||||
for i, c in enumerate(cisla):
|
||||
|
|
Loading…
Reference in a new issue