@ -244,9 +244,21 @@ class NotifyTestCase(BaseTestCase): | |||
self.assertEqual(len(mail.outbox), 1) | |||
email = mail.outbox[0] | |||
self.assertEqual(email.to[0], "[email protected]") | |||
self.assertTrue("X-Bounce-Url" in email.extra_headers) | |||
self.assertTrue("List-Unsubscribe" 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_skips_unverified_email(self): | |||
self._setup_data("email", "[email protected]", email_verified=False) | |||
self.channel.notify(self.check) | |||
@ -256,6 +268,15 @@ class NotifyTestCase(BaseTestCase): | |||
self.assertEqual(Notification.objects.count(), 0) | |||
self.assertEqual(len(mail.outbox), 0) | |||
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) | |||
@patch("hc.api.transports.requests.request") | |||
def test_pd(self, mock_post): | |||
self._setup_data("pd", "123") | |||
@ -1,3 +1,5 @@ | |||
import json | |||
from django.core import mail | |||
from django.test.utils import override_settings | |||
@ -12,7 +14,7 @@ class AddEmailTestCase(BaseTestCase): | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(self.url) | |||
self.assertContains(r, "Get an email message") | |||
self.assertContains(r, "Confirmation needed") | |||
self.assertContains(r, "Requires confirmation") | |||
def test_it_creates_channel(self): | |||
form = {"value": "[email protected]"} | |||
@ -22,8 +24,9 @@ class AddEmailTestCase(BaseTestCase): | |||
self.assertRedirects(r, "/integrations/") | |||
c = Channel.objects.get() | |||
doc = json.loads(c.value) | |||
self.assertEqual(c.kind, "email") | |||
self.assertEqual(c.value, "[email protected]") | |||
self.assertEqual(doc["value"], "[email protected]") | |||
self.assertFalse(c.email_verified) | |||
self.assertEqual(c.project, self.project) | |||
@ -32,6 +35,8 @@ class AddEmailTestCase(BaseTestCase): | |||
email = mail.outbox[0] | |||
self.assertTrue(email.subject.startswith("Verify email address on")) | |||
# Make sure we're sending to an email address, not a JSON string: | |||
self.assertEqual(email.to[0], "[email protected]") | |||
def test_team_access_works(self): | |||
form = {"value": "[email protected]"} | |||
@ -57,13 +62,14 @@ class AddEmailTestCase(BaseTestCase): | |||
self.client.post(self.url, form) | |||
c = Channel.objects.get() | |||
self.assertEqual(c.value, "[email protected]") | |||
doc = json.loads(c.value) | |||
self.assertEqual(doc["value"], "[email protected]") | |||
@override_settings(EMAIL_USE_VERIFICATION=False) | |||
def test_it_hides_confirmation_needed_notice(self): | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(self.url) | |||
self.assertNotContains(r, "Confirmation needed") | |||
self.assertNotContains(r, "Requires confirmation") | |||
@override_settings(EMAIL_USE_VERIFICATION=False) | |||
def test_it_auto_verifies_email(self): | |||
@ -74,8 +80,9 @@ class AddEmailTestCase(BaseTestCase): | |||
self.assertRedirects(r, "/integrations/") | |||
c = Channel.objects.get() | |||
doc = json.loads(c.value) | |||
self.assertEqual(c.kind, "email") | |||
self.assertEqual(c.value, "[email protected]") | |||
self.assertEqual(doc["value"], "[email protected]") | |||
self.assertTrue(c.email_verified) | |||
# Email should *not* have been sent | |||
@ -74,6 +74,34 @@ class ChannelsTestCase(BaseTestCase): | |||
self.assertEqual(r.status_code, 200) | |||
self.assertContains(r, "Unconfirmed") | |||
def test_it_shows_down_only_note_for_email(self): | |||
channel = Channel(project=self.project, kind="email") | |||
channel.value = json.dumps({ | |||
"value": "[email protected]", | |||
"up": False, | |||
"down": True | |||
}) | |||
channel.save() | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get("/integrations/") | |||
self.assertEqual(r.status_code, 200) | |||
self.assertContains(r, "(down only)") | |||
def test_it_shows_up_only_note_for_email(self): | |||
channel = Channel(project=self.project, kind="email") | |||
channel.value = json.dumps({ | |||
"value": "[email protected]", | |||
"up": True, | |||
"down": False | |||
}) | |||
channel.save() | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get("/integrations/") | |||
self.assertEqual(r.status_code, 200) | |||
self.assertContains(r, "(up only)") | |||
def test_it_shows_sms_label(self): | |||
ch = Channel(kind="sms", project=self.project) | |||
ch.value = json.dumps({"value": "+123", "label": "My Phone"}) | |||
@ -1,3 +1,5 @@ | |||
import json | |||
from hc.api.models import Channel, Check, Notification, Ping | |||
from hc.test import BaseTestCase | |||
@ -15,20 +17,20 @@ class LogTestCase(BaseTestCase): | |||
ping.created = "2000-01-01T00:00:00+00:00" | |||
ping.save() | |||
self.url = "/checks/%s/log/" % self.check.code | |||
def test_it_works(self): | |||
url = "/checks/%s/log/" % self.check.code | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(url) | |||
r = self.client.get(self.url) | |||
self.assertContains(r, "Local Time", status_code=200) | |||
def test_team_access_works(self): | |||
url = "/checks/%s/log/" % self.check.code | |||
# Logging in as bob, not alice. Bob has team access so this | |||
# should work. | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(url) | |||
r = self.client.get(self.url) | |||
self.assertEqual(r.status_code, 200) | |||
def test_it_handles_bad_uuid(self): | |||
@ -47,40 +49,50 @@ class LogTestCase(BaseTestCase): | |||
self.assertEqual(r.status_code, 404) | |||
def test_it_checks_ownership(self): | |||
url = "/checks/%s/log/" % self.check.code | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(url) | |||
r = self.client.get(self.url) | |||
self.assertEqual(r.status_code, 404) | |||
def test_it_shows_pushover_notifications(self): | |||
ch = Channel.objects.create(kind="po", project=self.project) | |||
def test_it_shows_email_notification(self): | |||
ch = Channel(kind="email", project=self.project) | |||
ch.value = json.dumps({ | |||
"value": "[email protected]", | |||
"up": True, | |||
"down": True | |||
}) | |||
ch.save() | |||
Notification(owner=self.check, channel=ch, check_status="down").save() | |||
url = "/checks/%s/log/" % self.check.code | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(self.url) | |||
self.assertContains(r, "Sent email alert to [email protected]", | |||
status_code=200) | |||
def test_it_shows_pushover_notification(self): | |||
ch = Channel.objects.create(kind="po", project=self.project) | |||
Notification(owner=self.check, channel=ch, check_status="down").save() | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(url) | |||
r = self.client.get(self.url) | |||
self.assertContains(r, "Sent a Pushover notification", status_code=200) | |||
def test_it_shows_webhook_notifications(self): | |||
def test_it_shows_webhook_notification(self): | |||
ch = Channel(kind="webhook", project=self.project) | |||
ch.value = "foo/$NAME" | |||
ch.save() | |||
Notification(owner=self.check, channel=ch, check_status="down").save() | |||
url = "/checks/%s/log/" % self.check.code | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(url) | |||
r = self.client.get(self.url) | |||
self.assertContains(r, "Called webhook foo/$NAME", status_code=200) | |||
def test_it_allows_cross_team_access(self): | |||
self.bobs_profile.current_project = None | |||
self.bobs_profile.save() | |||
url = "/checks/%s/log/" % self.check.code | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(url) | |||
r = self.client.get(self.url) | |||
self.assertEqual(r.status_code, 200) |
@ -1,26 +1,20 @@ | |||
{% extends "base.html" %} | |||
{% load humanize static hc_extras %} | |||
{% block title %}Notification Channels - {% site_name %}{% endblock %} | |||
{% block title %}Set Up Email Notifications - {% site_name %}{% endblock %} | |||
{% block content %} | |||
<div class="row"> | |||
<div class="col-sm-12"> | |||
<h1>Email</h1> | |||
<p>Get an email message when check goes up or down.</p> | |||
<p> | |||
<strong>Tip:</strong> | |||
Add multiple email addresses, to notify multiple team members. | |||
</p> | |||
{% if use_verification %} | |||
<p> | |||
<strong>Confirmation needed.</strong> | |||
<p class="alert alert-info"> | |||
<strong>Requires confirmation.</strong> | |||
After entering an email address, {% site_name %} will send out a confirmation link. | |||
Only confirmed addresses will receive notifications. | |||
Only confirmed addresses receive notifications. | |||
</p> | |||
{% endif %} | |||
@ -37,6 +31,7 @@ | |||
class="form-control" | |||
name="value" | |||
placeholder="[email protected]" | |||
required | |||
value="{{ form.value.value|default:"" }}"> | |||
{% if form.value.errors %} | |||
@ -46,6 +41,36 @@ | |||
{% endif %} | |||
</div> | |||
</div> | |||
<div id="add-email-notify-group" class="form-group"> | |||
<label class="col-sm-2 control-label">Notify When</label> | |||
<div class="col-sm-10"> | |||
<label class="checkbox-container"> | |||
<input | |||
type="checkbox" | |||
name="down" | |||
value="true" | |||
{% if form.down.value %} checked {% endif %}> | |||
<span class="checkmark"></span> | |||
A check goes <strong>down</strong> | |||
</label> | |||
<label class="checkbox-container"> | |||
<input | |||
type="checkbox" | |||
name="up" | |||
value="true" | |||
{% if form.up.value %} checked {% endif %}> | |||
<span class="checkmark"></span> | |||
A check goes <strong>up</strong> | |||
<br /> | |||
<span class="text-muted"> | |||
Ticketing system integrations: untick this and avoid creating new tickets | |||
when checks come back up. | |||
</span> | |||
</label> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-sm-offset-2 col-sm-10"> | |||
<button type="submit" class="btn btn-primary">Save Integration</button> | |||