__init__.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. from django.conf import settings
  2. from django.conf.urls import patterns, include, url
  3. from django.core.urlresolvers import resolve
  4. from django.utils.importlib import import_module
  5. """
  6. Clean admin path if it was defined, or leave variable empty if ACP is turned off.
  7. """
  8. ADMIN_PATH = ''
  9. if settings.ADMIN_PATH:
  10. ADMIN_PATH = settings.ADMIN_PATH
  11. while ADMIN_PATH[:1] == '/':
  12. ADMIN_PATH = ADMIN_PATH[1:]
  13. while ADMIN_PATH[-1:] == '/':
  14. ADMIN_PATH = ADMIN_PATH[:-1]
  15. ADMIN_PATH += '/'
  16. """
  17. Admin lists sorter for admin sections and actions
  18. """
  19. class SortList(object):
  20. def __init__(self, unsorted):
  21. self.unsorted = unsorted
  22. def sort(self):
  23. # Sort and return sorted list
  24. order = []
  25. cache = {}
  26. for item in self.unsorted:
  27. if item.after:
  28. try:
  29. cache[item.after].append(item.id)
  30. except KeyError:
  31. cache[item.after] = []
  32. cache[item.after].append(item.id)
  33. else:
  34. order.append(item.id)
  35. while cache:
  36. for item in cache.keys():
  37. try:
  38. target_index = order.index(item)
  39. for new_item in cache[item]:
  40. target_index += 1
  41. order.insert(target_index, new_item)
  42. del cache[item]
  43. except ValueError:
  44. pass
  45. sorted = []
  46. for item in order:
  47. for object in self.unsorted:
  48. if item == object.id:
  49. sorted.append(object)
  50. break
  51. return sorted
  52. """
  53. Admin site section
  54. """
  55. class AdminSiteItem(object):
  56. def __init__(self, id, name, icon, target=None, route=None, help=None, after=None):
  57. self.id = id
  58. self.name = name
  59. self.help = help
  60. self.after = after
  61. self.icon = icon
  62. self.target = target
  63. self.route = route
  64. self.sorted = False
  65. """
  66. Admin site action
  67. """
  68. class AdminAction(AdminSiteItem):
  69. def __init__(self, section=None, actions=[], model=None, messages={}, urlpatterns=None, **kwargs):
  70. self.actions = actions
  71. self.section = section
  72. self.model = model
  73. self.messages = messages
  74. self.urlpatterns = urlpatterns
  75. super(AdminAction, self).__init__(**kwargs)
  76. def get_action_attr(self, id, attr):
  77. for action in self.actions:
  78. if action['id'] == id:
  79. return action[attr]
  80. return None
  81. def is_active(self, full_path, section=None):
  82. if section:
  83. action_path = '/%s%s/%s/' % (ADMIN_PATH, section, self.id)
  84. else:
  85. action_path = '/%s%s/' % (ADMIN_PATH, self.id)
  86. # Paths overlap = active action
  87. return len(action_path) <= full_path and full_path[:len(action_path)] == action_path
  88. """
  89. Admin site section
  90. """
  91. class AdminSection(AdminSiteItem):
  92. def __init__(self, section=None, **kwargs):
  93. self.actions = []
  94. self.last = None
  95. super(AdminSection, self).__init__(**kwargs)
  96. def get_routes(self):
  97. routes = []
  98. first_action = True
  99. for action in self.actions:
  100. if first_action:
  101. routes += patterns('', url('^', include(action.urlpatterns)))
  102. first_action = False
  103. else:
  104. routes += patterns('', url(('^%s/' % action.id), include(action.urlpatterns)))
  105. return routes
  106. def is_active(self, full_path):
  107. action_path = '/%s%s/' % (ADMIN_PATH, self.id)
  108. # Paths overlap = active action
  109. return len(action_path) <= full_path and full_path[:len(action_path)] == action_path
  110. """
  111. Admin site class that knows ACP structure
  112. """
  113. class AdminSite(object):
  114. actions_index = {}
  115. routes = []
  116. sections = []
  117. sections_index = {}
  118. def discover(self):
  119. """
  120. Build admin site structure
  121. """
  122. # Return discovered admin routes, so we dont repeat ourself
  123. if self.routes:
  124. return self.routes
  125. # Found actions
  126. actions = []
  127. # Orphan actions that have no section yet
  128. late_actions = []
  129. # Iterate over installed applications
  130. for app_name in settings.INSTALLED_APPS:
  131. try:
  132. app = import_module(app_name + '.admin')
  133. # Attempt to import sections
  134. try:
  135. for section in app.ADMIN_SECTIONS:
  136. self.sections.append(section)
  137. self.sections_index[section.id] = section
  138. except AttributeError:
  139. pass
  140. # Attempt to import actions
  141. try:
  142. for action in app.ADMIN_ACTIONS:
  143. self.actions_index[action.id] = action
  144. if action.section in self.sections_index:
  145. if not action.after:
  146. action.after = self.sections_index[action.section].last
  147. actions.append(action)
  148. self.sections_index[action.section].last = action.after
  149. else:
  150. late_actions.append(action)
  151. except AttributeError:
  152. pass
  153. except ImportError:
  154. pass
  155. # So actions and late actions
  156. actions += late_actions
  157. # Sorth sections and actions
  158. sort_sections = SortList(self.sections)
  159. sort_actions = SortList(actions)
  160. self.sections = sort_sections.sort()
  161. actions = sort_actions.sort()
  162. # Put actions in sections
  163. for action in actions:
  164. self.sections_index[action.section].actions.append(action)
  165. # Return ready admin routing
  166. first_section = True
  167. for section in self.sections:
  168. if first_section:
  169. self.routes += patterns('', url('^', include(section.get_routes())))
  170. first_section = False
  171. else:
  172. self.routes += patterns('', url(('^%s/' % section.id), include(section.get_routes())))
  173. return self.routes
  174. def get_action(self, action):
  175. """
  176. Get admin action
  177. """
  178. return self.actions_index.get(action)
  179. def get_admin_index(self):
  180. """
  181. Return admin index route - first action of first section
  182. """
  183. return self.sections[0].actions[0].route
  184. def get_admin_navigation(self, request):
  185. """
  186. Find and return current admin navigation
  187. """
  188. sections = []
  189. actions = []
  190. active_section = False
  191. active_action = False
  192. # Loop sections, build list of sections and find active section
  193. for section in self.sections:
  194. is_active = section.is_active(request.path)
  195. sections.append({
  196. 'is_active': is_active,
  197. 'name': section.name,
  198. 'icon': section.icon,
  199. 'route': section.actions[0].route
  200. })
  201. if is_active:
  202. active_section = section
  203. # If no section was found to be active, default to first one
  204. if not active_section:
  205. active_section = self.sections[0]
  206. sections[0]['is_active'] = True
  207. # Loop active section actions
  208. for action in active_section.actions:
  209. is_active = action.is_active(request.path, active_section.id if active_section != self.sections[0] else None)
  210. actions.append({
  211. 'is_active': is_active,
  212. 'name': action.name,
  213. 'icon': action.icon,
  214. 'help': action.help,
  215. 'route': action.route
  216. })
  217. if is_active:
  218. active_action = action
  219. # If no action was found to be active, default to first one
  220. if not active_action:
  221. active_action = active_section.actions[0]
  222. actions[0]['is_active'] = True
  223. # Return admin navigation for this location
  224. return {
  225. 'sections': sections,
  226. 'actions': actions,
  227. 'admin_index': self.get_admin_index(),
  228. }
  229. site = AdminSite();