Add per-user Reminder model and adjust sendNotifications to use it
This commit is contained in:
parent
6640306113
commit
927094ee41
@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import Tool, Task, Event
|
from .models import Tool, Task, Reminder, Event
|
||||||
|
|
||||||
admin.site.register(Tool)
|
admin.site.register(Tool)
|
||||||
|
|
||||||
@ -10,4 +10,5 @@ class TaskAdmin(admin.ModelAdmin):
|
|||||||
prepopulated_fields = {"slug": ("name",)}
|
prepopulated_fields = {"slug": ("name",)}
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Reminder)
|
||||||
admin.site.register(Event)
|
admin.site.register(Event)
|
||||||
|
@ -1,20 +1,49 @@
|
|||||||
import smtplib
|
import smtplib
|
||||||
|
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
|
from itertools import groupby
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
from tasks.models import Tool, Task, Event
|
from tasks.models import Tool, Task, Event, Reminder
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Sends any notifications for upcoming and overdue tasks'
|
help = 'Sends any notifications for upcoming and overdue tasks'
|
||||||
|
|
||||||
# TODO: actually send notifications
|
def _send_email(self, to, subject, content):
|
||||||
|
msg = EmailMessage()
|
||||||
|
msg.set_content(content)
|
||||||
|
msg['Subject'] = subject
|
||||||
|
msg['From'] = 'adam@adamgoldsmith.name'
|
||||||
|
msg['To'] = to
|
||||||
|
|
||||||
|
with smtplib.SMTP("localhost") as server:
|
||||||
|
server.send_message(msg)
|
||||||
|
|
||||||
|
def _active_reminders(self):
|
||||||
|
for reminder in Reminder.objects.all():
|
||||||
|
if reminder.should_remind:
|
||||||
|
yield reminder
|
||||||
|
|
||||||
|
def _format_reminder_lines(self, reminders):
|
||||||
|
for reminder in reminders:
|
||||||
|
next_date = reminder.task.next_recurrence.strftime('%Y-%m-%d')
|
||||||
|
yield f" - {reminder.task.name} - {next_date}"
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
for tool in Tool.objects.all():
|
reminders_per_user = {
|
||||||
print(tool.name)
|
user: sorted(reminders, key=lambda r: r.task.next_recurrence)
|
||||||
for task in tool.task_set.all():
|
for user, reminders in groupby(self._active_reminders(), lambda r: r.user)
|
||||||
print('==>', task.name, 'next:', task.next_recurrence())
|
}
|
||||||
if task.is_overdue():
|
|
||||||
self.stdout.write(self.style.SUCCESS(
|
for user, reminders in reminders_per_user.items():
|
||||||
f'Sending Notification for task {task.name}'))
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f'Sending notification for {len(reminders)} task(s) to {user}'))
|
||||||
|
|
||||||
|
contents = "The following tasks are upcoming or overdue:\n\n" + \
|
||||||
|
('\n'.join(self._format_reminder_lines(reminders)))
|
||||||
|
|
||||||
|
self._send_email(
|
||||||
|
user.email,
|
||||||
|
f'[CMS Tool Maintenance] {len(reminders)} tasks are upcoming or overdue!',
|
||||||
|
contents)
|
||||||
|
25
tasks/migrations/0002_reminder.py
Normal file
25
tasks/migrations/0002_reminder.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 3.1.4 on 2020-12-07 21:13
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('tasks', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Subscription',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('days_before', models.IntegerField()),
|
||||||
|
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tasks.task')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
@ -58,6 +58,24 @@ class Task(models.Model):
|
|||||||
return next_rec < datetime.now()
|
return next_rec < datetime.now()
|
||||||
|
|
||||||
|
|
||||||
|
class Reminder(models.Model):
|
||||||
|
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||||
|
task = models.ForeignKey(Task, on_delete=models.CASCADE)
|
||||||
|
days_before = models.IntegerField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
# Django doesn't support multiple-column primary keys
|
||||||
|
unique_together = (("user", "task"),)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_remind(self):
|
||||||
|
time_until_overdue = self.task.next_recurrence - datetime.now()
|
||||||
|
return self.task.is_overdue or (time_until_overdue.days <= self.days_before)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.user}-{self.task}, {self.days_before} day(s)"
|
||||||
|
|
||||||
|
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
task = models.ForeignKey(Task, on_delete=models.CASCADE)
|
task = models.ForeignKey(Task, on_delete=models.CASCADE)
|
||||||
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||||
|
Loading…
Reference in New Issue
Block a user