0
0
Fork 0
mirror of https://github.com/healthchecks/healthchecks.git synced 2025-04-11 15:51:19 +00:00

Add Channel.email property

It replaces:

* Channel.email_value
* Channel.email_notify_up
* Channel.email_notify_down
This commit is contained in:
Pēteris Caune 2023-09-11 11:45:25 +03:00
parent ccc8faa953
commit dcf9f327f6
No known key found for this signature in database
GPG key ID: E28D7679E9A9EDE2
9 changed files with 45 additions and 49 deletions

View file

@ -39,7 +39,7 @@ class Command(BaseCommand):
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:
if channel.kind == "email" and channel.email.value in skip_emails:
continue
dummy = Check(name=name, desc=desc, status="down", project=channel.project)

View file

@ -219,7 +219,7 @@ class ChannelsAdmin(admin.ModelAdmin):
def project_(self, obj):
url = self.view_on_site(obj)
name = escape(obj.project_name or "Default")
email = escape(obj.email)
email = escape(obj.owner_email)
return f"{email} &rsaquo; <a href='{url}'>{name}</a>"
def time(self, obj):
@ -230,7 +230,7 @@ class ChannelsAdmin(admin.ModelAdmin):
qs = super().get_queryset(request)
qs = qs.annotate(project_code=F("project__code"))
qs = qs.annotate(project_name=F("project__name"))
qs = qs.annotate(email=F("project__owner__email"))
qs = qs.annotate(owner_email=F("project__owner__email"))
return qs
def view_on_site(self, obj):

View file

@ -727,6 +727,20 @@ class PhoneConf(BaseModel):
notify_down: bool | None = Field(None, alias="down")
class EmailConf(BaseModel):
value: str
notify_up: bool = Field(alias="up")
notify_down: bool = Field(alias="down")
@classmethod
def load(cls, data: Any) -> EmailConf:
# Is it a plain email address?
if not data.startswith("{"):
return cls.model_validate({"value": data, "up": True, "down": True})
return super().model_validate_json(data)
class Channel(models.Model):
name = models.CharField(max_length=100, blank=True)
code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
@ -745,7 +759,7 @@ class Channel(models.Model):
if self.name:
return self.name
if self.kind == "email":
return "Email to %s" % self.email_value
return "Email to %s" % self.email.value
elif self.kind == "sms":
return "SMS to %s" % self.phone.value
elif self.kind == "slack":
@ -779,7 +793,7 @@ class Channel(models.Model):
args = [self.code, self.make_token()]
verify_link = reverse("hc-verify-email", args=args)
verify_link = settings.SITE_ROOT + verify_link
emails.verify_email(self.email_value, {"verify_link": verify_link})
emails.verify_email(self.email.value, {"verify_link": verify_link})
def get_unsub_link(self) -> str:
signer = TimestampSigner(salt="alerts")
@ -977,28 +991,8 @@ class Channel(models.Model):
return doc["board_name"], doc["list_name"]
@property
def email_value(self) -> str:
assert self.kind == "email"
if not self.value.startswith("{"):
return self.value
return self.json["value"]
@property
def email_notify_up(self) -> bool:
assert self.kind == "email"
if not self.value.startswith("{"):
return True
return self.json.get("up")
@property
def email_notify_down(self) -> bool:
assert self.kind == "email"
if not self.value.startswith("{"):
return True
return self.json.get("down")
def email(self) -> EmailConf:
return EmailConf.load(self.value)
@property
def opsgenie_key(self) -> str:

View file

@ -25,7 +25,9 @@ class FlipModelTestCase(BaseTestCase):
self.assertEqual(channels, [self.channel])
def test_select_channels_handles_noop(self) -> None:
self.channel.value = json.dumps({"down": False})
self.channel.value = json.dumps(
{"value": "alice@example.org", "up": False, "down": False}
)
self.channel.save()
channels = self.flip.select_channels()

View file

@ -155,7 +155,7 @@ class Email(Transport):
# If this email address has an associated account, include
# a summary of projects the account has access to
try:
profile = Profile.objects.get(user__email=self.channel.email_value)
profile = Profile.objects.get(user__email=self.channel.email.value)
projects = list(profile.projects())
except Profile.DoesNotExist:
projects = None
@ -170,13 +170,13 @@ class Email(Transport):
"unsub_link": unsub_link,
}
emails.alert(self.channel.email_value, ctx, headers)
emails.alert(self.channel.email.value, ctx, headers)
def is_noop(self, check: Check) -> bool:
if check.status == "down":
return not self.channel.email_notify_down
return not self.channel.email.notify_down
else:
return not self.channel.email_notify_up
return not self.channel.email.notify_up
class Shell(Transport):

View file

@ -39,9 +39,9 @@ class EditEmailTestCase(BaseTestCase):
self.assertRedirects(r, self.channels_url)
self.channel.refresh_from_db()
self.assertEqual(self.channel.email_value, "new@example.org")
self.assertTrue(self.channel.email_notify_down)
self.assertFalse(self.channel.email_notify_up)
self.assertEqual(self.channel.email.value, "new@example.org")
self.assertTrue(self.channel.email.notify_down)
self.assertFalse(self.channel.email.notify_up)
# It should send a verification link
email = mail.outbox[0]
@ -58,9 +58,9 @@ class EditEmailTestCase(BaseTestCase):
self.client.post(self.url, form)
self.channel.refresh_from_db()
self.assertEqual(self.channel.email_value, "alerts@example.org")
self.assertFalse(self.channel.email_notify_down)
self.assertTrue(self.channel.email_notify_up)
self.assertEqual(self.channel.email.value, "alerts@example.org")
self.assertFalse(self.channel.email.notify_down)
self.assertTrue(self.channel.email.notify_up)
self.assertTrue(self.channel.email_verified)
# The email address did not change, so we should skip verification
@ -73,7 +73,7 @@ class EditEmailTestCase(BaseTestCase):
self.client.post(self.url, form)
self.channel.refresh_from_db()
self.assertEqual(self.channel.email_value, "new@example.org")
self.assertEqual(self.channel.email.value, "new@example.org")
@override_settings(EMAIL_USE_VERIFICATION=False)
def test_it_hides_confirmation_needed_notice(self) -> None:
@ -90,7 +90,7 @@ class EditEmailTestCase(BaseTestCase):
self.assertRedirects(r, self.channels_url)
self.channel.refresh_from_db()
self.assertEqual(self.channel.email_value, "dan@example.org")
self.assertEqual(self.channel.email.value, "dan@example.org")
# Email should *not* have been sent
self.assertEqual(len(mail.outbox), 0)
@ -103,7 +103,7 @@ class EditEmailTestCase(BaseTestCase):
self.assertRedirects(r, self.channels_url)
self.channel.refresh_from_db()
self.assertEqual(self.channel.email_value, "alice@example.org")
self.assertEqual(self.channel.email.value, "alice@example.org")
# Email should *not* have been sent
self.assertEqual(len(mail.outbox), 0)

View file

@ -1255,7 +1255,7 @@ def email_form(request: HttpRequest, channel: Channel) -> HttpResponse:
if request.method == "POST":
form = forms.EmailForm(request.POST)
if form.is_valid():
if channel.disabled or form.cleaned_data["value"] != channel.email_value:
if channel.disabled or form.cleaned_data["value"] != channel.email.value:
channel.disabled = False
if not settings.EMAIL_USE_VERIFICATION:
@ -1284,9 +1284,9 @@ def email_form(request: HttpRequest, channel: Channel) -> HttpResponse:
else:
form = forms.EmailForm(
{
"value": channel.email_value,
"up": channel.email_notify_up,
"down": channel.email_notify_down,
"value": channel.email.value,
"up": channel.email.notify_up,
"down": channel.email.notify_down,
}
)

View file

@ -39,11 +39,11 @@
{% endif %}
<div class="channel-details-mini">
{% if ch.kind == "email" %}
Email to <span>{{ ch.email_value }}</span>
{% if ch.email_notify_down and not ch.email_notify_up %}
Email to <span>{{ ch.email.value }}</span>
{% if ch.email.notify_down and not ch.email.notify_up %}
(down only)
{% endif %}
{% if ch.email_notify_up and not ch.email_notify_down %}
{% if ch.email.notify_up and not ch.email.notify_down %}
(up only)
{% endif %}
{% elif ch.kind == "pd" %}

View file

@ -1,5 +1,5 @@
{% if event.channel.kind == "email" %}
Sent email to {{ event.channel.email_value }}
Sent email to {{ event.channel.email.value }}
{% elif event.channel.kind == "slack" %}
Sent Slack alert
{% if event.channel.slack_channel %}