from django.conf import settings from django.conf.urls import patterns, include, url from django.core.urlresolvers import resolve from django.utils.importlib import import_module """ Clean admin path if it was defined, or leave variable empty if ACP is turned off. """ ADMIN_PATH = '' if settings.ADMIN_PATH: ADMIN_PATH = settings.ADMIN_PATH while ADMIN_PATH[:1] == '/': ADMIN_PATH = ADMIN_PATH[1:] while ADMIN_PATH[-1:] == '/': ADMIN_PATH = ADMIN_PATH[:-1] ADMIN_PATH += '/' """ Admin lists sorter for admin sections and actions """ class SortList(object): def __init__(self, unsorted): self.unsorted = unsorted def sort(self): # Sort and return sorted list order = [] cache = {} for item in self.unsorted: if item.after: try: cache[item.after].append(item.id) except KeyError: cache[item.after] = [] cache[item.after].append(item.id) else: order.append(item.id) while cache: for item in cache.keys(): try: target_index = order.index(item) for new_item in cache[item]: target_index += 1 order.insert(target_index, new_item) del cache[item] except ValueError: pass sorted = [] for item in order: for object in self.unsorted: if item == object.id: sorted.append(object) break return sorted """ Admin site section """ class AdminSiteItem(object): def __init__(self, id, name, icon, target=None, link=None, help=None, after=None): self.id = id self.name = name self.help = help self.after = after self.icon = icon self.target = target self.link = link self.sorted = False """ Admin site action """ class AdminAction(AdminSiteItem): def __init__(self, section=None, actions=[], model=None, messages={}, urlpatterns=None, **kwargs): self.actions = actions self.section = section self.model = model self.messages = messages self.urlpatterns = urlpatterns super(AdminAction, self).__init__(**kwargs) def get_action_attr(self, id, attr): for action in self.actions: if action['id'] == id: return action[attr] return None def is_active(self, full_path, section=None): if section: action_path = '/%s%s/%s/' % (ADMIN_PATH, section, self.id) else: action_path = '/%s%s/' % (ADMIN_PATH, self.id) # Paths overlap = active action return len(action_path) <= full_path and full_path[:len(action_path)] == action_path """ Admin site section """ class AdminSection(AdminSiteItem): def __init__(self, section=None, **kwargs): self.actions = [] self.last = None super(AdminSection, self).__init__(**kwargs) def get_links(self): links = [] first_action = True for action in self.actions: if first_action: links += patterns('', url('^', include(action.urlpatterns))) first_action = False else: links += patterns('', url(('^%s/' % action.id), include(action.urlpatterns))) return links def is_active(self, full_path): action_path = '/%s%s/' % (ADMIN_PATH, self.id) # Paths overlap = active action return len(action_path) <= full_path and full_path[:len(action_path)] == action_path """ Admin site class that knows ACP structure """ class AdminSite(object): actions_index = {} links = [] sections = [] sections_index = {} def discover(self): """ Build admin site structure """ if self.links: return self.links # Found actions actions = [] # Orphan actions that have no section yet late_actions = [] # Load default admin site from misago.apps.admin.sections import ADMIN_SECTIONS for section in ADMIN_SECTIONS: self.sections.append(section) self.sections_index[section.id] = section # Loop section actions section_actions = import_module('misago.apps.admin.sections.%s' % section.id) for action in section_actions.ADMIN_ACTIONS: self.actions_index[action.id] = action if not action.after: action.after = self.sections_index[section.id].last actions.append(action) self.sections_index[section.id].last = action.after # Iterate over installed applications for app_name in settings.INSTALLED_APPS: try: app = import_module(app_name + '.admin') # Attempt to import sections try: for section in app.ADMIN_SECTIONS: self.sections.append(section) self.sections_index[section.id] = section except AttributeError: pass # Attempt to import actions try: for action in app.ADMIN_ACTIONS: self.actions_index[action.id] = action if action.section in self.sections_index: if not action.after: action.after = self.sections_index[action.section].last actions.append(action) self.sections_index[action.section].last = action.after else: late_actions.append(action) except AttributeError: pass except ImportError: pass # So actions and late actions actions += late_actions # Sorth sections and actions sort_sections = SortList(self.sections) sort_actions = SortList(actions) self.sections = sort_sections.sort() actions = sort_actions.sort() # Put actions in sections for action in actions: self.sections_index[action.section].actions.append(action) # Return ready admin routing first_section = True for section in self.sections: if first_section: self.links += patterns('', url('^', include(section.get_links()))) first_section = False else: self.links += patterns('', url(('^%s/' % section.id), include(section.get_links()))) return self.links def get_action(self, action): """ Get admin action """ return self.actions_index.get(action) def get_admin_index(self): """ Return admin index link - first action of first section """ return self.sections[0].actions[0].link def get_admin_navigation(self, request): """ Find and return current admin navigation """ sections = [] actions = [] active_section = False active_action = False # Loop sections, build list of sections and find active section for section in self.sections: is_active = section.is_active(request.path) sections.append({ 'is_active': is_active, 'name': section.name, 'icon': section.icon, 'link': section.actions[0].link }) if is_active: active_section = section # If no section was found to be active, default to first one if not active_section: active_section = self.sections[0] sections[0]['is_active'] = True # Loop active section actions for action in active_section.actions: is_active = action.is_active(request.path, active_section.id if active_section != self.sections[0] else None) actions.append({ 'is_active': is_active, 'name': action.name, 'icon': action.icon, 'help': action.help, 'link': action.link }) if is_active: active_action = action # If no action was found to be active, default to first one if not active_action: active_action = active_section.actions[0] actions[0]['is_active'] = True # Return admin navigation for this location return { 'sections': sections, 'actions': actions, 'admin_index': self.get_admin_index(), } site = AdminSite();