2
0
Fork 0

feat: use native wuttjamaican app to send feedback email

This commit is contained in:
Lance Edgar 2024-08-26 13:21:05 -05:00
parent a377061da0
commit a010071985
10 changed files with 101 additions and 35 deletions

View file

@ -42,7 +42,7 @@ dependencies = [
"pyramid_tm",
"waitress",
"WebHelpers2",
"WuttJamaican[db]>=0.12.1",
"WuttJamaican[db,email]>=0.12.1",
"zope.sqlalchemy>=1.5",
]

View file

@ -37,9 +37,10 @@ from wuttaweb.auth import WuttaSecurityPolicy
class WebAppProvider(AppProvider):
"""
The :term:`app provider` for WuttaWeb. This adds some methods
specific to web apps.
The :term:`app provider` for WuttaWeb. This adds some methods to
the :term:`app handler`, which are specific to web apps.
"""
email_templates = 'wuttaweb:email/templates'
def get_web_handler(self, **kwargs):
"""

View file

@ -5,9 +5,9 @@
**User Name**
% if user:
${user}
${user}
% else:
${user_name}
${user_name}
% endif
**Referring URL**

View file

@ -73,6 +73,54 @@
</div>
<h3 class="block is-size-3">Email</h3>
<div class="block" style="padding-left: 2rem; width: 50%;">
<b-field>
<b-checkbox name="${config.appname}.mail.send_emails"
v-model="simpleSettings['${config.appname}.mail.send_emails']"
native-value="true"
@input="settingsNeedSaved = true">
Enable email sending
</b-checkbox>
</b-field>
<div v-show="simpleSettings['${config.appname}.mail.send_emails']">
<b-field label="Default Sender">
<b-input name="${app.appname}.email.default.sender"
v-model="simpleSettings['${app.appname}.email.default.sender']"
@input="settingsNeedSaved = true" />
</b-field>
<b-field label="Default Recipient(s)">
<b-input name="${app.appname}.email.default.to"
v-model="simpleSettings['${app.appname}.email.default.to']"
@input="settingsNeedSaved = true" />
</b-field>
<b-field label="Default Subject (optional)">
<b-input name="${app.appname}.email.default.subject"
v-model="simpleSettings['${app.appname}.email.default.subject']"
@input="settingsNeedSaved = true" />
</b-field>
<b-field label="Feedback Recipient(s) (optional)">
<b-input name="${app.appname}.email.feedback.to"
v-model="simpleSettings['${app.appname}.email.feedback.to']"
@input="settingsNeedSaved = true" />
</b-field>
<b-field label="Feedback Subject (optional)">
<b-input name="${app.appname}.email.feedback.subject"
v-model="simpleSettings['${app.appname}.email.feedback.subject']"
@input="settingsNeedSaved = true" />
</b-field>
</div>
</div>
<h3 class="block is-size-3">Web Libraries</h3>
<div class="block" style="padding-left: 2rem;">
@ -219,6 +267,19 @@
this.editWebLibraryShowDialog = false
}
ThisPage.methods.validateEmailSettings = function() {
if (this.simpleSettings['${config.appname}.mail.send_emails']) {
if (!this.simpleSettings['${config.appname}.email.default.sender']) {
return "Default Sender is required to send email."
}
if (!this.simpleSettings['${config.appname}.email.default.to']) {
return "Default Recipient(s) are required to send email."
}
}
}
ThisPageData.validators.push(ThisPage.methods.validateEmailSettings)
</script>
</%def>

View file

@ -20,7 +20,10 @@
<span>${app.get_node_title()}</span>
</b-field>
<b-field horizontal label="Production Mode">
<span>${config.production()}</span>
<span>${"Yes" if config.production() else "No"}</span>
</b-field>
<b-field horizontal label="Email Enabled">
<span>${"Yes" if app.get_email_handler().sending_is_enabled() else "No"}</span>
</b-field>
</div>
</div>

View file

@ -167,7 +167,11 @@
for (let validator of this.validators) {
let msg = validator.call(this)
if (msg) {
alert(msg)
this.$buefy.toast.open({
message: msg,
type: 'is-warning',
duration: 4000, // 4 seconds
})
return
}
}

View file

@ -132,31 +132,9 @@ class CommonView(View):
return schema
def feedback_send(self, context): # pragma: no cover
def feedback_send(self, context):
""" """
# TODO: this is definitely a stopgap bit of logic, until we
# have a more robust way to handle email via wuttjamaican etc.
from pyramid_mailer.mailer import Mailer
from pyramid_mailer.message import Message
From = self.config.require(f'{self.config.appname}.email.default.sender')
To = self.config.require(f'{self.config.appname}.email.feedback.to')
Subject = self.config.get(f'{self.config.appname}.email.feedback.subject',
default="User Feedback")
text_body = render('/temporary/feedback.txt.mako', context, request=self.request)
html_body = render('/temporary/feedback.html.mako', context, request=self.request)
msg = Message(subject=Subject,
sender=From,
recipients=[To],
body=text_body,
html=html_body)
mailer = Mailer()
mailer.send_immediately(msg)
self.app.send_email('feedback', context)
def setup(self, session=None):
"""

View file

@ -124,16 +124,25 @@ class AppInfoView(MasterView):
simple_settings = [
# basics
{'name': f'{self.app.appname}.app_title'},
{'name': f'{self.app.appname}.node_type'},
{'name': f'{self.app.appname}.node_title'},
{'name': f'{self.app.appname}.production',
{'name': f'{self.config.appname}.app_title'},
{'name': f'{self.config.appname}.node_type'},
{'name': f'{self.config.appname}.node_title'},
{'name': f'{self.config.appname}.production',
'type': bool},
# user/auth
{'name': 'wuttaweb.home_redirect_to_login',
'type': bool, 'default': False},
# email
{'name': f'{self.config.appname}.mail.send_emails',
'type': bool, 'default': False},
{'name': f'{self.config.appname}.email.default.sender'},
{'name': f'{self.config.appname}.email.default.subject'},
{'name': f'{self.config.appname}.email.default.to'},
{'name': f'{self.config.appname}.email.feedback.subject'},
{'name': f'{self.config.appname}.email.feedback.to'},
]
def getval(key):

View file

@ -117,6 +117,16 @@ class TestCommonView(WebTestCase):
self.assertEqual(list(context), ['error'])
self.assertIn('RuntimeError', context['error'])
def test_feedback_send(self):
view = self.make_view()
with patch.object(self.app, 'send_email') as send_email:
view.feedback_send({'user_name': "Barney",
'message': "hello world"})
send_email.assert_called_once_with('feedback', {
'user_name': "Barney",
'message': "hello world"
})
def test_setup(self):
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_route('login', '/login')