Skip to content

Commit

Permalink
Slack now supports <@userid> in message body (#1134)
Browse files Browse the repository at this point in the history
  • Loading branch information
caronc authored May 28, 2024
1 parent da14b3a commit e289279
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 29 deletions.
76 changes: 48 additions & 28 deletions apprise/plugins/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,40 @@ class NotifySlack(NotifyBase):
},
})

# Formatting requirements are defined here:
# https://api.slack.com/docs/message-formatting
_re_formatting_map = {
# New lines must become the string version
r'\r\*\n': '\\n',
# Escape other special characters
r'&': '&amp;',
r'<': '&lt;',
r'>': '&gt;',
}

# To notify a channel, one uses <!channel|channel>
_re_channel_support = re.compile(
r'(?P<match>(?:<|\&lt;)?[ \t]*'
r'!(?P<channel>[^| \n]+)'
r'(?:[ \t]*\|[ \t]*(?:(?P<val>[^\n]+?)[ \t]*)?(?:>|\&gt;)'
r'|(?:>|\&gt;)))', re.IGNORECASE)

# To notify a user by their ID, one uses <@U6TTX1F9R>
_re_user_id_support = re.compile(
r'(?P<match>(?:<|\&lt;)?[ \t]*'
r'@(?P<userid>[^| \n]+)'
r'(?:[ \t]*\|[ \t]*(?:(?P<val>[^\n]+?)[ \t]*)?(?:>|\&gt;)'
r'|(?:>|\&gt;)))', re.IGNORECASE)

# The markdown in slack isn't [desc](url), it's <url|desc>
#
# To accomodate this, we need to ensure we don't escape URLs that match
_re_url_support = re.compile(
r'(?P<match>(?:<|\&lt;)?[ \t]*'
r'(?P<url>(?:https?|mailto)://[^| \n]+)'
r'(?:[ \t]*\|[ \t]*(?:(?P<val>[^\n]+?)[ \t]*)?(?:>|\&gt;)'
r'|(?:>|\&gt;)))', re.IGNORECASE)

def __init__(self, access_token=None, token_a=None, token_b=None,
token_c=None, targets=None, include_image=True,
include_footer=True, use_blocks=None, **kwargs):
Expand Down Expand Up @@ -344,39 +378,11 @@ def __init__(self, access_token=None, token_a=None, token_b=None,
None if self.mode is SlackMode.WEBHOOK
else self.default_notification_channel)

# Formatting requirements are defined here:
# https://api.slack.com/docs/message-formatting
self._re_formatting_map = {
# New lines must become the string version
r'\r\*\n': '\\n',
# Escape other special characters
r'&': '&amp;',
r'<': '&lt;',
r'>': '&gt;',
}

# To notify a channel, one uses <!channel|channel>
self._re_channel_support = re.compile(
r'(?P<match>(?:<|\&lt;)?[ \t]*'
r'!(?P<channel>[^| \n]+)'
r'(?:[ \t]*\|[ \t]*(?:(?P<val>[^\n]+?)[ \t]*)?(?:>|\&gt;)'
r'|(?:>|\&gt;)))', re.IGNORECASE)

# The markdown in slack isn't [desc](url), it's <url|desc>
#
# To accomodate this, we need to ensure we don't escape URLs that match
self._re_url_support = re.compile(
r'(?P<match>(?:<|\&lt;)?[ \t]*'
r'(?P<url>(?:https?|mailto)://[^| \n]+)'
r'(?:[ \t]*\|[ \t]*(?:(?P<val>[^\n]+?)[ \t]*)?(?:>|\&gt;)'
r'|(?:>|\&gt;)))', re.IGNORECASE)

# Iterate over above list and store content accordingly
self._re_formatting_rules = re.compile(
r'(' + '|'.join(self._re_formatting_map.keys()) + r')',
re.IGNORECASE,
)

# Place a thumbnail image inline with the message body
self.include_image = include_image

Expand Down Expand Up @@ -478,6 +484,20 @@ def send(self, body, title='', notify_type=NotifyType.INFO, attach=None,
body,
re.IGNORECASE)

# Support <@userid|desc>, <@channel> entries
for match in self._re_user_id_support.findall(body):
# Swap back any ampersands previously updaated
user = match[1].strip()
desc = match[2].strip()

# Update our string
body = re.sub(
re.escape(match[0]),
'<@{user}|{desc}>'.format(user=user, desc=desc)
if desc else '<@{user}>'.format(user=user),
body,
re.IGNORECASE)

# Support <url|desc>, <url> entries
for match in self._re_url_support.findall(body):
# Swap back any ampersands previously updaated
Expand Down
7 changes: 6 additions & 1 deletion test/test_plugin_slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,10 @@ def test_plugin_slack_markdown(mock_get, mock_request):
Channel Testing
<!channelA>
<!channelA|Description>
User ID Testing
<@U1ZQL9N3Y>
<@U1ZQL9N3Y|heheh>
""")

# Send our notification
Expand All @@ -752,7 +756,8 @@ def test_plugin_slack_markdown(mock_get, mock_request):
"\n <https://slack.com?arg=val&arg2=val2|Slack Link>.\n"\
"We also want to be able to support <https://slack.com> "\
"links without the\ndescription."\
"\n\nChannel Testing\n<!channelA>\n<!channelA|Description>"
"\n\nChannel Testing\n<!channelA>\n<!channelA|Description>\n\n"\
"User ID Testing\n<@U1ZQL9N3Y>\n<@U1ZQL9N3Y|heheh>"


@mock.patch('requests.request')
Expand Down

0 comments on commit e289279

Please sign in to comment.