@ -2,22 +2,31 @@
from django . shortcuts import get_object_or_404 , render
from django . shortcuts import get_object_or_404 , render
from django . http import HttpResponse , HttpResponseRedirect , HttpResponseForbidden , JsonResponse
from django . http import HttpResponse , HttpResponseRedirect , HttpResponseForbidden , JsonResponse
from django . urls import reverse
from django . urls import reverse , reverse_lazy
from django . core . exceptions import PermissionDenied , ObjectDoesNotExist
from django . core . exceptions import PermissionDenied , ObjectDoesNotExist
from django . views import generic
from django . views import generic
from django . utils . translation import ugettext as _
from django . utils . translation import ugettext as _
from django . http import Http404 , HttpResponseBadRequest , HttpResponseRedirect
from django . http import Http404 , HttpResponseBadRequest , HttpResponseRedirect
from django . db . models import Q
from django . db . models import Q , Sum , Count
from django . views . decorators . csrf import ensure_csrf_cookie
from django . views . decorators . csrf import ensure_csrf_cookie
from django . contrib . auth import authenticate , login
from django . views . generic . edit import FormView
from django . contrib . auth import authenticate , login , get_user_model , logout
from . models import Problem , Cislo , Reseni , Nastaveni , Rocnik , Soustredeni , Organizator , Resitel , Novinky , Soustredeni_Ucastnici , Pohadka , Tema , Clanek
from django . contrib . auth import views as auth_views
from django . contrib . auth . models import User
from django . contrib . auth . mixins import LoginRequiredMixin
from django . db import transaction
from dal import autocomplete
import seminar . models as s
from . models import Problem , Cislo , Reseni , Nastaveni , Rocnik , Soustredeni , Organizator , Resitel , Novinky , Soustredeni_Ucastnici , Pohadka , Tema , Clanek , Osoba , Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
from . import utils
from . import utils
from . unicodecsv import UnicodeWriter
from . unicodecsv import UnicodeWriter
from . forms import NameForm
from . forms import PrihlaskaForm , LoginForm , ProfileEditForm
import seminar . forms as f
from datetime import timedelta , date , datetime
from datetime import timedelta , date , datetime
from django . utils import timezone
from itertools import groupby
from itertools import groupby
import tempfile
import tempfile
import subprocess
import subprocess
@ -30,6 +39,7 @@ import json
import traceback
import traceback
import sys
import sys
import csv
import csv
import logging
def verejna_temata ( rocnik ) :
def verejna_temata ( rocnik ) :
@ -37,6 +47,45 @@ def verejna_temata(rocnik):
"""
"""
return Problem . objects . filter ( typ = Problem . TYP_TEMA , cislo_zadani__rocnik = rocnik , cislo_zadani__verejne_db = True ) . order_by ( ' kod ' )
return Problem . objects . filter ( typ = Problem . TYP_TEMA , cislo_zadani__rocnik = rocnik , cislo_zadani__verejne_db = True ) . order_by ( ' kod ' )
def temata_v_rocniku ( rocnik ) :
return Problem . objects . filter ( typ = Problem . TYP_TEMA , rocnik = rocnik )
def get_problemy_k_tematu ( tema ) :
return Problemy . objects . filter ( nadproblem = tema )
class VlozBodyView ( generic . ListView ) :
template_name = ' seminar/org/vloz_body.html '
def get_queryset ( self ) :
self . tema = get_object_or_404 ( Problem , id = self . kwargs [ ' tema ' ] )
print ( self . tema )
self . problemy = Problem . objects . filter ( nadproblem = self . tema )
print ( self . problemy )
self . reseni = Reseni . objects . filter ( problem__in = self . problemy )
print ( self . reseni )
return self . reseni
class ObalkovaniView ( generic . ListView ) :
template_name = ' seminar/org/obalkovani.html '
def get_queryset ( self ) :
rocnik = get_object_or_404 ( Rocnik , rocnik = self . kwargs [ ' rocnik ' ] )
cislo = get_object_or_404 ( Cislo , rocnik = rocnik , poradi = self . kwargs [ ' cislo ' ] )
self . cislo = cislo
self . hodnoceni = s . Hodnoceni . objects . filter ( cislo_body = cislo )
self . reseni = Reseni . objects . filter ( hodnoceni__in = self . hodnoceni ) . annotate ( Sum ( ' hodnoceni__body ' ) ) . annotate ( Count ( ' hodnoceni ' ) ) . order_by ( ' resitele__osoba ' )
return self . reseni
def get_context_data ( self , * * kwargs ) :
context = super ( ObalkovaniView , self ) . get_context_data ( * * kwargs )
print ( self . cislo )
context [ ' cislo ' ] = self . cislo
return context
def AktualniZadaniView ( request ) :
def AktualniZadaniView ( request ) :
nastaveni = get_object_or_404 ( Nastaveni )
nastaveni = get_object_or_404 ( Nastaveni )
@ -67,6 +116,99 @@ def ZadaniTemataView(request):
}
}
)
)
# TODO Napsat tuto funkci znovu rekurzivně podle Jethrorad. Potom se podívat, jak lehce se dá modifikovat pro Rozcestník. Pokud lehce, rozšířit ji. Pokud složitě - použít tuhle
def vytahniZLesaSeznam ( tematko , koren , pouze_zajimave = False ) :
returnVal = [ ]
stack = [ ]
stack . append ( ( koren . first_child , 0 , False ) ) #Tuple of node, depth and relevance
while len ( stack ) > 0 :
wn , wd , wr = stack . pop ( )
if wn . succ != None :
stack . append ( ( wn . succ , wd , wr ) )
if isinstance ( wn , s . TemaVCisleNode ) :
print ( " TEMA " )
print ( wn . tema . id )
print ( tematko . id )
if wn . tema . id == tematko . id :
returnVal . append ( ( posledni_cislo , 0 ) )
print ( " PRIDANO " )
wr = True
wd = 1
if wn . srolovatelne :
tagOpen = s . Text ( na_web = " Otevírací srolovací tag " )
tagOpenNode = s . TextNode ( text = tagOpen )
tagClose = s . Text ( na_web = " Zavírací srolovací tag " )
tagCloseNode = s . TextNode ( text = tagClose )
stack . append ( ( tagCloseNode , wd , True ) )
if wn . first_child != None :
stack . append ( ( wn . first_child , wd + 1 , wr ) )
if isinstance ( wn , s . CisloNode ) :
posledni_cislo = wn
print ( wn )
if wr :
print ( " ZAJIMAVE " )
if pouze_zajimave :
if not wn . zajimave :
continue
returnVal . append ( ( wn , wd ) )
return returnVal
def TematkoView ( request , rocnik , tematko ) :
nastaveni = s . Nastaveni . objects . first ( )
rocnik_object = s . Rocnik . objects . filter ( rocnik = rocnik )
tematko_object = s . Tema . objects . filter ( rocnik = rocnik_object [ 0 ] , kod = tematko )
seznam = vytahniZLesaSeznam ( tematko_object [ 0 ] , nastaveni . aktualni_rocnik ( ) . rocniknode )
for node , depth in seznam :
if node . isinstance ( node , s . KonferaNode ) :
raise Exception ( " Not implemented yet " )
if node . isinstance ( node , s . PohadkaNode ) : # Mohu ignorovat, má pod sebou
pass
return render ( request , ' seminar/tematka/toaletak.html ' , { } )
def TemataRozcestnikView ( request ) :
print ( " ============================================= " )
nastaveni = s . Nastaveni . objects . first ( )
tematka_objects = s . Tema . objects . filter ( rocnik = nastaveni . aktualni_rocnik ( ) )
tematka = [ ] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku
for tematko_object in tematka_objects :
print ( " AKTUALNI TEMATKO " )
print ( tematko_object . id )
odkazy = vytahniZLesaSeznam ( tematko_object , nastaveni . aktualni_rocnik ( ) . rocniknode , pouze_zajimave = True ) #Odkazy jsou tuply (node, depth) v listu
print ( odkazy )
cisla = [ ] # List tuplů (nazev cisla, list odkazů)
vcisle = [ ]
cislo = None
for odkaz in odkazy :
if odkaz [ 1 ] == 0 :
if cislo != None :
cisla . append ( ( cislo , vcisle ) )
cislo = ( odkaz [ 0 ] . getOdkazStr ( ) , odkaz [ 0 ] . getOdkaz ( ) )
vcisle = [ ]
else :
print ( odkaz [ 0 ] . getOdkaz ( ) )
vcisle . append ( ( odkaz [ 0 ] . getOdkazStr ( ) , odkaz [ 0 ] . getOdkaz ( ) ) )
if cislo != None :
cisla . append ( ( cislo , vcisle ) )
print ( cisla )
tematka . append ( {
" kod " : tematko_object . kod ,
" nazev " : tematko_object . nazev ,
" abstrakt " : tematko_object . abstrakt ,
" obrazek " : tematko_object . obrazek ,
" cisla " : cisla
} )
return render ( request , ' seminar/tematka/rozcestnik.html ' , { " tematka " : tematka , " rocnik " : nastaveni . aktualni_rocnik ( ) . rocnik } )
#def ZadaniAktualniVysledkovkaView(request):
#def ZadaniAktualniVysledkovkaView(request):
# nastaveni = get_object_or_404(Nastaveni)
# nastaveni = get_object_or_404(Nastaveni)
@ -143,7 +285,7 @@ class StareNovinkyView(generic.ListView):
# Organizatori
# Organizatori
def aktivniOrganizatori ( datum = date . today ( ) ) :
def aktivniOrganizatori ( datum = timezone . now ( ) ) :
return Organizator . objects . exclude (
return Organizator . objects . exclude (
organizuje_do__isnull = False ,
organizuje_do__isnull = False ,
organizuje_do__lt = datum
organizuje_do__lt = datum
@ -252,26 +394,115 @@ class ArchivView(generic.ListView):
context [ " nahledy " ] = " \n " . join ( tags )
context [ " nahledy " ] = " \n " . join ( tags )
return context
return context
### Výsledky
def sloupec_s_poradim ( vysledky ) :
# počet řešitelů ve výsledkovce nad aktuálním
# ze setřízeného(!) seznamu všech bodů vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.)
lepsich_resitelu = 0
def sloupec_s_poradim ( seznam_s_body ) :
aktualni_poradi = 1
poradi_l = [ ]
sloupec_s_poradim = [ ]
# projdeme skupiny řešitelů se stejným počtem bodů
for skupina in ( list ( x ) for _ , x in groupby ( vysledky , lambda x : x . body ) ) :
# seskupíme seznam všech bodů podle hodnot
for index in range ( 0 , len ( seznam_s_body ) ) :
# připravíme si obsahy buněk ve sloupci pořadí pro skupinu
# pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah a chceme
if len ( skupina ) == 1 :
# vypsat už jen prázdné místo, než dojdeme na správný řádek
poradi_l + = [ " {} . " . format ( lepsich_resitelu + 1 ) ]
if ( index + 1 ) < aktualni_poradi :
# je-li účastníků se stejným počtem bodů víc, pořadí (rozsah X.-Y.) je jen u prvního
sloupec_s_poradim . append ( " " )
continue
velikost_skupiny = 0
# zjistíme počet po sobě jdoucích stejných hodnot
while seznam_s_body [ index ] == seznam_s_body [ index + velikost_skupiny ] :
velikost_skupiny = velikost_skupiny + 1
# na konci musíme ošetřit přetečení seznamu
if ( index + velikost_skupiny ) > len ( seznam_s_body ) - 1 :
break
# pokud je velikost skupiny 1, vypíšu pořadí
if velikost_skupiny == 1 :
sloupec_s_poradim . append ( " {} . " . format ( aktualni_poradi ) )
# pokud je skupina větší, vypíšu rozsah
else :
else :
poradi_l + = [ u " {} .– {} . " . format ( lepsich_resitelu + 1 , lepsich_resitelu + len ( skupina ) ) ] + [ " " ] * ( len ( skupina ) - 1 )
sloupec_s_poradim . append ( " {} .– {} . " . format ( aktualni_poradi ,
lepsich_resitelu + = len ( skupina )
aktualni_poradi + velikost_skupiny - 1 ) )
#pomlcka je opravdu pomlcka v unicode!!dulezite pro vysledkovku v TeXu
# zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno
aktualni_poradi = aktualni_poradi + velikost_skupiny
return poradi_l
return sloupec_s_poradim
# spočítá součet bodů získaných daným řešitelem za zadaný problém a všechny jeho podproblémy
def __soucet_resitele_problemu ( problem , resitel , cislo , soucet ) :
# sečteme body za daný problém přes všechna řešení daného problému
# od daného řešitele
reseni_resitele = problem . hodnoceni_set . filter ( reseni__resitele = resitel ,
cislo_body = cislo )
# XXX chyba na řádku výše - řešení může mít více řešitelů, asi chceme contains
# nebo in
for r in reseni_resitele :
soucet + = r . body
# a přičteme k tomu hodnocení všech podproblémů
for p in problem . podproblem . all ( ) :
# i přes jméno by to měla být množina jeho podproblémů
soucet + = __soucet_resitele_problemu ( p , resitel , soucet )
return soucet
# spočítá součet všech bodů ze všech podproblémů daného problému daného řešitele
def body_resitele_problemu_v_cisle ( problem , resitel , cislo ) :
# probably FIXED: nezohledňuje číslo, do kterého se body počítají
return __soucet_resitele_problemu ( problem , resitel , cislo , 0 )
# vrátí list všech problémů s body v daném čísle, které již nemají nadproblém
def hlavni_problemy_cisla ( cislo ) :
hodnoceni = cislo . hodnoceni . select_related ( ' problem ' , ' reseni ' ) . all ( ) # hodnocení, která se vážou k danému číslu
reseni = [ h . reseni for h in hodnoceni ]
problemy = [ h . problem for h in hodnoceni ]
problemy_set = set ( problemy ) # chceme každý problém unikátně,
problemy = ( list ( problemy_set ) ) # převedení na množinu a zpět to zaručí
# hlavní problémy čísla
# (mají vlastní sloupeček ve výsledkovce, nemají nadproblém)
hlavni_problemy = [ ]
for p in problemy :
while not ( p . nadproblem == None ) :
p = p . nadproblem
hlavni_problemy . append ( p )
# zunikátnění
hlavni_problemy_set = set ( hlavni_problemy )
hlavni_problemy = list ( hlavni_problemy_set )
hlavni_problemy . sort ( key = lambda k : k . kod_v_rocniku ( ) ) # setřídit podle t1, t2, c3, ...
return hlavni_problemy
def body_resitele_odjakziva ( resitel ) :
body = 0
resitelova_hodnoceni = Hodnoceni . objects . select_related ( ' body ' ) . all ( ) . filter ( reseni_resitele = resitel )
# TODO: v radku nahore chceme _in nebo _contains
for hodnoceni in resitelova_hodnoceni :
body = body + hodnoceni . body
return body
# spočítá součet všech bodů řešitele za dané číslo
def body_resitele_v_cisle ( resitel , cislo ) :
hlavni_problemy = hlavni_problemy_cisla ( cislo )
body_resitele = 0
for h in hlavni_problemy :
body_resitele = body_resitele + body_resitele_problemu_v_cisle ( h , resitel , cislo )
# TODO: je rozdíl mezi odevzdanou úlohou za 0 a tím, když řešitel nic neodevzdal
# řešit přes kontrolu velikosti množiny řešení daného problému do daného čísla?
# Tady to ale nevadí, tady se počítá součet za číslo.
return body_resitele
# spočítá součet všech bodů řešitele za daný rok (nebo jen do daného čísla včetně)
def body_resitele_v_rocniku ( resitel , rocnik , do_cisla = None ) :
# pokud do_cisla=None, tak do posledního čísla v ročníku
# do_cisla je objekt Cislo
cisla = rocnik . cisla . all ( ) # funkce vrátí pole objektů
# Cislo už lexikograficky setřízené, viz models
body = 0
for cislo in cisla :
if cislo . poradi == do_cisla . poradi : break
# druhá část zaručuje, že máme výsledky do daného čísla včetně
body = body + body_resitele_v_cisle ( resitel , cislo )
return body
#def vysledkovka_rocniku(rocnik, jen_verejne=True):
#def vysledkovka_rocniku(rocnik, jen_verejne=True):
# """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve
# """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve
@ -288,7 +519,7 @@ def sloupec_s_poradim(vysledky):
# return None
# return None
#
#
# #vybere vsechny vysledky z posledniho (verejneho) cisla a setridi sestupne dle bodu
# #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'))
# vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].poradi ).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel'))
#
#
# class Vysledkovka:
# class Vysledkovka:
# def __init__(self):
# def __init__(self):
@ -304,7 +535,7 @@ def sloupec_s_poradim(vysledky):
# v.poradi = poradi
# v.poradi = poradi
# v.resitel.rocnik = v.resitel.rocnik(rocnik)
# v.resitel.rocnik = v.resitel.rocnik(rocnik)
#
#
# verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].cislo )
# verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].poradi )
# if jen_verejne:
# if jen_verejne:
# verejne_vysl_odjakziva = verejne_vysl_odjakziva.filter(cislo__verejna_vysledkovka=True)
# verejne_vysl_odjakziva = verejne_vysl_odjakziva.filter(cislo__verejna_vysledkovka=True)
#
#
@ -380,16 +611,17 @@ class ProblemView(generic.DetailView):
class VysledkyResitele ( object ) :
class VysledkyResitele ( object ) :
""" Pro daného řešitele ukládá počet bodů za jednotlivé úlohy a celkový
""" Pro daného řešitele ukládá počet bodů za jednotlivé úlohy a celkový
počet bodů za číslo . """
počet bodů za konkrétní ročník do daného čísla a za dané číslo . """
def __init__ ( self , jmeno , prijmeni ) :
def __init__ ( self , resitel , cislo , rocnik ) :
resitel_jmeno = jmeno
self . resitel = resitel
resitel_prijmeni = prijmeni
self . cislo = cislo
body = { }
self . body_cislo = body_resitele_v_cisle ( resitel , cislo )
body_cislo = 0
self . body = [ ]
self . rocnik = rocnik
def body_za_cislo ( self ) :
self . body_rocnik = body_resitele_v_rocniku ( resitel , rocnik , cislo )
return sum ( body . values ( ) )
self . body_celkem_odjakziva = resitel . vsechny_body ( )
self . poradi = 0
class CisloView ( generic . DetailView ) :
class CisloView ( generic . DetailView ) :
model = Cislo
model = Cislo
@ -400,8 +632,8 @@ class CisloView(generic.DetailView):
if queryset is None :
if queryset is None :
queryset = self . get_queryset ( )
queryset = self . get_queryset ( )
rocnik_arg = self . kwargs . get ( ' rocnik ' )
rocnik_arg = self . kwargs . get ( ' rocnik ' )
cislo _arg = self . kwargs . get ( ' cislo ' )
poradi _arg = self . kwargs . get ( ' cislo ' )
queryset = queryset . filter ( rocnik__rocnik = rocnik_arg , cislo = cislo _arg)
queryset = queryset . filter ( rocnik__rocnik = rocnik_arg , poradi = poradi _arg)
try :
try :
obj = queryset . get ( )
obj = queryset . get ( )
@ -410,88 +642,53 @@ class CisloView(generic.DetailView):
{ ' verbose_name ' : queryset . model . _meta . verbose_name } )
{ ' verbose_name ' : queryset . model . _meta . verbose_name } )
return obj
return obj
# spočítá součet bodů získaných daným řešitelem za zadaný problém a všechny jeho podproblémy
def __soucet_resitele_problemu ( problem , resitel , soucet ) :
# FIXME: správně je nadproblem_(typ problemu), ale to by bylo potřeba nějak
# zjistit, jaký typ nodu to vlastně je a aplikovat to ve volání funkce
# sečteme body za daný problém přes všechna řešení daného problému
# od daného řešitele
reseni_resitele = problem . hodnoceni_set . filter ( reseni_resitele__contains = resitel )
for r in reseni_resitele :
soucet + = r . body
for p in problem . nadproblem_set :
# i přes jméno by to měla být množina jeho podproblémů
soucet + = __soucet_resitele_problemu ( p , resitel , soucet )
return soucet
def vysledky_resitele_problemu ( problem , resitel , cislo ) :
return __soucet_resitele_problemu ( problem , resitel , 0 )
def get_context_data ( self , * * kwargs ) :
def get_context_data ( self , * * kwargs ) :
context = super ( CisloView , self ) . get_context_data ( * * kwargs )
context = super ( CisloView , self ) . get_context_data ( * * kwargs )
## TODO upravit dle nového modelu
## TODO upravit dle nového modelu
cislo = context [ ' cislo ' ]
cislo = context [ ' cislo ' ]
hodnoceni = cislo . hodnoceni_set # hodnocení, která se vážou k danému číslu
hlavni_problemy = hlavni_problemy_cisla ( cislo )
reseni = [ h . reseni for h in hodnoceni ]
problemy = [ h . problem for h in hodnoceni ]
problemy_set = set ( problemy ) # chceme každý problém unikátně,
problemy = ( list ( problemy_set ) ) # převedení na množinu a zpět to zaručí
# hlavní problémy čísla
# (mají vlastní sloupeček ve výsledkovce, nemají nadproblém)
hlavni_problemy = [ ]
for p in problemy :
while not ( p . nadproblem == None ) :
p = nadproblem
hlavni_problemy . append ( p )
# zunikátnění
hlavni_problemy_set = set ( hlavni_problemy )
hlavni_problemy = list ( hlavni_problemy_set )
## TODO dostat pro tyto problémy součet v daném čísle pro daného řešitele
## TODO dostat pro tyto problémy součet v daném čísle pro daného řešitele
## TODO možná chytřeji vybírat aktivní řešitele
## TODO možná chytřeji vybírat aktivní řešitele
## chceme letos něco poslal
## chceme letos něco poslal
aktivni_resitele = Resitel . objects . filter (
aktivni_resitele = Resitel . objects . filter (
rok_maturity__gte = context [ ' rocnik ' ] . druhy_rok ( ) )
rok_maturity__gte = cislo . rocnik . druhy_rok ( ) )
# TODO: zkusit hodnoceni__rocnik...
#.filter(hodnoceni_set__rocnik__eq=cislo_rocnik)
#.filter(hodnoceni_set__rocnik__eq=cislo_rocnik)
radky_vysledkovky = [ ]
radky_vysledkovky = [ ]
for ar in aktivni_resitele :
for ar in aktivni_resitele :
vr = VysledkyResitele ( ar . jmeno , ar . prijmeni )
# získáme výsledky řešitele - součty přes číslo a ročník
for h in hlavni_problemy :
vr = VysledkyResitele ( ar , cislo , cislo . rocnik )
body = vysledky_resitele_problemu ( h , ar , cislo )
for hp in hlavni_problemy :
vr . body [ h . kod_v_rocniku ] = body
vr . body . append (
vr . body_cislo = vr . body_cislo + body
body_resitele_problemu_v_cisle ( hp , ar , cislo ) )
radky_vysledkovky . append ( vr )
radky_vysledkovky . append ( vr )
## TODO: spočítat počet bodů řešitele v daném ročníku a seřadit je podle toho
# setřídíme řádky výsledkovky/objekty VysledkyResitele podle bodů
## TODO: možná použít tyto funkce i v RocnikVysledkovkaView (a umístit sem nebo tam)?
radky_vysledkovky . sort ( key = lambda vr : vr . body_rocnik , reverse = True )
# vysledky = VysledkyKCisluZaRocnik.objects.filter(cislo = context['cislo']).\
# generujeme sloupec s pořadím pomocí stejně zvané funkce
# order_by('-body', 'resitel__prijmeni', 'resitel__jmeno')
pocty_bodu = [ rv . body_rocnik for rv in radky_vysledkovky ]
# reseni = Reseni.objects.filter(cislo_body = context['cislo']).select_related("resitel")
sloupec_poradi = sloupec_s_poradim ( pocty_bodu )
# každému řádku výsledkovky přidáme jeho pořadí
i = 0
for rv in radky_vysledkovky :
rv . poradi = sloupec_poradi [ i ]
i = i + 1
# vytahané informace předáváme do kontextu
context [ ' cislo ' ] = cislo
context [ ' radky_vysledkovky ' ] = radky_vysledkovky
context [ ' problemy ' ] = hlavni_problemy
# context['v_cisle_zadane'] = TODO
# context['resene_problemy'] = resene_problemy
#XXX testovat
#XXX opravit to, že se nezobrazují body za jednotlivé úlohy
# typy úloh, které se mají zobrazovat u čísla, tj. těch, které byly
return context
# 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()))
# 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
# #setridi problemy podle typu a poradi zadani
# problem_index = {}
# problem_index = {}
@ -529,7 +726,6 @@ class CisloView(generic.DetailView):
# context['problemy'] = problemy
# context['problemy'] = problemy
# context['v_cisle_zadane'] = v_cisle_zadane
# context['v_cisle_zadane'] = v_cisle_zadane
# context['resene_problemy'] = resene_problemy
# context['resene_problemy'] = resene_problemy
# return context
class ArchivTemataView ( generic . ListView ) :
class ArchivTemataView ( generic . ListView ) :
model = Problem
model = Problem
@ -601,9 +797,9 @@ def obalkyView(request,resitele):
tex = render ( request , ' seminar/archiv/obalky.tex ' , { ' resitele ' : resitele } ) . content
tex = render ( request , ' seminar/archiv/obalky.tex ' , { ' resitele ' : resitele } ) . content
tempdir = tempfile . mkdtemp ( )
tempdir = tempfile . mkdtemp ( )
with open ( tempdir + " /obalky.tex " , " wb " ) as texfile :
with open ( tempdir + " /obalky.tex " , " w " ) as texfile :
texfile . write ( tex )
texfile . write ( tex )
shutil . copy ( os . path . join ( settings . STATIC_ROOT , ' seminar/lisak.eps ' ) , tempdir )
shutil . copy ( os . path . join ( settings . STATIC_ROOT , ' seminar/lisak.pdf ' ) , tempdir )
subprocess . call ( [ " pdflatex " , " obalky.tex " ] , cwd = tempdir )
subprocess . call ( [ " pdflatex " , " obalky.tex " ] , cwd = tempdir )
with open ( tempdir + " /obalky.pdf " , " rb " ) as pdffile :
with open ( tempdir + " /obalky.pdf " , " rb " ) as pdffile :
@ -612,7 +808,7 @@ def obalkyView(request,resitele):
return response
return response
def obalkovaniView ( request , rocnik , cislo ) :
def oldO balkovaniView ( request , rocnik , cislo ) :
rocnik = Rocnik . objects . get ( rocnik = rocnik )
rocnik = Rocnik . objects . get ( rocnik = rocnik )
cislo = Cislo . objects . get ( rocnik = rocnik , cislo = cislo )
cislo = Cislo . objects . get ( rocnik = rocnik , cislo = cislo )
@ -749,7 +945,7 @@ def StavDatabazeView(request):
@ensure_csrf_cookie
@ensure_csrf_cookie
def LoginView ( request ) :
def TeXUpload LoginView( request ) :
""" Pro přihlášení při nahrávání z texu """
""" Pro přihlášení při nahrávání z texu """
q = request . POST
q = request . POST
# nastavení cookie csrftoken
# nastavení cookie csrftoken
@ -938,7 +1134,7 @@ def texDownloadView(request, rocnik, cislo):
" body " : p . body ,
" body " : p . body ,
" zadani " : p . text_zadani ,
" zadani " : p . text_zadani ,
" reseni " : p . text_reseni ,
" reseni " : p . text_reseni ,
" cislo_zadani " : p . cislo_zadani . cislo ,
" cislo_zadani " : p . cislo_zadani . poradi ,
} for p in resene
} for p in resene
] ,
] ,
}
}
@ -947,26 +1143,213 @@ def texDownloadView(request, rocnik, cislo):
cislo . save ( )
cislo . save ( )
return JsonResponse ( response )
return JsonResponse ( response )
class ResitelView ( LoginRequiredMixin , generic . DetailView ) :
model = Resitel
template_name = ' seminar/resitel.html '
def get_object ( self , queryset = None ) :
print ( self . request . user )
return Resitel . objects . get ( osoba__user = self . request . user )
## Formulare
## Formulare
class AddSolutionView ( LoginRequiredMixin , FormView ) :
template_name = ' seminar/org/vloz_reseni.html '
form_class = f . VlozReseniForm
success_url = ' / '
def resetPasswordView ( request ) :
pass
def get_name ( request ) :
def loginView ( request ) :
# if this is a POST request we need to process the form data
if request . method == ' POST ' :
if request . method == ' POST ' :
# create a form instance and populate it with data from the request:
form = LoginForm ( request . POST )
form = NameForm ( request . POST )
# check whether it's valid:
if form . is_valid ( ) :
if form . is_valid ( ) :
# process the data in form.cleaned_data as required
user = authenticate ( request ,
# ...
username = form . cleaned_data [ ' username ' ] ,
# redirect to a new URL:
password = form . cleaned_data [ ' password ' ] )
print ( form . cleaned_data )
if user is not None :
login ( request , user )
return HttpResponseRedirect ( ' / ' )
else :
return render ( request ,
' seminar/login.html ' ,
{ ' form ' : form , ' login_error ' : ' Neplatné jméno nebo heslo ' } )
else :
form = LoginForm ( )
return render ( request , ' seminar/login.html ' , { ' form ' : form } )
def logoutView ( request ) :
form = LoginForm ( )
if request . user . is_authenticated :
logout ( request )
return render ( request , ' seminar/login.html ' , { ' form ' : form , ' login_error ' : ' Byli jste úspěšně odhlášeni ' } )
return render ( request , ' seminar/login.html ' , { ' form ' : form } )
def prihlaska_log_gdpr_safe ( logger , gdpr_logger , msg , form_data ) :
msg = " {} , form_hash: {} " . format ( msg , hash ( form_data ) )
logger . warn ( msg )
gdpr_logger . warn ( msg + " , form: {} " . format ( form_data ) )
from django . forms . models import model_to_dict
def resitelEditView ( request ) :
err_logger = logging . getLogger ( ' seminar.prihlaska.problem ' )
## Načtení objektu Osoba a Resitel, patrici k aktuálně přihlášenému uživately
u = request . user
osoba_edit = Osoba . objects . get ( user = u )
resitel_edit = osoba_edit . resitel
user_edit = osoba_edit . user
## Vytvoření slovníku, kterým předvyplním formulář
prefill_1 = model_to_dict ( user_edit )
prefill_2 = model_to_dict ( resitel_edit )
prefill_3 = model_to_dict ( osoba_edit )
prefill_1 . update ( prefill_2 )
prefill_1 . update ( prefill_3 )
form = ProfileEditForm ( initial = prefill_1 )
## Změna údajů a jejich uložení
if request . method == ' POST ' :
form = ProfileEditForm ( request . POST )
if form . is_valid ( ) :
## Změny v osobě
fcd = form . cleaned_data
osoba_edit . jmeno = fcd [ ' jmeno ' ]
osoba_edit . prijmeni = fcd [ ' prijmeni ' ]
osoba_edit . pohlavi_muz = fcd [ ' pohlavi_muz ' ]
osoba_edit . email = fcd [ ' email ' ]
osoba_edit . telefon = fcd [ ' telefon ' ]
osoba_edit . ulice = fcd [ ' ulice ' ]
osoba_edit . mesto = fcd [ ' mesto ' ]
osoba_edit . psc = fcd [ ' psc ' ]
## Změny v osobě s podmínkami
if fcd . get ( ' spam ' , False ) :
osoba_edit . datum_souhlasu_zasilani = date . today ( )
if fcd . get ( ' stat ' , ' ' ) in ( ' CZ ' , ' SK ' ) :
osoba_edit . stat = fcd [ ' stat ' ]
else :
## Neznámá země
msg = " Unknown country {} " . format ( fcd [ ' stat_text ' ] )
## Změny v řešiteli
resitel_edit . skola = fcd [ ' skola ' ]
resitel_edit . rok_maturity = fcd [ ' rok_maturity ' ]
resitel_edit . zasilat = fcd [ ' zasilat ' ]
if fcd . get ( ' skola ' ) :
resitel_edit . skola = fcd [ ' skola ' ]
else :
# Unknown school - log it
msg = " Unknown school {} , {} " . format ( fcd [ ' skola_nazev ' ] , fcd [ ' skola_adresa ' ] )
resitel_edit . save ( )
osoba_edit . save ( )
return HttpResponseRedirect ( ' /thanks/ ' )
else :
## Stránka před odeslaním formuláře = předvyplněný formulář
return render ( request , ' seminar/edit.html ' , { ' form ' : form } )
def prihlaskaView ( request ) :
generic_logger = logging . getLogger ( ' seminar.prihlaska ' )
err_logger = logging . getLogger ( ' seminar.prihlaska.problem ' )
form_logger = logging . getLogger ( ' seminar.prihlaska.form ' )
if request . method == ' POST ' :
form = PrihlaskaForm ( request . POST )
# TODO vyresit, co se bude v jakych situacich zobrazovat
if form . is_valid ( ) :
generic_logger . info ( " Form valid " )
fcd = form . cleaned_data
form_hash = hash ( fcd )
form_logger . info ( fcd , form_hash = form_hash )
with transaction . atomic ( ) :
u = User . objects . create_user (
username = fcd [ ' username ' ] ,
password = fcd [ ' password ' ] ,
email = fcd [ ' email ' ] )
u . save ( )
o = Osoba (
jmeno = fcd [ ' jmeno ' ] ,
prijmeni = fcd [ ' prijmeni ' ] ,
pohlavi_muz = fcd [ ' pohlavi_muz ' ] ,
email = fcd [ ' email ' ] ,
telefon = fcd . get ( ' telefon ' , ' ' ) ,
datum_narozeni = fcd . get ( ' datum_narozeni ' , None ) ,
datum_souhlasu_udaje = date . today ( ) ,
datum_registrace = date . today ( ) ,
ulice = fcd . get ( ' ulice ' , ' ' ) ,
mesto = fcd . get ( ' mesto ' , ' ' ) ,
psc = fcd . get ( ' psc ' , ' ' ) ,
poznamka = str ( fcd )
)
if fcd . get ( ' spam ' , False ) :
o . datum_souhlasu_zasilani = date . today ( )
if fcd . get ( ' stat ' , ' ' ) in ( ' CZ ' , ' SK ' ) :
o . stat = fcd [ ' stat ' ]
else :
# Unknown country - log it
msg = " Unknown country {} " . format ( fcd [ ' stat_text ' ] )
err_logger . warn ( msg , form_hash = form_hash )
o . save ( )
o . user = u
o . save ( )
r = Resitel (
rok_maturity = fcd [ ' rok_maturity ' ] ,
zasilat = fcd [ ' zasilat ' ]
)
r . save ( )
r . osoba = o
if fcd . get ( ' skola ' ) :
r . skola = fcd [ ' skola ' ]
else :
# Unknown school - log it
msg = " Unknown school {} , {} " . format ( fcd [ ' skola_nazev ' ] , fcd [ ' skola_adresa ' ] )
err_logger . warn ( msg , form_hash = form_hash )
r . save ( )
return HttpResponseRedirect ( ' /thanks/ ' )
return HttpResponseRedirect ( ' /thanks/ ' )
# if a GET (or any other method) we'll create a blank form
# if a GET (or any other method) we'll create a blank form
else :
else :
form = NameForm ( )
form = Prihlaska Form( )
return render ( request , ' seminar/prihlaska.html ' , { ' form ' : form } )
return render ( request , ' seminar/prihlaska.html ' , { ' form ' : form } )
class SkolaAutocomplete ( autocomplete . Select2QuerySetView ) :
def get_queryset ( self ) :
# Don't forget to filter out results depending on the visitor !
qs = Skola . objects . all ( )
if self . q :
qs = qs . filter (
Q ( nazev__istartswith = self . q ) |
Q ( kratky_nazev__istartswith = self . q ) |
Q ( ulice__istartswith = self . q ) |
Q ( mesto__istartswith = self . q ) )
return qs
class LoginRequiredAjaxMixin ( object ) :
def dispatch ( self , request , * args , * * kwargs ) :
#if request.is_ajax() and not request.user.is_authenticated: # Pokud to otevřu jako stránku, tak se omezení neuplatní, takže to asi nechceme
if not request . user . is_authenticated :
return JsonResponse ( data = { ' results ' : [ ] , ' pagination ' : { } } , status = 401 )
return super ( LoginRequiredAjaxMixin , self ) . dispatch ( request , * args , * * kwargs )
class ResitelAutocomplete ( LoginRequiredAjaxMixin , autocomplete . Select2QuerySetView ) :
def get_queryset ( self ) :
qs = Resitel . objects . all ( )
if self . q :
qs = qs . filter (
Q ( osoba__jmeno__startswith = self . q ) |
Q ( osoba__prijmeni__startswith = self . q ) |
Q ( osoba__prezdivka__startswith = self . q )
)
return qs
# Ceka na autocomplete v3
# Ceka na autocomplete v3
# class OrganizatorAutocomplete(autocomplete.Select2QuerySetView):
# class OrganizatorAutocomplete(autocomplete.Select2QuerySetView):
# def get_queryset(self):
# def get_queryset(self):
@ -987,3 +1370,46 @@ def get_name(request):
# Q(user__last_name__isstartswith=query))
# Q(user__last_name__isstartswith=query))
#
#
# return qs
# return qs
# FIXME: Tohle asi vlastně vůbec nepatří do aplikace 'seminar'
class LoginView ( auth_views . LoginView ) :
# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL
template_name = ' seminar/login.html '
# Přesměrovací URL má být v kontextu:
def get_context_data ( self , * * kwargs ) :
ctx = super ( ) . get_context_data ( * * kwargs )
ctx [ ' next ' ] = reverse ( ' titulni_strana ' )
return ctx
class LogoutView ( auth_views . LogoutView ) :
# Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL
template_name = ' seminar/logout.html '
# Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité.
next_page = reverse_lazy ( ' titulni_strana ' )
# "Chci resetovat heslo"
class PasswordResetView ( auth_views . PasswordResetView ) :
#template_name = 'seminar/password_reset.html'
# TODO: vlastní email_template_name a subject_template_name a html_email_template_name
success_url = reverse_lazy ( ' reset_password_done ' )
from_email = ' login@mam.mff.cuni.cz '
# "Poslali jsme e-mail (pokud bylo kam))"
class PasswordResetDoneView ( auth_views . PasswordResetDoneView ) :
#template_name = 'seminar/password_reset_done.html'
pass
# "Vymysli si heslo"
class PasswordResetConfirmView ( auth_views . PasswordResetConfirmView ) :
#template_name = 'seminar/password_confirm_done.html'
success_url = reverse_lazy ( ' reset_password_complete ' )
# "Heslo se asi změnilo."
class PasswordResetCompleteView ( auth_views . PasswordResetCompleteView ) :
#template_name = 'seminar/password_complete_done.html'
pass
class PasswordChangeView ( auth_views . PasswordChangeView ) :
#template_name = 'seminar/password_change.html'
success_url = reverse_lazy ( ' titulni_strana ' )