1
0
Fork 0

feat: add "web handler" feature; it must get the menu handler

this makes more sense than (potentially) adding a whole bunch of
methods to the app handler.

also fix entry point for app provider, per wj changes
This commit is contained in:
Lance Edgar 2024-07-14 10:47:14 -05:00
parent 9c5320a31c
commit 1d113da45a
9 changed files with 121 additions and 16 deletions

View file

@ -0,0 +1,6 @@
``wuttaweb.handler``
====================
.. automodule:: wuttaweb.handler
:members:

View file

@ -8,6 +8,7 @@
:maxdepth: 1 :maxdepth: 1
app app
handler
helpers helpers
menus menus
static static

View file

@ -35,7 +35,7 @@ dependencies = [
"pyramid_mako", "pyramid_mako",
"waitress", "waitress",
"WebHelpers2", "WebHelpers2",
"WuttJamaican[db]>=0.6.1", "WuttJamaican[db]>=0.7.0",
] ]
@ -48,7 +48,7 @@ tests = ["pytest-cov", "tox"]
main = "wuttaweb.app:main" main = "wuttaweb.app:main"
[project.entry-points."wutta.providers"] [project.entry-points."wutta.app.providers"]
wuttaweb = "wuttaweb.app:WebAppProvider" wuttaweb = "wuttaweb.app:WebAppProvider"

View file

@ -34,28 +34,28 @@ from pyramid.config import Configurator
class WebAppProvider(AppProvider): class WebAppProvider(AppProvider):
""" """
The :term:`app provider<app provider>` for WuttaWeb. This adds The :term:`app provider` for WuttaWeb. This adds some methods
some methods to get web-specific :term:`handlers<handler>`. specific to web apps.
""" """
def get_web_menu_handler(self, **kwargs): def get_web_handler(self, **kwargs):
""" """
Get the configured "menu" handler for the web app. Get the configured "web" handler for the app.
Specify a custom handler in your config file like this: Specify a custom handler in your config file like this:
.. code-block:: ini .. code-block:: ini
[wuttaweb] [wutta]
menus.handler_spec = poser.web.menus:PoserMenuHandler web.handler_spec = poser.web.handler:PoserWebHandler
:returns: Instance of :class:`~wuttaweb.menus.MenuHandler`. :returns: Instance of :class:`~wuttaweb.handler.WebHandler`.
""" """
if 'web_menu_handler' not in self.__dict__: if 'web_handler' not in self.__dict__:
spec = self.config.get('wuttaweb.menus.handler_spec', spec = self.config.get(f'{self.appname}.web.handler_spec',
default='wuttaweb.menus:MenuHandler') default='wuttaweb.handler:WebHandler')
self.web_menu_handler = self.app.load_object(spec)(self.config) self.web_handler = self.app.load_object(spec)(self.config)
return self.web_menu_handler return self.web_handler
def make_wutta_config(settings): def make_wutta_config(settings):

57
src/wuttaweb/handler.py Normal file
View file

@ -0,0 +1,57 @@
# -*- coding: utf-8; -*-
################################################################################
#
# wuttaweb -- Web App for Wutta Framework
# Copyright © 2024 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework 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.
#
# Wutta Framework 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
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Web Handler
This defines the :term:`handler` for the web layer.
"""
from wuttjamaican.app import GenericHandler
class WebHandler(GenericHandler):
"""
Base class and default implementation for the "web" :term:`handler`.
This is responsible for determining the "menu handler" and
(eventually) possibly other things.
"""
def get_menu_handler(self, **kwargs):
"""
Get the configured "menu" handler for the web app.
Specify a custom handler in your config file like this:
.. code-block:: ini
[wutta.web]
menus.handler_spec = poser.web.menus:PoserMenuHandler
:returns: Instance of :class:`~wuttaweb.menus.MenuHandler`.
"""
if not hasattr(self, 'menu_handler'):
spec = self.config.get(f'{self.appname}.web.menus.handler_spec',
default='wuttaweb.menus:MenuHandler')
self.menu_handler = self.app.load_object(spec)(self.config)
return self.menu_handler

View file

@ -138,7 +138,7 @@ class MenuHandler(GenericHandler):
The web app calls this method but you normally should not need The web app calls this method but you normally should not need
to override it; you can override :meth:`make_menus()` instead. to override it; you can override :meth:`make_menus()` instead.
""" """
raw_menus = self.make_menus(request, **kwargs) raw_menus = self._make_raw_menus(request, **kwargs)
# 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
@ -209,6 +209,16 @@ class MenuHandler(GenericHandler):
return final_menus return final_menus
def _make_raw_menus(self, request, **kwargs):
"""
Construct the initial full set of "raw" menus.
For now this just calls :meth:`make_menus()` which generally
means a "hard-coded" menu set. Eventually it may allow for
loading dynamic menus from config instead.
"""
return self.make_menus(request, **kwargs)
def _is_allowed(self, request, item): def _is_allowed(self, request, item):
""" """
Logic to determine if a given menu item is "allowed" for Logic to determine if a given menu item is "allowed" for

View file

@ -36,12 +36,16 @@ hooks contained here, depending on the circumstance.
""" """
import json import json
import logging
from pyramid import threadlocal from pyramid import threadlocal
from wuttaweb import helpers from wuttaweb import helpers
log = logging.getLogger(__name__)
def new_request(event): def new_request(event):
""" """
Event hook called when processing a new request. Event hook called when processing a new request.
@ -129,6 +133,7 @@ def before_render(event):
request = event.get('request') or threadlocal.get_current_request() request = event.get('request') or threadlocal.get_current_request()
config = request.wutta_config config = request.wutta_config
app = config.get_app() app = config.get_app()
web = app.get_web_handler()
context = event context = event
context['app'] = app context['app'] = app
@ -137,7 +142,7 @@ def before_render(event):
context['url'] = request.route_url context['url'] = request.route_url
context['json'] = json context['json'] = json
menus = app.get_web_menu_handler() menus = web.get_menu_handler()
context['menus'] = menus.do_make_menus(request) context['menus'] = menus.do_make_menus(request)

20
tests/test_handler.py Normal file
View file

@ -0,0 +1,20 @@
# -*- coding: utf-8; -*-
from unittest import TestCase
from wuttjamaican.conf import WuttaConfig
from wuttaweb import handler as mod
from wuttaweb.menus import MenuHandler
class TestWebHandler(TestCase):
def setUp(self):
self.config = WuttaConfig()
self.app = self.config.get_app()
self.handler = mod.WebHandler(self.config)
def test_menu_handler_default(self):
menus = self.handler.get_menu_handler()
self.assertIsInstance(menus, MenuHandler)

View file

@ -159,6 +159,12 @@ class TestMenuHandler(TestCase):
self.assertTrue(entry['is_sep']) self.assertTrue(entry['is_sep'])
self.assertFalse(entry['is_menu']) self.assertFalse(entry['is_menu'])
def test_make_raw_menus(self):
# minimal test to ensure it calls the other method
with patch.object(self.handler, 'make_menus') as make_menus:
self.handler._make_raw_menus(self.request, foo='bar')
make_menus.assert_called_once_with(self.request, foo='bar')
def test_do_make_menus_prune_unallowed_item(self): def test_do_make_menus_prune_unallowed_item(self):
test_menus = [ test_menus = [
{ {