Coverage for .tox/coverage/lib/python3.11/site-packages/wuttaweb/handler.py: 100%
57 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-13 13:36 -0600
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-13 13:36 -0600
1# -*- coding: utf-8; -*-
2################################################################################
3#
4# wuttaweb -- Web App for Wutta Framework
5# Copyright © 2024 Lance Edgar
6#
7# This file is part of Wutta Framework.
8#
9# Wutta Framework is free software: you can redistribute it and/or modify it
10# under the terms of the GNU General Public License as published by the Free
11# Software Foundation, either version 3 of the License, or (at your option) any
12# later version.
13#
14# Wutta Framework is distributed in the hope that it will be useful, but
15# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17# more details.
18#
19# You should have received a copy of the GNU General Public License along with
20# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
21#
22################################################################################
23"""
24Web Handler
25"""
27import warnings
29from wuttjamaican.app import GenericHandler
30from wuttjamaican.util import load_entry_points
32from wuttaweb import static, forms, grids
35class WebHandler(GenericHandler):
36 """
37 Base class and default implementation for the :term:`web handler`.
39 This is responsible for determining the :term:`menu handler` and
40 various other customizations.
41 """
43 def get_fanstatic_url(self, request, resource):
44 """
45 Returns the full URL to the given Fanstatic resource.
47 :param request: Current :term:`request` object.
49 :param resource: :class:`fanstatic:fanstatic.Resource`
50 instance representing an image file or other resource.
51 """
52 needed = request.environ['fanstatic.needed']
53 url = needed.library_url(resource.library) + '/'
54 if request.script_name:
55 url = request.script_name + url
56 return url + resource.relpath
58 def get_favicon_url(self, request):
59 """
60 Returns the canonical app favicon image URL.
62 This will return the fallback favicon from WuttaWeb unless
63 config specifies an override:
65 .. code-block:: ini
67 [wuttaweb]
68 favicon_url = http://example.com/favicon.ico
69 """
70 url = self.config.get('wuttaweb.favicon_url')
71 if url:
72 return url
73 return self.get_fanstatic_url(request, static.favicon)
75 def get_header_logo_url(self, request):
76 """
77 Returns the canonical app header image URL.
79 This will return the value from config if specified (as shown
80 below); otherwise it will just call :meth:`get_favicon_url()`
81 and return that.
83 .. code-block:: ini
85 [wuttaweb]
86 header_logo_url = http://example.com/logo.png
87 """
88 url = self.config.get('wuttaweb.header_logo_url')
89 if url:
90 return url
91 return self.get_favicon_url(request)
93 def get_main_logo_url(self, request):
94 """
95 Returns the canonical app logo image URL.
97 This will return the fallback logo from WuttaWeb unless config
98 specifies an override:
100 .. code-block:: ini
102 [wuttaweb]
103 logo_url = http://example.com/logo.png
104 """
105 url = self.config.get('wuttaweb.logo_url')
106 if url:
107 return url
108 return self.get_fanstatic_url(request, static.logo)
110 def get_menu_handler(self, **kwargs):
111 """
112 Get the configured :term:`menu handler` for the web app.
114 Specify a custom handler in your config file like this:
116 .. code-block:: ini
118 [wutta.web]
119 menus.handler.spec = poser.web.menus:PoserMenuHandler
121 :returns: Instance of :class:`~wuttaweb.menus.MenuHandler`.
122 """
123 spec = self.config.get(f'{self.appname}.web.menus.handler.spec')
124 if not spec:
125 spec = self.config.get(f'{self.appname}.web.menus.handler_spec')
126 if spec:
127 warnings.warn(f"setting '{self.appname}.web.menus.handler_spec' is deprecated; "
128 f"please use '{self.appname}.web.menus.handler_spec' instead",
129 DeprecationWarning)
130 else:
131 spec = self.config.get(f'{self.appname}.web.menus.handler.default_spec',
132 default='wuttaweb.menus:MenuHandler')
133 factory = self.app.load_object(spec)
134 return factory(self.config)
136 def get_menu_handler_specs(self, default=None):
137 """
138 Get the :term:`spec` strings for all available :term:`menu
139 handlers <menu handler>`. See also
140 :meth:`get_menu_handler()`.
142 :param default: Default spec string(s) to include, even if not
143 registered. Can be a string or list of strings.
145 :returns: List of menu handler spec strings.
147 This will gather available spec strings from the following:
149 First, the ``default`` as provided by caller.
151 Second, the default spec from config, if set; for example:
153 .. code-block:: ini
155 [wutta.web]
156 menus.handler.default_spec = poser.web.menus:PoserMenuHandler
158 Third, each spec registered via entry points. For instance in
159 ``pyproject.toml``:
161 .. code-block:: toml
163 [project.entry-points."wutta.web.menus"]
164 poser = "poser.web.menus:PoserMenuHandler"
166 The final list will be "sorted" according to the above, with
167 the latter registered handlers being sorted alphabetically.
168 """
169 handlers = []
171 # defaults from caller
172 if isinstance(default, str):
173 handlers.append(default)
174 elif default:
175 handlers.extend(default)
177 # configured default, if applicable
178 default = self.config.get(f'{self.config.appname}.web.menus.handler.default_spec')
179 if default and default not in handlers:
180 handlers.append(default)
182 # registered via entry points
183 registered = []
184 for Handler in load_entry_points(f'{self.appname}.web.menus').values():
185 spec = Handler.get_spec()
186 if spec not in handlers:
187 registered.append(spec)
188 if registered:
189 registered.sort()
190 handlers.extend(registered)
192 return handlers
194 def make_form(self, request, **kwargs):
195 """
196 Make and return a new :class:`~wuttaweb.forms.base.Form`
197 instance, per the given ``kwargs``.
199 This is the "base" factory which merely invokes the
200 constructor.
201 """
202 return forms.Form(request, **kwargs)
204 def make_grid(self, request, **kwargs):
205 """
206 Make and return a new :class:`~wuttaweb.grids.base.Grid`
207 instance, per the given ``kwargs``.
209 This is the "base" factory which merely invokes the
210 constructor.
211 """
212 return grids.Grid(request, **kwargs)