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
« 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"""
27import colander
29from wuttaweb.views import MasterView
30from wuttaweb.forms.schema import EmailRecipients
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
48 labels = {
49 'key': "Email Key",
50 'replyto': "Reply-To",
51 }
53 grid_columns = [
54 'key',
55 'subject',
56 'to',
57 'enabled',
58 ]
60 # TODO: why does this not work?
61 sort_defaults = 'key'
63 form_fields = [
64 'key',
65 'description',
66 'subject',
67 'sender',
68 'replyto',
69 'to',
70 'cc',
71 'bcc',
72 'notes',
73 'enabled',
74 ]
76 def __init__(self, request, context=None):
77 super().__init__(request, context=context)
78 self.email_handler = self.app.get_email_handler()
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
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 }
107 def configure_grid(self, g):
108 """ """
109 super().configure_grid(g)
111 # key
112 g.set_searchable('key')
113 g.set_link('key')
115 # subject
116 g.set_searchable('subject')
117 g.set_link('subject')
119 # to
120 g.set_renderer('to', self.render_to_short)
122 def render_to_short(self, setting, field, value):
123 """ """
124 recips = value
125 if not recips:
126 return
128 if len(recips) < 3:
129 return ', '.join(recips)
131 recips = ', '.join(recips[:2])
132 return f"{recips}, ..."
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)
141 raise self.notfound()
143 def get_instance_title(self, setting):
144 """ """
145 return setting['subject']
147 def configure_form(self, f):
148 """ """
149 super().configure_form(f)
151 # description
152 f.set_readonly('description')
154 # replyto
155 f.set_required('replyto', False)
157 # to
158 f.set_node('to', EmailRecipients())
160 # cc
161 f.set_node('cc', EmailRecipients())
163 # bcc
164 f.set_node('bcc', EmailRecipients())
166 # notes
167 f.set_widget('notes', 'notes')
168 f.set_required('notes', False)
170 # enabled
171 f.set_node('enabled', colander.Boolean())
173 def persist(self, setting):
174 """ """
175 session = self.Session()
176 key = self.request.matchdict['key']
178 def save(name, value):
179 self.app.save_setting(session, f'{self.config.appname}.email.{key}.{name}', value)
181 def delete(name):
182 self.app.delete_setting(session, f'{self.config.appname}.email.{key}.{name}')
184 # subject
185 if setting['subject']:
186 save('subject', setting['subject'])
187 else:
188 delete('subject')
190 # sender
191 if setting['sender']:
192 save('sender', setting['sender'])
193 else:
194 delete('sender')
196 # replyto
197 if setting['replyto']:
198 save('replyto', setting['replyto'])
199 else:
200 delete('replyto')
202 # to
203 if setting['to']:
204 save('to', setting['to'])
205 else:
206 delete('to')
208 # cc
209 if setting['cc']:
210 save('cc', setting['cc'])
211 else:
212 delete('cc')
214 # bcc
215 if setting['bcc']:
216 save('bcc', setting['bcc'])
217 else:
218 delete('bcc')
220 # notes
221 if setting['notes']:
222 save('notes', setting['notes'])
223 else:
224 delete('notes')
226 # enabled
227 save('enabled', 'true' if setting['enabled'] else 'false')
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')
239 return super().render_to_response(template, context)
241 def preview(self):
242 """
243 View for showing a rendered preview of a given email template.
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')
253 if mode == 'txt':
254 body = self.email_handler.get_auto_txt_body(key, context)
255 self.request.response.content_type = 'text/plain'
257 else: # html
258 body = self.email_handler.get_auto_html_body(key, context)
260 self.request.response.text = body
261 return self.request.response
263 @classmethod
264 def defaults(cls, config):
265 """ """
266 cls._email_defaults(config)
267 cls._defaults(config)
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()
277 # fix permission group
278 config.add_wutta_permission_group(permission_prefix,
279 model_title_plural,
280 overwrite=False)
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')
290def defaults(config, **kwargs):
291 base = globals()
293 EmailSettingView = kwargs.get('EmailSettingView', base['EmailSettingView'])
294 EmailSettingView.defaults(config)
297def includeme(config):
298 defaults(config)