From f799066e0f7215eca73761ea19818b6255c2bbb0 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sat, 9 Sep 2023 14:20:48 -0400 Subject: [PATCH] Custom JSON wrapper updated to properly remap keys (#920) --- apprise/plugins/NotifyJSON.py | 66 ++++++++++++-------------------- test/test_plugin_custom_json.py | 68 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 42 deletions(-) diff --git a/apprise/plugins/NotifyJSON.py b/apprise/plugins/NotifyJSON.py index 0a36f4dc..0cba7a84 100644 --- a/apprise/plugins/NotifyJSON.py +++ b/apprise/plugins/NotifyJSON.py @@ -182,19 +182,6 @@ class NotifyJSON(NotifyBase): self.logger.warning(msg) raise TypeError(msg) - # A payload map allows users to over-ride the default mapping if - # they're detected with the :overide=value. Normally this would - # create a new key and assign it the value specified. However - # if the key you specify is actually an internally mapped one, - # then a re-mapping takes place using the value - self.payload_map = { - JSONPayloadField.VERSION: JSONPayloadField.VERSION, - JSONPayloadField.TITLE: JSONPayloadField.TITLE, - JSONPayloadField.MESSAGE: JSONPayloadField.MESSAGE, - JSONPayloadField.ATTACHMENTS: JSONPayloadField.ATTACHMENTS, - JSONPayloadField.MESSAGETYPE: JSONPayloadField.MESSAGETYPE, - } - self.params = {} if params: # Store our extra headers @@ -205,21 +192,10 @@ class NotifyJSON(NotifyBase): # Store our extra headers self.headers.update(headers) - self.payload_overrides = {} self.payload_extras = {} if payload: # Store our extra payload entries self.payload_extras.update(payload) - for key in list(self.payload_extras.keys()): - # Any values set in the payload to alter a system related one - # alters the system key. Hence :message=msg maps the 'message' - # variable that otherwise already contains the payload to be - # 'msg' instead (containing the payload) - if key in self.payload_map: - self.payload_map[key] = self.payload_extras[key].strip() - self.payload_overrides[key] = \ - self.payload_extras[key].strip() - del self.payload_extras[key] return @@ -245,8 +221,6 @@ class NotifyJSON(NotifyBase): # Append our payload extra's into our parameters params.update( {':{}'.format(k): v for k, v in self.payload_extras.items()}) - params.update( - {':{}'.format(k): v for k, v in self.payload_overrides.items()}) # Determine Authentication auth = '' @@ -320,22 +294,30 @@ class NotifyJSON(NotifyBase): self.logger.debug('I/O Exception: %s' % str(e)) return False - # prepare JSON Object - payload = {} - for key, value in ( - (JSONPayloadField.VERSION, self.json_version), - (JSONPayloadField.TITLE, title), - (JSONPayloadField.MESSAGE, body), - (JSONPayloadField.ATTACHMENTS, attachments), - (JSONPayloadField.MESSAGETYPE, notify_type)): - - if not self.payload_map[key]: - # Do not store element in payload response - continue - payload[self.payload_map[key]] = value - - # Apply any/all payload over-rides defined - payload.update(self.payload_extras) + # Prepare JSON Object + payload = { + JSONPayloadField.VERSION: self.json_version, + JSONPayloadField.TITLE: title, + JSONPayloadField.MESSAGE: body, + JSONPayloadField.ATTACHMENTS: attachments, + JSONPayloadField.MESSAGETYPE: notify_type, + } + + for key, value in self.payload_extras.items(): + + if key in payload: + if not value: + # Do not store element in payload response + del payload[key] + + else: + # Re-map + payload[value] = payload[key] + del payload[key] + + else: + # Append entry + payload[key] = value auth = None if self.user: diff --git a/test/test_plugin_custom_json.py b/test/test_plugin_custom_json.py index 184edcb7..41bb8014 100644 --- a/test/test_plugin_custom_json.py +++ b/test/test_plugin_custom_json.py @@ -295,3 +295,71 @@ def test_notify_json_plugin_attachments(mock_post): body='body', title='title', notify_type=NotifyType.INFO, attach=attach) is True assert mock_post.call_count == 1 + + +# Based on incomming webhook details defined here: +# https://kb.synology.com/en-au/DSM/help/Chat/chat_integration +@mock.patch('requests.post') +def test_plugin_custom_form_for_synology(mock_post): + """ + NotifyJSON() Synology Chat Test Case + + """ + + # Prepare our response + response = requests.Request() + response.status_code = requests.codes.ok + + # Prepare Mock + mock_post.return_value = response + + # This is rather confusing, it may be easier to leverage the + # synology:// and synologys:// plugins instead, but this is just to prove + # that the same message can be sent using the json:// plugin. + + results = NotifyJSON.parse_url( + 'jsons://localhost:8081/webapi/entry.cgi?' + '-api=SYNO.Chat.External&-method=incoming&-version=2&-token=abc123' + '&:message=text&:version=&:type=&:title=&:attachments' + '&:file_url=https://i.redd.it/my2t4d2fx0u31.jpg') + + assert isinstance(results, dict) + assert results['user'] is None + assert results['password'] is None + assert results['port'] == 8081 + assert results['host'] == 'localhost' + assert results['fullpath'] == '/webapi/entry.cgi' + assert results['path'] == '/webapi/' + assert results['query'] == 'entry.cgi' + assert results['schema'] == 'jsons' + assert results['url'] == 'jsons://localhost:8081/webapi/entry.cgi' + assert isinstance(results['qsd:'], dict) is True + # Header Entries + assert results['qsd-']['api'] == 'SYNO.Chat.External' + assert results['qsd-']['method'] == 'incoming' + assert results['qsd-']['version'] == '2' + assert results['qsd-']['token'] == 'abc123' + + instance = NotifyJSON(**results) + assert isinstance(instance, NotifyJSON) + + response = instance.send(title='title', body='body') + assert response is True + assert mock_post.call_count == 1 + + details = mock_post.call_args_list[0] + assert details[0][0] == 'https://localhost:8081/webapi/entry.cgi' + + params = details[1]['params'] + assert params.get('api') == 'SYNO.Chat.External' + assert params.get('method') == 'incoming' + assert params.get('version') == '2' + assert params.get('token') == 'abc123' + + payload = json.loads(details[1]['data']) + assert 'version' not in payload + assert 'title' not in payload + assert 'message' not in payload + assert 'type' not in payload + assert payload.get('text') == 'body' + assert payload.get('file_url') == 'https://i.redd.it/my2t4d2fx0u31.jpg'