From fc69240e6dee03d482c85fe84b9d4cbe6b6b6fca Mon Sep 17 00:00:00 2001 From: Xanders Date: Fri, 26 Feb 2021 17:46:23 +0300 Subject: [PATCH 1/7] Add JSON-encoded webhooks --- freqtrade/rpc/webhook.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index 5796201b5..6d9b718ff 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -28,6 +28,11 @@ class Webhook(RPCHandler): self._url = self._config['webhook']['url'] + self._format = self._config['webhook'].get('format', 'form') + + if self._format != 'form' and self._format != 'json': + raise NotImplementedError('Unknown webhook format `{}`, possible values are `form` (default) and `json`'.format(self._format)) + def cleanup(self) -> None: """ Cleanup pending module resources. @@ -66,7 +71,14 @@ class Webhook(RPCHandler): def _send_msg(self, payload: dict) -> None: """do the actual call to the webhook""" + if self._format == 'form': + kwargs = {'data': payload} + elif self._format == 'json': + kwargs = {'json': payload} + else: + raise NotImplementedError('Unknown format: {}'.format(self._format)) + try: - post(self._url, data=payload) + post(self._url, **kwargs) except RequestException as exc: logger.warning("Could not call webhook url. Exception: %s", exc) From a2cd3ed5ba0c17125787965cb5dd9e9528cce19f Mon Sep 17 00:00:00 2001 From: Xanders Date: Fri, 26 Feb 2021 17:59:38 +0300 Subject: [PATCH 2/7] Add documentation for JSON webhook format --- docs/webhook-config.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/webhook-config.md b/docs/webhook-config.md index db6d4d1ef..14ac7e7ee 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -40,6 +40,19 @@ Sample configuration (tested using IFTTT). The url in `webhook.url` should point to the correct url for your webhook. If you're using [IFTTT](https://ifttt.com) (as shown in the sample above) please insert our event and key to the url. +You can set the POST body format to Form-Encoded (default) or JSON-Encoded. Use `"format": "form"` or `"format": "json"` respectively. Example configuration for Mattermost Cloud integration: + +```json + "webhook": { + "enabled": true, + "url": "https://.cloud.mattermost.com/hooks/", + "format": "json", + "webhookstatus": { + "text": "Status: {status}" + } + }, +``` + Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called. ### Webhookbuy From 52641aaa315ce6903cade30c9db904816f2cfabd Mon Sep 17 00:00:00 2001 From: Xanders Date: Fri, 26 Feb 2021 18:12:10 +0300 Subject: [PATCH 3/7] Add test for webhook JSON format --- tests/rpc/test_rpc_webhook.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/rpc/test_rpc_webhook.py b/tests/rpc/test_rpc_webhook.py index 4ca547390..025b7326f 100644 --- a/tests/rpc/test_rpc_webhook.py +++ b/tests/rpc/test_rpc_webhook.py @@ -225,3 +225,14 @@ def test__send_msg(default_conf, mocker, caplog): mocker.patch("freqtrade.rpc.webhook.post", post) webhook._send_msg(msg) assert log_has('Could not call webhook url. Exception: ', caplog) + +def test__send_msg_with_json_format(default_conf, mocker, caplog): + default_conf["webhook"] = get_webhook_dict() + default_conf["webhook"]["format"] = "json" + webhook = Webhook(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf) + msg = {'text': 'Hello'} + post = MagicMock() + mocker.patch("freqtrade.rpc.webhook.post", post) + webhook._send_msg(msg) + + assert post.call_args[1] == {'json': msg} From 984e70d4e8dd8dc8e2303ac8997143b382c7f9ed Mon Sep 17 00:00:00 2001 From: Xanders Date: Fri, 26 Feb 2021 21:15:40 +0300 Subject: [PATCH 4/7] Add webhook result example to documentation --- docs/webhook-config.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/webhook-config.md b/docs/webhook-config.md index 14ac7e7ee..4d2b31ec9 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -53,6 +53,8 @@ You can set the POST body format to Form-Encoded (default) or JSON-Encoded. Use }, ``` +The result would be e.g. `Status: running` message in the Mattermost channel. + Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called. ### Webhookbuy From 7281e794b4fe547b147774c72cf4ce2b82dee99c Mon Sep 17 00:00:00 2001 From: Xanders Date: Fri, 26 Feb 2021 21:31:33 +0300 Subject: [PATCH 5/7] Fix too long line at webhook.py --- freqtrade/rpc/webhook.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index 6d9b718ff..5a30a9be8 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -31,7 +31,8 @@ class Webhook(RPCHandler): self._format = self._config['webhook'].get('format', 'form') if self._format != 'form' and self._format != 'json': - raise NotImplementedError('Unknown webhook format `{}`, possible values are `form` (default) and `json`'.format(self._format)) + raise NotImplementedError('Unknown webhook format `{}`, possible values are ' + '`form` (default) and `json`'.format(self._format)) def cleanup(self) -> None: """ From efa50be145eb08e4496d9c0114ffc14d5b2abcf2 Mon Sep 17 00:00:00 2001 From: Xanders Date: Fri, 26 Feb 2021 21:32:41 +0300 Subject: [PATCH 6/7] Fix blank lines rule at test_rpc_webhook.py --- tests/rpc/test_rpc_webhook.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/rpc/test_rpc_webhook.py b/tests/rpc/test_rpc_webhook.py index 025b7326f..5361cd947 100644 --- a/tests/rpc/test_rpc_webhook.py +++ b/tests/rpc/test_rpc_webhook.py @@ -226,6 +226,7 @@ def test__send_msg(default_conf, mocker, caplog): webhook._send_msg(msg) assert log_has('Could not call webhook url. Exception: ', caplog) + def test__send_msg_with_json_format(default_conf, mocker, caplog): default_conf["webhook"] = get_webhook_dict() default_conf["webhook"]["format"] = "json" From f0391d3761a1aec4f1ad2e03236d8552a4f135d7 Mon Sep 17 00:00:00 2001 From: Xanders Date: Fri, 26 Feb 2021 21:40:45 +0300 Subject: [PATCH 7/7] Better JSON webhook result description --- docs/webhook-config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/webhook-config.md b/docs/webhook-config.md index 4d2b31ec9..2e41ad2cc 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -53,7 +53,7 @@ You can set the POST body format to Form-Encoded (default) or JSON-Encoded. Use }, ``` -The result would be e.g. `Status: running` message in the Mattermost channel. +The result would be POST request with e.g. `{"text":"Status: running"}` body and `Content-Type: application/json` header which results `Status: running` message in the Mattermost channel. Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called.