979 lines
31 KiB
Python
979 lines
31 KiB
Python
# 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,HttpResponseRedirect
|
||
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, Tema, Clanek
|
||
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
|
||
from . import utils
|
||
from .unicodecsv import UnicodeWriter
|
||
from .forms import NameForm
|
||
|
||
from datetime import timedelta, date, datetime
|
||
from itertools import groupby
|
||
import tempfile
|
||
import subprocess
|
||
import shutil
|
||
import os
|
||
import os.path as op
|
||
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)
|
||
|
||
# zjisteni spravneho terminu
|
||
if nastaveni.aktualni_cislo.datum_deadline_soustredeni:
|
||
cas_deadline_soustredeni = nastaveni.aktualni_cislo.\
|
||
datum_deadline_soustredeni
|
||
if (datetime.now().date() <= cas_deadline_soustredeni):
|
||
cas_deadline = cas_deadline_soustredeni
|
||
deadline_soustredeni = True
|
||
else:
|
||
cas_deadline = nastaveni.aktualni_cislo.datum_deadline
|
||
deadline_soustredeni = False
|
||
else:
|
||
cas_deadline = nastaveni.aktualni_cislo.datum_deadline
|
||
deadline_soustredeni = False
|
||
|
||
# Pokud neni zverejnene cislo nezverejnuj odpocet
|
||
if nastaveni.aktualni_cislo.verejne():
|
||
# pokus se zjistit termin odeslani a pokud neni zadany,
|
||
# nezverejnuj odpocet
|
||
context['deadline_soustredeni'] = deadline_soustredeni
|
||
try:
|
||
context['dead'] = datetime.combine(cas_deadline,
|
||
datetime.max.time())
|
||
context['ted'] = datetime.now()
|
||
except:
|
||
context['dead'] = None
|
||
else:
|
||
context['dead'] = None
|
||
context['deadline_soustredeni'] = deadline_soustredeni
|
||
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
|
||
def aktivniOrganizatori(datum=date.today()):
|
||
return Organizator.objects.exclude(
|
||
organizuje_do__isnull=False,
|
||
organizuje_do__lt=datum
|
||
).order_by('user__first_name')
|
||
|
||
|
||
class CojemamOrganizatoriView(generic.ListView):
|
||
model = Organizator
|
||
template_name = 'seminar/cojemam/organizatori.html'
|
||
queryset = aktivniOrganizatori()
|
||
|
||
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.exclude(
|
||
id__in=aktivniOrganizatori()).order_by('-organizuje_do')
|
||
|
||
### Archiv
|
||
|
||
|
||
class ArchivView(generic.ListView):
|
||
model = Rocnik
|
||
template_name='seminar/archiv/cisla.html'
|
||
|
||
def get_context_data(self, **kwargs):
|
||
context = super(ArchivView, self).get_context_data(**kwargs)
|
||
|
||
vyska = 297 # px
|
||
sirka = 210 # px
|
||
|
||
cisla = Cislo.objects.filter(verejne_db=True)[:10]
|
||
|
||
png_dir = op.join(settings.MEDIA_ROOT, "cislo", "png")
|
||
|
||
# seznam [(url obrázku, číslo)]
|
||
urls = []
|
||
|
||
for i, c in enumerate(cisla):
|
||
if not c.pdf:
|
||
continue
|
||
filename = os.path.split(c.pdf.file.name)[1].split(".")[0]
|
||
png_filename = "{}-{}px.png".format(filename, vyska)
|
||
|
||
# Pokud obrázek neexistuje nebo není aktuální, vytvoř jej
|
||
png_path = op.join(png_dir, png_filename)
|
||
if not op.exists(png_path) or \
|
||
op.getmtime(png_path) < op.getmtime(c.pdf.path):
|
||
|
||
subprocess.call([
|
||
"convert",
|
||
"-density", "180x180",
|
||
"-geometry", "{}x{}".format(vyska, vyska),
|
||
"-background", "white",
|
||
"-flatten",
|
||
"-rotate", str(90 * i),
|
||
"{}[0]".format(c.pdf.path), # titulní strana
|
||
png_path
|
||
])
|
||
|
||
urls.append(
|
||
(op.join(settings.MEDIA_URL, "cislo", "png", png_filename), c)
|
||
)
|
||
vyska, sirka = sirka, vyska / 2
|
||
|
||
tags = []
|
||
|
||
def spirala(urls, tags, idx):
|
||
"""Rekurzivně prochází urls a generuje strom elementů do tags"""
|
||
if idx >= len(urls):
|
||
return
|
||
|
||
img_url, cislo = urls[idx]
|
||
tags.append(
|
||
"<div style='top:{}%;left:{}%;width:{}%;height:{}%;'>"
|
||
.format(
|
||
50 if idx % 4 == 2 else 0,
|
||
50 if idx % 4 == 1 else 0,
|
||
50 if idx % 2 == 1 else 100,
|
||
50 if idx > 0 and idx % 2 == 0 else 100
|
||
)
|
||
)
|
||
tags.append("<a href='{}' title='{}'>".format(
|
||
cislo.verejne_url(), cislo.kod()
|
||
))
|
||
tags.append(
|
||
"<img src='{}' style='top:{}%;left:{}%;width:{}%;height:{}%;'>"
|
||
.format(
|
||
img_url,
|
||
50 if idx % 4 == 3 else 0,
|
||
50 if idx % 4 == 2 else 0,
|
||
50 if idx % 2 == 0 else 100,
|
||
50 if idx % 2 == 1 else 100
|
||
)
|
||
)
|
||
tags.append("</a>")
|
||
spirala(urls, tags, idx + 1)
|
||
tags.append("</div>")
|
||
spirala(urls, tags, 0)
|
||
|
||
context["nahledy"] = "\n".join(tags)
|
||
return context
|
||
|
||
|
||
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
|
||
|
||
## Prispevek byl zrusen, mozna ale bude podobny nahled na neco jineho.
|
||
#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 = Tema.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__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__in = letos.cisla)
|
||
else:
|
||
problemy = Problem.objects.filter(Q(cislo_zadani__in = letos.cisla)|Q(cislo_zadani__in = loni.cisla))
|
||
resitele = aktualni_resitele.filter(reseni__in = Reseni.objects.filter(problem__in=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:
|
||
texfile.write(tex)
|
||
shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.eps'),tempdir)
|
||
subprocess.call(["pdflatex","obalky.tex"],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
|
||
# FIXME: prepsat, aby nepouzivalo VysledkyK...
|
||
#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 SoustredeniUcastniciBaseView(generic.ListView):
|
||
model = Soustredeni_Ucastnici
|
||
|
||
def get_queryset(self):
|
||
soustredeni = get_object_or_404(
|
||
Soustredeni,
|
||
pk=self.kwargs["soustredeni"]
|
||
)
|
||
return Soustredeni_Ucastnici.objects.filter(
|
||
soustredeni=soustredeni).select_related('resitel')
|
||
|
||
|
||
class SoustredeniMailyUcastnikuView(SoustredeniUcastniciBaseView):
|
||
"""Seznam e-mailů řešitelů oddělených čárkami"""
|
||
model = Soustredeni_Ucastnici
|
||
template_name = 'seminar/soustredeni/maily_ucastniku.txt'
|
||
|
||
|
||
class SoustredeniUcastniciView(SoustredeniUcastniciBaseView):
|
||
"""HTML tabulka účastníků pro tisk"""
|
||
model = Soustredeni_Ucastnici
|
||
template_name = 'seminar/soustredeni/seznam_ucastniku.html'
|
||
|
||
|
||
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
|
||
|
||
# FIXME: clanky jsou vsechny, pokud budou i neresitelske, tak se take zobrazi
|
||
class ClankyResitelView(generic.ListView):
|
||
model = Problem
|
||
template_name = 'seminar/clanky/resitelske_clanky.html'
|
||
queryset = Clanek.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__rocnik').order_by('-cislo_zadani__rocnik__rocnik', 'kod')
|
||
|
||
# FIXME: pokud chceme orgoclanky, tak nejak zavest do modelu a podle toho odkomentovat a upravit
|
||
#class ClankyOrganizatorView(generic.ListView)<F12>:
|
||
# model = Problem
|
||
# template_name = 'seminar/clanky/organizatorske_clanky.html'
|
||
# queryset = Problem.objects.filter(stav=Problem.STAV_ZADANY).select_related('cislo_zadani__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", "tema"]:
|
||
|
||
# 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"]
|
||
|
||
# Zjistíme typ ukládaného problému
|
||
typy = {
|
||
"uloha": Problem.TYP_ULOHA,
|
||
"serial": Problem.TYP_SERIAL,
|
||
"reseni": Problem.TYP_ULOHA,
|
||
"tema": Problem.TYP_TEMA,
|
||
}
|
||
problem_typ = typy[meta["typ"]]
|
||
|
||
# Pokud už problém existuje, vytáhneme jej z db a upravíme
|
||
# Pokud neexistuje, vytvoříme jej jedině pokud je to vynucené
|
||
|
||
# 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]
|
||
elif "vytvor" in q:
|
||
# vytvoříme nový
|
||
problem = Problem(
|
||
typ=problem_typ,
|
||
stav=Problem.STAV_ZADANY,
|
||
kod=meta["kod"],
|
||
cislo_zadani=cislo
|
||
)
|
||
else:
|
||
return JsonResponse({
|
||
"error": "Problém neexistuje: {} {}.{} kód {}".format(
|
||
meta["typ"], meta["rocnik"], meta["cislo"], meta["kod"]
|
||
)
|
||
})
|
||
|
||
uloz_soubory(request.FILES.items(), meta["rocnik"], c)
|
||
|
||
if meta["typ"] == "reseni":
|
||
problem.text_reseni = html
|
||
|
||
# Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku ->
|
||
# číslo/ročník se musí založit ručně v adminu
|
||
problem.cislo_reseni = Cislo.objects.get(
|
||
rocnik=rocnik,
|
||
cislo=meta["cislo_reseni"]
|
||
)
|
||
# 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"]
|
||
if meta["typ"] != "tema":
|
||
problem.body = meta["body"]
|
||
|
||
problem.save()
|
||
cislo.faze = cislo.FAZE_NAHRANO
|
||
cislo.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 as 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)
|
||
if cislo.faze == cislo.FAZE_NAHRANO:
|
||
# obsah byl nahrán z TeXu na web, už je příliš složitý
|
||
return JsonResponse(
|
||
{"error": "Obsah čísla už byl nahrán z TeXu na web."}
|
||
)
|
||
|
||
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
|
||
],
|
||
}
|
||
|
||
cislo.faze = Cislo.FAZE_TEX
|
||
cislo.save()
|
||
return JsonResponse(response)
|
||
|
||
## Formulare
|
||
|
||
def get_name(request):
|
||
# if this is a POST request we need to process the form data
|
||
if request.method == 'POST':
|
||
# create a form instance and populate it with data from the request:
|
||
form = NameForm(request.POST)
|
||
# check whether it's valid:
|
||
if form.is_valid():
|
||
# process the data in form.cleaned_data as required
|
||
# ...
|
||
# redirect to a new URL:
|
||
return HttpResponseRedirect('/thanks/')
|
||
|
||
# if a GET (or any other method) we'll create a blank form
|
||
else:
|
||
form = NameForm()
|
||
|
||
return render(request, 'seminar/prihlaska.html', {'form': form})
|
||
|
||
# Ceka na autocomplete v3
|
||
# class OrganizatorAutocomplete(autocomplete.Select2QuerySetView):
|
||
# def get_queryset(self):
|
||
# if not self.request.user.is_authenticated():
|
||
# return Organizator.objects.none()
|
||
#
|
||
# qs = aktivniOrganizatori()
|
||
#
|
||
# if self.q:
|
||
# if self.q[0] == "!":
|
||
# qs = Organizator.objects.all()
|
||
# query = self.q[1:]
|
||
# else:
|
||
# query = self.q
|
||
# qs = qs.filter(
|
||
# Q(prezdivka__isstartswith=query)|
|
||
# Q(user__first_name__isstartswith=query)|
|
||
# Q(user__last_name__isstartswith=query))
|
||
#
|
||
# return qs
|