From d8e05be54be7659c0d15c8c87b87af86d0facb38 Mon Sep 17 00:00:00 2001 From: phantom Date: Thu, 11 Jul 2024 12:53:56 +0200 Subject: [PATCH 1/5] #202: Add possibility of not passing body --- apprise_api/api/views.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/apprise_api/api/views.py b/apprise_api/api/views.py index e286b9b..9c0e68d 100644 --- a/apprise_api/api/views.py +++ b/apprise_api/api/views.py @@ -707,6 +707,9 @@ def post(self, request, key): # rules rules = {k[1:]: v for k, v in request.GET.items() if k[0] == ':'} + body_not_required = request.GET.get('body_not_required') == 'true' + title_not_required = request.GET.get('title_not_required') == 'true' + # our content content = {} if not json_payload: @@ -912,7 +915,7 @@ def post(self, request, key): content['title'] = request.GET['title'] # Some basic error checking - if not content.get('body') and not attach or \ + if (not content.get('body') and not body_not_required and not attach) or \ content.get('type', apprise.NotifyType.INFO) \ not in apprise.NOTIFY_TYPES: @@ -1124,12 +1127,15 @@ def post(self, request, key): if content_type == 'text/html' else \ settings.LOGGING['formatters']['standard']['format'] + notif_body = content.get('body') if not body_not_required else apprise.NOT_REQUIRED + notif_title = content.get('title', '') if not title_not_required else apprise.NOT_REQUIRED + # Now specify our format (and over-ride the default): with apprise.LogCapture(level=level, fmt=fmt) as logs: # Perform our notification at this point result = a_obj.notify( - content.get('body'), - title=content.get('title', ''), + notif_body, + title=notif_title, notify_type=content.get('type', apprise.NotifyType.INFO), tag=content.get('tag'), attach=attach, @@ -1323,8 +1329,11 @@ def post(self, request): if not content.get('title') and 'title' in request.GET: content['title'] = request.GET['title'] + body_not_required = request.GET.get('body_not_required') == 'true' + title_not_required = request.GET.get('title_not_required') == 'true' + # Some basic error checking - if not content.get('body') or \ + if (not content.get('body') and not body_not_required) or \ content.get('type', apprise.NotifyType.INFO) \ not in apprise.NOTIFY_TYPES: @@ -1492,14 +1501,17 @@ def post(self, request): elif level == 'TRACE': level = logging.DEBUG - 1 + notif_body = content.get('body') if not body_not_required else apprise.NOT_REQUIRED + notif_title = content.get('title', '') if not title_not_required else apprise.NOT_REQUIRED + if settings.APPRISE_WEBHOOK_URL: esc = '' fmt = f'["%(levelname)s","%(asctime)s","{esc}%(message)s{esc}"]' with apprise.LogCapture(level=level, fmt=fmt) as logs: # Perform our notification at this point result = a_obj.notify( - content.get('body'), - title=content.get('title', ''), + notif_body, + title=notif_title, notify_type=content.get('type', apprise.NotifyType.INFO), tag='all', attach=attach, @@ -1527,8 +1539,8 @@ def post(self, request): else: # Perform our notification at this point result = a_obj.notify( - content.get('body'), - title=content.get('title', ''), + notif_body, + title=notif_title, notify_type=content.get('type', apprise.NotifyType.INFO), tag='all', attach=attach, From 0a4606fe0bcd35086e2bd87fa615efd1e8b31323 Mon Sep 17 00:00:00 2001 From: phantom Date: Thu, 11 Jul 2024 14:47:33 +0200 Subject: [PATCH 2/5] #202: Handle case with stateful notify and no body --- apprise_api/api/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apprise_api/api/views.py b/apprise_api/api/views.py index 9c0e68d..bda4e4b 100644 --- a/apprise_api/api/views.py +++ b/apprise_api/api/views.py @@ -764,7 +764,7 @@ def post(self, request, key): 'error': msg, }, encoder=JSONEncoder, safe=False, status=status) - if not content: + if not content and not body_not_required: # We could not handle the Content-Type logger.warning( 'NOTIFY - %s - Invalid FORM Payload provided using KEY: %s', @@ -1236,6 +1236,9 @@ def post(self, request): # rules rules = {k[1:]: v for k, v in request.GET.items() if k[0] == ':'} + body_not_required = request.GET.get('body_not_required') == 'true' + title_not_required = request.GET.get('title_not_required') == 'true' + # our content content = {} if not json_payload: @@ -1329,9 +1332,6 @@ def post(self, request): if not content.get('title') and 'title' in request.GET: content['title'] = request.GET['title'] - body_not_required = request.GET.get('body_not_required') == 'true' - title_not_required = request.GET.get('title_not_required') == 'true' - # Some basic error checking if (not content.get('body') and not body_not_required) or \ content.get('type', apprise.NotifyType.INFO) \ From 6abd08ea90ec000d0ec6a712874dd6e67f601a41 Mon Sep 17 00:00:00 2001 From: phantom Date: Thu, 11 Jul 2024 14:48:07 +0200 Subject: [PATCH 3/5] #202: Add tests for nody not required --- apprise_api/api/tests/test_notify.py | 37 +++++++++++++++++++ .../api/tests/test_stateless_notify.py | 32 ++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/apprise_api/api/tests/test_notify.py b/apprise_api/api/tests/test_notify.py index 74ddeff..41ca2ac 100644 --- a/apprise_api/api/tests/test_notify.py +++ b/apprise_api/api/tests/test_notify.py @@ -1483,3 +1483,40 @@ def test_stateful_notify_recursion(self, mock_notify): '/notify/{}'.format(key), data=form_data, **headers) assert response.status_code == 400 assert mock_notify.call_count == 0 + + + @mock.patch('apprise.Apprise.notify') + def test_notify_no_body(self, mock_notify): + """ + Test sending a notification without a body (if supported) + """ + + key = "dummy" + + # Add some content + response = self.client.post( + '/add/{}'.format(key), + {'urls': 'onesignal://template_id:account_id@app_key/target_player_id'}) + assert response.status_code == 200 + + # Set our return value + mock_notify.return_value = True + + # Expect to fail because body is not provided + response = self.client.post( + '/notify/{}'.format(key), + data=json.dumps({}), + content_type='application/json', + ) + assert response.status_code == 400 and response.json() == { + "error": "Bad FORM Payload provided" + } + + # This now succeeds because body is set to not required explicitly + response = self.client.post( + '/notify/{}?body_not_required=true'.format(key), + data=json.dumps({}), + content_type='application/json', + ) + assert response.status_code == 200 and mock_notify.call_count == 1 + diff --git a/apprise_api/api/tests/test_stateless_notify.py b/apprise_api/api/tests/test_stateless_notify.py index db87416..e6eef43 100644 --- a/apprise_api/api/tests/test_stateless_notify.py +++ b/apprise_api/api/tests/test_stateless_notify.py @@ -757,3 +757,35 @@ def test_notify_with_filters(self, mock_send): # nothing was changed assert N_MGR['json'].enabled is True + + @mock.patch('apprise.Apprise.notify') + def test_notify_no_body(self, mock_notify): + """ + Test sending a notification without a body (if supported) + """ + + # Set our return value + mock_notify.return_value = True + + # Prepare our JSON data + json_data = { + 'urls': 'onesignal://template_id:account_id@app_key/target_player_id', + } + + # Expect to fail because body is not provided + response = self.client.post( + '/notify/', + data=json.dumps(json_data), + content_type='application/json', + ) + assert response.status_code == 400 and response.json() == { + "error": "Payload lacks minimum requirements" + } + + # This now succeeds because body is set to not required explicitly + response = self.client.post( + '/notify/?body_not_required=true', + data=json.dumps(json_data), + content_type='application/json', + ) + assert response.status_code == 200 and mock_notify.call_count == 1 From 781b5222bbd110343107eb021fd0b97656d3faf8 Mon Sep 17 00:00:00 2001 From: phantom Date: Thu, 11 Jul 2024 14:49:17 +0200 Subject: [PATCH 4/5] #202: Bump apprise requirement version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5f78d9f..3b678db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ # apprise @ git+https://github.com/caronc/apprise@custom-tag-or-version ## 3. The below grabs our stable version (generally the best choice): -apprise == 1.8.0 +apprise == 1.9.0 ## Apprise API Minimum Requirements django From 0c879b9e85bb086eecab5cbb0cba5a593af0f9f7 Mon Sep 17 00:00:00 2001 From: phantom Date: Thu, 11 Jul 2024 14:55:07 +0200 Subject: [PATCH 5/5] #202: Update documentation --- apprise_api/api/templates/welcome.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apprise_api/api/templates/welcome.html b/apprise_api/api/templates/welcome.html index bc80f0e..b242300 100644 --- a/apprise_api/api/templates/welcome.html +++ b/apprise_api/api/templates/welcome.html @@ -52,7 +52,7 @@

{% trans "Stateless Endpoints" %}

body - {% blocktrans %}Defines the message body. This field is required!{% endblocktrans %} + {% blocktrans %}Defines the message body. This field is required (unless body_not_required GET parameter is provided - only used with templated notifications).{% endblocktrans %} title @@ -453,7 +453,7 @@

{% trans "Persistent Store Endpoints" %}

body - {% blocktrans %}Defines the message body. This field is required!{% endblocktrans %} + {% blocktrans %}Defines the message body. This field is required (unless body_not_required GET parameter is provided - only used with templated notifications).{% endblocktrans %} title