diff --git a/apprise/plugins/slack.py b/apprise/plugins/slack.py index 9fa6092e..127fba94 100644 --- a/apprise/plugins/slack.py +++ b/apprise/plugins/slack.py @@ -76,6 +76,7 @@ import re import requests from json import dumps from json import loads +from json import JSONDecodeError from time import time from .base import NotifyBase @@ -410,18 +411,30 @@ class NotifySlack(NotifyBase): if self.notify_format == NotifyFormat.MARKDOWN \ else 'plain_text' + # If we have to handle Blocks API serialized JSON + if kwargs.get('body_format', None) == 'json': + try: + content = loads(body) + except JSONDecodeError: + self.logger.error( + "'body_format' is set as 'json'," + "but body is not valid JSON string" + ) + return False + # Else, we continue as before + else: + content = {'blocks': [{ + 'type': 'section', + 'text': { + 'type': _slack_format, + 'text': body + } + }]} + content.update({'color': self.color(notify_type)}) + payload = { 'username': self.user if self.user else self.app_id, - 'attachments': [{ - 'blocks': [{ - 'type': 'section', - 'text': { - 'type': _slack_format, - 'text': body - } - }], - 'color': self.color(notify_type), - }] + 'attachments': [content.copy()] } # Slack only accepts non-empty header sections @@ -463,6 +476,14 @@ class NotifySlack(NotifyBase): payload['attachments'][0]['blocks'].append(_footer) else: + # We do not support JSON body without the Blocks API + if kwargs.get('body_format', None) == 'json': + self.logger.error( + "'body_format' is set as 'json'," + "the 'blocks' URL parameter is not set" + ) + return False + # # Legacy API Formatting # diff --git a/test/test_plugin_slack.py b/test/test_plugin_slack.py index 5af84511..3ea87366 100644 --- a/test/test_plugin_slack.py +++ b/test/test_plugin_slack.py @@ -759,6 +759,53 @@ def test_plugin_slack_markdown(mock_get, mock_request): "\n\nChannel Testing\n\n\n\n"\ "User ID Testing\n<@U1ZQL9N3Y>\n<@U1ZQL9N3Y|heheh>" +@mock.patch('requests.request') +@mock.patch('requests.get') +def test_plugin_slack_body_format_blocks(mock_get, mock_request): + """ + NotifySlack() for using Blocks API directly + + """ + + request = mock.Mock() + request.content = b'ok' + request.status_code = requests.codes.ok + + # Prepare Mock + mock_request.return_value = request + mock_get.return_value = request + + # Variation Initializations + aobj = Apprise() + assert aobj.add( + 'slack://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/?blocks=yes') + + body_text = "Blocks API" + title_text = "title" + body = dumps({"blocks":[ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": body_text + } + }, + ]}) + + # Send our notification + assert aobj.notify( + body=body, title=title_text, notify_type=NotifyType.INFO, + body_format="json") + + data = loads(mock_request.call_args_list[0][1]['data']) + + # Our added block is not [0], as a title block + # has been injected by the plugin + title_block = data['attachments'][0]["blocks"][0] + added_block = data['attachments'][0]["blocks"][1] + assert title_block["text"]["text"] == title_text + assert added_block["text"]["text"] == body_text + @mock.patch('requests.request') def test_plugin_slack_single_thread_reply(mock_request):