mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-11 15:51:19 +00:00
Update senddeletionscheduled to also notify over configured channels
This commit is contained in:
parent
a7395115db
commit
455dc66ce2
2 changed files with 81 additions and 1 deletions
hc/accounts
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from datetime import timedelta as td
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
@ -8,6 +9,7 @@ from django.core.management.base import BaseCommand
|
|||
from django.utils.timezone import now
|
||||
|
||||
from hc.accounts.models import Profile
|
||||
from hc.api.models import Channel, Check
|
||||
from hc.lib import emails
|
||||
|
||||
|
||||
|
@ -22,6 +24,38 @@ class Command(BaseCommand):
|
|||
q = q.exclude(last_login=None)
|
||||
return q.order_by("email")
|
||||
|
||||
def send_channel_notifications(self, profile, skip_emails):
|
||||
# Sending deletion notices to configured notification channels is
|
||||
# a last ditch effort: only do this if 14 or fewer days are left.
|
||||
delta = profile.deletion_scheduled_date - now()
|
||||
if delta.days > 14:
|
||||
return
|
||||
|
||||
formatted = profile.deletion_scheduled_date.strftime("%B %-d, %Y")
|
||||
name = f"{settings.SITE_NAME} Account Deletion on {formatted}"
|
||||
desc = (
|
||||
f"The {settings.SITE_NAME} account registered to {profile.user.email} "
|
||||
f"is scheduled for deletion on {formatted}. To keep the account, "
|
||||
f"please contact {settings.SUPPORT_EMAIL} ASAP."
|
||||
)
|
||||
for channel in Channel.objects.filter(project__owner_id=profile.user_id):
|
||||
if channel.kind == "email" and channel.email_value in skip_emails:
|
||||
continue
|
||||
|
||||
dummy = Check(name=name, desc=desc, status="down", project=channel.project)
|
||||
dummy.last_ping = now() - td(days=1)
|
||||
dummy.n_pings = 1
|
||||
|
||||
self.stdout.write(f" * Sending notification to {channel.kind}")
|
||||
error = channel.notify(dummy, is_test=True)
|
||||
if error == "no-op":
|
||||
# This channel may be configured to send "up" notifications only.
|
||||
dummy.status = "up"
|
||||
error = channel.notify(dummy, is_test=True)
|
||||
|
||||
if error:
|
||||
self.stdout.write(f" Error sending notification: {error}")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
q = Profile.objects.order_by("id")
|
||||
q = q.filter(deletion_scheduled_date__gt=now())
|
||||
|
@ -42,6 +76,7 @@ class Command(BaseCommand):
|
|||
"deletion_scheduled_date": profile.deletion_scheduled_date,
|
||||
}
|
||||
emails.deletion_scheduled(recipients, ctx)
|
||||
self.send_channel_notifications(profile, skip_emails=recipients)
|
||||
sent += 1
|
||||
|
||||
# Throttle so we don't send too many emails at once:
|
||||
|
|
|
@ -5,11 +5,12 @@ from datetime import timedelta as td
|
|||
from unittest.mock import Mock
|
||||
|
||||
from django.core import mail
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.timezone import now
|
||||
|
||||
from hc.accounts.management.commands.senddeletionscheduled import Command
|
||||
from hc.accounts.models import Member, Project
|
||||
from hc.api.models import Check
|
||||
from hc.api.models import Channel, Check
|
||||
from hc.test import BaseTestCase
|
||||
|
||||
|
||||
|
@ -18,7 +19,16 @@ def counts(result):
|
|||
return [int(s) for s in re.findall(r"\d+", result)]
|
||||
|
||||
|
||||
@override_settings(SITE_NAME="Mychecks")
|
||||
class SendDeletionScheduledTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.channel = Channel(project=self.project, kind="email")
|
||||
self.channel.value = "alerts@example.org"
|
||||
self.channel.email_verified = True
|
||||
self.channel.save()
|
||||
|
||||
def test_it_sends_notice(self):
|
||||
self.profile.deletion_scheduled_date = now() + td(days=31)
|
||||
self.profile.save()
|
||||
|
@ -90,3 +100,38 @@ class SendDeletionScheduledTestCase(BaseTestCase):
|
|||
cmd.handle()
|
||||
# Bob should be listed as a recipient a single time, despite two memberships:
|
||||
self.assertEqual(mail.outbox[0].to, ["alice@example.org", "bob@example.org"])
|
||||
|
||||
def test_it_notifies_channel(self):
|
||||
self.profile.deletion_scheduled_date = now() + td(days=5)
|
||||
self.profile.save()
|
||||
|
||||
cmd = Command(stdout=Mock())
|
||||
cmd.pause = Mock() # don't pause for 1s
|
||||
cmd.handle()
|
||||
|
||||
self.assertEqual(mail.outbox[0].subject, "Account Deletion Warning")
|
||||
s = "DOWN | Mychecks Account Deletion"
|
||||
self.assertTrue(mail.outbox[1].subject.startswith(s))
|
||||
|
||||
def test_it_does_not_notify_channels_if_more_than_14_days_left(self):
|
||||
self.profile.deletion_scheduled_date = now() + td(days=15, minutes=1)
|
||||
self.profile.save()
|
||||
|
||||
cmd = Command(stdout=Mock())
|
||||
cmd.pause = Mock() # don't pause for 1s
|
||||
cmd.handle()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
|
||||
def test_it_skips_email_channels_of_team_members(self):
|
||||
self.profile.deletion_scheduled_date = now() + td(days=5)
|
||||
self.profile.save()
|
||||
|
||||
self.channel.value = "alice@example.org"
|
||||
self.channel.save()
|
||||
|
||||
cmd = Command(stdout=Mock())
|
||||
cmd.pause = Mock() # don't pause for 1s
|
||||
cmd.handle()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
|
|
Loading…
Add table
Reference in a new issue