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