From aba1161597203c00fde726b2e2f47e1353be536e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C4=93teris=20Caune?= <cuu508@gmail.com>
Date: Wed, 18 Dec 2024 11:51:16 +0200
Subject: [PATCH] Update RocketChat notification template to include failure
 reason

cc: #1069
---
 hc/api/tests/test_notify_rocketchat.py        | 27 +++++++++++++++++--
 hc/api/transports.py                          |  2 +-
 .../integrations/rocketchat_message.html      |  1 +
 3 files changed, 27 insertions(+), 3 deletions(-)
 create mode 100644 templates/integrations/rocketchat_message.html

diff --git a/hc/api/tests/test_notify_rocketchat.py b/hc/api/tests/test_notify_rocketchat.py
index 4bde18f6..70ee112d 100644
--- a/hc/api/tests/test_notify_rocketchat.py
+++ b/hc/api/tests/test_notify_rocketchat.py
@@ -1,4 +1,3 @@
-
 from __future__ import annotations
 
 from datetime import timedelta as td
@@ -37,6 +36,7 @@ class NotifyRocketChatTestCase(BaseTestCase):
         self.flip.created = now()
         self.flip.old_status = "new"
         self.flip.new_status = "down"
+        self.flip.reason = "timeout"
 
     @patch("hc.api.transports.curl.request", autospec=True)
     def test_it_works(self, mock_post: Mock) -> None:
@@ -49,13 +49,36 @@ class NotifyRocketChatTestCase(BaseTestCase):
         self.assertEqual(url, "https://example.org")
 
         text = mock_post.call_args.kwargs["json"]["text"]
-        self.assertTrue(text.endswith("is DOWN."))
+        self.assertIn(
+            "is DOWN (success signal did not arrive on time, grace time passed).", text
+        )
 
         attachment = mock_post.call_args.kwargs["json"]["attachments"][0]
         fields = {f["title"]: f["value"] for f in attachment["fields"]}
         self.assertEqual(fields["Last Ping"], "Success, 10 minutes ago")
         self.assertEqual(fields["Total Pings"], "112233")
 
+    @patch("hc.api.transports.curl.request", autospec=True)
+    def test_it_handles_reason_fail(self, mock_post: Mock) -> None:
+        mock_post.return_value.status_code = 200
+
+        self.flip.reason = "fail"
+        self.channel.notify(self.flip)
+
+        text = mock_post.call_args.kwargs["json"]["text"]
+        self.assertIn("is DOWN (received a failure signal).", text)
+
+    @patch("hc.api.transports.curl.request", autospec=True)
+    def test_it_does_not_escape_name(self, mock_post: Mock) -> None:
+        mock_post.return_value.status_code = 200
+
+        self.check.name = "Foo & Bar"
+        self.check.save()
+        self.channel.notify(self.flip)
+
+        text = mock_post.call_args.kwargs["json"]["text"]
+        self.assertIn("[Foo & Bar]", text)
+
     @override_settings(ROCKETCHAT_ENABLED=False)
     def test_it_requires_rocketchat_enabled(self) -> None:
         self.channel.notify(self.flip)
diff --git a/hc/api/transports.py b/hc/api/transports.py
index f51b5e46..0ebe983d 100644
--- a/hc/api/transports.py
+++ b/hc/api/transports.py
@@ -771,7 +771,7 @@ class RocketChat(HttpTransport):
         result: JSONDict = {
             "alias": settings.SITE_NAME,
             "avatar": absolute_site_logo_url(),
-            "text": f"[{check.name_then_code()}]({url}) is {flip.new_status.upper()}.",
+            "text": tmpl("rocketchat_message.html", flip=flip, check=check),
             "attachments": [{"color": color, "fields": fields}],
         }
 
diff --git a/templates/integrations/rocketchat_message.html b/templates/integrations/rocketchat_message.html
new file mode 100644
index 00000000..71ee59de
--- /dev/null
+++ b/templates/integrations/rocketchat_message.html
@@ -0,0 +1 @@
+[{{ check.name_then_code|safe }}]({{ check.cloaked_url }}) is {{ flip.new_status|upper }}{% if flip.reason %} ({{ flip.reason_long }}){% endif %}.