From 5f31b8b873f6c5aecf3ed5581eb8c42413c25d84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C4=93teris=20Caune?=
Date: Fri, 29 Jan 2021 13:20:44 +0200
Subject: [PATCH] Add the MSTEAMS_ENABLED setting
---
CHANGELOG.md | 1 +
docker/.env | 1 +
hc/api/tests/test_notify.py | 39 ----------
hc/api/tests/test_notify_msteams.py | 71 +++++++++++++++++++
hc/api/transports.py | 3 +
hc/front/tests/test_add_msteams.py | 7 ++
hc/front/views.py | 3 +
hc/settings.py | 3 +
templates/docs/self_hosted_configuration.html | 3 +
templates/docs/self_hosted_configuration.md | 6 ++
templates/front/channels.html | 2 +
templates/front/welcome.html | 2 +
12 files changed, 102 insertions(+), 39 deletions(-)
create mode 100644 hc/api/tests/test_notify_msteams.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 85be1a2d..7e82fbf9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file.
- Add the WEBHOOKS_ENABLED setting (#471)
- Add the SLACK_ENABLED setting (#471)
- Add the MATTERMOST_ENABLED setting (#471)
+- Add the MSTEAMS_ENABLED setting (#471)
## Bug Fixes
- Fix unwanted HTML escaping in SMS and WhatsApp notifications
diff --git a/docker/.env b/docker/.env
index 1d0310d7..1aa7514f 100644
--- a/docker/.env
+++ b/docker/.env
@@ -26,6 +26,7 @@ MATRIX_ACCESS_TOKEN=
MATRIX_HOMESERVER=
MATRIX_USER_ID=
MATTERMOST_ENABLED=True
+MSTEAMS_ENABLED=True
PD_VENDOR_KEY=
PING_BODY_LIMIT=10000
PING_EMAIL_DOMAIN=localhost
diff --git a/hc/api/tests/test_notify.py b/hc/api/tests/test_notify.py
index 0eb73268..54d7be2d 100644
--- a/hc/api/tests/test_notify.py
+++ b/hc/api/tests/test_notify.py
@@ -283,45 +283,6 @@ class NotifyTestCase(BaseTestCase):
with self.assertRaises(NotImplementedError):
self.channel.notify(self.check)
- @patch("hc.api.transports.requests.request")
- def test_msteams(self, mock_post):
- self._setup_data("msteams", "http://example.com/webhook")
- mock_post.return_value.status_code = 200
-
- self.check.name = "_underscores_ & more"
-
- self.channel.notify(self.check)
- assert Notification.objects.count() == 1
-
- args, kwargs = mock_post.call_args
- payload = kwargs["json"]
- self.assertEqual(payload["@type"], "MessageCard")
-
- # summary and title should be the same, except
- # title should have any special HTML characters escaped
- self.assertEqual(payload["summary"], "“_underscores_ & more” is DOWN.")
- self.assertEqual(payload["title"], "“_underscores_ & more” is DOWN.")
-
- @patch("hc.api.transports.requests.request")
- def test_msteams_escapes_html_and_markdown_in_desc(self, mock_post):
- self._setup_data("msteams", "http://example.com/webhook")
- mock_post.return_value.status_code = 200
-
- self.check.desc = """
- TEST _underscore_ `backticks` underline \\backslash\\ "quoted"
- """
-
- self.channel.notify(self.check)
-
- args, kwargs = mock_post.call_args
- text = kwargs["json"]["sections"][0]["text"]
-
- self.assertIn(r"\_underscore\_", text)
- self.assertIn(r"\`backticks\`", text)
- self.assertIn("<u>underline</u>", text)
- self.assertIn(r"\\backslash\\ ", text)
- self.assertIn(""quoted"", text)
-
@patch("hc.api.transports.os.system")
@override_settings(SHELL_ENABLED=True)
def test_shell(self, mock_system):
diff --git a/hc/api/tests/test_notify_msteams.py b/hc/api/tests/test_notify_msteams.py
new file mode 100644
index 00000000..7acdff0b
--- /dev/null
+++ b/hc/api/tests/test_notify_msteams.py
@@ -0,0 +1,71 @@
+# coding: utf-8
+
+from datetime import timedelta as td
+from unittest.mock import patch
+
+from django.utils.timezone import now
+from hc.api.models import Channel, Check, Notification
+from hc.test import BaseTestCase
+from django.test.utils import override_settings
+
+
+class NotifyTestCase(BaseTestCase):
+ def _setup_data(self, value, status="down", email_verified=True):
+ self.check = Check(project=self.project)
+ self.check.status = status
+ self.check.last_ping = now() - td(minutes=61)
+ self.check.save()
+
+ self.channel = Channel(project=self.project)
+ self.channel.kind = "msteams"
+ self.channel.value = value
+ self.channel.email_verified = email_verified
+ self.channel.save()
+ self.channel.checks.add(self.check)
+
+ @patch("hc.api.transports.requests.request")
+ def test_msteams(self, mock_post):
+ self._setup_data("http://example.com/webhook")
+ mock_post.return_value.status_code = 200
+
+ self.check.name = "_underscores_ & more"
+
+ self.channel.notify(self.check)
+ assert Notification.objects.count() == 1
+
+ args, kwargs = mock_post.call_args
+ payload = kwargs["json"]
+ self.assertEqual(payload["@type"], "MessageCard")
+
+ # summary and title should be the same, except
+ # title should have any special HTML characters escaped
+ self.assertEqual(payload["summary"], "“_underscores_ & more” is DOWN.")
+ self.assertEqual(payload["title"], "“_underscores_ & more” is DOWN.")
+
+ @patch("hc.api.transports.requests.request")
+ def test_msteams_escapes_html_and_markdown_in_desc(self, mock_post):
+ self._setup_data("http://example.com/webhook")
+ mock_post.return_value.status_code = 200
+
+ self.check.desc = """
+ TEST _underscore_ `backticks` underline \\backslash\\ "quoted"
+ """
+
+ self.channel.notify(self.check)
+
+ args, kwargs = mock_post.call_args
+ text = kwargs["json"]["sections"][0]["text"]
+
+ self.assertIn(r"\_underscore\_", text)
+ self.assertIn(r"\`backticks\`", text)
+ self.assertIn("<u>underline</u>", text)
+ self.assertIn(r"\\backslash\\ ", text)
+ self.assertIn(""quoted"", text)
+
+ @override_settings(MSTEAMS_ENABLED=False)
+ def test_it_requires_msteams_enabled(self):
+ self._setup_data("http://example.com/webhook")
+ self.channel.notify(self.check)
+
+ n = Notification.objects.get()
+ self.assertEqual(n.error, "MS Teams notifications are not enabled.")
diff --git a/hc/api/transports.py b/hc/api/transports.py
index e93b968d..d7d642b3 100644
--- a/hc/api/transports.py
+++ b/hc/api/transports.py
@@ -610,6 +610,9 @@ class MsTeams(HttpTransport):
return s
def notify(self, check):
+ if not settings.MSTEAMS_ENABLED:
+ return "MS Teams notifications are not enabled."
+
text = tmpl("msteams_message.json", check=check)
payload = json.loads(text)
diff --git a/hc/front/tests/test_add_msteams.py b/hc/front/tests/test_add_msteams.py
index 7fb9894d..5bbbbf77 100644
--- a/hc/front/tests/test_add_msteams.py
+++ b/hc/front/tests/test_add_msteams.py
@@ -1,3 +1,4 @@
+from django.test.utils import override_settings
from hc.api.models import Channel
from hc.test import BaseTestCase
@@ -31,3 +32,9 @@ class AddMsTeamsTestCase(BaseTestCase):
self.client.login(username="bob@example.org", password="password")
r = self.client.get(self.url)
self.assertEqual(r.status_code, 403)
+
+ @override_settings(MSTEAMS_ENABLED=False)
+ def test_it_handles_disabled_integration(self):
+ self.client.login(username="alice@example.org", password="password")
+ r = self.client.get(self.url)
+ self.assertEqual(r.status_code, 404)
diff --git a/hc/front/views.py b/hc/front/views.py
index 7a301654..f60baaaa 100644
--- a/hc/front/views.py
+++ b/hc/front/views.py
@@ -296,6 +296,7 @@ def index(request):
"enable_linenotify": settings.LINENOTIFY_CLIENT_ID is not None,
"enable_matrix": settings.MATRIX_ACCESS_TOKEN is not None,
"enable_mattermost": settings.MATTERMOST_ENABLED is True,
+ "enable_msteams": settings.MSTEAMS_ENABLED is True,
"enable_pdc": settings.PD_VENDOR_KEY is not None,
"enable_pushbullet": settings.PUSHBULLET_CLIENT_ID is not None,
"enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
@@ -765,6 +766,7 @@ def channels(request, code):
"enable_linenotify": settings.LINENOTIFY_CLIENT_ID is not None,
"enable_matrix": settings.MATRIX_ACCESS_TOKEN is not None,
"enable_mattermost": settings.MATTERMOST_ENABLED is True,
+ "enable_msteams": settings.MSTEAMS_ENABLED is True,
"enable_pdc": settings.PD_VENDOR_KEY is not None,
"enable_pushbullet": settings.PUSHBULLET_CLIENT_ID is not None,
"enable_pushover": settings.PUSHOVER_API_TOKEN is not None,
@@ -1783,6 +1785,7 @@ def trello_settings(request):
return render(request, "integrations/trello_settings.html", ctx)
+@require_setting("MSTEAMS_ENABLED")
@login_required
def add_msteams(request, code):
project = _get_rw_project_for_user(request, code)
diff --git a/hc/settings.py b/hc/settings.py
index 65e00961..fd656ce8 100644
--- a/hc/settings.py
+++ b/hc/settings.py
@@ -202,6 +202,9 @@ MATRIX_ACCESS_TOKEN = os.getenv("MATRIX_ACCESS_TOKEN")
# Mattermost
MATTERMOST_ENABLED = envbool("MATTERMOST_ENABLED", "True")
+# MS Teams
+MSTEAMS_ENABLED = envbool("MSTEAMS_ENABLED", "True")
+
# PagerDuty
PD_VENDOR_KEY = os.getenv("PD_VENDOR_KEY")
diff --git a/templates/docs/self_hosted_configuration.html b/templates/docs/self_hosted_configuration.html
index 3ac83246..d8e68a06 100644
--- a/templates/docs/self_hosted_configuration.html
+++ b/templates/docs/self_hosted_configuration.html
@@ -143,6 +143,9 @@ integration.
MATTERMOST_ENABLED
Default: True
A boolean that turns on/off the Mattermost integration. Enabled by default.
+MSTEAMS_ENABLED
+Default: True
+A boolean that turns on/off the MS Teams integration. Enabled by default.
PD_VENDOR_KEY
Default: None
PagerDuty vendor key,
diff --git a/templates/docs/self_hosted_configuration.md b/templates/docs/self_hosted_configuration.md
index cc66d165..57460fb5 100644
--- a/templates/docs/self_hosted_configuration.md
+++ b/templates/docs/self_hosted_configuration.md
@@ -236,6 +236,12 @@ Default: `True`
A boolean that turns on/off the Mattermost integration. Enabled by default.
+## `MSTEAMS_ENABLED` {: #MSTEAMS_ENABLED }
+
+Default: `True`
+
+A boolean that turns on/off the MS Teams integration. Enabled by default.
+
## `PD_VENDOR_KEY` {: #PD_VENDOR_KEY }
Default: `None`
diff --git a/templates/front/channels.html b/templates/front/channels.html
index fa32c652..19ed3429 100644
--- a/templates/front/channels.html
+++ b/templates/front/channels.html
@@ -276,6 +276,7 @@
{% endif %}
+ {% if enable_msteams %}
@@ -284,6 +285,7 @@
Chat and collaboration platform for Microsoft Office 365 customers.
Add Integration
+ {% endif %}
{% endif %}
+ {% if enable_msteams %}
@@ -481,6 +482,7 @@
+ {% endif %}