464 lines
15 KiB
Python
464 lines
15 KiB
Python
from django.forms import model_to_dict
|
|
from django.shortcuts import redirect
|
|
from django.http import JsonResponse
|
|
from django.views import generic
|
|
from django.views.generic.edit import CreateView
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.core.exceptions import PermissionDenied
|
|
|
|
from seminar.models.pomocne import Obrazek
|
|
import treenode.models as s
|
|
import treenode.models as m
|
|
from treenode import treelib
|
|
import treenode.forms as f
|
|
import treenode.templatetags as tnltt
|
|
import treenode.serializers as vr
|
|
|
|
|
|
# ze starého modelu
|
|
#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')
|
|
|
|
|
|
# FIXME: Pozor, níž je ještě jeden ProblemView!
|
|
#class ProblemView(generic.DetailView):
|
|
# model = s.Problem
|
|
# # Zkopírujeme template_name od TreeNodeView, protože jsme prakticky jen trošku upravený TreeNodeView
|
|
# template_name = TreeNodeView.template_name
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# user = self.request.user
|
|
# # Teď potřebujeme doplnit tnldata do kontextu.
|
|
# # Ošklivý type switch, hezčí by bylo udělat to polymorfni. FIXME.
|
|
# if False:
|
|
# # Hezčí formátování zbytku :-P
|
|
# pass
|
|
# elif isinstance(self.object, s.Clanek) or isinstance(self.object, s.Konfera):
|
|
# # Tyhle Problémy mají ŘešeníNode
|
|
# context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user)
|
|
# elif isinstance(self.object, s.Uloha):
|
|
# # FIXME: Teď vždycky zobrazujeme i vzorák! Možná by bylo hezčí/lepší mít to stejně jako pro Téma: procházet jen dosažitelné z Ročníku / čísla / whatever
|
|
# tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user)
|
|
# tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user)
|
|
# context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak])
|
|
# elif isinstance(self.object, s.Tema):
|
|
# rocniknode = self.object.rocnik.rocniknode
|
|
# context['tnldata'] = TNLData.filter_treenode(rocniknode, lambda x: isinstance(x, s.TemaVCisleNode))
|
|
# else:
|
|
# raise ValueError("Obecný problém nejde zobrazit.")
|
|
# return context
|
|
|
|
#class AktualniZadaniView(generic.TemplateView):
|
|
# template_name = 'seminar/treenode.html'
|
|
|
|
# TODO Co chceme vlastně zobrazovat na této stránce? Zatím je zde aktuální číslo, ale může tu být cokoli jiného...
|
|
#class AktualniZadaniView(TreeNodeView):
|
|
# def get_object(self):
|
|
# nastaveni = get_object_or_404(Nastaveni)
|
|
# return nastaveni.aktualni_cislo.cislonode
|
|
#
|
|
# def get_context_data(self,**kwargs):
|
|
# nastaveni = get_object_or_404(Nastaveni)
|
|
# context = super().get_context_data(**kwargs)
|
|
# verejne = nastaveni.aktualni_cislo.verejne()
|
|
# context['verejne'] = verejne
|
|
# return context
|
|
|
|
|
|
# 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 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})
|
|
#
|
|
|
|
|
|
# FIXME: Pozor, výš je ještě jeden ProblemView!
|
|
#class ProblemView(generic.DetailView):
|
|
# model = Problem
|
|
#
|
|
# # Používáme funkci, protože přímo template_name neumí mít v přiřazení dost logiky. Ledaže by se to udělalo polymorfně...
|
|
# def get_template_names(self, **kwargs):
|
|
# # FIXME: Switch podle typu není hezký, ale nechtělo se mi to přepisovat celé. Správně by se tohle mělo řešit polymorfismem.
|
|
# spravne_templaty = {
|
|
# s.Uloha: "uloha",
|
|
# s.Tema: "tema",
|
|
# s.Konfera: "konfera",
|
|
# s.Clanek: "clanek",
|
|
# }
|
|
# context = super().get_context_data(**kwargs)
|
|
# return ['seminar/archiv/problem_' + spravne_templaty[context['object'].__class__] + '.html']
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# # Musí se používat context['object'], protože nevíme, jestli dostaneme úložku, téma, článek, .... a tyhle věci vyrábějí různé klíče.
|
|
# if not context['object'].verejne() and not self.request.user.je_org:
|
|
# raise PermissionDenied()
|
|
# if isinstance(context['object'], Clanek):
|
|
# context['reseni'] = Reseni.objects.filter(problem=context['object']).select_related('resitel').order_by('resitel__prijmeni')
|
|
# return context
|
|
|
|
class TNLData(object):
|
|
def __init__(self,anode,parent=None, index=None):
|
|
self.node = anode
|
|
self.sernode = vr.TreeNodeSerializer(anode)
|
|
self.children = []
|
|
self.parent = parent
|
|
self.tema_in_path = False
|
|
self.index = index
|
|
|
|
if parent:
|
|
self.tema_in_path = parent.tema_in_path
|
|
if isinstance(anode, m.TemaVCisleNode):
|
|
self.tema_in_path = True
|
|
|
|
def add_edit_options(self):
|
|
self.deletable = tnltt.deletable(self)
|
|
self.editable_siblings = tnltt.editableSiblings(self)
|
|
self.editable_children = tnltt.editableChildren(self)
|
|
self.text_only_subtree = tnltt.textOnlySubtree(self)
|
|
self.can_podvesit_za = tnltt.canPodvesitZa(self)
|
|
self.can_podvesit_pred = tnltt.canPodvesitPred(self)
|
|
self.appendable_children = tnltt.appendableChildren(self)
|
|
print("appChld",self.appendable_children)
|
|
if self.parent:
|
|
self.appendable_siblings = tnltt.appendableChildren(self.parent)
|
|
else:
|
|
self.appendable_siblings = []
|
|
@classmethod
|
|
def public_above(cls, anode):
|
|
""" Returns output of verejne for closest Rocnik, Cislo or Problem above.
|
|
(All of them have method verejne.)"""
|
|
parent = anode # chceme začít už od konkrétního node včetně
|
|
while True:
|
|
rocnik = isinstance(parent, s.RocnikNode)
|
|
cislo = isinstance(parent, s.CisloNode)
|
|
uloha = (isinstance(parent, s.UlohaVzorakNode) or
|
|
isinstance(parent, s.UlohaZadaniNode))
|
|
tema = isinstance(parent, s.TemaVCisleNode)
|
|
|
|
if (rocnik or cislo or uloha or tema) or parent==None:
|
|
break
|
|
else:
|
|
parent = treelib.get_parent(parent)
|
|
if rocnik:
|
|
return parent.rocnik.verejne()
|
|
elif cislo:
|
|
return parent.cislo.verejne()
|
|
elif uloha:
|
|
return parent.uloha.verejne()
|
|
elif tema:
|
|
return parent.tema.verejne()
|
|
elif None:
|
|
print("Existuje TreeNode, který není pod číslem, ročníkem, úlohou"
|
|
"ani tématem. {}".format(anode))
|
|
return False
|
|
|
|
@classmethod
|
|
def all_public_children(cls, anode):
|
|
for ch in treelib.all_children(anode):
|
|
if TNLData.public_above(ch):
|
|
yield ch
|
|
else:
|
|
continue
|
|
|
|
@classmethod
|
|
def from_treenode(cls, anode, user, parent=None, index=None):
|
|
if TNLData.public_above(anode) or user.has_perm('auth.org'):
|
|
out = cls(anode,parent,index)
|
|
else:
|
|
raise PermissionDenied()
|
|
|
|
if user.has_perm('auth.org'):
|
|
enum_children = enumerate(treelib.all_children(anode))
|
|
else:
|
|
enum_children = enumerate(TNLData.all_public_children(anode))
|
|
|
|
for (idx,ch) in enum_children:
|
|
outitem = cls.from_treenode(ch, user, out, idx)
|
|
out.children.append(outitem)
|
|
out.add_edit_options()
|
|
return out
|
|
|
|
@classmethod
|
|
def from_tnldata_list(cls, tnllist):
|
|
"""Vyrobíme virtuální TNL, který nemá obsah, ale má za potomky všechna zadaná TNLData"""
|
|
result = cls(None)
|
|
for idx, tnl in enumerate(tnllist):
|
|
result.children.append(tnl)
|
|
tnl.parent = result
|
|
tnl.index = idx
|
|
result.add_edit_options()
|
|
return result
|
|
|
|
@classmethod
|
|
def filter_treenode(cls, treenode, predicate):
|
|
tnll = cls._filter_treenode_recursive(treenode, predicate) # TreeNodeList List :-)
|
|
return TNLData.from_tnldata_list(tnll)
|
|
|
|
@classmethod
|
|
def _filter_treenode_recursive(cls, treenode, predicate):
|
|
if predicate(treenode):
|
|
return [cls.from_treenode(treenode)]
|
|
else:
|
|
found = []
|
|
for tn in treelib.all_children(treenode):
|
|
result = cls.filter_treenode(tn, predicate)
|
|
# Result by v tuhle chvíli měl být seznam TNLDat odpovídající treenodům, jež matchnuly predikát.
|
|
for tnl in result:
|
|
found.append(tnl)
|
|
return found
|
|
|
|
def to_json(self):
|
|
#self.node = anode
|
|
#self.children = []
|
|
#self.parent = parent
|
|
#self.tema_in_path = False
|
|
#self.index = index
|
|
out = {}
|
|
out['node'] = self.sernode.data
|
|
out['children'] = [n.to_json() for n in self.children]
|
|
out['tema_in_path'] = self.tema_in_path
|
|
out['index'] = self.index
|
|
out['deletable'] = self.deletable
|
|
out['editable_siblings'] = self.editable_siblings
|
|
out['editable_children'] = self.editable_children
|
|
out['text_only_subtree'] = self.text_only_subtree
|
|
out['can_podvesit_za'] = self.can_podvesit_za
|
|
out['can_podvesit_pod'] = self.can_podvesit_pred
|
|
out['appendable_children'] = self.appendable_children
|
|
out['appendable_siblings'] = self.appendable_siblings
|
|
|
|
return out
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
return("TNL({})".format(self.node))
|
|
|
|
|
|
class TreeNodeView(generic.DetailView):
|
|
model = s.TreeNode
|
|
template_name = 'treenode/treenode.html'
|
|
|
|
def get_context_data(self,**kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['tnldata'] = TNLData.from_treenode(self.object,self.request.user)
|
|
return context
|
|
|
|
|
|
class TreeNodeJSONView(generic.DetailView):
|
|
model = s.TreeNode
|
|
|
|
def get(self,request,*args, **kwargs):
|
|
self.object = self.get_object()
|
|
data = TNLData.from_treenode(self.object,self.request.user).to_json()
|
|
return JsonResponse(data)
|
|
|
|
|
|
class TreeNodePridatView(generic.View):
|
|
type_from_str = {
|
|
'rocnikNode': m.RocnikNode,
|
|
'cisloNode': m.CisloNode,
|
|
'castNode': m.CastNode,
|
|
'textNode': m.TextNode,
|
|
'temaVCisleNode': m.TemaVCisleNode,
|
|
'reseniNode': m.ReseniNode,
|
|
'ulohaZadaniNode': m.UlohaZadaniNode,
|
|
'ulohaVzorakNode': m.UlohaVzorakNode,
|
|
'pohadkaNode': m.PohadkaNode,
|
|
'orgText': m.OrgTextNode,
|
|
}
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
######## FIXME: ROZEPSANE, NEFUNGUJE, DOPSAT !!!!!! ###########
|
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
|
kam = self.kwargs['kam']
|
|
co = self.kwargs['co']
|
|
typ = self.type_from_str[co]
|
|
|
|
raise NotImplementedError('Neni to dopsane, dopis to!')
|
|
|
|
if kam not in ('pred','syn','za'):
|
|
raise ValidationError('Přidat lze pouze před nebo za node nebo jako syna')
|
|
|
|
if co == m.TextNode:
|
|
new_obj = m.Text()
|
|
new_obj.save()
|
|
elif co == m.CastNode:
|
|
new_obj = m.CastNode()
|
|
new_obj.nadpis = request.POST.get('pridat-castNode-{}-{}'.format(node.id,kam))
|
|
new_obj.save()
|
|
elif co == m.ReseniNode:
|
|
new_obj = m
|
|
pass
|
|
elif co == m.UlohaZadaniNode:
|
|
pass
|
|
elif co == m.UlohaReseniNode:
|
|
pass
|
|
else:
|
|
new_obj = None
|
|
|
|
|
|
if kam == 'pred':
|
|
pass
|
|
|
|
|
|
if kam == 'syn':
|
|
if typ == m.TextNode:
|
|
text_obj = m.Text()
|
|
text_obj.save()
|
|
node = treelib.create_child(node, typ, text=text_obj)
|
|
else:
|
|
node = treelib.create_child(node, typ)
|
|
if kam == 'za':
|
|
if typ == m.TextNode:
|
|
text_obj = m.Text()
|
|
text_obj.save()
|
|
node = treelib.create_node_after(node, typ, text=text_obj)
|
|
else:
|
|
node = treelib.create_node_after(node, typ)
|
|
|
|
return redirect(node.get_admin_url())
|
|
|
|
|
|
class TreeNodeSmazatView(generic.base.View):
|
|
def post(self, request, *args, **kwargs):
|
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
|
if node.first_child:
|
|
raise NotImplementedError('Mazání TreeNode se syny není zatím podporováno!')
|
|
treelib.disconnect_node(node)
|
|
node.delete()
|
|
return redirect(request.headers.get('referer'))
|
|
|
|
|
|
class TreeNodeOdvesitPrycView(generic.base.View):
|
|
def post(self, request, *args, **kwargs):
|
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
|
treelib.disconnect_node(node)
|
|
node.root = None
|
|
node.save()
|
|
return redirect(request.headers.get('referer'))
|
|
|
|
|
|
class TreeNodePodvesitView(generic.base.View):
|
|
def post(self, request, *args, **kwargs):
|
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
|
kam = self.kwargs['kam']
|
|
if kam == 'pred':
|
|
treelib.lower_node(node)
|
|
elif kam == 'za':
|
|
raise NotImplementedError('Podvěsit za není zatím podporováno')
|
|
return redirect(request.headers.get('referer'))
|
|
|
|
|
|
class TreeNodeProhoditView(generic.base.View):
|
|
def post(self, request, *args, **kwargs):
|
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
|
treelib.swap_succ(node)
|
|
return redirect(request.headers.get('referer'))
|
|
#FIXME ve formulari predat puvodni url a vratit redirect na ni
|
|
|
|
class SirotcinecView(generic.ListView):
|
|
model = s.TreeNode
|
|
template_name = 'treenode/orphanage.html'
|
|
|
|
def get_queryset(self):
|
|
return s.TreeNode.objects.not_instance_of(s.RocnikNode).filter(root=None,prev=None,succ=None,father_of_first=None)
|
|
|
|
# FIXME pouzit Django REST Framework
|
|
class TextWebView(generic.DetailView):
|
|
model = s.Text
|
|
|
|
def get(self,request,*args, **kwargs):
|
|
self.object = self.get_object()
|
|
return JsonResponse(model_to_dict(self.object,exclude='do_cisla'))
|
|
|
|
|
|
class VueTestView(generic.TemplateView):
|
|
template_name = 'treenode/vuetest.html'
|
|
|
|
|
|
class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView):
|
|
model = Obrazek
|
|
form_class = f.NahrajObrazekKTreeNoduForm
|
|
|
|
def get_initial(self):
|
|
initial = super().get_initial()
|
|
initial['na_web'] = self.request.FILES['upload']
|
|
return initial
|
|
|
|
|
|
def form_valid(self,form):
|
|
print(self.request.headers)
|
|
print(self.request.headers['Textid'])
|
|
print(form.instance)
|
|
print(form)
|
|
self.object = form.save(commit=False)
|
|
print(self.object.na_web)
|
|
self.object.text = m.Text.objects.get(pk=int(self.request.headers['Textid']))
|
|
self.object.save()
|
|
|
|
return JsonResponse({"url":self.object.na_web.url})
|