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

128 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2024-12-28 21:19 -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""" 

24Views for email settings 

25""" 

26 

27import colander 

28 

29from wuttaweb.views import MasterView 

30from wuttaweb.forms.schema import EmailRecipients 

31 

32 

33class EmailSettingView(MasterView): 

34 """ 

35 Master view for :term:`email settings <email setting>`. 

36 """ 

37 model_name = 'email_setting' 

38 model_key = 'key' 

39 model_title = "Email Setting" 

40 url_prefix = '/email/settings' 

41 filterable = False 

42 sortable = True 

43 sort_on_backend = False 

44 paginated = False 

45 creatable = False 

46 deletable = False 

47 

48 labels = { 

49 'key': "Email Key", 

50 'replyto': "Reply-To", 

51 } 

52 

53 grid_columns = [ 

54 'key', 

55 'subject', 

56 'to', 

57 'enabled', 

58 ] 

59 

60 # TODO: why does this not work? 

61 sort_defaults = 'key' 

62 

63 form_fields = [ 

64 'key', 

65 'description', 

66 'subject', 

67 'sender', 

68 'replyto', 

69 'to', 

70 'cc', 

71 'bcc', 

72 'notes', 

73 'enabled', 

74 ] 

75 

76 def __init__(self, request, context=None): 

77 super().__init__(request, context=context) 

78 self.email_handler = self.app.get_email_handler() 

79 

80 def get_grid_data(self, columns=None, session=None): 

81 """ 

82 This view calls 

83 :meth:`~wuttjamaican:wuttjamaican.email.EmailHandler.get_email_settings()` 

84 on the :attr:`email_handler` to obtain its grid data. 

85 """ 

86 data = [] 

87 for setting in self.email_handler.get_email_settings().values(): 

88 data.append(self.normalize_setting(setting)) 

89 return data 

90 

91 def normalize_setting(self, setting): 

92 """ """ 

93 key = setting.__name__ 

94 return { 

95 'key': key, 

96 'description': setting.__doc__, 

97 'subject': self.email_handler.get_auto_subject(key, rendered=False, setting=setting), 

98 'sender': self.email_handler.get_auto_sender(key), 

99 'replyto': self.email_handler.get_auto_replyto(key) or colander.null, 

100 'to': self.email_handler.get_auto_to(key), 

101 'cc': self.email_handler.get_auto_cc(key), 

102 'bcc': self.email_handler.get_auto_bcc(key), 

103 'notes': self.email_handler.get_notes(key) or colander.null, 

104 'enabled': self.email_handler.is_enabled(key), 

105 } 

106 

107 def configure_grid(self, g): 

108 """ """ 

109 super().configure_grid(g) 

110 

111 # key 

112 g.set_searchable('key') 

113 g.set_link('key') 

114 

115 # subject 

116 g.set_searchable('subject') 

117 g.set_link('subject') 

118 

119 # to 

120 g.set_renderer('to', self.render_to_short) 

121 

122 def render_to_short(self, setting, field, value): 

123 """ """ 

124 recips = value 

125 if not recips: 

126 return 

127 

128 if len(recips) < 3: 

129 return ', '.join(recips) 

130 

131 recips = ', '.join(recips[:2]) 

132 return f"{recips}, ..." 

133 

134 def get_instance(self): 

135 """ """ 

136 key = self.request.matchdict['key'] 

137 setting = self.email_handler.get_email_setting(key, instance=False) 

138 if setting: 

139 return self.normalize_setting(setting) 

140 

141 raise self.notfound() 

142 

143 def get_instance_title(self, setting): 

144 """ """ 

145 return setting['subject'] 

146 

147 def configure_form(self, f): 

148 """ """ 

149 super().configure_form(f) 

150 

151 # description 

152 f.set_readonly('description') 

153 

154 # replyto 

155 f.set_required('replyto', False) 

156 

157 # to 

158 f.set_node('to', EmailRecipients()) 

159 

160 # cc 

161 f.set_node('cc', EmailRecipients()) 

162 

163 # bcc 

164 f.set_node('bcc', EmailRecipients()) 

165 

166 # notes 

167 f.set_widget('notes', 'notes') 

168 f.set_required('notes', False) 

169 

170 # enabled 

171 f.set_node('enabled', colander.Boolean()) 

172 

173 def persist(self, setting): 

174 """ """ 

175 session = self.Session() 

176 key = self.request.matchdict['key'] 

177 

178 def save(name, value): 

179 self.app.save_setting(session, f'{self.config.appname}.email.{key}.{name}', value) 

180 

181 def delete(name): 

182 self.app.delete_setting(session, f'{self.config.appname}.email.{key}.{name}') 

183 

184 # subject 

185 if setting['subject']: 

186 save('subject', setting['subject']) 

187 else: 

188 delete('subject') 

189 

190 # sender 

191 if setting['sender']: 

192 save('sender', setting['sender']) 

193 else: 

194 delete('sender') 

195 

196 # replyto 

197 if setting['replyto']: 

198 save('replyto', setting['replyto']) 

199 else: 

200 delete('replyto') 

201 

202 # to 

203 if setting['to']: 

204 save('to', setting['to']) 

205 else: 

206 delete('to') 

207 

208 # cc 

209 if setting['cc']: 

210 save('cc', setting['cc']) 

211 else: 

212 delete('cc') 

213 

214 # bcc 

215 if setting['bcc']: 

216 save('bcc', setting['bcc']) 

217 else: 

218 delete('bcc') 

219 

220 # notes 

221 if setting['notes']: 

222 save('notes', setting['notes']) 

223 else: 

224 delete('notes') 

225 

226 # enabled 

227 save('enabled', 'true' if setting['enabled'] else 'false') 

228 

229 def render_to_response(self, template, context): 

230 """ """ 

231 if self.viewing: 

232 setting = context['instance'] 

233 context['setting'] = setting 

234 context['has_html_template'] = self.email_handler.get_auto_body_template( 

235 setting['key'], 'html') 

236 context['has_txt_template'] = self.email_handler.get_auto_body_template( 

237 setting['key'], 'txt') 

238 

239 return super().render_to_response(template, context) 

240 

241 def preview(self): 

242 """ 

243 View for showing a rendered preview of a given email template. 

244 

245 This will render the email template according to the "mode" 

246 requested - i.e. HTML or TXT. 

247 """ 

248 key = self.request.matchdict['key'] 

249 setting = self.email_handler.get_email_setting(key) 

250 context = setting.sample_data() 

251 mode = self.request.params.get('mode', 'html') 

252 

253 if mode == 'txt': 

254 body = self.email_handler.get_auto_txt_body(key, context) 

255 self.request.response.content_type = 'text/plain' 

256 

257 else: # html 

258 body = self.email_handler.get_auto_html_body(key, context) 

259 

260 self.request.response.text = body 

261 return self.request.response 

262 

263 @classmethod 

264 def defaults(cls, config): 

265 """ """ 

266 cls._email_defaults(config) 

267 cls._defaults(config) 

268 

269 @classmethod 

270 def _email_defaults(cls, config): 

271 """ """ 

272 route_prefix = cls.get_route_prefix() 

273 permission_prefix = cls.get_permission_prefix() 

274 model_title_plural = cls.get_model_title_plural() 

275 instance_url_prefix = cls.get_instance_url_prefix() 

276 

277 # fix permission group 

278 config.add_wutta_permission_group(permission_prefix, 

279 model_title_plural, 

280 overwrite=False) 

281 

282 # preview 

283 config.add_route(f'{route_prefix}.preview', 

284 f'{instance_url_prefix}/preview') 

285 config.add_view(cls, attr='preview', 

286 route_name=f'{route_prefix}.preview', 

287 permission=f'{permission_prefix}.view') 

288 

289 

290def defaults(config, **kwargs): 

291 base = globals() 

292 

293 EmailSettingView = kwargs.get('EmailSettingView', base['EmailSettingView']) 

294 EmailSettingView.defaults(config) 

295 

296 

297def includeme(config): 

298 defaults(config)