Notification emails #80
@ -1,4 +1,4 @@
|
||||
# Generated by Django 4.2.11 on 2024-04-12 18:14
|
||||
# Generated by Django 4.2.11 on 2024-04-16 15:56
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
@ -10,8 +10,8 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('actstream', '0003_add_follow_flag'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('actstream', '0003_add_follow_flag'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -21,10 +21,12 @@ class Migration(migrations.Migration):
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('recipient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
('action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='actstream.action')),
|
||||
('sent', models.BooleanField(default=False)),
|
||||
('email_sent', models.BooleanField(default=False)),
|
||||
('processed_by_mailer_at', models.DateTimeField(default=None, null=True)),
|
||||
('read_at', models.DateTimeField(default=None, null=True)),
|
||||
],
|
||||
options={
|
||||
'indexes': [models.Index(fields=['processed_by_mailer_at'], name='notificatio_process_fc95bc_idx'), models.Index(fields=['recipient', 'read_at'], name='notificatio_recipie_564b1f_idx')],
|
||||
'unique_together': {('recipient', 'action')},
|
||||
},
|
||||
),
|
||||
|
@ -10,19 +10,24 @@ User = get_user_model()
|
||||
|
||||
class Notification(models.Model):
|
||||
"""Notification records are created in Action's post_save signal.
|
||||
When a user marks a notification as read, a record is deleted.
|
||||
While a notification exists it can be picked up by a send_notifications management command
|
||||
that runs periodically in background.
|
||||
If a recipient opted out from receiving notifications of particular type (based on action.verb),
|
||||
we shouldn't include it in the email, leaving sent=False.
|
||||
When a user marks a notification as read, read_at is set.
|
||||
send_notification_emails management command runs periodically in background and sends all
|
||||
notifications that haven't been processed yet, read_at is not checked when sending emails.
|
||||
email_sent flag is used only to record the fact that we attempted to send an email.
|
||||
A user can unsubscribe from notification emails in their profile settings.
|
||||
"""
|
||||
|
||||
recipient = models.ForeignKey(User, null=False, on_delete=models.CASCADE)
|
||||
action = models.ForeignKey(Action, null=False, on_delete=models.CASCADE)
|
||||
sent = models.BooleanField(default=False, null=False)
|
||||
email_sent = models.BooleanField(default=False, null=False)
|
||||
processed_by_mailer_at = models.DateTimeField(default=None, null=True)
|
||||
read_at = models.DateTimeField(default=None, null=True)
|
||||
|
||||
class Meta:
|
||||
indexes = [
|
||||
models.Index(fields=['processed_by_mailer_at']),
|
||||
models.Index(fields=['recipient', 'read_at']),
|
||||
]
|
||||
unique_together = ['recipient', 'action']
|
||||
|
||||
def format_email_txt(self):
|
||||
|
@ -28,7 +28,7 @@ class Command(BaseCommand):
|
||||
logger.info(f'{recipient} has unconfirmed email, skipping')
|
||||
n.save()
|
||||
continue
|
||||
n.sent = True
|
||||
n.email_sent = True
|
||||
# first mark as processed, then send: avoid spamming in case of a crash-loop
|
||||
n.save()
|
||||
logger.info(f'sending an email to {recipient}: {n.action}')
|
Loading…
Reference in New Issue
Block a user