Jonas Havelka
3 years ago
32 changed files with 459 additions and 292 deletions
@ -1,5 +1,4 @@ |
|||
from .views_all import * |
|||
from .views_rest import * |
|||
|
|||
# Dočsasné views |
|||
from .docasne import * |
|||
|
@ -0,0 +1,88 @@ |
|||
from django.contrib import admin |
|||
|
|||
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter |
|||
|
|||
import seminar.models as m |
|||
|
|||
# Polymorfismus pro stromy |
|||
# TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html |
|||
|
|||
@admin.register(m.TreeNode) |
|||
class TreeNodeAdmin(PolymorphicParentModelAdmin): |
|||
base_model = m.TreeNode |
|||
child_models = [ |
|||
m.RocnikNode, |
|||
m.CisloNode, |
|||
m.MezicisloNode, |
|||
m.TemaVCisleNode, |
|||
m.UlohaZadaniNode, |
|||
m.PohadkaNode, |
|||
m.UlohaVzorakNode, |
|||
m.TextNode, |
|||
m.CastNode, |
|||
m.OrgTextNode, |
|||
] |
|||
|
|||
actions = ['aktualizuj_nazvy'] |
|||
|
|||
# XXX: nejspíš je to totální DB HOG, nechcete to použít moc často. |
|||
def aktualizuj_nazvy(self, request, queryset): |
|||
newqs = queryset.get_real_instances() |
|||
for tn in newqs: |
|||
tn.aktualizuj_nazev() |
|||
tn.save() |
|||
self.message_user(request, "Názvy aktualizovány.") |
|||
aktualizuj_nazvy.short_description = "Aktualizuj vybraným TreeNodům názvy" |
|||
|
|||
@admin.register(m.RocnikNode) |
|||
class RocnikNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.RocnikNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.CisloNode) |
|||
class CisloNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.CisloNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.MezicisloNode) |
|||
class MezicisloNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.MezicisloNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.TemaVCisleNode) |
|||
class TemaVCisleNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.TemaVCisleNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.UlohaZadaniNode) |
|||
class UlohaZadaniNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.UlohaZadaniNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.PohadkaNode) |
|||
class PohadkaNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.PohadkaNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.UlohaVzorakNode) |
|||
class UlohaVzorakNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.UlohaVzorakNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.TextNode) |
|||
class TextNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.TextNode |
|||
show_in_index = True |
|||
|
|||
@admin.register(m.CastNode) |
|||
class TextNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.CastNode |
|||
show_in_index = True |
|||
fields = ('nadpis',) |
|||
|
|||
@admin.register(m.OrgTextNode) |
|||
class TextNodeAdmin(PolymorphicChildModelAdmin): |
|||
base_model = m.OrgTextNode |
|||
show_in_index = True |
|||
|
|||
|
@ -0,0 +1,5 @@ |
|||
from django.apps import AppConfig |
|||
|
|||
|
|||
class TreenodeConfig(AppConfig): |
|||
name = 'treenode' |
@ -1,5 +1,5 @@ |
|||
from rest_framework import routers |
|||
from seminar import viewsets as vs |
|||
from treenode import viewsets as vs |
|||
|
|||
router = routers.DefaultRouter() |
|||
|
@ -1,5 +1,5 @@ |
|||
from django.test import TestCase |
|||
import seminar.treelib as tl |
|||
import treenode.treelib as tl |
|||
import seminar.models as m |
|||
|
|||
class SimpleTreeLibTests(TestCase): |
@ -0,0 +1,18 @@ |
|||
from django.urls import path, re_path |
|||
from . import views |
|||
|
|||
urlpatterns = [ |
|||
#path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='seminar_treenode'), |
|||
#path('treenode/<int:pk>/json/', views.TreeNodeJSONView.as_view(), name='seminar_treenode_json'), |
|||
#path('treenode/text/<int:pk>/', views.TextWebView.as_view(), name='seminar_textnode_web'), |
|||
#path('treenode/editor/pridat/<str:co>/<int:pk>/<str:kam>/', views.TreeNodePridatView.as_view(), name='treenode_pridat'), |
|||
#path('treenode/editor/smazat/<int:pk>/', views.TreeNodeSmazatView.as_view(), name='treenode_smazat'), |
|||
#path('treenode/editor/odvesitpryc/<int:pk>/', views.TreeNodeOdvesitPrycView.as_view(), name='treenode_odvesitpryc'), |
|||
#path('treenode/editor/podvesit/<int:pk>/<str:kam>/', views.TreeNodePodvesitView.as_view(), name='treenode_podvesit'), |
|||
#path('treenode/editor/prohodit/<int:pk>/', views.TreeNodeProhoditView.as_view(), name='treenode_prohodit'), |
|||
#path('treenode/sirotcinec/', views.SirotcinecView.as_view(), name='seminar_treenode_sirotcinec'), |
|||
#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'), |
|||
|
|||
re_path(r'^temp/vue/.*$',views.VueTestView.as_view(),name='vue_test_view'), |
|||
path('temp/image_upload/', views.NahrajObrazekKTreeNoduView.as_view()), |
|||
] |
@ -0,0 +1,322 @@ |
|||
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 |
|||
|
|||
import seminar.models as s |
|||
import seminar.models as m |
|||
from treenode import treelib |
|||
import treenode.forms as f |
|||
import treenode.templatetags as tnltt |
|||
import treenode.serializers as vr |
|||
|
|||
import logging |
|||
|
|||
logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
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 = s.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}) |
Loading…
Reference in new issue