123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- from django.urls import reverse
- class Node:
- def __init__(self, name=None, icon=None, link=None):
- self.parent = None
- self.name = name
- self.icon = icon
- self.link = link
- self._children = []
- self._children_dict = {}
- self._resolved_namespace = None
- @property
- def namespace(self):
- if self._resolved_namespace:
- return self._resolved_namespace
- bits = self.link.split(":")
- self._resolved_namespace = ":".join(bits[:-1])
- return self._resolved_namespace
- def children(self):
- return self._children
- def children_as_dicts(self):
- childrens = []
- for children in self._children:
- childrens.append(
- {
- "name": children.name,
- "icon": children.icon,
- "link": reverse(children.link),
- "namespace": children.namespace,
- }
- )
- return childrens
- def add_node(self, node, after=None, before=None):
- if after:
- return self.add_node_after(node, after)
- if before:
- return self.add_node_before(node, before)
- node.parent = self
- self._children.append(node)
- self._children_dict[node.link] = node
- return True
- def add_node_after(self, node, after):
- success = False
- new_children_list = []
- for children in self._children:
- new_children_list.append(children)
- if children.link == after:
- new_children_list.append(node)
- success = True
- if success:
- node.parent = self
- self._children_dict[node.link] = node
- self._children = new_children_list
- return success
- def add_node_before(self, node, before):
- success = False
- new_children_list = []
- for children in self._children:
- if children.link == before:
- new_children_list.append(node)
- success = True
- new_children_list.append(children)
- if success:
- node.parent = self
- self._children_dict[node.link] = node
- self._children = new_children_list
- return success
- def child(self, namespace):
- try:
- return self._children_dict[namespace]
- except KeyError:
- raise ValueError(
- "Node %s is not a child of node %s" % (namespace, self.name)
- )
- def is_root(self):
- return False
- class AdminHierarchyBuilder:
- def __init__(self):
- self.nodes_record = []
- self.nodes_dict = {}
- def build_nodes_dict(self):
- nodes_dict = {"misago:admin": Node(link="misago:admin:index")}
- iterations = 0
- while self.nodes_record:
- iterations += 1
- if iterations > 512:
- message = (
- "Misago Admin hierarchy is invalid or too complex to resolve. "
- "Nodes left: %s"
- )
- raise ValueError(message % self.nodes_record)
- for index, node in enumerate(self.nodes_record):
- if node["parent"] in nodes_dict:
- node_obj = Node(
- name=node["name"], icon=node["icon"], link=node["link"]
- )
- parent = nodes_dict[node["parent"]]
- if node["after"]:
- node_added = parent.add_node(node_obj, after=node["after"])
- elif node["before"]:
- node_added = parent.add_node(node_obj, before=node["before"])
- else:
- node_added = parent.add_node(node_obj)
- if node_added:
- namespace = node.get("namespace") or node_obj.namespace
- if namespace not in nodes_dict:
- nodes_dict[namespace] = node_obj
- del self.nodes_record[index]
- break
- return nodes_dict
- def add_node(
- self,
- name=None,
- icon=None,
- parent="misago:admin",
- after=None,
- before=None,
- namespace=None,
- link=None,
- ):
- if self.nodes_dict:
- raise RuntimeError(
- "Misago admin site has already been initialized. "
- "You can't add new nodes to it."
- )
- if after and before:
- raise ValueError("after and before arguments are exclusive")
- self.nodes_record.append(
- {
- "name": name,
- "icon": icon,
- "parent": parent,
- "namespace": namespace,
- "after": after,
- "before": before,
- "link": link,
- }
- )
- def visible_branches(self, request):
- if not self.nodes_dict:
- self.nodes_dict = self.build_nodes_dict()
- branches = []
- try:
- namespace = request.resolver_match.namespace
- except AttributeError:
- namespace = "misago:admin"
- if namespace in self.nodes_dict:
- node = self.nodes_dict[namespace]
- while node:
- children = node.children_as_dicts()
- if children:
- branches.append(children)
- node = node.parent
- try:
- namespaces = request.resolver_match.namespaces
- except AttributeError:
- namespaces = ["misago", "admin"]
- branches.reverse()
- for depth, branch in enumerate(branches):
- depth_namespace = namespaces[2 : 3 + depth]
- for node in branch:
- node_namespace = node["namespace"].split(":")[2 : 3 + depth]
- if request.resolver_match:
- node["is_active"] = depth_namespace == node_namespace
- else:
- node["is_active"] = False
- return branches
- site = AdminHierarchyBuilder()
|