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:
		
							parent
							
								
									9c5320a31c
								
							
						
					
					
						commit
						1d113da45a
					
				
					 9 changed files with 121 additions and 16 deletions
				
			
		
							
								
								
									
										6
									
								
								docs/api/wuttaweb/handler.rst
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								docs/api/wuttaweb/handler.rst
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | 
 | ||||||
|  | ``wuttaweb.handler`` | ||||||
|  | ==================== | ||||||
|  | 
 | ||||||
|  | .. automodule:: wuttaweb.handler | ||||||
|  |    :members: | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
|    :maxdepth: 1 |    :maxdepth: 1 | ||||||
| 
 | 
 | ||||||
|    app |    app | ||||||
|  |    handler | ||||||
|    helpers |    helpers | ||||||
|    menus |    menus | ||||||
|    static |    static | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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
									
								
							
							
						
						
									
										57
									
								
								src/wuttaweb/handler.py
									
										
									
									
									
										Normal 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 | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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
									
								
							
							
						
						
									
										20
									
								
								tests/test_handler.py
									
										
									
									
									
										Normal 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) | ||||||
|  | @ -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 = [ | ||||||
|             { |             { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar