3
0
Fork 0

feat: add feature to edit email settings, basic message preview

This commit is contained in:
Lance Edgar 2024-12-23 19:24:17 -06:00
parent 3035d1f58a
commit 95ff87fbf3
19 changed files with 826 additions and 4 deletions

View file

@ -392,3 +392,47 @@ class TestFileDownload(DataTestCase):
widget = typ.widget_maker()
self.assertIsInstance(widget, widgets.FileDownloadWidget)
self.assertEqual(widget.url, '/foo')
class TestEmailRecipients(TestCase):
def test_serialize(self):
typ = mod.EmailRecipients()
node = colander.SchemaNode(typ)
recips = [
'alice@example.com',
'bob@example.com',
]
recips_str = ', '.join(recips)
# values
result = typ.serialize(node, recips_str)
self.assertEqual(result, '\n'.join(recips))
# null
result = typ.serialize(node, colander.null)
self.assertIs(result, colander.null)
def test_deserialize(self):
typ = mod.EmailRecipients()
node = colander.SchemaNode(typ)
recips = [
'alice@example.com',
'bob@example.com',
]
recips_str = ', '.join(recips)
# values
result = typ.deserialize(node, recips_str)
self.assertEqual(result, recips_str)
# null
result = typ.deserialize(node, colander.null)
self.assertIs(result, colander.null)
def test_widget_maker(self):
typ = mod.EmailRecipients()
widget = typ.widget_maker()
self.assertIsInstance(widget, widgets.EmailRecipientsWidget)

View file

@ -10,7 +10,7 @@ from pyramid import testing
from wuttaweb import grids
from wuttaweb.forms import widgets as mod
from wuttaweb.forms.schema import (FileDownload, PersonRef, RoleRefs, UserRefs, Permissions,
WuttaDateTime)
WuttaDateTime, EmailRecipients)
from tests.util import WebTestCase
@ -304,6 +304,55 @@ class TestPermissionsWidget(WebTestCase):
self.assertIn("Polish the widgets", html)
class TestEmailRecipientsWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def test_serialize(self):
node = colander.SchemaNode(EmailRecipients())
field = self.make_field(node)
widget = mod.EmailRecipientsWidget()
recips = [
'alice@example.com',
'bob@example.com',
]
recips_str = ', '.join(recips)
# readonly
result = widget.serialize(field, recips_str, readonly=True)
self.assertIn('<ul>', result)
self.assertIn('<li>alice@example.com</li>', result)
# editable
result = widget.serialize(field, recips_str)
self.assertIn('<b-input', result)
self.assertIn('type="textarea"', result)
def test_deserialize(self):
node = colander.SchemaNode(EmailRecipients())
field = self.make_field(node)
widget = mod.EmailRecipientsWidget()
recips = [
'alice@example.com',
'bob@example.com',
]
recips_str = ', '.join(recips)
# values
result = widget.deserialize(field, recips_str)
self.assertEqual(result, recips_str)
# null
result = widget.deserialize(field, colander.null)
self.assertIs(result, colander.null)
class TestBatchIdWidget(WebTestCase):
def make_field(self, node, **kwargs):

23
tests/test_emails.py Normal file
View file

@ -0,0 +1,23 @@
# -*- coding: utf-8; -*-
from wuttjamaican.testing import DataTestCase
from wuttjamaican.email import EmailSetting
from wuttaweb import emails as mod
class TestAllSettings(DataTestCase):
def check_setting(self, setting):
self.assertIsNotNone(setting.default_subject)
setting = setting(self.config)
context = setting.sample_data()
self.assertIsInstance(context, dict)
def test_all(self):
for name in dir(mod):
obj = getattr(mod, name)
if (isinstance(obj, type)
and obj is not EmailSetting
and issubclass(obj, EmailSetting)):
self.check_setting(obj)

211
tests/views/test_email.py Normal file
View file

@ -0,0 +1,211 @@
# -*- coding: utf-8; -*-
from unittest.mock import patch
from wuttjamaican.email import EmailSetting
import colander
from pyramid.httpexceptions import HTTPNotFound
from pyramid.response import Response
from wuttaweb.views import email as mod
from tests.util import WebTestCase
class TestEmailSettingViews(WebTestCase):
def make_view(self):
return mod.EmailSettingView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.email')
def test_get_grid_data(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
view = self.make_view()
data = view.get_grid_data()
self.assertIsInstance(data, list)
self.assertTrue(data) # 1+ items
setting = data[0]
self.assertIn('key', setting)
self.assertIn('subject', setting)
self.assertIn('sender', setting)
self.assertIn('to', setting)
self.assertIn('cc', setting)
self.assertIn('notes', setting)
def test_configure_grid(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
view = self.make_view()
grid = view.make_model_grid()
self.assertIn('key', grid.searchable_columns)
self.assertIn('subject', grid.searchable_columns)
def test_render_to_short(self):
view = self.make_view()
setting = EmailSetting(self.config)
# more than 2 recips
result = view.render_to_short(setting, 'to', [
'alice@example.com',
'bob@example.com',
'charlie@example.com',
'diana@example.com',
])
self.assertEqual(result, 'alice@example.com, bob@example.com, ...')
# just 2 recips
result = view.render_to_short(setting, 'to', [
'alice@example.com',
'bob@example.com',
])
self.assertEqual(result, 'alice@example.com, bob@example.com')
# just 1 recip
result = view.render_to_short(setting, 'to', ['alice@example.com'])
self.assertEqual(result, 'alice@example.com')
# no recips
result = view.render_to_short(setting, 'to', [])
self.assertIsNone(result)
def test_get_instance(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
view = self.make_view()
# normal
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
setting = view.get_instance()
self.assertIsInstance(setting, dict)
self.assertIn('key', setting)
self.assertIn('sender', setting)
self.assertIn('subject', setting)
self.assertIn('to', setting)
self.assertIn('cc', setting)
self.assertIn('notes', setting)
self.assertIn('enabled', setting)
# not found
with patch.object(self.request, 'matchdict', new={'key': 'this-should_notEXIST'}):
self.assertRaises(HTTPNotFound, view.get_instance)
def test_get_instance_title(self):
view = self.make_view()
result = view.get_instance_title({'subject': 'whatever'})
self.assertEqual(result, 'whatever')
def test_configure_form(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
view = self.make_view()
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
setting = view.get_instance()
form = view.make_model_form(setting)
self.assertIn('description', form.readonly_fields)
self.assertFalse(form.required_fields['replyto'])
def test_persist(self):
model = self.app.model
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
view = self.make_view()
# start w/ no settings in db
self.assertEqual(self.session.query(model.Setting).count(), 0)
# "edit" settings for feedback email
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
setting = view.get_instance()
setting['subject'] = 'Testing Feedback'
setting['sender'] = 'feedback@example.com'
setting['replyto'] = 'feedback4@example.com'
setting['to'] = 'feedback@example.com'
setting['cc'] = 'feedback2@example.com'
setting['bcc'] = 'feedback3@example.com'
setting['notes'] = "did this work?"
setting['enabled'] = True
# persist email settings
with patch.object(view, 'Session', return_value=self.session):
view.persist(setting)
self.session.commit()
# check settings in db
self.assertEqual(self.session.query(model.Setting).count(), 8)
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.subject'),
"Testing Feedback")
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.sender'),
'feedback@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.replyto'),
'feedback4@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.to'),
'feedback@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.cc'),
'feedback2@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.bcc'),
'feedback3@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.notes'),
"did this work?")
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.enabled'),
'true')
# "edit" settings for feedback email
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
setting = view.get_instance()
setting['subject'] = None
setting['sender'] = None
setting['replyto'] = None
setting['to'] = None
setting['cc'] = None
setting['bcc'] = None
setting['notes'] = None
setting['enabled'] = False
# persist email settings
with patch.object(view, 'Session', return_value=self.session):
view.persist(setting)
self.session.commit()
# check settings in db
self.assertEqual(self.session.query(model.Setting).count(), 1)
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.subject'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.sender'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.replyto'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.to'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.cc'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.bcc'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.notes'))
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.enabled'),
'false')
def test_render_to_response(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_route('login', '/auth/login')
self.pyramid_config.add_route('email_settings', '/email/settings')
self.pyramid_config.add_route('email_settings.preview', '/email/settings/{key}/preview')
view = self.make_view()
# nb. this gives coverage, but tests nothing..
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
setting = view.get_instance()
with patch.object(view, 'viewing', new=True):
context = {'instance': setting}
response = view.render_to_response('view', context)
self.assertIsInstance(response, Response)
def test_preview(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
view = self.make_view()
# nb. this gives coverage, but tests nothing..
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
# html
with patch.object(self.request, 'params', new={'mode': 'html'}):
response = view.preview()
self.assertEqual(response.content_type, 'text/html')
# txt
with patch.object(self.request, 'params', new={'mode': 'txt'}):
response = view.preview()
self.assertEqual(response.content_type, 'text/plain')

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8; -*-
from wuttaweb.views import essential as mod
from tests.util import WebTestCase
class TestEssentialViews(WebTestCase):
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.essential')