From 05742f42f938bf6b9a2630caf36560c728d1d0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= <cuu508@gmail.com> Date: Fri, 14 Jul 2023 09:51:36 +0300 Subject: [PATCH] Update the senddeletionscheduled command to notify team members too --- .../commands/senddeletionscheduled.py | 33 ++++++++++----- .../tests/test_senddeletionscheduled.py | 41 +++++++++++++++---- .../emails/deletion-scheduled-body-html.html | 21 +++++----- .../emails/deletion-scheduled-body-text.html | 10 +++-- 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/hc/accounts/management/commands/senddeletionscheduled.py b/hc/accounts/management/commands/senddeletionscheduled.py index 75c0a9b7..e53cab82 100644 --- a/hc/accounts/management/commands/senddeletionscheduled.py +++ b/hc/accounts/management/commands/senddeletionscheduled.py @@ -3,6 +3,7 @@ from __future__ import annotations import time from django.conf import settings +from django.contrib.auth.models import User from django.core.management.base import BaseCommand from django.utils.timezone import now @@ -16,23 +17,35 @@ class Command(BaseCommand): def pause(self): time.sleep(1) + def members(self, user): + q = User.objects.filter(memberships__project__owner=user) + q = q.exclude(last_login=None) + return q.order_by("email") + def handle(self, *args, **options): q = Profile.objects.order_by("id") q = q.filter(deletion_scheduled_date__gt=now()) sent = 0 for profile in q: - self.stdout.write(f"Sending notice to {profile.user.email}") + recipients = [profile.user.email] + # Include team members in the recipient list too: + for u in self.members(profile.user): + recipients.append(u.email) - ctx = { - "email": profile.user.email, - "support_email": settings.SUPPORT_EMAIL, - "deletion_scheduled_date": profile.deletion_scheduled_date, - } - emails.deletion_scheduled(profile.user.email, ctx) - sent += 1 + for recipient in recipients: + role = "owner" if recipient == profile.user.email else "member" + self.stdout.write(f"Sending notice to {recipient} ({role})") + ctx = { + "owner_email": profile.user.email, + "num_checks": profile.num_checks_used(), + "support_email": settings.SUPPORT_EMAIL, + "deletion_scheduled_date": profile.deletion_scheduled_date, + } + emails.deletion_scheduled(recipient, ctx) + sent += 1 - # Throttle so we don't send too many emails at once: - self.pause() + # Throttle so we don't send too many emails at once: + self.pause() return f"Done!\nNotices sent: {sent}\n" diff --git a/hc/accounts/tests/test_senddeletionscheduled.py b/hc/accounts/tests/test_senddeletionscheduled.py index a44231e0..6d372e47 100644 --- a/hc/accounts/tests/test_senddeletionscheduled.py +++ b/hc/accounts/tests/test_senddeletionscheduled.py @@ -8,6 +8,7 @@ from django.core import mail from django.utils.timezone import now from hc.accounts.management.commands.senddeletionscheduled import Command +from hc.api.models import Check from hc.test import BaseTestCase @@ -16,19 +17,14 @@ def counts(result): return [int(s) for s in re.findall(r"\d+", result)] -class SendDeletionNoticesTestCase(BaseTestCase): - def test_it_skips_profiles_with_deletion_scheduled_date_not_set(self): - cmd = Command(stdout=Mock()) - cmd.pause = Mock() # don't pause for 1s - - result = cmd.handle() - self.assertEqual(counts(result), [0]) - self.assertEqual(len(mail.outbox), 0) - +class SendDeletionScheduledTestCase(BaseTestCase): def test_it_sends_notice(self): self.profile.deletion_scheduled_date = now() + td(days=31) self.profile.save() + Check.objects.create(project=self.project) + Check.objects.create(project=self.project) + cmd = Command(stdout=Mock()) cmd.pause = Mock() # don't pause for 1s @@ -37,6 +33,33 @@ class SendDeletionNoticesTestCase(BaseTestCase): email = mail.outbox[0] self.assertEqual(email.subject, "Account Deletion Warning") + self.assertEqual(email.to[0], "alice@example.org") + self.assertIn("Owner: alice@example.org", email.body) + self.assertIn("Number of checks in the account: 2", email.body) + + def test_it_sends_notice_to_team_members(self): + self.profile.deletion_scheduled_date = now() + td(days=31) + self.profile.save() + + self.bob.last_login = now() + self.bob.save() + + cmd = Command(stdout=Mock()) + cmd.pause = Mock() # don't pause for 1s + + result = cmd.handle() + self.assertEqual(counts(result), [2]) + + self.assertEqual(mail.outbox[0].to[0], "alice@example.org") + self.assertEqual(mail.outbox[1].to[0], "bob@example.org") + + def test_it_skips_profiles_with_deletion_scheduled_date_not_set(self): + cmd = Command(stdout=Mock()) + cmd.pause = Mock() # don't pause for 1s + + result = cmd.handle() + self.assertEqual(counts(result), [0]) + self.assertEqual(len(mail.outbox), 0) def test_it_skips_profiles_with_deletion_scheduled_date_in_past(self): self.profile.deletion_scheduled_date = now() - td(minutes=1) diff --git a/templates/emails/deletion-scheduled-body-html.html b/templates/emails/deletion-scheduled-body-html.html index 6b9c6dec..f538a8ff 100644 --- a/templates/emails/deletion-scheduled-body-html.html +++ b/templates/emails/deletion-scheduled-body-html.html @@ -2,16 +2,17 @@ {% load hc_extras %} {% block content %} -Hello,<br /><br /> - -Your {% site_name %} account is -<strong>scheduled for deletion on {{ deletion_scheduled_date.date }}</strong>. - -<br /><br /> -If you wish to keep your account, please contact us at {{ support_email}} as -soon as possible. - -<br /><br /> +Hello,<br /> +<br /> +The {% site_name %} account registered to <strong>{{ owner_email }}</strong> +is scheduled for deletion on <strong>{{ deletion_scheduled_date.date }}</strong>.<br /> +<br /> +Account details:<br /> +Owner: <strong>{{ owner_email }}</strong><br /> +Number of checks in the account: <strong>{{ num_checks }}</strong><br /> +<br /> +To prevent deletion, please contact us at {{ support_email}} as soon as possible.<br /> +<br /> Sincerely,<br /> The {% site_name %} Team {% endblock %} diff --git a/templates/emails/deletion-scheduled-body-text.html b/templates/emails/deletion-scheduled-body-text.html index 0536893c..688f7cd6 100644 --- a/templates/emails/deletion-scheduled-body-text.html +++ b/templates/emails/deletion-scheduled-body-text.html @@ -1,10 +1,14 @@ {% load hc_extras %} Hello, -Your {% site_name %} account is scheduled for deletion on {{ deletion_scheduled_date.date }}. +The {% site_name %} account registered to {{ owner_email }} is scheduled for deletion +on {{ deletion_scheduled_date.date }}. -If you wish to keep your account, please contact us at {{ support_email}} as -soon as possible. +Account details: +Owner: {{ owner_email }} +Number of checks in the account: {{ num_checks }} + +To prevent deletion, please contact us at {{ support_email}} as soon as possible. -- Sincerely,