Browse Source

Can configure the email integration to only report the "down" events. Fixes #231

pull/241/head
Pēteris Caune 6 years ago
parent
commit
a4fde44e3a
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
18 changed files with 209 additions and 64 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +29
    -2
      hc/api/models.py
  3. +21
    -0
      hc/api/tests/test_notify.py
  4. +9
    -3
      hc/api/transports.py
  5. +2
    -0
      hc/front/forms.py
  6. +12
    -5
      hc/front/tests/test_add_email.py
  7. +28
    -0
      hc/front/tests/test_channels.py
  8. +28
    -16
      hc/front/tests/test_log.py
  9. +5
    -1
      hc/front/views.py
  10. +2
    -2
      static/css/base.css
  11. +5
    -0
      static/css/radio.css
  12. +1
    -1
      templates/accounts/notifications.html
  13. +21
    -21
      templates/base.html
  14. +7
    -1
      templates/front/channels.html
  15. +1
    -1
      templates/front/details_events.html
  16. +1
    -1
      templates/front/log.html
  17. +35
    -10
      templates/integrations/add_email.html
  18. +1
    -0
      templates/integrations/add_pushover.html

+ 1
- 0
CHANGELOG.md View File

@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
- Add the EMAIL_USE_VERIFICATION configuration setting (#232) - Add the EMAIL_USE_VERIFICATION configuration setting (#232)
- Show "Badges" and "Settings" in top navigation (#234) - Show "Badges" and "Settings" in top navigation (#234)
- Upgrade to Django 2.2 - Upgrade to Django 2.2
- Can configure the email integration to only report the "down" events (#231)
## 1.6.0 - 2019-04-01 ## 1.6.0 - 2019-04-01


+ 29
- 2
hc/api/models.py View File

@ -272,7 +272,7 @@ class Channel(models.Model):
if self.name: if self.name:
return self.name return self.name
if self.kind == "email": if self.kind == "email":
return "Email to %s" % self.value
return "Email to %s" % self.email_value
elif self.kind == "sms": elif self.kind == "sms":
return "SMS to %s" % self.sms_number return "SMS to %s" % self.sms_number
elif self.kind == "slack": elif self.kind == "slack":
@ -302,7 +302,7 @@ class Channel(models.Model):
args = [self.code, self.make_token()] args = [self.code, self.make_token()]
verify_link = reverse("hc-verify-email", args=args) verify_link = reverse("hc-verify-email", args=args)
verify_link = settings.SITE_ROOT + verify_link verify_link = settings.SITE_ROOT + verify_link
emails.verify_email(self.value, {"verify_link": verify_link})
emails.verify_email(self.email_value, {"verify_link": verify_link})
def get_unsub_link(self): def get_unsub_link(self):
args = [self.code, self.make_token()] args = [self.code, self.make_token()]
@ -526,6 +526,33 @@ class Channel(models.Model):
doc = json.loads(self.value) doc = json.loads(self.value)
return doc["list_id"] return doc["list_id"]
@property
def email_value(self):
assert self.kind == "email"
if not self.value.startswith("{"):
return self.value
doc = json.loads(self.value)
return doc.get("value")
@property
def email_notify_up(self):
assert self.kind == "email"
if not self.value.startswith("{"):
return True
doc = json.loads(self.value)
return doc.get("up")
@property
def email_notify_down(self):
assert self.kind == "email"
if not self.value.startswith("{"):
return True
doc = json.loads(self.value)
return doc.get("down")
class Notification(models.Model): class Notification(models.Model):
class Meta: class Meta:


+ 21
- 0
hc/api/tests/test_notify.py View File

@ -244,9 +244,21 @@ class NotifyTestCase(BaseTestCase):
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
email = mail.outbox[0] email = mail.outbox[0]
self.assertEqual(email.to[0], "[email protected]")
self.assertTrue("X-Bounce-Url" in email.extra_headers) self.assertTrue("X-Bounce-Url" in email.extra_headers)
self.assertTrue("List-Unsubscribe" 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): def test_it_skips_unverified_email(self):
self._setup_data("email", "[email protected]", email_verified=False) self._setup_data("email", "[email protected]", email_verified=False)
self.channel.notify(self.check) self.channel.notify(self.check)
@ -256,6 +268,15 @@ class NotifyTestCase(BaseTestCase):
self.assertEqual(Notification.objects.count(), 0) self.assertEqual(Notification.objects.count(), 0)
self.assertEqual(len(mail.outbox), 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") @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")


+ 9
- 3
hc/api/transports.py View File

@ -59,7 +59,7 @@ class Email(Transport):
try: try:
# Look up the sorting preference for this email address # Look up the sorting preference for this email address
p = Profile.objects.get(user__email=self.channel.value)
p = Profile.objects.get(user__email=self.channel.email_value)
sort = p.sort sort = p.sort
except Profile.DoesNotExist: except Profile.DoesNotExist:
# Default sort order is by check's creation time # Default sort order is by check's creation time
@ -75,10 +75,16 @@ class Email(Transport):
"unsub_link": unsub_link "unsub_link": unsub_link
} }
emails.alert(self.channel.value, ctx, headers)
emails.alert(self.channel.email_value, ctx, headers)
def is_noop(self, check): def is_noop(self, check):
return not self.channel.email_verified
if not self.channel.email_verified:
return True
if check.status == "down":
return not self.channel.email_notify_down
else:
return not self.channel.email_notify_up
class HttpTransport(Transport): class HttpTransport(Transport):


+ 2
- 0
hc/front/forms.py View File

@ -57,6 +57,8 @@ class AddOpsGenieForm(forms.Form):
class AddEmailForm(forms.Form): class AddEmailForm(forms.Form):
error_css_class = "has-error" error_css_class = "has-error"
value = forms.EmailField(max_length=100) value = forms.EmailField(max_length=100)
down = forms.BooleanField(required=False, initial=True)
up = forms.BooleanField(required=False, initial=True)
class AddUrlForm(forms.Form): class AddUrlForm(forms.Form):


+ 12
- 5
hc/front/tests/test_add_email.py View File

@ -1,3 +1,5 @@
import json
from django.core import mail from django.core import mail
from django.test.utils import override_settings from django.test.utils import override_settings
@ -12,7 +14,7 @@ class AddEmailTestCase(BaseTestCase):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
r = self.client.get(self.url) r = self.client.get(self.url)
self.assertContains(r, "Get an email message") self.assertContains(r, "Get an email message")
self.assertContains(r, "Confirmation needed")
self.assertContains(r, "Requires confirmation")
def test_it_creates_channel(self): def test_it_creates_channel(self):
form = {"value": "[email protected]"} form = {"value": "[email protected]"}
@ -22,8 +24,9 @@ class AddEmailTestCase(BaseTestCase):
self.assertRedirects(r, "/integrations/") self.assertRedirects(r, "/integrations/")
c = Channel.objects.get() c = Channel.objects.get()
doc = json.loads(c.value)
self.assertEqual(c.kind, "email") self.assertEqual(c.kind, "email")
self.assertEqual(c.value, "[email protected]")
self.assertEqual(doc["value"], "[email protected]")
self.assertFalse(c.email_verified) self.assertFalse(c.email_verified)
self.assertEqual(c.project, self.project) self.assertEqual(c.project, self.project)
@ -32,6 +35,8 @@ class AddEmailTestCase(BaseTestCase):
email = mail.outbox[0] email = mail.outbox[0]
self.assertTrue(email.subject.startswith("Verify email address on")) 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): def test_team_access_works(self):
form = {"value": "[email protected]"} form = {"value": "[email protected]"}
@ -57,13 +62,14 @@ class AddEmailTestCase(BaseTestCase):
self.client.post(self.url, form) self.client.post(self.url, form)
c = Channel.objects.get() 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) @override_settings(EMAIL_USE_VERIFICATION=False)
def test_it_hides_confirmation_needed_notice(self): def test_it_hides_confirmation_needed_notice(self):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
r = self.client.get(self.url) r = self.client.get(self.url)
self.assertNotContains(r, "Confirmation needed")
self.assertNotContains(r, "Requires confirmation")
@override_settings(EMAIL_USE_VERIFICATION=False) @override_settings(EMAIL_USE_VERIFICATION=False)
def test_it_auto_verifies_email(self): def test_it_auto_verifies_email(self):
@ -74,8 +80,9 @@ class AddEmailTestCase(BaseTestCase):
self.assertRedirects(r, "/integrations/") self.assertRedirects(r, "/integrations/")
c = Channel.objects.get() c = Channel.objects.get()
doc = json.loads(c.value)
self.assertEqual(c.kind, "email") self.assertEqual(c.kind, "email")
self.assertEqual(c.value, "[email protected]")
self.assertEqual(doc["value"], "[email protected]")
self.assertTrue(c.email_verified) self.assertTrue(c.email_verified)
# Email should *not* have been sent # Email should *not* have been sent


+ 28
- 0
hc/front/tests/test_channels.py View File

@ -74,6 +74,34 @@ class ChannelsTestCase(BaseTestCase):
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r, "Unconfirmed") 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): def test_it_shows_sms_label(self):
ch = Channel(kind="sms", project=self.project) ch = Channel(kind="sms", project=self.project)
ch.value = json.dumps({"value": "+123", "label": "My Phone"}) ch.value = json.dumps({"value": "+123", "label": "My Phone"})


+ 28
- 16
hc/front/tests/test_log.py View File

@ -1,3 +1,5 @@
import json
from hc.api.models import Channel, Check, Notification, Ping from hc.api.models import Channel, Check, Notification, Ping
from hc.test import BaseTestCase from hc.test import BaseTestCase
@ -15,20 +17,20 @@ class LogTestCase(BaseTestCase):
ping.created = "2000-01-01T00:00:00+00:00" ping.created = "2000-01-01T00:00:00+00:00"
ping.save() ping.save()
self.url = "/checks/%s/log/" % self.check.code
def test_it_works(self): def test_it_works(self):
url = "/checks/%s/log/" % self.check.code
self.client.login(username="[email protected]", password="password") 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) self.assertContains(r, "Local Time", status_code=200)
def test_team_access_works(self): 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 # Logging in as bob, not alice. Bob has team access so this
# should work. # should work.
self.client.login(username="[email protected]", password="password") 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) self.assertEqual(r.status_code, 200)
def test_it_handles_bad_uuid(self): def test_it_handles_bad_uuid(self):
@ -47,40 +49,50 @@ class LogTestCase(BaseTestCase):
self.assertEqual(r.status_code, 404) self.assertEqual(r.status_code, 404)
def test_it_checks_ownership(self): def test_it_checks_ownership(self):
url = "/checks/%s/log/" % self.check.code
self.client.login(username="[email protected]", password="password") 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) 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() 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") 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) 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 = Channel(kind="webhook", project=self.project)
ch.value = "foo/$NAME" ch.value = "foo/$NAME"
ch.save() ch.save()
Notification(owner=self.check, channel=ch, check_status="down").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") 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) self.assertContains(r, "Called webhook foo/$NAME", status_code=200)
def test_it_allows_cross_team_access(self): def test_it_allows_cross_team_access(self):
self.bobs_profile.current_project = None self.bobs_profile.current_project = None
self.bobs_profile.save() self.bobs_profile.save()
url = "/checks/%s/log/" % self.check.code
self.client.login(username="[email protected]", password="password") 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) self.assertEqual(r.status_code, 200)

+ 5
- 1
hc/front/views.py View File

@ -678,7 +678,11 @@ def add_email(request):
form = AddEmailForm(request.POST) form = AddEmailForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(project=request.project, kind="email") channel = Channel(project=request.project, kind="email")
channel.value = form.cleaned_data["value"]
channel.value = json.dumps({
"value": form.cleaned_data["value"],
"up": form.cleaned_data["up"],
"down": form.cleaned_data["down"]
})
channel.save() channel.save()
channel.assign_all_checks() channel.assign_all_checks()


+ 2
- 2
static/css/base.css View File

@ -77,13 +77,13 @@ body {
.status.icon-grace { color: #f0ad4e; } .status.icon-grace { color: #f0ad4e; }
.status.icon-down { color: #d9534f; } .status.icon-down { color: #d9534f; }
.label-start {
.label.label-start {
background-color: #FFF; background-color: #FFF;
color: #117a3f;; color: #117a3f;;
border: 1px solid #117a3f; border: 1px solid #117a3f;
} }
.label-ign {
.label.label-ign {
background: #e0e0e0; background: #e0e0e0;
color: #333; color: #333;
} }


+ 5
- 0
static/css/radio.css View File

@ -13,6 +13,11 @@
font-weight: normal; font-weight: normal;
} }
.form-horizontal .radio-container, .form-horizontal .checkbox-container {
margin-top: 7px;
margin-left: 0;
}
/* Hide the browser's default radio button */ /* Hide the browser's default radio button */
.radio-container input { .radio-container input {
position: absolute; position: absolute;


+ 1
- 1
templates/accounts/notifications.html View File

@ -73,7 +73,7 @@
</label> </label>
<br /> <br />
<p style="color: #888">
<p class="text-muted">
Reports will be delivered to {{ profile.user.email }}. <br /> Reports will be delivered to {{ profile.user.email }}. <br />
{% if profile.next_report_date %} {% if profile.next_report_date %}
Next monthly report date is Next monthly report date is


+ 21
- 21
templates/base.html View File

@ -16,35 +16,35 @@
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'img/apple-touch-180.png' %}"> <link rel="apple-touch-icon" sizes="180x180" href="{% static 'img/apple-touch-180.png' %}">
{% compress css %} {% compress css %}
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/icomoon.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/nouislider.min.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/nouislider.pips.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/bootstrap-select.min.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/snippet-copy.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_project_modal.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_pushover.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_webhook.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/base.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/base.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/billing.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/bootstrap-select.min.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/channel_checks.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/channels.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/checkbox.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/details.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/docs.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/docs.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/docs_cron.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/docs_cron.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/welcome.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/icomoon.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/log.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/login.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/my_checks.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/my_checks.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/my_checks_desktop.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/my_checks_desktop.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/pricing.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/syntax.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/channels.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/channel_checks.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/details.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/log.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_pushover.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_webhook.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/settings.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/nouislider.min.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/nouislider.pips.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/ping_details.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/ping_details.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/pricing.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/profile.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/profile.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/checkbox.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/radio.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/billing.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/login.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/projects.css' %}" type="text/css"> <link rel="stylesheet" href="{% static 'css/projects.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/add_project_modal.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/radio.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/settings.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/snippet-copy.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/syntax.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/welcome.css' %}" type="text/css">
{% endcompress %} {% endcompress %}
</head> </head>
<body class="page-{{ page }}"> <body class="page-{{ page }}">


+ 7
- 1
templates/front/channels.html View File

@ -42,7 +42,13 @@
{% endif %} {% endif %}
<div class="channel-details-mini"> <div class="channel-details-mini">
{% if ch.kind == "email" %} {% if ch.kind == "email" %}
Email to <span>{{ ch.value }}</span>
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 %}
(up only)
{% endif %}
{% elif ch.kind == "pd" %} {% elif ch.kind == "pd" %}
PagerDuty account <span>{{ ch.pd_account }}</span> PagerDuty account <span>{{ ch.pd_account }}</span>
{% elif ch.kind == "pagertree" %} {% elif ch.kind == "pagertree" %}


+ 1
- 1
templates/front/details_events.html View File

@ -54,7 +54,7 @@
<td class="time"></td> <td class="time"></td>
<td class="alert-info" colspan="2"> <td class="alert-info" colspan="2">
{% if event.channel.kind == "email" %} {% if event.channel.kind == "email" %}
Sent email alert to {{ event.channel.value }}
Sent email alert to {{ event.channel.email_value }}
{% elif event.channel.kind == "slack" %} {% elif event.channel.kind == "slack" %}
Sent Slack alert Sent Slack alert
{% if event.channel.slack_channel %} {% if event.channel.slack_channel %}


+ 1
- 1
templates/front/log.html View File

@ -97,7 +97,7 @@
<td class="time"></td> <td class="time"></td>
<td class="alert-info" colspan="2"> <td class="alert-info" colspan="2">
{% if event.channel.kind == "email" %} {% if event.channel.kind == "email" %}
Sent email alert to {{ event.channel.value }}
Sent email alert to {{ event.channel.email_value }}
{% elif event.channel.kind == "slack" %} {% elif event.channel.kind == "slack" %}
Sent Slack alert Sent Slack alert
{% if event.channel.slack_channel %} {% if event.channel.slack_channel %}


+ 35
- 10
templates/integrations/add_email.html View File

@ -1,26 +1,20 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load humanize static hc_extras %} {% load humanize static hc_extras %}
{% block title %}Notification Channels - {% site_name %}{% endblock %}
{% block title %}Set Up Email Notifications - {% site_name %}{% endblock %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<h1>Email</h1> <h1>Email</h1>
<p>Get an email message when check goes up or down.</p> <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 %} {% 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. 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> </p>
{% endif %} {% endif %}
@ -37,6 +31,7 @@
class="form-control" class="form-control"
name="value" name="value"
placeholder="[email protected]" placeholder="[email protected]"
required
value="{{ form.value.value|default:"" }}"> value="{{ form.value.value|default:"" }}">
{% if form.value.errors %} {% if form.value.errors %}
@ -46,6 +41,36 @@
{% endif %} {% endif %}
</div> </div>
</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="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">Save Integration</button> <button type="submit" class="btn btn-primary">Save Integration</button>


+ 1
- 0
templates/integrations/add_pushover.html View File

@ -7,6 +7,7 @@
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<h1>Pushbover</h1>
<div class="jumbotron"> <div class="jumbotron">
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<p> <p>


Loading…
Cancel
Save