diff --git a/gas/sites.py b/gas/sites.py index 67dbb68..94f02dc 100644 --- a/gas/sites.py +++ b/gas/sites.py @@ -7,14 +7,20 @@ from django.utils.translation import gettext_lazy as _ class Entry: - def __init__(self, name, label, icon=None, url=None, roles=None, parent=None, children=None): + def __init__(self, name, label, icon=None, url=None, roles=None, parent=None, order=None): self.name = name self.label = label self.icon = icon self.url = url self.roles = roles - self.children = children or dict() + self.children = dict() self.parent = parent + self.order = order if order is not None else float("inf") + + def __lt__(self, other): + if isinstance(other, Entry): + return (self.parent, self.order, self.label) < (other.parent, other.order, other.label) + return super().__lt__(other) class GASSite(object): @@ -42,7 +48,7 @@ class GASSite(object): raise ImproperlyConfigured("Prefix {0} already in use".format(prefix)) self._registry['urls'][prefix] = urls - def register_menu(self, name, label, url=None, icon=None, roles=None, parent=None): + def register_menu(self, name, label, url=None, icon=None, roles=None, parent=None, order=None): if name in self._registry['menu']: raise ImproperlyConfigured("Menu entry '{0}' already registered.".format(name)) @@ -53,7 +59,7 @@ class GASSite(object): roles.add(self.base_role) - entry = Entry(name, label, icon, url, roles, parent=parent) + entry = Entry(name, label, icon, url, roles, parent=parent, order=order) if parent: try: diff --git a/gas/templates/gas/delete_confirmation.html b/gas/templates/gas/delete_confirmation.html index d00942a..34c9804 100644 --- a/gas/templates/gas/delete_confirmation.html +++ b/gas/templates/gas/delete_confirmation.html @@ -18,6 +18,6 @@
{% endblock %} diff --git a/gas/templatetags/gas_tags.py b/gas/templatetags/gas_tags.py index 246dc4b..4d95a80 100644 --- a/gas/templatetags/gas_tags.py +++ b/gas/templatetags/gas_tags.py @@ -15,7 +15,7 @@ def show_navigation(user): if user.is_superuser: user_roles.add('admins') menu = site.get_root_menu(user_roles) - menu.sort(key=lambda a: a.label) + menu.sort() return { 'menu': menu, 'user_roles': user_roles, @@ -29,7 +29,6 @@ def get_children(entry, roles): child for child in entry.children.values() if child.roles.intersection(roles) ], - key=lambda a: a.label ) diff --git a/gas/tests/test_site.py b/gas/tests/test_site.py index 0d9787f..f236dc3 100644 --- a/gas/tests/test_site.py +++ b/gas/tests/test_site.py @@ -84,6 +84,66 @@ class SiteTestCase(TestCase): url="gas:role_list", ) + def test_menu_ordering(self): + test_site = GASSite() + admin_roles = set(('admins',)) + + # With no explicit order, sort by label + test_site.register_menu(name='c', label="c") + test_site.register_menu(name='b', label="b") + test_site.register_menu(name='a', label="a") + entries = [ + entry.name + for entry in sorted(test_site.get_root_menu(admin_roles)) + ] + self.assertEqual(entries, ['a', 'b', 'c']) + + # Explicit order takes preference + test_site.register_menu(name='z', label="z", order=1) + entries = [ + entry.name + for entry in sorted(test_site.get_root_menu(admin_roles)) + ] + self.assertEqual(entries, ['z', 'a', 'b', 'c']) + + # Explicit order inside parent don't change the order + test_site.register_menu(name='y', label="y", order=2, parent='a') + entries = [ + entry.name + for entry in sorted(test_site.get_root_menu(admin_roles)) + ] + self.assertEqual(entries, ['z', 'a', 'b', 'c']) + + # With same explicit order, sort by label + test_site.register_menu(name='x', label="x", order=1) + entries = [ + entry.name + for entry in sorted(test_site.get_root_menu(admin_roles)) + ] + self.assertEqual(entries, ['x', 'z', 'a', 'b', 'c']) + + def test_menu_visibility(self): + test_site = GASSite() + admin_roles = set(('admins',)) + staff_roles = set(('staff',)) + + test_site.register_menu(name='a', label='a', roles=admin_roles) + test_site.register_menu(name='b', label='b', roles=staff_roles) + + # Admins gets all menu + entries = [ + entry.name + for entry in test_site.get_root_menu(admin_roles) + ] + self.assertEqual(entries, ['a', 'b']) + + # Staff gets filtered menu + entries = [ + entry.name + for entry in test_site.get_root_menu(staff_roles) + ] + self.assertEqual(entries, ['b']) + class SampleAppIntegrationTest(TestCase): def test_gas_autodiscover(self):