Coverage for .tox/coverage/lib/python3.11/site-packages/wuttaweb/app.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-26 14:40 -0500

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""" 

24Application 

25""" 

26 

27import os 

28 

29from wuttjamaican.app import AppProvider 

30from wuttjamaican.conf import make_config 

31 

32from pyramid.config import Configurator 

33 

34import wuttaweb.db 

35from wuttaweb.auth import WuttaSecurityPolicy 

36 

37 

38class WebAppProvider(AppProvider): 

39 """ 

40 The :term:`app provider` for WuttaWeb. This adds some methods to 

41 the :term:`app handler`, which are specific to web apps. 

42 """ 

43 email_templates = 'wuttaweb:email/templates' 

44 

45 def get_web_handler(self, **kwargs): 

46 """ 

47 Get the configured "web" handler for the app. 

48 

49 Specify a custom handler in your config file like this: 

50 

51 .. code-block:: ini 

52 

53 [wutta] 

54 web.handler_spec = poser.web.handler:PoserWebHandler 

55 

56 :returns: Instance of :class:`~wuttaweb.handler.WebHandler`. 

57 """ 

58 if 'web_handler' not in self.__dict__: 

59 spec = self.config.get(f'{self.appname}.web.handler_spec', 

60 default='wuttaweb.handler:WebHandler') 

61 self.web_handler = self.app.load_object(spec)(self.config) 

62 return self.web_handler 

63 

64 

65def make_wutta_config(settings, config_maker=None, **kwargs): 

66 """ 

67 Make a WuttaConfig object from the given settings. 

68 

69 Note that ``settings`` dict will (typically) correspond to the 

70 ``[app:main]`` section of your config file. 

71 

72 Regardless, the ``settings`` must contain a special key/value 

73 which is needed to identify the location of the config file. 

74 Assuming the typical scenario then, your config file should have 

75 an entry like this: 

76 

77 .. code-block:: ini 

78 

79 [app:main] 

80 wutta.config = %(__file__)s 

81 

82 The ``%(__file__)s`` is auto-replaced with the config file path, 

83 so ultimately ``settings`` would contain something like (at 

84 minimum):: 

85 

86 {'wutta.config': '/path/to/config/file'} 

87 

88 If this config file path cannot be discovered, an error is raised. 

89 """ 

90 # validate config file path 

91 path = settings.get('wutta.config') 

92 if not path or not os.path.exists(path): 

93 raise ValueError("Please set 'wutta.config' in [app:main] " 

94 "section of config to the path of your " 

95 "config file. Lame, but necessary.") 

96 

97 # make config, add to settings 

98 config_maker = config_maker or make_config 

99 wutta_config = config_maker(path, **kwargs) 

100 settings['wutta_config'] = wutta_config 

101 

102 # configure database sessions 

103 if hasattr(wutta_config, 'appdb_engine'): 

104 wuttaweb.db.Session.configure(bind=wutta_config.appdb_engine) 

105 

106 return wutta_config 

107 

108 

109def make_pyramid_config(settings): 

110 """ 

111 Make and return a Pyramid config object from the given settings. 

112 

113 The config is initialized with certain features deemed useful for 

114 all apps. 

115 

116 :returns: Instance of 

117 :class:`pyramid:pyramid.config.Configurator`. 

118 """ 

119 settings.setdefault('fanstatic.versioning', 'true') 

120 settings.setdefault('mako.directories', ['wuttaweb:templates']) 

121 settings.setdefault('pyramid_deform.template_search_path', 

122 'wuttaweb:templates/deform') 

123 

124 pyramid_config = Configurator(settings=settings) 

125 

126 # configure user authorization / authentication 

127 pyramid_config.set_security_policy(WuttaSecurityPolicy()) 

128 

129 # require CSRF token for POST 

130 pyramid_config.set_default_csrf_options(require_csrf=True, 

131 token='_csrf', 

132 header='X-CSRF-TOKEN') 

133 

134 pyramid_config.include('pyramid_beaker') 

135 pyramid_config.include('pyramid_deform') 

136 pyramid_config.include('pyramid_fanstatic') 

137 pyramid_config.include('pyramid_mako') 

138 pyramid_config.include('pyramid_tm') 

139 

140 # add some permissions magic 

141 pyramid_config.add_directive('add_wutta_permission_group', 

142 'wuttaweb.auth.add_permission_group') 

143 pyramid_config.add_directive('add_wutta_permission', 

144 'wuttaweb.auth.add_permission') 

145 

146 return pyramid_config 

147 

148 

149def main(global_config, **settings): 

150 """ 

151 This function returns a Pyramid WSGI application. 

152 

153 Typically there is no need to call this function directly, but it 

154 may be configured as the web app entry point like so: 

155 

156 .. code-block:: ini 

157 

158 [app:main] 

159 use = egg:wuttaweb 

160 

161 The app returned by this function is quite minimal, so most apps 

162 will need to define their own ``main()`` function, and use that 

163 instead. 

164 """ 

165 wutta_config = make_wutta_config(settings) 

166 pyramid_config = make_pyramid_config(settings) 

167 

168 pyramid_config.include('wuttaweb.static') 

169 pyramid_config.include('wuttaweb.subscribers') 

170 pyramid_config.include('wuttaweb.views') 

171 

172 return pyramid_config.make_wsgi_app()