fix(notify): gracefully fail notifications

Instead of allowing an exception to propogate through the framework
routes, catch it and log out an error about notifications not being
sent.

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2021-12-17 17:23:41 -08:00
parent d6d41cdbad
commit 36bc9ae29b
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
2 changed files with 42 additions and 2 deletions

View file

@ -13,10 +13,12 @@ import aurweb.config
import aurweb.db import aurweb.db
import aurweb.l10n import aurweb.l10n
from aurweb import db from aurweb import db, logging
from aurweb.models import (PackageBase, PackageComaintainer, PackageComment, PackageNotification, PackageRequest, RequestType, from aurweb.models import (PackageBase, PackageComaintainer, PackageComment, PackageNotification, PackageRequest, RequestType,
TUVote, User) TUVote, User)
logger = logging.get_logger(__name__)
aur_location = aurweb.config.get('options', 'aur_location') aur_location = aurweb.config.get('options', 'aur_location')
@ -49,7 +51,7 @@ class Notification:
body += '\n' + '[%d] %s' % (i + 1, ref) body += '\n' + '[%d] %s' % (i + 1, ref)
return body.rstrip() return body.rstrip()
def send(self): def _send(self) -> None:
sendmail = aurweb.config.get('notifications', 'sendmail') sendmail = aurweb.config.get('notifications', 'sendmail')
sender = aurweb.config.get('notifications', 'sender') sender = aurweb.config.get('notifications', 'sender')
reply_to = aurweb.config.get('notifications', 'reply-to') reply_to = aurweb.config.get('notifications', 'reply-to')
@ -111,6 +113,14 @@ class Notification:
server.sendmail(sender, deliver_to, msg.as_bytes()) server.sendmail(sender, deliver_to, msg.as_bytes())
server.quit() server.quit()
def send(self) -> None:
try:
self._send()
except OSError as exc:
logger.error("Unable to emit notification due to an "
"OSError (precise exception following).")
logger.error(str(exc))
class ResetKeyNotification(Notification): class ResetKeyNotification(Notification):
def __init__(self, uid): def __init__(self, uid):

View file

@ -1,4 +1,5 @@
from datetime import datetime from datetime import datetime
from logging import ERROR
from typing import List from typing import List
from unittest import mock from unittest import mock
@ -634,3 +635,32 @@ def test_notification_defaults():
assert notif.get_refs() == tuple() assert notif.get_refs() == tuple()
assert notif.get_headers() == dict() assert notif.get_headers() == dict()
assert notif.get_cc() == list() assert notif.get_cc() == list()
def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture):
""" Try sending a notification with a bad SMTP configuration. """
caplog.set_level(ERROR)
config_get = config.get
mocked_options = {
"sendmail": str(),
"smtp-server": "mail.server.xyz",
"smtp-port": "587",
"smtp-user": "notify@server.xyz",
"smtp-password": "notify_server_xyz",
"sender": "notify@server.xyz",
"reply-to": "no-reply@server.xyz"
}
def mock_config_get(section: str, key: str) -> str:
if section == "notifications":
if key in mocked_options:
return mocked_options.get(key)
return config_get(section, key)
notif = notify.WelcomeNotification(user.ID)
with mock.patch("aurweb.config.get", side_effect=mock_config_get):
notif.send()
expected = "Unable to emit notification due to an OSError"
assert expected in caplog.text