hierarchy.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. from django.core.urlresolvers import reverse
  2. from misago.admin.urlpatterns import URLPatterns
  3. class Node(object):
  4. def __init__(self, link=None, name=None, icon=None):
  5. self.parent = None
  6. self.link = link
  7. self.name = name
  8. self.icon = icon
  9. self._children = []
  10. self._children_dict = {}
  11. @property
  12. def namespace(self):
  13. try:
  14. return self._resolved_namespace
  15. except AttributeError:
  16. bits = self.link.split(':')
  17. self._resolved_namespace = ':'.join(bits[:-1])
  18. return self._resolved_namespace
  19. def children(self):
  20. return self._children
  21. def children_as_dicts(self):
  22. childrens = []
  23. for children in self._children:
  24. childrens.append(
  25. {
  26. 'link': reverse(children.link),
  27. 'namespace': self.namespace,
  28. 'name': children.name,
  29. 'icon': children.icon,
  30. })
  31. return childrens
  32. def add_node(self, node, after=None, before=None):
  33. if after:
  34. return self.add_node_after(node, after)
  35. elif before:
  36. return self.add_node_before(node, before)
  37. else:
  38. node.parent = self
  39. self._children.append(node)
  40. self._children_dict[node.link] = node
  41. return True
  42. def add_node_after(self, node, after):
  43. success = False
  44. new_children_list = []
  45. for children in self._children:
  46. new_children_list.append(children)
  47. if children.link == after:
  48. new_children_list.append(node)
  49. success = True
  50. if success:
  51. node.parent = self
  52. self._children_dict[node.link] = node
  53. self._children = new_children_list
  54. return success
  55. def add_node_before(self, node, before):
  56. success = False
  57. new_children_list = []
  58. for children in self._children:
  59. if children.link == before:
  60. new_children_list.append(node)
  61. success = True
  62. new_children_list.append(children)
  63. if success:
  64. node.parent = self
  65. self._children_dict[node.link] = node
  66. self._children = new_children_list
  67. return success
  68. def child(self, namespace):
  69. try:
  70. return self._children_dict[namespace]
  71. except KeyError:
  72. raise ValueError(
  73. "Node %s is not a child of node %s" % (namespace, self.name))
  74. def is_root(self):
  75. return False
  76. class AdminHierarchyBuilder(object):
  77. def __init__(self):
  78. self.nodes_record = []
  79. self.nodes_dict = {}
  80. self.urlpatterns = URLPatterns()
  81. def build_nodes_dict(self):
  82. nodes_dict = {'misago:admin': Node(link='misago:admin:index')}
  83. iterations = 0
  84. while self.nodes_record:
  85. iterations += 1
  86. if iterations > 512:
  87. message = ("Misago Admin hierarchy is invalid or too complex "
  88. "to resolve. Nodes left: %s" % self.nodes_record)
  89. raise ValueError(message)
  90. for index, node in enumerate(self.nodes_record):
  91. if node['parent'] in nodes_dict:
  92. node_obj = Node(link=node['link'],
  93. name=node['name'],
  94. icon=node['icon'])
  95. parent = nodes_dict[node['parent']]
  96. if node['after']:
  97. node_added = parent.add_node(node_obj,
  98. after=node['after'])
  99. elif node['before']:
  100. node_added = parent.add_node(node_obj,
  101. before=node['before'])
  102. else:
  103. node_added = parent.add_node(node_obj)
  104. if node_added:
  105. namespace = node.get('namespace') or node_obj.namespace
  106. if namespace not in nodes_dict:
  107. nodes_dict[namespace] = node_obj
  108. del self.nodes_record[index]
  109. break
  110. return nodes_dict
  111. def add_node(self, parent='misago:admin', after=None, before=None,
  112. namespace=None, link=None, name=None, icon=None):
  113. if self.nodes_dict:
  114. raise ValueError("Misago admin site has already been "
  115. "initialized. You can't add new nodes to it.")
  116. if after and before:
  117. raise ValueError("You cannot use both after and before kwargs.")
  118. self.nodes_record.append(
  119. {
  120. 'parent': parent,
  121. 'namespace': namespace,
  122. 'after': after,
  123. 'before': before,
  124. 'link': link,
  125. 'name': name,
  126. 'icon': icon,
  127. })
  128. def visible_branches(self, request):
  129. if not self.nodes_dict:
  130. self.nodes_dict = self.build_nodes_dict()
  131. branches = []
  132. if request.resolver_match.namespace in self.nodes_dict:
  133. node = self.nodes_dict[request.resolver_match.namespace]
  134. while node:
  135. children = node.children_as_dicts()
  136. if children:
  137. branches.append(children)
  138. node = node.parent
  139. branches.reverse()
  140. # Lowest level branch, active link
  141. for node in branches[0]:
  142. node['is_active'] = node['link'] in request.path
  143. # Other levels branches
  144. for branch in branches[1:]:
  145. for node in branch:
  146. active = node['namespace'] in request.resolver_match.namespace
  147. node['is_active'] = active
  148. # Hack for index link
  149. full_url_name = '%s:%s' % (request.resolver_match.namespace,
  150. request.resolver_match.url_name)
  151. if full_url_name != 'misago:admin:index':
  152. branches[0][0]['is_active'] = False
  153. return branches
  154. site = AdminHierarchyBuilder()
  155. urlpatterns = site.urlpatterns