Web M&M
https://mam.matfyz.cz
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
784 lines
30 KiB
784 lines
30 KiB
# coding:utf-8
|
|
|
|
from django.shortcuts import get_object_or_404, render
|
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
|
|
from django.core.urlresolvers import reverse
|
|
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
|
|
from django.views import generic
|
|
from django.utils.translation import ugettext as _
|
|
from django.http import Http404,HttpResponseBadRequest
|
|
from django.db.models import Q
|
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
|
from django.contrib.auth import authenticate, login
|
|
|
|
from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Prispevek
|
|
from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
|
|
from . import utils
|
|
from .unicodecsv import UnicodeWriter
|
|
|
|
from datetime import timedelta, date, datetime
|
|
from itertools import groupby
|
|
import tempfile
|
|
import subprocess
|
|
import shutil
|
|
import os
|
|
from django.conf import settings
|
|
import unicodedata
|
|
import json
|
|
import traceback
|
|
import sys
|
|
import csv
|
|
|
|
|
|
def verejna_temata(rocnik):
|
|
"""Vrací queryset zveřejněných témat v daném ročníku.
|
|
"""
|
|
return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod')
|
|
|
|
|
|
def AktualniZadaniView(request):
|
|
nastaveni = get_object_or_404(Nastaveni)
|
|
verejne = nastaveni.aktualni_cislo.verejne()
|
|
problemy = Problem.objects.filter(cislo_zadani=nastaveni.aktualni_cislo).filter(stav = 'zadany')
|
|
ulohy = problemy.filter(typ = 'uloha').order_by('kod')
|
|
serialy = problemy.filter(typ = 'serial').order_by('kod')
|
|
jednorazove_problemy = [ulohy, serialy]
|
|
return render(request, 'seminar/zadani/AktualniZadani.html',
|
|
{'nastaveni': nastaveni,
|
|
'jednorazove_problemy': jednorazove_problemy,
|
|
'temata': verejna_temata(nastaveni.aktualni_rocnik),
|
|
'verejne': verejne,
|
|
},
|
|
)
|
|
|
|
def ZadaniTemataView(request):
|
|
nastaveni = get_object_or_404(Nastaveni)
|
|
temata = verejna_temata(nastaveni.aktualni_rocnik)
|
|
for t in temata:
|
|
if request.user.is_staff:
|
|
t.prispevky = t.prispevek_set.filter(problem=t)
|
|
else:
|
|
t.prispevky = t.prispevek_set.filter(problem=t, zverejnit=True)
|
|
return render(request, 'seminar/zadani/Temata.html',
|
|
{
|
|
'temata': temata,
|
|
}
|
|
)
|
|
|
|
|
|
def ZadaniAktualniVysledkovkaView(request):
|
|
nastaveni = get_object_or_404(Nastaveni)
|
|
# Aktualni verejna vysledkovka
|
|
vysledkovka = vysledkovka_rocniku(nastaveni.aktualni_rocnik)
|
|
# kdyz neni verejna vysledkovka, tak zobraz starou
|
|
if not vysledkovka:
|
|
try:
|
|
minuly_rocnik = Rocnik.objects.get(
|
|
prvni_rok=(nastaveni.aktualni_rocnik.prvni_rok-1))
|
|
vysledkovka = vysledkovka_rocniku(minuly_rocnik)
|
|
except ObjectDoesNotExist:
|
|
pass
|
|
# vysledkovka s neverejnyma vysledkama
|
|
vysledkovka_s_neverejnymi = vysledkovka_rocniku(nastaveni.aktualni_rocnik, jen_verejne=False)
|
|
return render(
|
|
request,
|
|
'seminar/zadani/AktualniVysledkovka.html',
|
|
{
|
|
'nastaveni': nastaveni,
|
|
'vysledkovka': vysledkovka,
|
|
'vysledkovka_s_neverejnymi': vysledkovka_s_neverejnymi,
|
|
}
|
|
)
|
|
|
|
|
|
### Titulni strana
|
|
|
|
class TitulniStranaView(generic.ListView):
|
|
model = Novinky
|
|
template_name='seminar/titulnistrana.html'
|
|
queryset = Novinky.objects.order_by('-datum')[:5]
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(TitulniStranaView, self).get_context_data(**kwargs)
|
|
nastaveni = get_object_or_404(Nastaveni)
|
|
cas_deadline = nastaveni.aktualni_cislo.datum_deadline
|
|
# Pokud neni zverejnene cislo nezverejnuj odpocet
|
|
if nastaveni.aktualni_cislo.verejne():
|
|
# pokus se zjistit termin odeslani a pokud neni zadany,
|
|
# nezverejnuj odpocet
|
|
try:
|
|
context['dead'] = datetime.combine(cas_deadline, datetime.max.time())
|
|
context['ted'] = datetime.now()
|
|
except:
|
|
context['dead'] = None
|
|
else:
|
|
context['dead'] = None
|
|
return context
|
|
|
|
class StareNovinkyView(generic.ListView):
|
|
model = Novinky
|
|
template_name = 'seminar/stare_novinky.html'
|
|
queryset = Novinky.objects.filter(zverejneno=True).order_by('-datum')
|
|
|
|
### Co je M&M
|
|
|
|
## Organizatori
|
|
|
|
class CojemamOrganizatoriView(generic.ListView):
|
|
model = Organizator
|
|
template_name='seminar/cojemam/organizatori.html'
|
|
queryset = Organizator.objects.exclude(organizuje_do_roku__isnull=False, organizuje_do_roku__lt=date.today().year).order_by('user__first_name')
|
|
def get_context_data(self, **kwargs):
|
|
context = super(CojemamOrganizatoriView, self).get_context_data(**kwargs)
|
|
context['aktivni'] = True
|
|
return context
|
|
|
|
class CojemamOrganizatoriStariView(generic.ListView):
|
|
model = Organizator
|
|
template_name='seminar/cojemam/organizatori.html'
|
|
queryset = Organizator.objects.filter(organizuje_do_roku__isnull=False, organizuje_do_roku__lt=date.today().year).order_by('-organizuje_do_roku')
|
|
|
|
### Archiv
|
|
|
|
class CislaView(generic.ListView):
|
|
model = Rocnik
|
|
template_name='seminar/archiv/cisla.html'
|
|
|
|
|
|
def sloupec_s_poradim(vysledky):
|
|
# počet řešitelů ve výsledkovce nad aktuálním
|
|
lepsich_resitelu = 0
|
|
|
|
poradi_l = []
|
|
# projdeme skupiny řešitelů se stejným počtem bodů
|
|
for skupina in (list(x) for _, x in groupby(vysledky, lambda x: x.body)):
|
|
|
|
# připravíme si obsahy buněk ve sloupci pořadí pro skupinu
|
|
if len(skupina) == 1:
|
|
poradi_l += ["{}.".format(lepsich_resitelu + 1)]
|
|
# je-li účastníků se stejným počtem bodů víc, pořadí (rozsah X.-Y.) je jen u prvního
|
|
else:
|
|
poradi_l += [u"{}.–{}.".format(lepsich_resitelu + 1, lepsich_resitelu + len(skupina))] + [""] * (len(skupina)-1)
|
|
lepsich_resitelu += len(skupina)
|
|
#pomlcka je opravdu pomlcka v unicode!!dulezite pro vysledkovku v TeXu
|
|
|
|
return poradi_l
|
|
|
|
|
|
def vysledkovka_rocniku(rocnik, jen_verejne=True):
|
|
"""Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve
|
|
formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html"
|
|
"""
|
|
|
|
#vyberu vsechny vysledky z rocniku
|
|
cisla_v_rocniku = VysledkyKCisluZaRocnik.objects.filter(cislo__rocnik=rocnik).order_by('cislo')
|
|
if jen_verejne:
|
|
cisla_v_rocniku = cisla_v_rocniku.filter(cislo__verejna_vysledkovka=True)
|
|
|
|
#pokud žádné nejsou, výsledkovka se nezobrazí
|
|
if not cisla_v_rocniku:
|
|
return None
|
|
|
|
#vybere vsechny vysledky z posledniho (verejneho) cisla a setridi sestupne dle bodu
|
|
vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].cislo).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel'))
|
|
|
|
class Vysledkovka:
|
|
def __init__(self):
|
|
self.rocnik = rocnik.rocnik
|
|
self.radky = []
|
|
self.cisla = []
|
|
|
|
vysledkovka = Vysledkovka()
|
|
vysledkovka.cisla = (rocnik.verejne_vysledkovky_cisla() if jen_verejne else rocnik.cisla.all().order_by('cislo'))
|
|
|
|
# doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině
|
|
for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky):
|
|
v.poradi = poradi
|
|
v.resitel.rocnik = v.resitel.rocnik(rocnik)
|
|
|
|
verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].cislo)
|
|
if jen_verejne:
|
|
verejne_vysl_odjakziva = verejne_vysl_odjakziva.filter(cislo__verejna_vysledkovka=True)
|
|
|
|
v.body_odjakziva = verejne_vysl_odjakziva.filter(resitel = v.resitel)[0].body
|
|
v.titul = v.resitel.get_titul(v.body_odjakziva)
|
|
v.body_rocnik = v.body
|
|
v.body_cisla = []
|
|
|
|
#pokud pro dany rok a cislo nema resitel vysledky, ma defaultne 0
|
|
for cis in vysledkovka.cisla:
|
|
if not jen_verejne or cis.verejna_vysledkovka:
|
|
#seznam vysledku se spravnym rocnikem a cislem pro resitele
|
|
#zobrazim jen je-li vysledkovka verejna
|
|
body_za_cislo = VysledkyZaCislo.objects.filter(cislo__rocnik=rocnik).filter(cislo = cis).filter(resitel = v.resitel)
|
|
if body_za_cislo:
|
|
#neprazdne vysledky by mely obsahovat prave jeden vysledek
|
|
v.body_cisla.append(body_za_cislo[0].body)
|
|
else:
|
|
#resitel nema za cislo body
|
|
v.body_cisla.append(0)
|
|
|
|
vysledkovka.radky.append(v)
|
|
|
|
return vysledkovka
|
|
|
|
|
|
class RocnikView(generic.DetailView):
|
|
model = Rocnik
|
|
template_name = 'seminar/archiv/rocnik.html'
|
|
|
|
# Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik)
|
|
def get_object(self, queryset=None):
|
|
if queryset is None:
|
|
queryset = self.get_queryset()
|
|
rocnik_arg = self.kwargs.get('rocnik')
|
|
queryset = queryset.filter(rocnik=rocnik_arg)
|
|
|
|
try:
|
|
obj = queryset.get()
|
|
except queryset.model.DoesNotExist:
|
|
raise Http404(_("No %(verbose_name)s found matching the query") %
|
|
{'verbose_name': queryset.model._meta.verbose_name})
|
|
return obj
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RocnikView, self).get_context_data(**kwargs)
|
|
|
|
context['vysledkovka'] = vysledkovka_rocniku(context["rocnik"])
|
|
context['vysledkovka_s_neverejnymi'] = vysledkovka_rocniku(context["rocnik"], jen_verejne=False)
|
|
context['temata_v_rocniku'] = verejna_temata(context["rocnik"])
|
|
|
|
return context
|
|
|
|
|
|
class ProblemView(generic.DetailView):
|
|
model = Problem
|
|
|
|
def _je_clanek(self, problem):
|
|
return problem.typ in [Problem.TYP_ORG_CLANEK, Problem.TYP_RES_CLANEK]
|
|
|
|
def get_template_names(self, **kwargs):
|
|
context = super(ProblemView, self).get_context_data(**kwargs)
|
|
return ['seminar/archiv/problem_' + ('clanek.html' if self._je_clanek(context['problem']) else 'uloha_tema.html')]
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ProblemView, self).get_context_data(**kwargs)
|
|
if not context['problem'].verejne() and not self.request.user.is_staff:
|
|
raise PermissionDenied()
|
|
if context['problem'].typ == Problem.TYP_RES_CLANEK:
|
|
context['reseni'] = Reseni.objects.filter(problem=context['problem']).select_related('resitel').order_by('resitel__prijmeni')
|
|
return context
|
|
|
|
class PrispevekView(generic.DetailView):
|
|
model = Prispevek
|
|
template_name = 'seminar/archiv/prispevek.html'
|
|
|
|
# Vlastni ziskavani objektu z databaze podle prispevku
|
|
# pokud je prispevek neverejny zobrazi se jenom orgum
|
|
def get_object(self, queryset=None):
|
|
if queryset is None:
|
|
queryset = self.get_queryset()
|
|
problem_arg = self.kwargs.get('pk')
|
|
prispevek_arg = self.kwargs.get('prispevek')
|
|
queryset = queryset.filter(pk=prispevek_arg)
|
|
|
|
try:
|
|
obj = queryset.get()
|
|
except queryset.model.DoesNotExist:
|
|
raise Http404(_("No %(verbose_name)s found matching the query") %
|
|
{'verbose_name': queryset.model._meta.verbose_name})
|
|
|
|
if self.request.user.is_staff or obj.zverejnit:
|
|
return obj
|
|
else:
|
|
raise Http404()
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(PrispevekView, self).get_context_data(**kwargs)
|
|
# snaho o ziskani titulu
|
|
titul = ''
|
|
try:
|
|
resitel = context['prispevek'].reseni.resitel
|
|
cislo = context['prispevek'].reseni.cislo_body
|
|
body = VysledkyKCisluOdjakziva.objects.get(resitel=resitel,
|
|
cislo=cislo).body
|
|
titul = resitel.get_titul(body)
|
|
except:
|
|
pass
|
|
context['titul'] = titul
|
|
return context
|
|
|
|
|
|
|
|
class RadekVysledkovky(object):
|
|
pass
|
|
|
|
class CisloView(generic.DetailView):
|
|
model = Cislo
|
|
template_name = 'seminar/archiv/cislo.html'
|
|
|
|
# Vlastni ziskavani objektu z databaze podle (Rocnik.rocnik)
|
|
def get_object(self, queryset=None):
|
|
if queryset is None:
|
|
queryset = self.get_queryset()
|
|
rocnik_arg = self.kwargs.get('rocnik')
|
|
cislo_arg = self.kwargs.get('cislo')
|
|
queryset = queryset.filter(rocnik__rocnik=rocnik_arg, cislo=cislo_arg)
|
|
|
|
try:
|
|
obj = queryset.get()
|
|
except queryset.model.DoesNotExist:
|
|
raise Http404(_("No %(verbose_name)s found matching the query") %
|
|
{'verbose_name': queryset.model._meta.verbose_name})
|
|
return obj
|
|
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(CisloView, self).get_context_data(**kwargs)
|
|
|
|
vysledky = VysledkyKCisluZaRocnik.objects.filter(cislo = context['cislo']).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno')
|
|
reseni = Reseni.objects.filter(cislo_body = context['cislo']).select_related("resitel")
|
|
|
|
# typy úloh, které se mají zobrazovat u čísla, tj. těch, které byly v čísle skutečně zadány
|
|
typy_skutecne_zadanych = [Problem.TYP_ULOHA, Problem.TYP_SERIAL, Problem.TYP_ORG_CLANEK]
|
|
v_cisle_zadane = Problem.objects.filter(cislo_zadani=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('kod')
|
|
|
|
resene_problemy = Problem.objects.filter(cislo_reseni=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('cislo_zadani__cislo', 'kod')
|
|
|
|
poradi_typu = {
|
|
Problem.TYP_ULOHA: 1,
|
|
Problem.TYP_SERIAL: 2,
|
|
Problem.TYP_ORG_CLANEK: 3,
|
|
Problem.TYP_TEMA: 4,
|
|
Problem.TYP_RES_CLANEK: 5
|
|
}
|
|
problemy = sorted(set(r.problem for r in reseni), key=lambda x:(poradi_typu[x.typ], x.kod_v_rocniku()))
|
|
#setridi problemy podle typu a poradi zadani
|
|
problem_index = {}
|
|
for i in range(len(problemy)):
|
|
problem_index[problemy[i].id] = i
|
|
#umoznuje zjistit index podle id problemu
|
|
|
|
vysledky_resitele = {}
|
|
vysledkovka = []
|
|
|
|
# doplníme některé údaje do řádků výsledkovky pro řešitele ve skupině
|
|
for poradi, v in zip(sloupec_s_poradim(vysledky), vysledky):
|
|
v.poradi = poradi
|
|
v.body_celkem_rocnik = v.body
|
|
v.body_celkem_odjakziva = VysledkyKCisluOdjakziva.objects.get(resitel=v.resitel, cislo=context['cislo']).body
|
|
v.resitel.rocnik = v.resitel.rocnik(v.cislo.rocnik)
|
|
|
|
# je tady '', aby se nezobrazovala 0, pokud se řešitel o řešení úlohy ani nepokusil
|
|
v.body_ulohy = [''] * len(problemy)
|
|
|
|
v.titul = v.resitel.get_titul(v.body_celkem_odjakziva)
|
|
|
|
body_cislo_q = VysledkyZaCislo.objects.filter(resitel=v.resitel, cislo=context['cislo'])
|
|
v.body_cislo = body_cislo_q[0].body if body_cislo_q else 0
|
|
|
|
vysledkovka.append(v)
|
|
|
|
# připravíme si odkaz na řádek, abychom do něj mohli doplnit body za jednotlivé úlohy
|
|
vysledky_resitele[v.resitel.id] = v
|
|
|
|
# za každé řešení doplníme k příslušnému řešiteli a úloze body
|
|
for r in reseni:
|
|
vysledky_resitele[r.resitel.id].body_ulohy[problem_index[r.problem.id]] = r.body
|
|
|
|
context['vysledkovka'] = vysledkovka
|
|
context['problemy'] = problemy
|
|
context['v_cisle_zadane'] = v_cisle_zadane
|
|
context['resene_problemy'] = resene_problemy
|
|
return context
|
|
|
|
class ArchivTemataView(generic.ListView):
|
|
model = Problem
|
|
template_name = 'seminar/archiv/temata.html'
|
|
queryset = Problem.objects.filter(typ=Problem.TYP_TEMA, stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod')
|
|
|
|
### Generovani vysledkovky
|
|
|
|
class CisloVysledkovkaView(CisloView):
|
|
model = Cislo
|
|
template_name = 'seminar/archiv/cislo_vysledkovka.tex'
|
|
#content_type = 'application/x-tex; charset=UTF8'
|
|
#umozni rovnou stahnout TeXovsky dokument
|
|
content_type = 'text/plain; charset=UTF8'
|
|
#vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani
|
|
|
|
class RocnikVysledkovkaView(RocnikView):
|
|
model = Rocnik
|
|
template_name = 'seminar/archiv/rocnik_vysledkovka.tex'
|
|
#content_type = 'application/x-tex; charset=UTF8'
|
|
#umozni rovnou stahnout TeXovsky dokument
|
|
content_type = 'text/plain; charset=UTF8'
|
|
#vypise na stranku textovy obsah vyTeXane vysledkovky k okopirovani
|
|
|
|
### Generovani obalek
|
|
class CisloObalkyStruct:
|
|
rocnik = None
|
|
cisla = None
|
|
|
|
|
|
# Vraci QuerySet aktualnich resitelu = nekdy neco poslali, ale jeste neodmaturovali
|
|
def aktualniResitele(rocnik):
|
|
letos = Rocnik.objects.get(rocnik = rocnik)
|
|
return Resitel.objects.filter(rok_maturity__gt = letos.prvni_rok)
|
|
# # ALERT: pokud nekdo nema vypleny rok maturity, tak neni aktualni, protoze Karel Tesar a jini
|
|
# return Resitel.objects.filter(Q(rok_maturity__gt = letos.prvni_rok)|Q(rok_maturity = None))
|
|
|
|
# Vraci QuerySet aktivnich resitelu =
|
|
# jeste neodmaturovali &&
|
|
# (pokud je aktualni cislo mensi nez 3, pak (letos || loni) neco poslali
|
|
# jinak letos neco poslali)
|
|
def aktivniResitele(rocnik,cislo):
|
|
letos = CisloObalkyStruct()
|
|
loni = CisloObalkyStruct()
|
|
|
|
aktualni_resitele = aktualniResitele(rocnik)
|
|
|
|
letos.rocnik = Rocnik.objects.get(rocnik = rocnik)
|
|
loni.rocnik = Rocnik.objects.get(rocnik = int(rocnik)-1)
|
|
letos.cisla = Cislo.objects.filter(rocnik=letos.rocnik,cislo__lte = cislo)
|
|
loni.cisla = Cislo.objects.filter(rocnik=loni.rocnik)
|
|
if int(cislo) > 3:
|
|
problemy = Problem.objects.filter(cislo_zadani = letos.cisla)
|
|
else:
|
|
problemy = Problem.objects.filter(Q(cislo_zadani = letos.cisla)|Q(cislo_zadani=loni.cisla))
|
|
resitele = aktualni_resitele.filter(reseni = Reseni.objects.filter(problem=problemy)).distinct()
|
|
|
|
return resitele
|
|
|
|
|
|
def cisloObalkyView(request,rocnik,cislo):
|
|
return obalkyView(request,aktivniResitele(rocnik,cislo))
|
|
|
|
|
|
def obalkyView(request,resitele):
|
|
tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content
|
|
|
|
tempdir = tempfile.mkdtemp()
|
|
with open(tempdir+"/obalky.tex","w") as texfile:
|
|
# Pokud TeX chce ISO Latin, tak se da encode nastavit
|
|
texfile.write(tex.decode("utf-8").encode("iso-8859-2"))
|
|
shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.eps'),tempdir)
|
|
subprocess.call(["csplain","obalky.tex"],cwd = tempdir)
|
|
subprocess.call(["dvipdf","obalky.dvi"],cwd = tempdir)
|
|
|
|
with open(tempdir+"/obalky.pdf","rb") as pdffile:
|
|
response = HttpResponse(pdffile.read(),content_type='application/pdf')
|
|
shutil.rmtree(tempdir)
|
|
return response
|
|
|
|
def obalkovaniView(request, rocnik, cislo):
|
|
rocnik = Rocnik.objects.get(rocnik=rocnik)
|
|
cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo)
|
|
|
|
reseni = (
|
|
Reseni.objects.filter(cislo_body=cislo)
|
|
.order_by(
|
|
'resitel__prijmeni',
|
|
'resitel__jmeno',
|
|
'problem__typ',
|
|
'problem__kod'
|
|
)
|
|
)
|
|
|
|
problemy = sorted(set(r.problem for r in reseni), key=lambda p: (p.typ, p.kod))
|
|
return render(
|
|
request,
|
|
'seminar/archiv/cislo_obalkovani.html',
|
|
{'cislo': cislo, 'problemy': problemy, 'reseni': reseni}
|
|
)
|
|
|
|
### Tituly
|
|
|
|
# TODO udelat neco jako get_objects_or_404
|
|
def TitulyView(request, rocnik, cislo):
|
|
rocnik_obj = Rocnik.objects.get(rocnik = rocnik)
|
|
resitele = Resitel.objects.filter(rok_maturity__gte = rocnik_obj.prvni_rok)
|
|
cislo_obj = Cislo.objects.get(rocnik = rocnik_obj, cislo = cislo)
|
|
|
|
asciijmena = []
|
|
broken = False
|
|
|
|
for resitel in resitele:
|
|
try:
|
|
vys = VysledkyKCisluOdjakziva.objects.get(resitel = resitel, cislo = cislo_obj)
|
|
body = vys.body
|
|
except ObjectDoesNotExist:
|
|
body = 0
|
|
resitel.titul = resitel.get_titul(body)
|
|
resitel.ascii = unicodedata.normalize('NFKD',resitel.jmeno+resitel.prijmeni).encode("ascii","ignore").replace(" ","")
|
|
if resitel.ascii not in asciijmena:
|
|
asciijmena.append(resitel.ascii)
|
|
else:
|
|
broken = True
|
|
|
|
return render(request, 'seminar/archiv/tituly.tex',{'resitele': resitele,'broken':broken},content_type="text/plain")
|
|
|
|
|
|
### Soustredeni
|
|
|
|
class SoustredeniListView(generic.ListView):
|
|
model = Soustredeni
|
|
template_name = 'seminar/soustredeni/seznam_soustredeni.html'
|
|
|
|
class SoustredeniView(generic.DetailView):
|
|
model = Soustredeni
|
|
template_name = 'seminar/archiv/soustredeni.html'
|
|
|
|
def soustredeniObalkyView(request,soustredeni):
|
|
soustredeni = get_object_or_404(Soustredeni,id = soustredeni)
|
|
return obalkyView(request,soustredeni.ucastnici.all())
|
|
|
|
class SoustredeniUcastniciView(generic.ListView):
|
|
model = Soustredeni_Ucastnici
|
|
template_name = 'seminar/soustredeni/seznam_ucastniku.html'
|
|
|
|
def get_queryset(self):
|
|
self.soustredeni = get_object_or_404(Soustredeni, id=self.kwargs["soustredeni"])
|
|
return Soustredeni_Ucastnici.objects.filter(soustredeni=self.soustredeni).select_related('resitel')
|
|
|
|
def soustredeniStvrzenkyExportView(request,soustredeni,first_num):
|
|
first_num = int(first_num)
|
|
soustredeni = get_object_or_404(Soustredeni,id = soustredeni)
|
|
ucastnici = Resitel.objects.filter(soustredeni=soustredeni)
|
|
for (idx,u) in enumerate(ucastnici):
|
|
u.cislo_stvrzenky = first_num+idx;
|
|
tex = render(request,'seminar/soustredeni/ucastnici.tex', {'ucastnici': ucastnici, 'datum':soustredeni.datum_zacatku }).content
|
|
|
|
tempdir = tempfile.mkdtemp()
|
|
with open(tempdir+"/ucastnici.tex","w") as texfile:
|
|
# Pokud TeX chce ISO Latin, tak se da encode nastavit
|
|
texfile.write(tex.decode("utf-8").encode("utf-8"))
|
|
shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/stvrzenka.sty'),tempdir)
|
|
shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/stvrzenky.tex'),tempdir)
|
|
subprocess.call(["cslatex","stvrzenky.tex"],cwd = tempdir)
|
|
subprocess.call(["dvipdf","stvrzenky.dvi"],cwd = tempdir)
|
|
|
|
with open(tempdir+"/stvrzenky.pdf","rb") as pdffile:
|
|
response = HttpResponse(pdffile.read(),content_type='application/pdf')
|
|
shutil.rmtree(tempdir)
|
|
return response
|
|
|
|
|
|
def soustredeniUcastniciExportView(request,soustredeni):
|
|
soustredeni = get_object_or_404(Soustredeni,id = soustredeni)
|
|
ucastnici = Resitel.objects.filter(soustredeni=soustredeni)
|
|
response = HttpResponse(content_type='text/csv')
|
|
response['Content-Disposition'] = 'attachment; filename="ucastnici.csv"'
|
|
|
|
writer = UnicodeWriter(response)
|
|
writer.writerow(["jmeno", "prijmeni", "rok_maturity", "telefon", "email", "ulice", "mesto", "psc","stat"])
|
|
for u in ucastnici:
|
|
writer.writerow([u.jmeno, u.prijmeni, str(u.rok_maturity), u.telefon, u.email, u.ulice, u.mesto, u.psc, u.stat.name])
|
|
return response
|
|
|
|
|
|
### Články
|
|
|
|
class ClankyResitelView(generic.ListView):
|
|
model = Problem
|
|
template_name = 'seminar/clanky/resitelske_clanky.html'
|
|
queryset = Problem.objects.filter(typ=Problem.TYP_RES_CLANEK, stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod')
|
|
|
|
class ClankyOrganizatorView(generic.ListView):
|
|
model = Problem
|
|
template_name = 'seminar/clanky/organizatorske_clanky.html'
|
|
queryset = Problem.objects.filter(typ=Problem.TYP_ORG_CLANEK, stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod')
|
|
|
|
|
|
### Status
|
|
|
|
def StavDatabazeView(request):
|
|
# nastaveni = Nastaveni.objects.get()
|
|
problemy = utils.seznam_problemu()
|
|
muzi = Resitel.objects.filter(pohlavi_muz=True)
|
|
zeny = Resitel.objects.filter(pohlavi_muz=False)
|
|
return render(request, 'seminar/stav_databaze.html',
|
|
{
|
|
# 'nastaveni': nastaveni,
|
|
'problemy': problemy,
|
|
|
|
'resitele': Resitel.objects.all(),
|
|
'muzi': muzi,
|
|
'zeny': zeny,
|
|
'jmena_muzu': utils.histogram([r.jmeno for r in muzi]),
|
|
'jmena_zen': utils.histogram([r.jmeno for r in zeny]),
|
|
})
|
|
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def LoginView(request):
|
|
"""Pro přihlášení při nahrávání z texu"""
|
|
q = request.POST
|
|
# nastavení cookie csrftoken
|
|
if not q:
|
|
return JsonResponse({"ok": 1})
|
|
|
|
if "username" in q:
|
|
username = q["username"]
|
|
password = q["password"]
|
|
user = authenticate(username=username, password=password)
|
|
if user is not None and user.is_staff:
|
|
login(request, user)
|
|
return JsonResponse({"ok": 1})
|
|
else:
|
|
return JsonResponse({"error": "Neplatné uživatelské jméno nebo heslo"})
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def texUploadView(request):
|
|
|
|
def uloz_soubory(files, rocnik, cislo):
|
|
for filename, f in files:
|
|
path = os.path.join(
|
|
settings.MEDIA_ROOT,
|
|
settings.CISLO_IMG_DIR,
|
|
rocnik,
|
|
cislo,
|
|
filename
|
|
)
|
|
|
|
adresar = os.path.dirname(path)
|
|
if not os.path.exists(adresar):
|
|
os.makedirs(adresar)
|
|
|
|
with open(path, "wb+") as fout:
|
|
for chunk in f.chunks():
|
|
fout.write(chunk)
|
|
|
|
q = request.POST
|
|
# nastavení cookie csrftoken
|
|
if not q:
|
|
return JsonResponse({"ok": 1})
|
|
|
|
# Odchytíme všechny výjimky a traceback pošleme v odpovědi
|
|
try:
|
|
meta = json.loads(q["meta"])
|
|
html = q["html"]
|
|
|
|
if meta["typ"] in ["uloha", "serial", "reseni"]:
|
|
|
|
# Uložíme soubory
|
|
if meta["typ"] != "reseni":
|
|
c = meta["cislo"]
|
|
else:
|
|
# Řešení má nastavené číslo svojí úlohy, ale obrázky jsou
|
|
# ukládány do čísla, kde řešení vyšlo
|
|
c = meta["cislo_reseni"]
|
|
uloz_soubory(request.FILES.items(), meta["rocnik"], c)
|
|
|
|
# Zjistíme typ ukládaného problému
|
|
typy = {
|
|
"uloha": Problem.TYP_ULOHA,
|
|
"serial": Problem.TYP_SERIAL,
|
|
"reseni": Problem.TYP_ULOHA,
|
|
}
|
|
problem_typ = typy[meta["typ"]]
|
|
|
|
|
|
# Pokud už problém existuje, vytáhneme jej z db a upravíme
|
|
|
|
# Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku ->
|
|
# číslo/ročník se musí založit ručně v adminu
|
|
rocnik = Rocnik.objects.get(rocnik=meta["rocnik"])
|
|
cislo = Cislo.objects.get(rocnik=rocnik, cislo=meta["cislo"])
|
|
|
|
existujici = Problem.objects.filter(
|
|
typ=problem_typ,
|
|
stav=Problem.STAV_ZADANY,
|
|
cislo_zadani=cislo,
|
|
kod=meta["kod"]
|
|
)
|
|
|
|
problem = None
|
|
if existujici:
|
|
problem = existujici[0]
|
|
# Jinak vytvoříme nový
|
|
else:
|
|
problem = Problem(
|
|
typ=problem_typ,
|
|
stav=Problem.STAV_ZADANY,
|
|
kod=meta["kod"],
|
|
cislo_zadani=cislo
|
|
)
|
|
|
|
if meta["typ"] == "reseni":
|
|
problem.text_reseni = html
|
|
#při nahrávání řešení už původní zadání atd. neměníme
|
|
else:
|
|
problem.text_zadani = html
|
|
problem.nazev = meta["nazev"]
|
|
problem.body = meta["body"]
|
|
|
|
problem.save()
|
|
|
|
# Vrátíme id dané úlohy, aby se k ní dala případně připojit pohádka
|
|
return JsonResponse({"db_id": problem.id})
|
|
|
|
elif meta["typ"] == "pohadka":
|
|
uloha = Problem.objects.get(typ=Problem.TYP_ULOHA, pk=meta["uloha"])
|
|
|
|
# Pokud už příslušná pohádka existuje, jen ji upravíme
|
|
existujici = Pohadka.objects.filter(uloha=uloha, pred=meta["pred"])
|
|
pohadka = None
|
|
if existujici:
|
|
pohadka = existujici[0]
|
|
else:
|
|
pohadka = Pohadka(uloha=uloha, pred=meta["pred"])
|
|
pohadka.text = q["html"]
|
|
pohadka.save()
|
|
|
|
return JsonResponse({"db_id": pohadka.id})
|
|
|
|
except Exception, e:
|
|
# Pošleme zpátky traceback, ať uživatel ví, v čem je problém
|
|
tb = "".join(traceback.format_exception(type(e), e, sys.exc_info()[2]))
|
|
return JsonResponse({"error": tb})
|
|
|
|
|
|
def texDownloadView(request, rocnik, cislo):
|
|
"""View posílající JSON se zadanými a řešenými problémy pro založení čísla
|
|
"""
|
|
cislo = Cislo.objects.get(rocnik__rocnik=rocnik, cislo=cislo)
|
|
zadane = Problem.objects.filter(
|
|
cislo_zadani=cislo,
|
|
stav=Problem.STAV_ZADANY
|
|
)
|
|
resene = Problem.objects.filter(
|
|
cislo_reseni=cislo,
|
|
stav=Problem.STAV_ZADANY,
|
|
typ=Problem.TYP_ULOHA
|
|
)
|
|
pred_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=True)
|
|
po_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=False)
|
|
|
|
response = {
|
|
"zadane": [
|
|
{
|
|
"nazev": p.nazev,
|
|
"typ": p.typ,
|
|
"kod": p.kod,
|
|
"body": p.body,
|
|
"zadani": p.text_zadani,
|
|
"pred_pohadky": [x.text for x in pred_pohadky.filter(uloha=p)],
|
|
"po_pohadky": [x.text for x in po_pohadky.filter(uloha=p)],
|
|
} for p in zadane
|
|
],
|
|
"resene": [
|
|
{
|
|
"nazev": p.nazev,
|
|
"typ": p.typ,
|
|
"kod": p.kod,
|
|
"body": p.body,
|
|
"zadani": p.text_zadani,
|
|
"reseni": p.text_reseni,
|
|
"cislo_zadani": p.cislo_zadani.cislo,
|
|
} for p in resene
|
|
],
|
|
}
|
|
return JsonResponse(response)
|
|
|