Implement broken link email handling

This commit is contained in:
Quantum 2022-01-24 20:03:13 -05:00
parent f065351dda
commit 637069c4e7
6 changed files with 118 additions and 0 deletions

30
qlinks/email.py Normal file
View file

@ -0,0 +1,30 @@
from django.conf import settings
from django.core.mail import send_mail
from django.template import Context
from django.template.loader import get_template
from django.utils.translation import gettext as _
from qlinks.models import Link
template = get_template('qlinks/broken_email.txt')
def send_broken_email(link: Link):
if link.created_by and link.created_by.email:
emails = [link.created_by.email]
name = link.created_by.get_full_name()
else:
emails = [email for name, email in settings.ADMINS]
if not emails:
return
name = _('Admin')
send_mail(
subject=_('Broken link: %s') % link.short_url,
message=template.render({
'name': name,
'link': link,
}),
from_email=None,
recipient_list=emails,
)

View file

@ -6,6 +6,7 @@ from django.core.management import BaseCommand
from django.db.models import Min
from django.utils import timezone
from qlinks.email import send_broken_email
from qlinks.models import Link
logger = logging.getLogger('qlinks.checker')
@ -50,5 +51,6 @@ class Command(BaseCommand):
link.check_url()
if was_working and not link.is_working:
self.stdout.write(f'URL for {link.short} just broke: {link.long}')
send_broken_email(link)
time.sleep(settings.QLINKS_CHECK_THROTTLE)

View file

@ -91,3 +91,4 @@ QLINKS_CDN_CACHE = None
QLINKS_CHECK_MIN = timedelta(days=6)
QLINKS_CHECK_MAX = timedelta(days=8)
QLINKS_CHECK_THROTTLE = 1
QLINKS_BROKEN_EMAIL = False

View file

@ -22,6 +22,35 @@ DATABASES = {
STATIC_ROOT = '/srv/example'
# STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
# Email
# https://docs.djangoproject.com/en/4.0/topics/email/#email-backends
# The email all broken links notifications will come from, among other things.
# DEFAULT_FROM_MAIL = 'qlinks@example.com'
# A tuple of (name, email) pairs that specifies those who will be mailed
# when the server experiences an error when DEBUG = False.
# ADMINS = (
# ('Your Name', 'your.email@example.com'),
# )
# The following block is included for your convenience, if you want to use Gmail.
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# EMAIL_USE_TLS = True
# EMAIL_HOST = 'smtp.gmail.com'
# EMAIL_HOST_USER = '<your account>@gmail.com'
# EMAIL_HOST_PASSWORD = '<your password>'
# EMAIL_PORT = 587
# To use Mailgun, uncomment this block.
# You will need to run `pip install django-mailgun` for to get `MailgunBackend`.
# EMAIL_BACKEND = 'django_mailgun.MailgunBackend'
# MAILGUN_ACCESS_KEY = '<your Mailgun access key>'
# MAILGUN_SERVER_NAME = '<your Mailgun domain>'
# You can also use Sendgrid, with `pip install sendgrid-django`.
# EMAIL_BACKEND = 'sgbackend.SendGridBackend'
# SENDGRID_API_KEY = '<Your SendGrid API Key>'
# qlinks configuration
QLINKS_ADMIN_HOST = r'admin'
@ -42,3 +71,6 @@ QLINKS_CANONICAL = None
# Minimum time in seconds between two consecutive checks.
# QLINKS_CHECK_THROTTLE = 1
# Enable emails.
# QLINKS_BROKEN_EMAIL = True

View file

@ -0,0 +1,8 @@
{% load i18n %}{% blocktranslate %}Dear {{ name }},{% endblocktranslate %}
{% translate "QLinks has found a broken link:" %}
* {% translate "short link" %}: {{ link.short_url }}
* {% translate "destination" %}: {{ link.long }}
{% translate "Please log onto the admin site and fix this." %}

View file

@ -0,0 +1,45 @@
from django.contrib.auth.models import User
from django.core import mail
from django.test import TestCase
from django.utils import timezone
from qlinks.email import send_broken_email
from qlinks.models import Link
class EmailTest(TestCase):
def create_link(self, user) -> Link:
return Link.objects.create(
short='short',
long='https://long.example.com',
created_by=user,
is_working=False,
last_check=timezone.now(),
)
def assert_email(self, link: Link, name: str, to: str):
self.assertEqual(len(mail.outbox), 1)
self.assertEqual([to], mail.outbox[0].to)
self.assertIn(link.short_url, mail.outbox[0].subject)
self.assertIn(link.short_url, mail.outbox[0].body)
self.assertIn(link.long, mail.outbox[0].body)
self.assertIn(f'Dear {name},', mail.outbox[0].body)
def test_send_no_user(self):
link = self.create_link(None)
with self.settings(ADMINS=[('someone', 'someone@example.com')]):
send_broken_email(link=link)
self.assert_email(link, 'Admin', 'someone@example.com')
def test_send_user(self):
link = self.create_link(User.objects.create_user(
'test', email='user@example.com', first_name='Test', last_name='User'
))
send_broken_email(link=link)
self.assert_email(link, 'Test User', 'user@example.com')
def test_send_user_no_email(self):
link = self.create_link(User.objects.create_user('test', first_name='Test', last_name='User'))
with self.settings(ADMINS=[('someone', 'someone@example.com')]):
send_broken_email(link=link)
self.assert_email(link, 'Admin', 'someone@example.com')