Notification emails #80

Merged
Oleg-Komarov merged 31 commits from notifications into main 2024-04-18 16:11:20 +02:00
Showing only changes of commit 0e0e8df024 - Show all commits

View File

@ -1,5 +1,4 @@
"""Send user notifications as emails, at most once delivery."""
from collections import defaultdict
import logging
from django.conf import settings
@ -15,37 +14,33 @@ logger.setLevel(logging.INFO)
class Command(BaseCommand):
def handle(self, *args, **options): # noqa: D102
logger.info('start, checking for outstanding notifications')
notifications = Notification.objects.filter(processed_by_mailer_at=None)
batched_by_recipient = defaultdict(list)
for n in notifications:
batched_by_recipient[n.recipient].append(n)
for recipient, batch in batched_by_recipient.items():
to_send = []
for n in batch:
n.processed_by_mailer_at = timezone.now()
if not recipient.is_subscribed_to_notification_emails:
continue
# check that email is confirmed to avoid spamming unsuspecting email owners
if recipient.confirmed_email_at is None:
continue
n.sent = True
to_send.append(n)
unprocessed_notifications = Notification.objects.filter(processed_by_mailer_at=None)
for n in unprocessed_notifications:
logger.info(f'processing Notification pk={n.pk}')
n.processed_by_mailer_at = timezone.now()
recipient = n.recipient
if not recipient.is_subscribed_to_notification_emails:
logger.info(f'{recipient} is not subscribed, skipping')
n.save()
continue
# check that email is confirmed to avoid spamming unsuspecting email owners
if recipient.confirmed_email_at is None:
logger.info(f'{recipient} has unconfirmed email, skipping')
n.save()
continue
n.sent = True
# first mark as processed, then send: avoid spamming in case of a crash-loop
Notification.objects.bulk_update(batch, ['processed_by_mailer_at', 'sent'])
if len(to_send) > 0:
logger.info(f'sending an email to {recipient} about {len(to_send)} notifications')
send_batch_notification_email(recipient, to_send)
logger.info('finish')
n.save()
logger.info(f'sending an email to {recipient}: {n.action}')
send_notification_email(n)
def send_batch_notification_email(recipient, notifications):
def send_notification_email(notification):
subject = 'New activity'
message = '\n\n'.join([n.format_email_txt() for n in notifications])
message = notification.format_email_txt()
send_mail(
subject,
message,
settings.DEFAULT_FROM_EMAIL,
[recipient.email],
[notification.recipient.email],
)