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})