@ -329,58 +329,6 @@ class NotifyTestCase(BaseTestCase): | |||||
"get", "http://foo.com", headers=headers, timeout=5 | "get", "http://foo.com", headers=headers, timeout=5 | ||||
) | ) | ||||
def test_email(self): | |||||
self._setup_data("email", "[email protected]") | |||||
self.channel.notify(self.check) | |||||
n = Notification.objects.get() | |||||
self.assertEqual(n.error, "") | |||||
# And email should have been sent | |||||
self.assertEqual(len(mail.outbox), 1) | |||||
email = mail.outbox[0] | |||||
self.assertEqual(email.to[0], "[email protected]") | |||||
self.assertTrue("X-Status-Url" in email.extra_headers) | |||||
self.assertTrue("List-Unsubscribe" in email.extra_headers) | |||||
self.assertTrue("List-Unsubscribe-Post" in email.extra_headers) | |||||
def test_email_transport_handles_json_value(self): | |||||
payload = {"value": "[email protected]", "up": True, "down": True} | |||||
self._setup_data("email", json.dumps(payload)) | |||||
self.channel.notify(self.check) | |||||
# And email should have been sent | |||||
self.assertEqual(len(mail.outbox), 1) | |||||
email = mail.outbox[0] | |||||
self.assertEqual(email.to[0], "[email protected]") | |||||
def test_it_reports_unverified_email(self): | |||||
self._setup_data("email", "[email protected]", email_verified=False) | |||||
self.channel.notify(self.check) | |||||
# If an email is not verified, it should say so in the notification: | |||||
n = Notification.objects.get() | |||||
self.assertEqual(n.error, "Email not verified") | |||||
def test_email_checks_up_down_flags(self): | |||||
payload = {"value": "[email protected]", "up": True, "down": False} | |||||
self._setup_data("email", json.dumps(payload)) | |||||
self.channel.notify(self.check) | |||||
# This channel should not notify on "down" events: | |||||
self.assertEqual(Notification.objects.count(), 0) | |||||
self.assertEqual(len(mail.outbox), 0) | |||||
def test_email_handles_amperstand(self): | |||||
self._setup_data("email", "[email protected]") | |||||
self.check.name = "Foo & Bar" | |||||
self.channel.notify(self.check) | |||||
email = mail.outbox[0] | |||||
self.assertEqual(email.subject, "DOWN | Foo & Bar") | |||||
@patch("hc.api.transports.requests.request") | @patch("hc.api.transports.requests.request") | ||||
def test_pd(self, mock_post): | def test_pd(self, mock_post): | ||||
self._setup_data("pd", "123") | self._setup_data("pd", "123") | ||||
@ -0,0 +1,151 @@ | |||||
# coding: utf-8 | |||||
from datetime import timedelta as td | |||||
import json | |||||
from django.core import mail | |||||
from django.utils.timezone import now | |||||
from hc.api.models import Channel, Check, Notification, Ping | |||||
from hc.test import BaseTestCase | |||||
class NotifyTestCase(BaseTestCase): | |||||
def setUp(self): | |||||
super().setUp() | |||||
self.check = Check(project=self.project) | |||||
self.check.name = "Daily Backup" | |||||
self.check.desc = "Line 1\nLine2" | |||||
self.check.tags = "foo bar" | |||||
self.check.status = "down" | |||||
self.check.last_ping = now() - td(minutes=61) | |||||
self.check.n_pings = 112233 | |||||
self.check.save() | |||||
self.ping = Ping(owner=self.check) | |||||
self.ping.remote_addr = "1.2.3.4" | |||||
self.ping.body = "Body Line 1\nBody Line 2" | |||||
self.ping.save() | |||||
self.channel = Channel(project=self.project) | |||||
self.channel.kind = "email" | |||||
self.channel.value = "[email protected]" | |||||
self.channel.email_verified = True | |||||
self.channel.save() | |||||
self.channel.checks.add(self.check) | |||||
def test_email(self): | |||||
self.channel.notify(self.check) | |||||
n = Notification.objects.get() | |||||
self.assertEqual(n.error, "") | |||||
# And email should have been sent | |||||
self.assertEqual(len(mail.outbox), 1) | |||||
email = mail.outbox[0] | |||||
self.assertEqual(email.to[0], "[email protected]") | |||||
self.assertTrue("X-Status-Url" in email.extra_headers) | |||||
self.assertTrue("List-Unsubscribe" in email.extra_headers) | |||||
self.assertTrue("List-Unsubscribe-Post" in email.extra_headers) | |||||
html = email.alternatives[0][0] | |||||
self.assertIn("Daily Backup", html) | |||||
self.assertIn("Line 1<br>Line2", html) | |||||
self.assertIn("Alices Project", html) | |||||
self.assertIn("foo</code>", html) | |||||
self.assertIn("bar</code>", html) | |||||
self.assertIn("1 day", html) | |||||
self.assertIn("from 1.2.3.4", html) | |||||
self.assertIn("112233", html) | |||||
self.assertIn("Body Line 1<br>Body Line 2", html) | |||||
def test_it_shows_cron_schedule(self): | |||||
self.check.kind = "cron" | |||||
self.check.schedule = "0 18-23,0-8 * * *" | |||||
self.check.save() | |||||
self.channel.notify(self.check) | |||||
email = mail.outbox[0] | |||||
html = email.alternatives[0][0] | |||||
self.assertIn("<code>0 18-23,0-8 * * *</code>", html) | |||||
def test_it_truncates_long_body(self): | |||||
self.ping.body = "X" * 10000 + ", and the rest gets cut off" | |||||
self.ping.save() | |||||
self.channel.notify(self.check) | |||||
email = mail.outbox[0] | |||||
html = email.alternatives[0][0] | |||||
self.assertIn("[truncated]", html) | |||||
self.assertNotIn("the rest gets cut off", html) | |||||
def test_it_handles_missing_ping_object(self): | |||||
self.ping.delete() | |||||
self.channel.notify(self.check) | |||||
email = mail.outbox[0] | |||||
html = email.alternatives[0][0] | |||||
self.assertIn("Daily Backup", html) | |||||
def test_it_handles_missing_profile(self): | |||||
self.channel.value = "[email protected]" | |||||
self.channel.save() | |||||
self.channel.notify(self.check) | |||||
email = mail.outbox[0] | |||||
self.assertEqual(email.to[0], "[email protected]") | |||||
html = email.alternatives[0][0] | |||||
self.assertIn("Daily Backup", html) | |||||
self.assertNotIn("Projects Overview", html) | |||||
def test_email_transport_handles_json_value(self): | |||||
payload = {"value": "[email protected]", "up": True, "down": True} | |||||
self.channel.value = json.dumps(payload) | |||||
self.channel.save() | |||||
self.channel.notify(self.check) | |||||
# And email should have been sent | |||||
self.assertEqual(len(mail.outbox), 1) | |||||
email = mail.outbox[0] | |||||
self.assertEqual(email.to[0], "[email protected]") | |||||
def test_it_reports_unverified_email(self): | |||||
self.channel.email_verified = False | |||||
self.channel.save() | |||||
self.channel.notify(self.check) | |||||
# If an email is not verified, it should say so in the notification: | |||||
n = Notification.objects.get() | |||||
self.assertEqual(n.error, "Email not verified") | |||||
def test_email_checks_up_down_flags(self): | |||||
payload = {"value": "[email protected]", "up": True, "down": False} | |||||
self.channel.value = json.dumps(payload) | |||||
self.channel.save() | |||||
self.channel.notify(self.check) | |||||
# This channel should not notify on "down" events: | |||||
self.assertEqual(Notification.objects.count(), 0) | |||||
self.assertEqual(len(mail.outbox), 0) | |||||
def test_email_handles_amperstand(self): | |||||
self.check.name = "Foo & Bar" | |||||
self.check.save() | |||||
self.channel.notify(self.check) | |||||
email = mail.outbox[0] | |||||
self.assertEqual(email.subject, "DOWN | Foo & Bar") |
@ -1,32 +1,108 @@ | |||||
{% extends "emails/base.html" %} | |||||
{% load hc_extras %} | |||||
{% block content %} | |||||
The check <a href="{{ check.details_url }}">{{ check.name_then_code|mangle_link }}</a> | |||||
has gone <strong>{{ check.status|upper }}</strong>. | |||||
<br> | |||||
{% if check.status == "down" and check.desc %} | |||||
Additional notes:<br><br> | |||||
<div style="padding: 10px 15px; background: #F2F4F6;"> | |||||
{{ check.desc|linebreaksbr|urlize }} | |||||
</div> | |||||
{% load hc_extras humanize %} | |||||
<p> | |||||
"{{ check.name_then_code }}" is {{ check.status|upper }}. | |||||
<a href="{{ check.details_url }}">View on {% site_name %}…</a> | |||||
</p> | |||||
{% if check.desc %} | |||||
<p> | |||||
<b>Description</b><br> | |||||
{{ check.desc|linebreaksbr }} | |||||
</p> | |||||
{% endif %} | {% endif %} | ||||
<br /> | |||||
A summary of your checks: | |||||
<br /> | |||||
{% cycle '' '</tr><tr>' as trtr silent %} | |||||
<table> | |||||
<tr> | |||||
{% if check.project.name %} | |||||
<td style="padding-right: 32px; padding-bottom: 8px; vertical-align: top;"> | |||||
<b>Project</b><br> | |||||
{{ check.project.name }} | |||||
</td> | |||||
{{ trtr|safe }} {% cycle trtr %} | |||||
{% endif %} | |||||
{% if check.tags_list %} | |||||
<td style="padding-right: 32px; padding-bottom: 8px; vertical-align: top;"> | |||||
<b>Tags</b><br> | |||||
{% for tag in check.tags_list %} | |||||
<code style="background-color: #eeeeee; padding: 2px 4px; border-radius: 2px;">{{ tag }}</code> | |||||
{% endfor %} | |||||
</td> | |||||
{{ trtr|safe }} {% cycle trtr %} | |||||
{% endif %} | |||||
{% if check.kind == "simple" %} | |||||
<td style="padding-right: 32px; padding-bottom: 8px; vertical-align: top;"> | |||||
<b>Period</b><br> | |||||
{{ check.timeout|hc_duration }} | |||||
</td> | |||||
{{ trtr|safe }} {% cycle trtr %} | |||||
{% endif %} | |||||
{% include "emails/summary-html.html" %} | |||||
{% if check.kind == "cron" %} | |||||
<td style="padding-right: 32px; padding-bottom: 8px; vertical-align: top;"> | |||||
<b>Schedule</b><br> | |||||
<code>{{ check.schedule }}</code> | |||||
</td> | |||||
{% if trttr %}Yo!{% endif %} | |||||
{{ trtr|safe }} {% cycle trtr %} | |||||
{% endif %} | |||||
Thanks,<br> | |||||
The {% site_name %} Team | |||||
{% if ping %} | |||||
<td style="padding-right: 32px; padding-bottom: 8px; vertical-align: top;"> | |||||
<b>Last Ping</b><br> | |||||
{{ ping.created|naturaltime }}{% if ping.remote_addr %}, from {{ ping.remote_addr }}{% endif %} | |||||
</td> | |||||
{% if trttr %}Yo!{% endif %} | |||||
{{ trtr|safe }} {% cycle trtr %} | |||||
{% endif %} | |||||
{% endblock %} | |||||
<td style="padding-right: 32px; padding-bottom: 8px; vertical-align: top;"> | |||||
<b>Total Pings</b><br> | |||||
{{ check.n_pings }} | |||||
{% if check.created %}(since {{ check.created|date:'M j, Y' }}){% endif %} | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
{% if ping.body %} | |||||
<p><b>Last Ping Body</b></p> | |||||
<pre style="background: #eeeeee">{{ ping.body|slice:":10000"|linebreaksbr }}{% if ping.body|length > 10000 %} [truncated]{% endif %}</pre> | |||||
{% endif %} | |||||
{% if projects %} | |||||
<p><b>Projects Overview</b></p> | |||||
<table> | |||||
{% for project in projects %} | |||||
<tr> | |||||
<td style="padding-right: 32px; padding-bottom: 4px;"> | |||||
<a href="{{ project.checks_url }}">{{ project }}</a> | |||||
</td> | |||||
<td style="padding-right: 32px; padding-bottom: 4px;"> | |||||
{% with project.get_n_down as n_down %} | |||||
{% if n_down %} | |||||
<b>{{ n_down }} check{{ n_down|pluralize }} down</b> | |||||
{% else %} | |||||
OK, all checks up | |||||
{% endif %} | |||||
{% endwith %} | |||||
</td> | |||||
</tr> | |||||
{% endfor %} | |||||
</table> | |||||
{% endif %} | |||||
{% block unsub %} | |||||
<br> | |||||
<p style="color: #666666"> | |||||
—<br> | |||||
{% site_name %}<br> | |||||
<a href="{{ unsub_link }}" target="_blank" style="color: #666666; text-decoration: underline;"> | <a href="{{ unsub_link }}" target="_blank" style="color: #666666; text-decoration: underline;"> | ||||
{% if check.project.name %} | |||||
Unsubscribe from "{{ check.project.name }}" notifications | |||||
{% else %} | |||||
Unsubscribe | Unsubscribe | ||||
{% endif %} | |||||
</a> | </a> | ||||
{% endblock %} | |||||
</p> |