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
app
handler
helpers
menus
static

View file

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

View file

@ -34,28 +34,28 @@ from pyramid.config import Configurator
class WebAppProvider(AppProvider):
"""
The :term:`app provider<app provider>` for WuttaWeb. This adds
some methods to get web-specific :term:`handlers<handler>`.
The :term:`app provider` for WuttaWeb. This adds some methods
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:
.. code-block:: ini
[wuttaweb]
menus.handler_spec = poser.web.menus:PoserMenuHandler
[wutta]
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__:
spec = self.config.get('wuttaweb.menus.handler_spec',
default='wuttaweb.menus:MenuHandler')
self.web_menu_handler = self.app.load_object(spec)(self.config)
return self.web_menu_handler
if 'web_handler' not in self.__dict__:
spec = self.config.get(f'{self.appname}.web.handler_spec',
default='wuttaweb.handler:WebHandler')
self.web_handler = self.app.load_object(spec)(self.config)
return self.web_handler
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
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
# that somewhat to produce our final menus
@ -209,6 +209,16 @@ class MenuHandler(GenericHandler):
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):
"""
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 logging
from pyramid import threadlocal
from wuttaweb import helpers
log = logging.getLogger(__name__)
def new_request(event):
"""
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()
config = request.wutta_config
app = config.get_app()
web = app.get_web_handler()
context = event
context['app'] = app
@ -137,7 +142,7 @@ def before_render(event):
context['url'] = request.route_url
context['json'] = json
menus = app.get_web_menu_handler()
menus = web.get_menu_handler()
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.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):
test_menus = [
{