From b1adfaf77b7a0c0bec340d915e14ba76d7f075ee Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sat, 17 Feb 2024 21:07:47 -0500 Subject: [PATCH] Support 'attach' keyword (alias of 'attachment') --- apprise_api/api/tests/test_notify.py | 45 +++++++++++++++++++ .../api/tests/test_stateless_notify.py | 44 ++++++++++++++++++ apprise_api/api/views.py | 39 +++++++++++++--- 3 files changed, 121 insertions(+), 7 deletions(-) diff --git a/apprise_api/api/tests/test_notify.py b/apprise_api/api/tests/test_notify.py index 6df89c7..a95a6d3 100644 --- a/apprise_api/api/tests/test_notify.py +++ b/apprise_api/api/tests/test_notify.py @@ -847,6 +847,22 @@ class NotifyTests(SimpleTestCase): assert response.status_code == 400 assert mock_notify.call_count == 0 + # Reset our mock object + mock_notify.reset_mock() + + # Preare our form data + form_data = { + 'body': 'test notifiction', + 'attach': 'https://localhost/invalid/path/to/image.png', + } + + # Send our notification + response = self.client.post( + '/notify/{}'.format(key), form_data) + # We fail because we couldn't retrieve our attachment + assert response.status_code == 400 + assert mock_notify.call_count == 0 + @mock.patch('apprise.Apprise.notify') def test_notify_by_loaded_urls_with_json(self, mock_notify): """ @@ -998,9 +1014,38 @@ class NotifyTests(SimpleTestCase): assert response.status_code == 200 assert mock_notify.call_count == 1 + # Reset our mock object mock_notify.reset_mock() + # If an empty format is specified, it is accepted and + # no imput format is specified + json_data = { + 'body': 'test message', + 'format': None, + 'attach': 'https://localhost/invalid/path/to/image.png', + } + + # Test case with format changed + response = self.client.post( + '/notify/{}'.format(key), + data=json.dumps(json_data), + content_type='application/json', + ) + + # We failed to send notification because we couldn't fetch the + # attachment + assert response.status_code == 400 + assert mock_notify.call_count == 0 + + # Reset our mock object + mock_notify.reset_mock() + + json_data = { + 'body': 'test message', + 'format': None, + } + # Same results for any empty string: json_data['format'] = '' response = self.client.post( diff --git a/apprise_api/api/tests/test_stateless_notify.py b/apprise_api/api/tests/test_stateless_notify.py index e487ef2..507272f 100644 --- a/apprise_api/api/tests/test_stateless_notify.py +++ b/apprise_api/api/tests/test_stateless_notify.py @@ -250,6 +250,50 @@ class StatelessNotifyTests(SimpleTestCase): assert response.status_code == 400 assert mock_notify.call_count == 0 + # Reset our mock object + mock_notify.reset_mock() + + # Preare our form data (support attach keyword) + form_data = { + 'body': 'test notifiction', + 'urls': ', '.join([ + 'mailto://user:pass@hotmail.com', + 'mailto://user:pass@gmail.com', + ]), + 'attach': 'https://localhost/invalid/path/to/image.png', + } + + # Send our notification + response = self.client.post('/notify', form_data) + # We fail because we couldn't retrieve our attachment + assert response.status_code == 400 + assert mock_notify.call_count == 0 + + # Reset our mock object + mock_notify.reset_mock() + + # Preare our json data (and support attach keyword as alias) + json_data = { + 'body': 'test notifiction', + 'urls': ', '.join([ + 'mailto://user:pass@hotmail.com', + 'mailto://user:pass@gmail.com', + ]), + 'attach': 'https://localhost/invalid/path/to/image.png', + } + + # Same results + response = self.client.post( + '/notify/', + data=json.dumps(json_data), + content_type='application/json', + ) + + # We fail because we couldn't retrieve our attachment + assert response.status_code == 400 + assert mock_notify.call_count == 0 + + @override_settings(APPRISE_RECURSION_MAX=1) @mock.patch('apprise.Apprise.notify') def test_stateless_notify_recursion(self, mock_notify): diff --git a/apprise_api/api/views.py b/apprise_api/api/views.py index 4696256..6f9c586 100644 --- a/apprise_api/api/views.py +++ b/apprise_api/api/views.py @@ -610,9 +610,19 @@ class NotifyView(View): # Handle Attachments attach = None - if not content.get('attachment') and 'attachment' in request.POST: - # Acquire attachments to work with them - content['attachment'] = request.POST.getlist('attachment') + if not content.get('attachment'): + if 'attachment' in request.POST: + # Acquire attachments to work with them + content['attachment'] = request.POST.getlist('attachment') + + elif 'attach' in request.POST: + # Acquire kw (alias) attach to work with them + content['attachment'] = request.POST.getlist('attach') + + elif content.get('attach'): + # Acquire kw (alias) attach from payload to work with + content['attachment'] = content['attach'] + del content['attach'] if 'attachment' in content or request.FILES: try: @@ -1029,7 +1039,7 @@ class StatelessNotifyView(View): logger.warning( 'NOTIFY - %s - Invalid FORM Payload provided', request.META['REMOTE_ADDR']) - + return HttpResponse( _('Bad FORM Payload provided.'), status=ResponseCode.bad_request) @@ -1148,9 +1158,19 @@ class StatelessNotifyView(View): # Handle Attachments attach = None - if not content.get('attachment') and 'attachment' in request.POST: - # Acquire attachments to work with them - content['attachment'] = request.POST.getlist('attachment') + if not content.get('attachment'): + if 'attachment' in request.POST: + # Acquire attachments to work with them + content['attachment'] = request.POST.getlist('attachment') + + elif 'attach' in request.POST: + # Acquire kw (alias) attach to work with them + content['attachment'] = request.POST.getlist('attach') + + elif content.get('attach'): + # Acquire kw (alias) attach from payload to work with + content['attachment'] = content['attach'] + del content['attach'] if 'attachment' in content or request.FILES: try: @@ -1158,6 +1178,11 @@ class StatelessNotifyView(View): content.get('attachment'), request.FILES) except (TypeError, ValueError): + # Invalid entry found in list + logger.warning( + 'NOTIFY - %s - Bad attachment specified', + request.META['REMOTE_ADDR']) + return HttpResponse( _('Bad attachment'), status=ResponseCode.bad_request)