Add new handlers, TailboneHandler and MenuHandler
This commit is contained in:
parent
cfdaa1e927
commit
39d53617bd
49
tailbone/handler.py
Normal file
49
tailbone/handler.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2023 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Tailbone Handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
from rattail.app import GenericHandler
|
||||||
|
|
||||||
|
|
||||||
|
class TailboneHandler(GenericHandler):
|
||||||
|
"""
|
||||||
|
Base class and default implementation for Tailbone handler.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_menu_handler(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Get the configured "menu" handler.
|
||||||
|
|
||||||
|
:returns: The :class:`~tailbone.menus.MenuHandler` instance
|
||||||
|
for the app.
|
||||||
|
"""
|
||||||
|
if not hasattr(self, 'menu_handler'):
|
||||||
|
spec = self.config.get('tailbone.menus', 'handler',
|
||||||
|
default='tailbone.menus:MenuHandler')
|
||||||
|
Handler = self.app.load_object(spec)
|
||||||
|
self.menu_handler = Handler(self.config)
|
||||||
|
return self.menu_handler
|
|
@ -28,7 +28,9 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from rattail.app import GenericHandler
|
||||||
from rattail.util import import_module_path, prettify, simple_error
|
from rattail.util import import_module_path, prettify, simple_error
|
||||||
|
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
@ -39,35 +41,336 @@ from tailbone.db import Session
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MenuHandler(GenericHandler):
|
||||||
|
"""
|
||||||
|
Base class and default implementation for menu handler.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def make_raw_menus(self, request, **kwargs):
|
||||||
|
"""
|
||||||
|
Generate a full set of "raw" menus for the app.
|
||||||
|
|
||||||
|
The "raw" menus are basically just a set of dicts to represent
|
||||||
|
the final menus.
|
||||||
|
"""
|
||||||
|
# first try to make menus from config, but this is highly
|
||||||
|
# susceptible to failure, so try to warn user of problems
|
||||||
|
try:
|
||||||
|
menus = self.make_menus_from_config(request)
|
||||||
|
if menus:
|
||||||
|
return menus
|
||||||
|
except Exception as error:
|
||||||
|
|
||||||
|
# TODO: these messages show up multiple times on some pages?!
|
||||||
|
# that must mean the BeforeRender event is firing multiple
|
||||||
|
# times..but why?? seems like there is only 1 request...
|
||||||
|
log.warning("failed to make menus from config", exc_info=True)
|
||||||
|
request.session.flash(simple_error(error), 'error')
|
||||||
|
request.session.flash("Menu config is invalid! Reverting to menus "
|
||||||
|
"defined in code!", 'warning')
|
||||||
|
msg = HTML.literal('Please edit your {} ASAP.'.format(
|
||||||
|
tags.link_to("Menu Config", request.route_url('configure_menus'))))
|
||||||
|
request.session.flash(msg, 'warning')
|
||||||
|
|
||||||
|
# okay, no config, so menus must be built from code..
|
||||||
|
|
||||||
|
# first check for a "simple menus" module; use that if defined
|
||||||
|
menumod = self.config.get('tailbone', 'menus')
|
||||||
|
if menumod:
|
||||||
|
menumod = import_module_path(menumod)
|
||||||
|
if (not hasattr(menumod, 'simple_menus')
|
||||||
|
or not callable(menumod.simple_menus)):
|
||||||
|
raise RuntimeError("module does not have a simple_menus() "
|
||||||
|
"callable: {}".format(menumod))
|
||||||
|
return menumod.simple_menus(request)
|
||||||
|
|
||||||
|
# now we fallback to menu handler method
|
||||||
|
return self.make_menus(request)
|
||||||
|
|
||||||
|
def make_menus_from_config(self, request, **kwargs):
|
||||||
|
"""
|
||||||
|
Try to build a complete menu set from config/settings.
|
||||||
|
|
||||||
|
This will look in the DB settings table, or config file, for
|
||||||
|
menu data. If found, it constructs menus from that data.
|
||||||
|
"""
|
||||||
|
# bail unless config defines top-level menu keys
|
||||||
|
main_keys = self.config.getlist('tailbone.menu', 'menus')
|
||||||
|
if not main_keys:
|
||||||
|
return
|
||||||
|
|
||||||
|
model = self.model
|
||||||
|
menus = []
|
||||||
|
|
||||||
|
# menu definition can come either from config file or db
|
||||||
|
# settings, but if the latter then we want to optimize with
|
||||||
|
# one big query
|
||||||
|
if self.config.getbool('tailbone.menu', 'from_settings',
|
||||||
|
default=False):
|
||||||
|
|
||||||
|
# fetch all menu-related settings at once
|
||||||
|
query = Session().query(model.Setting)\
|
||||||
|
.filter(model.Setting.name.like('tailbone.menu.%'))
|
||||||
|
settings = self.app.cache_model(Session(), model.Setting,
|
||||||
|
query=query, key='name',
|
||||||
|
normalizer=lambda s: s.value)
|
||||||
|
for key in main_keys:
|
||||||
|
menus.append(self.make_single_menu_from_settings(request, key,
|
||||||
|
settings))
|
||||||
|
|
||||||
|
else: # read from config file only
|
||||||
|
for key in main_keys:
|
||||||
|
menus.append(self.make_single_menu_from_config(request, key))
|
||||||
|
|
||||||
|
return menus
|
||||||
|
|
||||||
|
def make_single_menu_from_config(self, request, key, **kwargs):
|
||||||
|
"""
|
||||||
|
Makes a single top-level menu dict from config file. Note
|
||||||
|
that this will read from config file(s) *only* and avoids
|
||||||
|
querying the database, for efficiency.
|
||||||
|
"""
|
||||||
|
menu = {
|
||||||
|
'key': key,
|
||||||
|
'type': 'menu',
|
||||||
|
'items': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
# title
|
||||||
|
title = self.config.get('tailbone.menu',
|
||||||
|
'menu.{}.label'.format(key),
|
||||||
|
usedb=False)
|
||||||
|
menu['title'] = title or prettify(key)
|
||||||
|
|
||||||
|
# items
|
||||||
|
item_keys = self.config.getlist('tailbone.menu',
|
||||||
|
'menu.{}.items'.format(key),
|
||||||
|
usedb=False)
|
||||||
|
for item_key in item_keys:
|
||||||
|
item = {}
|
||||||
|
|
||||||
|
if item_key == 'SEP':
|
||||||
|
item['type'] = 'sep'
|
||||||
|
|
||||||
|
else:
|
||||||
|
item['type'] = 'item'
|
||||||
|
item['key'] = item_key
|
||||||
|
|
||||||
|
# title
|
||||||
|
title = self.config.get('tailbone.menu',
|
||||||
|
'menu.{}.item.{}.label'.format(key, item_key),
|
||||||
|
usedb=False)
|
||||||
|
item['title'] = title or prettify(item_key)
|
||||||
|
|
||||||
|
# route
|
||||||
|
route = self.config.get('tailbone.menu',
|
||||||
|
'menu.{}.item.{}.route'.format(key, item_key),
|
||||||
|
usedb=False)
|
||||||
|
if route:
|
||||||
|
item['route'] = route
|
||||||
|
item['url'] = request.route_url(route)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
# url
|
||||||
|
url = self.config.get('tailbone.menu',
|
||||||
|
'menu.{}.item.{}.url'.format(key, item_key),
|
||||||
|
usedb=False)
|
||||||
|
if not url:
|
||||||
|
url = request.route_url(item_key)
|
||||||
|
elif url.startswith('route:'):
|
||||||
|
url = request.route_url(url[6:])
|
||||||
|
item['url'] = url
|
||||||
|
|
||||||
|
# perm
|
||||||
|
perm = self.config.get('tailbone.menu',
|
||||||
|
'menu.{}.item.{}.perm'.format(key, item_key),
|
||||||
|
usedb=False)
|
||||||
|
item['perm'] = perm or '{}.list'.format(item_key)
|
||||||
|
|
||||||
|
menu['items'].append(item)
|
||||||
|
|
||||||
|
return menu
|
||||||
|
|
||||||
|
def make_single_menu_from_settings(self, request, key, settings, **kwargs):
|
||||||
|
"""
|
||||||
|
Makes a single top-level menu dict from DB settings.
|
||||||
|
"""
|
||||||
|
menu = {
|
||||||
|
'key': key,
|
||||||
|
'type': 'menu',
|
||||||
|
'items': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
# title
|
||||||
|
title = settings.get('tailbone.menu.menu.{}.label'.format(key))
|
||||||
|
menu['title'] = title or prettify(key)
|
||||||
|
|
||||||
|
# items
|
||||||
|
item_keys = self.config.parse_list(
|
||||||
|
settings.get('tailbone.menu.menu.{}.items'.format(key)))
|
||||||
|
for item_key in item_keys:
|
||||||
|
item = {}
|
||||||
|
|
||||||
|
if item_key == 'SEP':
|
||||||
|
item['type'] = 'sep'
|
||||||
|
|
||||||
|
else:
|
||||||
|
item['type'] = 'item'
|
||||||
|
item['key'] = item_key
|
||||||
|
|
||||||
|
# title
|
||||||
|
title = settings.get('tailbone.menu.menu.{}.item.{}.label'.format(
|
||||||
|
key, item_key))
|
||||||
|
item['title'] = title or prettify(item_key)
|
||||||
|
|
||||||
|
# route
|
||||||
|
route = settings.get('tailbone.menu.menu.{}.item.{}.route'.format(
|
||||||
|
key, item_key))
|
||||||
|
if route:
|
||||||
|
item['route'] = route
|
||||||
|
item['url'] = request.route_url(route)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
# url
|
||||||
|
url = settings.get('tailbone.menu.menu.{}.item.{}.url'.format(
|
||||||
|
key, item_key))
|
||||||
|
if not url:
|
||||||
|
url = request.route_url(item_key)
|
||||||
|
if url.startswith('route:'):
|
||||||
|
url = request.route_url(url[6:])
|
||||||
|
item['url'] = url
|
||||||
|
|
||||||
|
# perm
|
||||||
|
perm = settings.get('tailbone.menu.menu.{}.item.{}.perm'.format(
|
||||||
|
key, item_key))
|
||||||
|
item['perm'] = perm or '{}.list'.format(item_key)
|
||||||
|
|
||||||
|
menu['items'].append(item)
|
||||||
|
|
||||||
|
return menu
|
||||||
|
|
||||||
|
def make_menus(self, request, **kwargs):
|
||||||
|
"""
|
||||||
|
Make the full set of menus for the app.
|
||||||
|
|
||||||
|
This method provides a semi-sane menu set by default, but it
|
||||||
|
is expected for most apps to override it.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
self.make_admin_menu(request),
|
||||||
|
]
|
||||||
|
|
||||||
|
def make_admin_menu(self, request, include_stores=False, **kwargs):
|
||||||
|
"""
|
||||||
|
Generate a typical Admin menu
|
||||||
|
"""
|
||||||
|
items = []
|
||||||
|
|
||||||
|
if include_stores:
|
||||||
|
items.append({
|
||||||
|
'title': "Stores",
|
||||||
|
'route': 'stores',
|
||||||
|
'perm': 'stores.list',
|
||||||
|
})
|
||||||
|
|
||||||
|
items.extend([
|
||||||
|
{
|
||||||
|
'title': "Users",
|
||||||
|
'route': 'users',
|
||||||
|
'perm': 'users.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "User Events",
|
||||||
|
'route': 'userevents',
|
||||||
|
'perm': 'userevents.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Roles",
|
||||||
|
'route': 'roles',
|
||||||
|
'perm': 'roles.list',
|
||||||
|
},
|
||||||
|
{'type': 'sep'},
|
||||||
|
{
|
||||||
|
'title': "App Settings",
|
||||||
|
'route': 'appsettings',
|
||||||
|
'perm': 'settings.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Email Settings",
|
||||||
|
'route': 'emailprofiles',
|
||||||
|
'perm': 'emailprofiles.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Email Attempts",
|
||||||
|
'route': 'email_attempts',
|
||||||
|
'perm': 'email_attempts.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Raw Settings",
|
||||||
|
'route': 'settings',
|
||||||
|
'perm': 'settings.list',
|
||||||
|
},
|
||||||
|
{'type': 'sep'},
|
||||||
|
{
|
||||||
|
'title': "DataSync Changes",
|
||||||
|
'route': 'datasyncchanges',
|
||||||
|
'perm': 'datasync_changes.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "DataSync Status",
|
||||||
|
'route': 'datasync.status',
|
||||||
|
'perm': 'datasync.status',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Importing / Exporting",
|
||||||
|
'route': 'importing',
|
||||||
|
'perm': 'importing.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Luigi Tasks",
|
||||||
|
'route': 'luigi',
|
||||||
|
'perm': 'luigi.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Tables",
|
||||||
|
'route': 'tables',
|
||||||
|
'perm': 'tables.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "App Info",
|
||||||
|
'route': 'appinfo',
|
||||||
|
'perm': 'appinfo.list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Configure App",
|
||||||
|
'route': 'appinfo.configure',
|
||||||
|
'perm': 'appinfo.configure',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': "Upgrades",
|
||||||
|
'route': 'upgrades',
|
||||||
|
'perm': 'upgrades.list',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
return {
|
||||||
|
'title': "Admin",
|
||||||
|
'type': 'menu',
|
||||||
|
'items': items,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def make_simple_menus(request):
|
def make_simple_menus(request):
|
||||||
"""
|
"""
|
||||||
Build the main menu list for the app.
|
Build the main menu list for the app.
|
||||||
"""
|
"""
|
||||||
# first try to make menus from config, but this is highly
|
app = request.rattail_config.get_app()
|
||||||
# susceptible to failure, so try to warn user of problems
|
tailbone_handler = app.get_tailbone_handler()
|
||||||
raw_menus = None
|
menu_handler = tailbone_handler.get_menu_handler()
|
||||||
try:
|
|
||||||
raw_menus = make_menus_from_config(request)
|
|
||||||
except Exception as error:
|
|
||||||
# TODO: these messages show up multiple times on some pages?!
|
|
||||||
# that must mean the BeforeRender event is firing multiple
|
|
||||||
# times..but why?? seems like there is only 1 request...
|
|
||||||
log.warning("failed to make menus from config", exc_info=True)
|
|
||||||
request.session.flash(simple_error(error), 'error')
|
|
||||||
request.session.flash("Menu config is invalid! Reverting to menus "
|
|
||||||
"defined in code!", 'warning')
|
|
||||||
msg = HTML.literal('Please edit your {} ASAP.'.format(
|
|
||||||
tags.link_to("Menu Config", request.route_url('configure_menus'))))
|
|
||||||
request.session.flash(msg, 'warning')
|
|
||||||
|
|
||||||
if not raw_menus:
|
raw_menus = menu_handler.make_raw_menus(request)
|
||||||
|
|
||||||
# no config, so import/invoke code function to build them
|
|
||||||
menus_module = import_module_path(
|
|
||||||
request.rattail_config.require('tailbone', 'menus'))
|
|
||||||
if not hasattr(menus_module, 'simple_menus') or not callable(menus_module.simple_menus):
|
|
||||||
raise RuntimeError("module does not have a simple_menus() callable: {}".format(menus_module))
|
|
||||||
raw_menus = menus_module.simple_menus(request)
|
|
||||||
|
|
||||||
# now we have "simple" (raw) menus definition, but must refine
|
# now we have "simple" (raw) menus definition, but must refine
|
||||||
# that somewhat to produce our final menus
|
# that somewhat to produce our final menus
|
||||||
|
@ -140,185 +443,6 @@ def make_simple_menus(request):
|
||||||
return final_menus
|
return final_menus
|
||||||
|
|
||||||
|
|
||||||
def make_menus_from_config(request):
|
|
||||||
"""
|
|
||||||
Try to build a complete menu set from config/settings.
|
|
||||||
|
|
||||||
This essentially checks for the top-level menu list in config; if
|
|
||||||
found then it will build a full menu set from config. If this
|
|
||||||
top-level list is not present in config then menus will be built
|
|
||||||
purely from code instead. An example of this top-level list:
|
|
||||||
|
|
||||||
.. code-hightlight:: ini
|
|
||||||
|
|
||||||
[tailbone.menu]
|
|
||||||
menus = first, second, third, admin
|
|
||||||
|
|
||||||
Obviously much more config would be needed to define those menus
|
|
||||||
etc. but that is the option that determines whether the rest of
|
|
||||||
menu config is even read, or not.
|
|
||||||
"""
|
|
||||||
config = request.rattail_config
|
|
||||||
main_keys = config.getlist('tailbone.menu', 'menus')
|
|
||||||
if not main_keys:
|
|
||||||
return
|
|
||||||
|
|
||||||
menus = []
|
|
||||||
|
|
||||||
# menu definition can come either from config file or db settings,
|
|
||||||
# but if the latter then we want to optimize with one big query
|
|
||||||
if config.getbool('tailbone.menu', 'from_settings',
|
|
||||||
default=False):
|
|
||||||
app = config.get_app()
|
|
||||||
model = config.get_model()
|
|
||||||
|
|
||||||
# fetch all menu-related settings at once
|
|
||||||
query = Session().query(model.Setting)\
|
|
||||||
.filter(model.Setting.name.like('tailbone.menu.%'))
|
|
||||||
settings = app.cache_model(Session(), model.Setting,
|
|
||||||
query=query, key='name',
|
|
||||||
normalizer=lambda s: s.value)
|
|
||||||
for key in main_keys:
|
|
||||||
menus.append(make_single_menu_from_settings(request, key, settings))
|
|
||||||
|
|
||||||
else: # read from config file only
|
|
||||||
for key in main_keys:
|
|
||||||
menus.append(make_single_menu_from_config(request, key))
|
|
||||||
|
|
||||||
return menus
|
|
||||||
|
|
||||||
|
|
||||||
def make_single_menu_from_config(request, key):
|
|
||||||
"""
|
|
||||||
Makes a single top-level menu dict from config file. Note that
|
|
||||||
this will read from config file(s) *only* and avoids querying the
|
|
||||||
database, for efficiency.
|
|
||||||
"""
|
|
||||||
config = request.rattail_config
|
|
||||||
menu = {
|
|
||||||
'key': key,
|
|
||||||
'type': 'menu',
|
|
||||||
'items': [],
|
|
||||||
}
|
|
||||||
|
|
||||||
# title
|
|
||||||
title = config.get('tailbone.menu',
|
|
||||||
'menu.{}.label'.format(key),
|
|
||||||
usedb=False)
|
|
||||||
menu['title'] = title or prettify(key)
|
|
||||||
|
|
||||||
# items
|
|
||||||
item_keys = config.getlist('tailbone.menu',
|
|
||||||
'menu.{}.items'.format(key),
|
|
||||||
usedb=False)
|
|
||||||
for item_key in item_keys:
|
|
||||||
item = {}
|
|
||||||
|
|
||||||
if item_key == 'SEP':
|
|
||||||
item['type'] = 'sep'
|
|
||||||
|
|
||||||
else:
|
|
||||||
item['type'] = 'item'
|
|
||||||
item['key'] = item_key
|
|
||||||
|
|
||||||
# title
|
|
||||||
title = config.get('tailbone.menu',
|
|
||||||
'menu.{}.item.{}.label'.format(key, item_key),
|
|
||||||
usedb=False)
|
|
||||||
item['title'] = title or prettify(item_key)
|
|
||||||
|
|
||||||
# route
|
|
||||||
route = config.get('tailbone.menu',
|
|
||||||
'menu.{}.item.{}.route'.format(key, item_key),
|
|
||||||
usedb=False)
|
|
||||||
if route:
|
|
||||||
item['route'] = route
|
|
||||||
item['url'] = request.route_url(route)
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
# url
|
|
||||||
url = config.get('tailbone.menu',
|
|
||||||
'menu.{}.item.{}.url'.format(key, item_key),
|
|
||||||
usedb=False)
|
|
||||||
if not url:
|
|
||||||
url = request.route_url(item_key)
|
|
||||||
elif url.startswith('route:'):
|
|
||||||
url = request.route_url(url[6:])
|
|
||||||
item['url'] = url
|
|
||||||
|
|
||||||
# perm
|
|
||||||
perm = config.get('tailbone.menu',
|
|
||||||
'menu.{}.item.{}.perm'.format(key, item_key),
|
|
||||||
usedb=False)
|
|
||||||
item['perm'] = perm or '{}.list'.format(item_key)
|
|
||||||
|
|
||||||
menu['items'].append(item)
|
|
||||||
|
|
||||||
return menu
|
|
||||||
|
|
||||||
|
|
||||||
def make_single_menu_from_settings(request, key, settings):
|
|
||||||
"""
|
|
||||||
Makes a single top-level menu dict from DB settings.
|
|
||||||
"""
|
|
||||||
config = request.rattail_config
|
|
||||||
menu = {
|
|
||||||
'key': key,
|
|
||||||
'type': 'menu',
|
|
||||||
'items': [],
|
|
||||||
}
|
|
||||||
|
|
||||||
# title
|
|
||||||
title = settings.get('tailbone.menu.menu.{}.label'.format(key))
|
|
||||||
menu['title'] = title or prettify(key)
|
|
||||||
|
|
||||||
# items
|
|
||||||
item_keys = config.parse_list(
|
|
||||||
settings.get('tailbone.menu.menu.{}.items'.format(key)))
|
|
||||||
for item_key in item_keys:
|
|
||||||
item = {}
|
|
||||||
|
|
||||||
if item_key == 'SEP':
|
|
||||||
item['type'] = 'sep'
|
|
||||||
|
|
||||||
else:
|
|
||||||
item['type'] = 'item'
|
|
||||||
item['key'] = item_key
|
|
||||||
|
|
||||||
# title
|
|
||||||
title = settings.get('tailbone.menu.menu.{}.item.{}.label'.format(
|
|
||||||
key, item_key))
|
|
||||||
item['title'] = title or prettify(item_key)
|
|
||||||
|
|
||||||
# route
|
|
||||||
route = settings.get('tailbone.menu.menu.{}.item.{}.route'.format(
|
|
||||||
key, item_key))
|
|
||||||
if route:
|
|
||||||
item['route'] = route
|
|
||||||
item['url'] = request.route_url(route)
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
# url
|
|
||||||
url = settings.get('tailbone.menu.menu.{}.item.{}.url'.format(
|
|
||||||
key, item_key))
|
|
||||||
if not url:
|
|
||||||
url = request.route_url(item_key)
|
|
||||||
if url.startswith('route:'):
|
|
||||||
url = request.route_url(url[6:])
|
|
||||||
item['url'] = url
|
|
||||||
|
|
||||||
# perm
|
|
||||||
perm = settings.get('tailbone.menu.menu.{}.item.{}.perm'.format(
|
|
||||||
key, item_key))
|
|
||||||
item['perm'] = perm or '{}.list'.format(item_key)
|
|
||||||
|
|
||||||
menu['items'].append(item)
|
|
||||||
|
|
||||||
return menu
|
|
||||||
|
|
||||||
|
|
||||||
def make_menu_key(config, value):
|
def make_menu_key(config, value):
|
||||||
"""
|
"""
|
||||||
Generate a normalized menu key for the given value.
|
Generate a normalized menu key for the given value.
|
||||||
|
@ -405,101 +529,15 @@ def mark_allowed(request, menus):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def make_admin_menu(request, include_stores=False):
|
def make_admin_menu(request, **kwargs):
|
||||||
"""
|
"""
|
||||||
Generate a typical Admin menu
|
Generate a typical Admin menu
|
||||||
"""
|
"""
|
||||||
items = []
|
warnings.warn("make_admin_menu() function is deprecated; please use "
|
||||||
|
"MenuHandler.make_admin_menu() instead",
|
||||||
|
DeprecationWarning, stacklevel=2)
|
||||||
|
|
||||||
if include_stores:
|
app = request.rattail_config.get_app()
|
||||||
items.append({
|
tailbone_handler = app.get_tailbone_handler()
|
||||||
'title': "Stores",
|
menu_handler = tailbone_handler.get_menu_handler()
|
||||||
'route': 'stores',
|
return menu_handler.make_admin_menu(request, **kwargs)
|
||||||
'perm': 'stores.list',
|
|
||||||
})
|
|
||||||
|
|
||||||
items.extend([
|
|
||||||
{
|
|
||||||
'title': "Users",
|
|
||||||
'route': 'users',
|
|
||||||
'perm': 'users.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "User Events",
|
|
||||||
'route': 'userevents',
|
|
||||||
'perm': 'userevents.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Roles",
|
|
||||||
'route': 'roles',
|
|
||||||
'perm': 'roles.list',
|
|
||||||
},
|
|
||||||
{'type': 'sep'},
|
|
||||||
{
|
|
||||||
'title': "App Settings",
|
|
||||||
'route': 'appsettings',
|
|
||||||
'perm': 'settings.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Email Settings",
|
|
||||||
'route': 'emailprofiles',
|
|
||||||
'perm': 'emailprofiles.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Email Attempts",
|
|
||||||
'route': 'email_attempts',
|
|
||||||
'perm': 'email_attempts.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Raw Settings",
|
|
||||||
'route': 'settings',
|
|
||||||
'perm': 'settings.list',
|
|
||||||
},
|
|
||||||
{'type': 'sep'},
|
|
||||||
{
|
|
||||||
'title': "DataSync Changes",
|
|
||||||
'route': 'datasyncchanges',
|
|
||||||
'perm': 'datasync_changes.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "DataSync Status",
|
|
||||||
'route': 'datasync.status',
|
|
||||||
'perm': 'datasync.status',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Importing / Exporting",
|
|
||||||
'route': 'importing',
|
|
||||||
'perm': 'importing.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Luigi Tasks",
|
|
||||||
'route': 'luigi',
|
|
||||||
'perm': 'luigi.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Tables",
|
|
||||||
'route': 'tables',
|
|
||||||
'perm': 'tables.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "App Info",
|
|
||||||
'route': 'appinfo',
|
|
||||||
'perm': 'appinfo.list',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Configure App",
|
|
||||||
'route': 'appinfo.configure',
|
|
||||||
'perm': 'appinfo.configure',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': "Upgrades",
|
|
||||||
'route': 'upgrades',
|
|
||||||
'perm': 'upgrades.list',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return {
|
|
||||||
'title': "Admin",
|
|
||||||
'type': 'menu',
|
|
||||||
'items': items,
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue