diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2daaa5dc..ae8539e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
- Show the number of downtimes and total downtime minutes in monthly reports (#104)
- Show the number of downtimes and total downtime minutes in "Check Details" page
- Add the `pruneflips` management command
+- Add Mattermost integration (#276)
## Bug Fixes
- Fix javascript code to construct correct URLs when running from a subdirectory (#273)
diff --git a/hc/api/models.py b/hc/api/models.py
index dd2f9245..7e8114d1 100644
--- a/hc/api/models.py
+++ b/hc/api/models.py
@@ -42,6 +42,7 @@ CHANNEL_KINDS = (
("matrix", "Matrix"),
("whatsapp", "WhatsApp"),
("apprise", "Apprise"),
+ ("mattermost", "Mattermost"),
)
PO_PRIORITIES = {-2: "lowest", -1: "low", 0: "normal", 1: "high", 2: "emergency"}
@@ -363,7 +364,7 @@ class Channel(models.Model):
return transports.Email(self)
elif self.kind == "webhook":
return transports.Webhook(self)
- elif self.kind == "slack":
+ elif self.kind in ("slack", "mattermost"):
return transports.Slack(self)
elif self.kind == "hipchat":
return transports.HipChat(self)
@@ -504,7 +505,7 @@ class Channel(models.Model):
@property
def slack_webhook_url(self):
- assert self.kind == "slack"
+ assert self.kind in ("slack", "mattermost")
if not self.value.startswith("{"):
return self.value
diff --git a/hc/front/tests/test_add_mattermost.py b/hc/front/tests/test_add_mattermost.py
new file mode 100644
index 00000000..1481462d
--- /dev/null
+++ b/hc/front/tests/test_add_mattermost.py
@@ -0,0 +1,23 @@
+from django.test.utils import override_settings
+
+from hc.api.models import Channel
+from hc.test import BaseTestCase
+
+
+class AddMattermostTestCase(BaseTestCase):
+ def test_instructions_work(self):
+ self.client.login(username="alice@example.org", password="password")
+ r = self.client.get("/integrations/add_mattermost/")
+ self.assertContains(r, "Integration Settings", status_code=200)
+
+ def test_it_works(self):
+ form = {"value": "http://example.org"}
+
+ self.client.login(username="alice@example.org", password="password")
+ r = self.client.post("/integrations/add_mattermost/", form)
+ self.assertRedirects(r, "/integrations/")
+
+ c = Channel.objects.get()
+ self.assertEqual(c.kind, "mattermost")
+ self.assertEqual(c.value, "http://example.org")
+ self.assertEqual(c.project, self.project)
diff --git a/hc/front/urls.py b/hc/front/urls.py
index a3c98d5e..f0e3fc68 100644
--- a/hc/front/urls.py
+++ b/hc/front/urls.py
@@ -30,6 +30,7 @@ channel_urls = [
path("add_pagertree/", views.add_pagertree, name="hc-add-pagertree"),
path("add_pagerteam/", views.add_pagerteam, name="hc-add-pagerteam"),
path("add_slack/", views.add_slack, name="hc-add-slack"),
+ path("add_mattermost/", views.add_mattermost, name="hc-add-mattermost"),
path("add_slack_btn/", views.add_slack_btn, name="hc-add-slack-btn"),
path("add_pushbullet/", views.add_pushbullet, name="hc-add-pushbullet"),
path("add_discord/", views.add_discord, name="hc-add-discord"),
diff --git a/hc/front/views.py b/hc/front/views.py
index e391f875..d4fe3bae 100644
--- a/hc/front/views.py
+++ b/hc/front/views.py
@@ -902,6 +902,25 @@ def add_slack(request):
return render(request, "integrations/add_slack.html", ctx)
+@login_required
+def add_mattermost(request):
+ if request.method == "POST":
+ form = AddUrlForm(request.POST)
+ if form.is_valid():
+ channel = Channel(project=request.project, kind="mattermost")
+ channel.value = form.cleaned_data["value"]
+ channel.save()
+
+ channel.assign_all_checks()
+ return redirect("hc-channels")
+ else:
+ form = AddUrlForm()
+
+ ctx = {"page": "channels", "form": form, "project": request.project}
+
+ return render(request, "integrations/add_mattermost.html", ctx)
+
+
@login_required
def add_slack_btn(request):
code = _get_validated_code(request, "slack")
@@ -1346,11 +1365,7 @@ def add_apprise(request):
else:
form = AddAppriseForm()
- ctx = {
- "page": "channels",
- "project": request.project,
- "form": form,
- }
+ ctx = {"page": "channels", "project": request.project, "form": form}
return render(request, "integrations/add_apprise.html", ctx)
diff --git a/static/css/icomoon.css b/static/css/icomoon.css
index bd46e685..85eb4a0a 100644
--- a/static/css/icomoon.css
+++ b/static/css/icomoon.css
@@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
- src: url('../fonts/icomoon.eot?iewxyq');
- src: url('../fonts/icomoon.eot?iewxyq#iefix') format('embedded-opentype'),
- url('../fonts/icomoon.ttf?iewxyq') format('truetype'),
- url('../fonts/icomoon.woff?iewxyq') format('woff'),
- url('../fonts/icomoon.svg?iewxyq#icomoon') format('svg');
+ src: url('../fonts/icomoon.eot?smade2');
+ src: url('../fonts/icomoon.eot?smade2#iefix') format('embedded-opentype'),
+ url('../fonts/icomoon.ttf?smade2') format('truetype'),
+ url('../fonts/icomoon.woff?smade2') format('woff'),
+ url('../fonts/icomoon.svg?smade2#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
@@ -24,6 +24,10 @@
-moz-osx-font-smoothing: grayscale;
}
+.icon-mattermost:before {
+ content: "\e907";
+ color: #045acc;
+}
.icon-pagerteam:before {
content: "\e914";
color: #cd2a00;
diff --git a/static/fonts/icomoon.eot b/static/fonts/icomoon.eot
index 6ed5c24a..16db047b 100644
Binary files a/static/fonts/icomoon.eot and b/static/fonts/icomoon.eot differ
diff --git a/static/fonts/icomoon.svg b/static/fonts/icomoon.svg
index abeb4ac1..73bac290 100644
--- a/static/fonts/icomoon.svg
+++ b/static/fonts/icomoon.svg
@@ -25,6 +25,7 @@
High Trust Messaging for the Enterprise.
+ + Add Integration +If your team uses Mattermost, you can set + up {% site_name %} to post status updates directly to an appropriate + Mattermost channel.
+ ++ In the "Integrations" screen, select Incoming Webhook + and then Add Incoming Webhook. +
+Fill in the form and hit "Save".
+Copy the displayed URL and paste it down below.
+Save the integration, and it's done!
+