Skip to content

Commit 87bc6c0

Browse files
author
MiltonLn
committed
Code cleaning, test completing, added the icon_class feature
1 parent 1c661b5 commit 87bc6c0

File tree

12 files changed

+178
-194
lines changed

12 files changed

+178
-194
lines changed

.coveragerc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[run]
2+
source = menu_generator
3+
omit =
4+
*/tests/*
5+
*/apps.py

menu_generator/defaults.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from django.conf import settings
2-
31
MENU_NOT_FOUND = [
42
{
53
"name": "MENU NOT FOUND",

menu_generator/menu.py

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import copy
2-
3-
4-
from django.core.urlresolvers import reverse
5-
from django.core.urlresolvers import NoReverseMatch
62
from django.core.exceptions import ImproperlyConfigured
3+
from django.urls import reverse, NoReverseMatch
74

8-
from . import utils as util
5+
from .utils import get_callable
96

107

118
class MenuBase(object):
@@ -19,14 +16,15 @@ def __init__(self):
1916
def save_user_state(self, request):
2017
"""
2118
Given a request object, store the current user attributes
19+
:param request: HttpRequest
2220
"""
2321
self.request = request
2422
self.path = request.path
2523

26-
def is_validated(self, item_dict):
24+
def _is_validated(self, item_dict):
2725
"""
28-
Given a menu item dictionary, it returns true if menu item should be only shown
29-
to users if a set validators are true. (e.g. show if user is remember of admin group)
26+
Given a menu item dictionary, it returns true if the user passes all the validator's conditions, it means,
27+
if the user passes all the conditions, the user can see the menu
3028
"""
3129
validators = item_dict.get('validators')
3230
if not validators:
@@ -35,106 +33,104 @@ def is_validated(self, item_dict):
3533
if not isinstance(validators, (list, tuple)):
3634
raise ImproperlyConfigured("validators must be a list")
3735

38-
for validate in validators:
39-
if isinstance(validate, tuple):
40-
if len(validate) <= 1:
41-
raise ImproperlyConfigured("You are passing a tuple validator with no params %s" % str(validate))
42-
func = util.get_callable(validate[0])
36+
for validator in validators:
37+
if isinstance(validator, tuple):
38+
if len(validator) <= 1:
39+
raise ImproperlyConfigured("You are passing a tuple validator without args %s" % str(validator))
40+
func = get_callable(validator[0])
4341
# Using a python slice to get all items after the first to build function args
44-
args = validate[1:]
42+
args = validator[1:]
43+
# Pass the request as first arg by default
4544
return func(self.request, *args)
4645
else:
47-
func = util.get_callable(validate)
46+
func = get_callable(validator)
4847
return func or func(self.request) # pragma: no cover
4948

50-
def has_name(self, item_dict):
49+
def _has_attr(self, item_dict, attr):
50+
"""
51+
Given a menu item dictionary, it returns true if an attr is set.
52+
"""
53+
if item_dict.get(attr, False):
54+
return True
55+
return False
56+
57+
def _get_icon(self, parent_dict):
5158
"""
52-
Given a menu item dictionary, it returns true if attribute `name` is set.
59+
Given a menu item dictionary, this returns an icon class if one exist, or
60+
returns an empty string.
5361
"""
54-
yep = True
55-
if not item_dict.get('name', False):
56-
yep = False
57-
return yep
62+
return parent_dict.get('icon_class', '')
5863

59-
def get_url(self, item_dict):
64+
def _get_url(self, item_dict):
6065
"""
6166
Given a menu item dictionary, it returns the URL or an empty string.
6267
"""
63-
final_url = ''
6468
url = item_dict.get('url', '')
6569
try:
6670
final_url = reverse(**url) if type(url) is dict else reverse(url)
6771
except NoReverseMatch:
6872
final_url = url
6973
return final_url
7074

71-
def has_url(self, item_dict):
72-
"""
73-
Given a menu item dictionary, it returns true if attribute `url` is set.
74-
"""
75-
if not self.get_url(item_dict):
76-
return False
77-
return True
78-
79-
def is_selected(self, item_dict):
75+
def _is_selected(self, item_dict):
8076
"""
8177
Given a menu item dictionary, it returns true if `url` is on path.
8278
"""
83-
url = self.get_url(item_dict)
84-
if len(url) and url == self.path:
85-
return True
86-
return False
79+
url = self._get_url(item_dict)
80+
return url == self.path
8781

88-
def process_breadcrums(self, menu_list):
82+
def _process_breadcrums(self, menu_list):
8983
"""
9084
Given a menu list, it marks the items on the current path as selected, which
9185
can be used as breadcrumbs
9286
"""
9387
for item in menu_list:
9488
if item['submenu']:
95-
item['selected'] = self.process_breadcrums(item['submenu'])
89+
item['selected'] = self._process_breadcrums(item['submenu'])
9690
if item['selected']:
9791
return True
9892
return False
9993

100-
def get_submenu_list(self, parent_dict, depth):
94+
def _get_submenu_list(self, parent_dict):
10195
"""
10296
Given a menu item dictionary, it returns a submenu if one exist, or
10397
returns None.
10498
"""
10599
submenu = parent_dict.get('submenu', None)
106-
if submenu is not None:
100+
if submenu:
107101
for child_dict in submenu:
108-
child_dict['validators'] = list(set(list(parent_dict.get('validators', [])) +
109-
list(child_dict.get('validators', []))))
110-
submenu = self.generate_menu(submenu, depth)
102+
# This does a join between the menu item validators and submenu item validators and stores it on the
103+
# submenu's validators
104+
child_dict['validators'] = list(
105+
set(list(parent_dict.get('validators', [])) + list(child_dict.get('validators', [])))
106+
)
107+
submenu = self.generate_menu(submenu)
111108
if not submenu:
112109
submenu = None
113110
return submenu
114111

115-
def get_menu_list(self, list_dict):
112+
def _get_menu_list(self, list_dict):
116113
"""
117114
A generator that returns only the visible menu items.
118115
"""
119116
for item in list_dict:
120-
if self.has_name(item) and self.has_url(item):
121-
if self.is_validated(item):
117+
if self._has_attr(item, 'name') and self._has_attr(item, 'url'):
118+
if self._is_validated(item):
122119
yield copy.copy(item)
123120

124-
def generate_menu(self, list_dict, depth=None):
121+
def generate_menu(self, list_dict):
125122
"""
126123
Given a list of dictionaries, returns a menu list.
127124
"""
128125
visible_menu = []
129-
current_depth = depth or 0
130-
for item in self.get_menu_list(list_dict):
131-
item['depth'] = current_depth
132-
item['url'] = self.get_url(item)
133-
item['selected'] = self.is_selected(item)
134-
item['submenu'] = self.get_submenu_list(item, depth=current_depth + 1)
126+
for item in self._get_menu_list(list_dict):
127+
item['url'] = self._get_url(item)
128+
item['selected'] = self._is_selected(item)
129+
item['submenu'] = self._get_submenu_list(item)
130+
item['icon_class'] = self._get_icon(item)
135131
visible_menu.append(item)
136132

137-
self.process_breadcrums(visible_menu)
133+
self._process_breadcrums(visible_menu)
138134

139135
return visible_menu
140136

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,12 @@
11
from django import template
22
from django.conf import settings
33

4-
from ..utils import get_callable
4+
from .utils import get_menu_from_apps
5+
from .. import defaults
56
from ..menu import generate_menu
6-
from .. import defaults as defs
77

88
register = template.Library()
99

10-
MENU_DICT = ".menus.MENUS"
11-
12-
13-
def get_menu_from_apps(menu_name):
14-
"""
15-
Returns a consumable menulist for a given menu_name found in each menus.py file (if exists) on each app on
16-
INSTALLED_APPS
17-
:param menu_name: String, name of the menu to be found
18-
:return: Consumable menu list
19-
"""
20-
installed_apps = getattr(settings, "INSTALLED_APPS", [])
21-
menu_list = []
22-
for app in installed_apps:
23-
try:
24-
all_menus_dict = get_callable(app + MENU_DICT)
25-
except ImportError:
26-
all_menus_dict = None
27-
except AttributeError:
28-
all_menus_dict = None
29-
if all_menus_dict:
30-
menu_list += all_menus_dict.get(menu_name, [])
31-
return menu_list
32-
3310

3411
@register.assignment_tag(takes_context=True)
3512
def get_menu(context, menu_name):
@@ -39,11 +16,16 @@ def get_menu(context, menu_name):
3916
4017
Update, March 18 2017: Now the function get the menu list from settings and append more items if found on the
4118
menus.py's 'MENUS' dict.
19+
:param context: Template context
20+
:param menu_name: String, name of the menu to be found
21+
:return: Generated menu
4222
"""
43-
menu_list = getattr(settings, menu_name, defs.MENU_NOT_FOUND)
23+
menu_list = getattr(settings, menu_name, defaults.MENU_NOT_FOUND)
4424
menu_from_apps = get_menu_from_apps(menu_name)
45-
if menu_list == defs.MENU_NOT_FOUND and menu_from_apps:
25+
# If there isn't a menu on settings but there is menu from apps we built menu from apps
26+
if menu_list == defaults.MENU_NOT_FOUND and menu_from_apps:
4627
menu_list = menu_from_apps
47-
elif menu_list != defs.MENU_NOT_FOUND and menu_from_apps:
28+
# It there is a menu on settings and also on apps we merge both menus
29+
elif menu_list != defaults.MENU_NOT_FOUND and menu_from_apps:
4830
menu_list += menu_from_apps
4931
return generate_menu(context['request'], menu_list)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from django.conf import settings
2+
from menu_generator.utils import get_callable
3+
4+
MENU_DICT = ".menus.MENUS"
5+
6+
7+
def get_menu_from_apps(menu_name):
8+
"""
9+
Returns a consumable menulist for a given menu_name found in each menus.py file (if exists) on each app on
10+
INSTALLED_APPS
11+
:param menu_name: String, name of the menu to be found
12+
:return: Consumable menu list
13+
"""
14+
installed_apps = getattr(settings, "INSTALLED_APPS", [])
15+
menu_list = []
16+
for app in installed_apps:
17+
try:
18+
all_menus_dict = get_callable(app + MENU_DICT)
19+
except ImportError:
20+
all_menus_dict = None
21+
except AttributeError:
22+
all_menus_dict = None
23+
if all_menus_dict:
24+
menu_list += all_menus_dict.get(menu_name, [])
25+
return menu_list

0 commit comments

Comments
 (0)