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 @@ + diff --git a/static/fonts/icomoon.ttf b/static/fonts/icomoon.ttf index ef3b55cd..b9a9c0dd 100644 Binary files a/static/fonts/icomoon.ttf and b/static/fonts/icomoon.ttf differ diff --git a/static/fonts/icomoon.woff b/static/fonts/icomoon.woff index f80d4902..938addd8 100644 Binary files a/static/fonts/icomoon.woff and b/static/fonts/icomoon.woff differ diff --git a/static/img/integrations/mattermost.png b/static/img/integrations/mattermost.png new file mode 100644 index 00000000..30b387df Binary files /dev/null and b/static/img/integrations/mattermost.png differ diff --git a/static/img/integrations/setup_mattermost_1.png b/static/img/integrations/setup_mattermost_1.png new file mode 100644 index 00000000..d22c755f Binary files /dev/null and b/static/img/integrations/setup_mattermost_1.png differ diff --git a/static/img/integrations/setup_mattermost_2.png b/static/img/integrations/setup_mattermost_2.png new file mode 100644 index 00000000..a98f41c9 Binary files /dev/null and b/static/img/integrations/setup_mattermost_2.png differ diff --git a/static/img/integrations/setup_mattermost_3.png b/static/img/integrations/setup_mattermost_3.png new file mode 100644 index 00000000..742ec938 Binary files /dev/null and b/static/img/integrations/setup_mattermost_3.png differ diff --git a/templates/front/channels.html b/templates/front/channels.html index efc57a4e..a289468a 100644 --- a/templates/front/channels.html +++ b/templates/front/channels.html @@ -100,6 +100,8 @@ {% if ch.whatsapp_notify_up and not ch.whatsapp_notify_down %} (up only) {% endif %} + {% elif ch.kind == "mattermost" %} + Mattermost {% else %} {{ ch.kind }} {% endif %} @@ -348,6 +350,15 @@ Add Integration {% endif %} +
  • + Mattermost icon + +

    Mattermost

    +

    High Trust Messaging for the Enterprise.

    + + Add Integration +