Browse Source

Merge remote-tracking branch 'origin/data_migrations' into treenode_editor

export_seznamu_prednasek
parent
commit
e4818d28ea
  1. 28
      seminar/export.py
  2. 8
      seminar/urls.py
  3. 22
      seminar/utils.py
  4. 225
      seminar/views/views_all.py

28
seminar/export.py

@ -8,10 +8,10 @@ from django.utils.encoding import force_text
from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
from .ovvpfile import OvvpFile from .ovvpfile import OvvpFile
from seminar import views
class ExportIndexView(generic.View): class ExportIndexView(generic.View):
def get(self, request): def get(self, request):
ls = [] ls = []
for r in Rocnik.objects.filter(exportovat = True): for r in Rocnik.objects.filter(exportovat = True):
url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok}) url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok})
@ -63,7 +63,7 @@ class ExportSousView(generic.View):
return of.to_HttpResponse() return of.to_HttpResponse()
# POZOR! Předělání na nový model neotestováno v reálu (ale zase jen drobné změny)
class ExportRocnikView(generic.View): class ExportRocnikView(generic.View):
def get(self, request, prvni_rok=None): def get(self, request, prvni_rok=None):
@ -76,30 +76,28 @@ class ExportRocnikView(generic.View):
rocnik = get_object_or_404(Rocnik, prvni_rok=pr, exportovat=True) rocnik = get_object_or_404(Rocnik, prvni_rok=pr, exportovat=True)
cislo = rocnik.posledni_zverejnena_vysledkovka_cislo() cislo = rocnik.posledni_zverejnena_vysledkovka_cislo()
vysledky = VysledkyKCisluZaRocnik.objects.filter(cislo = cislo).select_related("resitel").order_by('-body').all() resitele = views.aktivniResitele(cislo.rocnik.rocnik, cislo.poradi, True)
slovnik_body = views.secti_body_za_rocnik(cislo, resitele)
_, setrizeni_resitele, setrizene_body = views.setrid_resitele_a_body(slovnik_body)
of = default_ovvpfile('MaM.rocnik', rocnik) of = default_ovvpfile('MaM.rocnik', rocnik)
of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format( of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format(rocnik=rocnik, cislo=cislo)
rocnik=rocnik, cislo=cislo)
of.columns = ['id', 'name', 'surname', 'gender', 'born', 'email', 'end-year', of.columns = ['id', 'name', 'surname', 'gender', 'born', 'email', 'end-year',
'street', 'town', 'postcode', 'country', 'spam-flag', 'spam-date', 'street', 'town', 'postcode', 'country', 'spam-flag', 'spam-date',
'school', 'school-name', 'points', 'rank',] 'school', 'school-name', 'points', 'rank',]
# počítání pořadí řešitelů
posledni_body = 100000 posledni_body = 100000
posledni_poradi = 0 posledni_poradi = 0
for vi in range(len(vysledky)): for i in range(len(setrizeni_resitele)):
rd = setrizeni_resitele[i].export_row()
v = vysledky[vi]
rd = v.resitel.export_row()
if posledni_body > v.body: if posledni_body > body[i]:
posledni_body = v.body posledni_body = body[i]
posledni_poradi = vi + 1 posledni_poradi = i + 1
rd['rank'] = posledni_poradi rd['rank'] = posledni_poradi
rd['points'] = v.body rd['points'] = body[i]
of.rows.append(rd) of.rows.append(rd)
return of.to_HttpResponse() return of.to_HttpResponse()

8
seminar/urls.py

@ -94,17 +94,9 @@ urlpatterns = [
staff_member_required(views.StavDatabazeView), name='stav_databaze'), staff_member_required(views.StavDatabazeView), name='stav_databaze'),
path('cislo/<int:rocnik>.<int:cislo>/obalkovani', path('cislo/<int:rocnik>.<int:cislo>/obalkovani',
staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'), staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'),
path('cislo/<int:rocnik>.<int:cislo>/tex-download.json',
staff_member_required(views.texDownloadView), name='seminar_tex_download'),
path('soustredeni/<int:soustredeni>/obalky.pdf', path('soustredeni/<int:soustredeni>/obalky.pdf',
staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'),
path('tex-upload/login/', views.TeXUploadLoginView, name='seminar_login'),
path(
'tex-upload/',
staff_member_required(views.texUploadView),
name='seminar_tex_upload'
),
path('org/vloz_body/<int:tema>/', path('org/vloz_body/<int:tema>/',
staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'), staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'),
path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'),

22
seminar/utils.py

@ -49,40 +49,40 @@ def seznam_problemu():
# Pomocna fce k formatovani problemovych hlasek # Pomocna fce k formatovani problemovych hlasek
def prb(cls, msg, objs=None): def prb(cls, msg, objs=None):
s = u'<b>%s:</b> %s' % (cls.__name__, msg) s = '<b>%s:</b> %s' % (cls.__name__, msg)
if objs: if objs:
s += u' [' s += ' ['
for o in objs: for o in objs:
try: try:
url = o.admin_url() url = o.admin_url()
except: except:
url = None url = None
if url: if url:
s += u'<a href="%s">%s</a>, ' % (url, o.pk, ) s += '<a href="%s">%s</a>, ' % (url, o.pk, )
else: else:
s += u'%s, ' % (o.pk, ) s += '%s, ' % (o.pk, )
s = s[:-2] + u']' s = s[:-2] + ']'
problemy.append(s) problemy.append(s)
# Duplicita jmen # Duplicita jmen
jmena = {} jmena = {}
for r in m.Resitel.objects.all(): for r in m.Resitel.objects.all():
j = r.plne_jmeno() j = r.osoba.plne_jmeno()
if j not in jmena: if j not in jmena:
jmena[j] = [] jmena[j] = []
jmena[j].append(r) jmena[j].append(r)
for j in jmena: for j in jmena:
if len(jmena[j]) > 1: if len(jmena[j]) > 1:
prb(m.Resitel, u'Duplicitní jméno "%s"' % (j, ), jmena[j]) prb(m.Resitel, 'Duplicitní jméno "%s"' % (j, ), jmena[j])
# Data maturity a narození # Data maturity a narození
for r in m.Resitel.objects.all(): for r in m.Resitel.objects.all():
if not r.rok_maturity: if not r.rok_maturity:
prb(m.Resitel, u'Neznámý rok maturity', [r]) prb(m.Resitel, 'Neznámý rok maturity', [r])
if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10):
prb(m.Resitel, u'Podezřelé datum maturity', [r]) prb(m.Resitel, 'Podezřelé datum maturity', [r])
if r.datum_narozeni and (r.datum_narozeni.year < 1970 or r.datum_narozeni.year > datetime.date.today().year - 12): if r.osoba.datum_narozeni and (r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12):
prb(m.Resitel, u'Podezřelé datum narození', [r]) prb(m.Resitel, 'Podezřelé datum narození', [r])
# if not r.email: # if not r.email:
# prb(Resitel, u'Neznámý email', [r]) # prb(Resitel, u'Neznámý email', [r])

225
seminar/views/views_all.py

@ -645,6 +645,12 @@ class RadekVysledkovkyRocniku(object):
self.body_cisla_sezn = body_cisla_sezn self.body_cisla_sezn = body_cisla_sezn
self.titul = resitel.get_titul(body_odjakziva) self.titul = resitel.get_titul(body_odjakziva)
def setrid_resitele_a_body(slov_resitel_body):
setrizeni_resitele_id = [dvojice[0] for dvojice in slov_resitel_body]
setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id]
setrizene_body = [dvojice[1] for dvojice in slov_resitel_body]
return setrizeni_resitele_id, setrizeni_resitele, setrizene_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
formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html"
@ -665,9 +671,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True):
resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele) resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele)
# setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší # setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší
setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] setrizeni_resitele_id, setrizeni_resitele, setrizene_body = setrid_resitele_a_body(resitel_rocnikbody_sezn)
setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id]
setrizene_body = [dvojice[1] for dvojice in resitel_rocnikbody_sezn]
poradi = sloupec_s_poradim(setrizene_body) poradi = sloupec_s_poradim(setrizene_body)
# získáme body odjakživa # získáme body odjakživa
@ -958,12 +962,13 @@ def resi_v_rocniku(rocnik, cislo=None):
return letosni_resitele.distinct() return letosni_resitele.distinct()
def aktivniResitele(rocnik, cislo): def aktivniResitele(rocnik, cislo, pouze_realni=False):
""" Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali """ Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali
a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla). a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla).
Parametry: Parametry:
rocnik (typu int) číslo ročníku, o který se jedná rocnik (typu int) číslo ročníku, o který se jedná
cislo (typu int) pořadí čísla, o které se jedná cislo (typu int) pořadí čísla, o které se jedná
pouze_realni jen řešitelé, kteří tento rok něco poslali
""" """
letos = Rocnik.objects.get(rocnik = rocnik) letos = Rocnik.objects.get(rocnik = rocnik)
@ -980,6 +985,10 @@ def aktivniResitele(rocnik, cislo):
# pravděpodobně se jedná o číslo 7-8 # pravděpodobně se jedná o číslo 7-8
zacatek_rocniku = False zacatek_rocniku = False
# nehledě na číslo chceme jen řešitele, kteří letos něco odevzdali
if pouze_realni:
zacatek_rocniku = False
if not zacatek_rocniku: if not zacatek_rocniku:
return resi_v_rocniku(letos) return resi_v_rocniku(letos)
else: else:
@ -1123,8 +1132,8 @@ class ClankyResitelView(generic.ListView):
def StavDatabazeView(request): def StavDatabazeView(request):
# nastaveni = Nastaveni.objects.get() # nastaveni = Nastaveni.objects.get()
problemy = utils.seznam_problemu() problemy = utils.seznam_problemu()
muzi = Resitel.objects.filter(pohlavi_muz=True) muzi = Resitel.objects.filter(osoba__pohlavi_muz=True)
zeny = Resitel.objects.filter(pohlavi_muz=False) zeny = Resitel.objects.filter(osoba__pohlavi_muz=False)
return render(request, 'seminar/stav_databaze.html', return render(request, 'seminar/stav_databaze.html',
{ {
# 'nastaveni': nastaveni, # 'nastaveni': nastaveni,
@ -1133,211 +1142,11 @@ def StavDatabazeView(request):
'resitele': Resitel.objects.all(), 'resitele': Resitel.objects.all(),
'muzi': muzi, 'muzi': muzi,
'zeny': zeny, 'zeny': zeny,
'jmena_muzu': utils.histogram([r.jmeno for r in muzi]), 'jmena_muzu': utils.histogram([r.osoba.jmeno for r in muzi]),
'jmena_zen': utils.histogram([r.jmeno for r in zeny]), 'jmena_zen': utils.histogram([r.osoba.jmeno for r in zeny]),
}) })
@ensure_csrf_cookie
def TeXUploadLoginView(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.poradi,
} for p in resene
],
}
cislo.faze = Cislo.FAZE_TEX
cislo.save()
return JsonResponse(response)
class ResitelView(LoginRequiredMixin,generic.DetailView): class ResitelView(LoginRequiredMixin,generic.DetailView):
model = Resitel model = Resitel
template_name = 'seminar/resitel.html' template_name = 'seminar/resitel.html'

Loading…
Cancel
Save