forked from GithubBackups/healthchecks
Set the "title" and "summary" fields in MS Teams notifications
Fixes: #435
This commit is contained in:
parent
63beeb05a1
commit
463ec8c988
@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fix missing Resume button (#421)
|
- Fix missing Resume button (#421)
|
||||||
- When decoding inbound emails, decode encoded headers (#420)
|
- When decoding inbound emails, decode encoded headers (#420)
|
||||||
- Escape markdown in MS Teams notifications (#426)
|
- Escape markdown in MS Teams notifications (#426)
|
||||||
|
- Set the "title" and "summary" fields in MS Teams notifications (#435)
|
||||||
|
|
||||||
## v1.16.0 - 2020-08-04
|
## v1.16.0 - 2020-08-04
|
||||||
|
|
||||||
|
@ -859,6 +859,8 @@ class NotifyTestCase(BaseTestCase):
|
|||||||
self._setup_data("msteams", "http://example.com/webhook")
|
self._setup_data("msteams", "http://example.com/webhook")
|
||||||
mock_post.return_value.status_code = 200
|
mock_post.return_value.status_code = 200
|
||||||
|
|
||||||
|
self.check.name = "_underscores_ & more"
|
||||||
|
|
||||||
self.channel.notify(self.check)
|
self.channel.notify(self.check)
|
||||||
assert Notification.objects.count() == 1
|
assert Notification.objects.count() == 1
|
||||||
|
|
||||||
@ -866,19 +868,24 @@ class NotifyTestCase(BaseTestCase):
|
|||||||
payload = kwargs["json"]
|
payload = kwargs["json"]
|
||||||
self.assertEqual(payload["@type"], "MessageCard")
|
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")
|
@patch("hc.api.transports.requests.request")
|
||||||
def test_msteams_escapes_markdown(self, mock_post):
|
def test_msteams_escapes_html_and_markdown_in_desc(self, mock_post):
|
||||||
self._setup_data("msteams", "http://example.com/webhook")
|
self._setup_data("msteams", "http://example.com/webhook")
|
||||||
mock_post.return_value.status_code = 200
|
mock_post.return_value.status_code = 200
|
||||||
|
|
||||||
self.check.name = """
|
self.check.desc = """
|
||||||
TEST _underscore_ `backticks` <u>underline</u> \\backslash\\ "quoted"
|
TEST _underscore_ `backticks` <u>underline</u> \\backslash\\ "quoted"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.channel.notify(self.check)
|
self.channel.notify(self.check)
|
||||||
|
|
||||||
args, kwargs = mock_post.call_args
|
args, kwargs = mock_post.call_args
|
||||||
text = kwargs["json"]["text"]
|
text = kwargs["json"]["sections"][0]["text"]
|
||||||
|
|
||||||
self.assertIn(r"\_underscore\_", text)
|
self.assertIn(r"\_underscore\_", text)
|
||||||
self.assertIn(r"\`backticks\`", text)
|
self.assertIn(r"\`backticks\`", text)
|
||||||
|
@ -580,17 +580,34 @@ class Apprise(HttpTransport):
|
|||||||
|
|
||||||
|
|
||||||
class MsTeams(HttpTransport):
|
class MsTeams(HttpTransport):
|
||||||
|
def escape_md(self, s):
|
||||||
|
# Escape special HTML characters
|
||||||
|
s = escape(s)
|
||||||
|
# Escape characters that have special meaning in Markdown
|
||||||
|
for c in r"\`*_{}[]()#+-.!|":
|
||||||
|
s = s.replace(c, "\\" + c)
|
||||||
|
return s
|
||||||
|
|
||||||
def notify(self, check):
|
def notify(self, check):
|
||||||
text = tmpl("msteams_message.json", check=check)
|
text = tmpl("msteams_message.json", check=check)
|
||||||
payload = json.loads(text)
|
payload = json.loads(text)
|
||||||
|
|
||||||
# Escape special HTML characters in check's name
|
# MS Teams escapes HTML special characters in the summary field.
|
||||||
safe_name = escape(check.name_then_code())
|
# It does not interpret summary content as Markdown.
|
||||||
# Escape characters that have special meaning in Markdown
|
name = check.name_then_code()
|
||||||
for c in r"\`*_{}[]()#+-.!|":
|
payload["summary"] = f"“{name}” is {check.status.upper()}."
|
||||||
safe_name = safe_name.replace(c, "\\" + c)
|
|
||||||
|
|
||||||
payload["text"] = f"“{safe_name}” is {check.status.upper()}."
|
# MS teams *strips* HTML special characters from the title field.
|
||||||
|
# To avoid that, we use escape().
|
||||||
|
# It does not interpret title as Markdown.
|
||||||
|
safe_name = escape(name)
|
||||||
|
payload["title"] = f"“{safe_name}” is {check.status.upper()}."
|
||||||
|
|
||||||
|
# MS teams allows some HTML in the section text.
|
||||||
|
# It also interprets the section text as Markdown.
|
||||||
|
# We want to display the raw content, angle brackets and all,
|
||||||
|
# so we run escape() and then additionally escape Markdown:
|
||||||
|
payload["sections"][0]["text"] = self.escape_md(check.desc)
|
||||||
|
|
||||||
return self.post(self.channel.value, json=payload)
|
return self.post(self.channel.value, json=payload)
|
||||||
|
|
||||||
|
@ -35,8 +35,7 @@
|
|||||||
"name": "Total Pings:",
|
"name": "Total Pings:",
|
||||||
"value": "{{ check.n_pings }}"
|
"value": "{{ check.n_pings }}"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"text": "{{ check.desc|escapejs }}"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"potentialAction": [
|
"potentialAction": [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user