mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Enhancement: allow specifying JSON encoding for webhooks (#8799)
This commit is contained in:
		| @@ -0,0 +1,18 @@ | ||||
| # Generated by Django 5.1.4 on 2025-01-18 19:35 | ||||
|  | ||||
| from django.db import migrations | ||||
| from django.db import models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("documents", "1060_alter_customfieldinstance_value_select"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name="workflowactionwebhook", | ||||
|             name="as_json", | ||||
|             field=models.BooleanField(default=False, verbose_name="send as JSON"), | ||||
|         ), | ||||
|     ] | ||||
| @@ -1209,6 +1209,11 @@ class WorkflowActionWebhook(models.Model): | ||||
|         verbose_name=_("use parameters"), | ||||
|     ) | ||||
|  | ||||
|     as_json = models.BooleanField( | ||||
|         default=False, | ||||
|         verbose_name=_("send as JSON"), | ||||
|     ) | ||||
|  | ||||
|     params = models.JSONField( | ||||
|         _("webhook parameters"), | ||||
|         null=True, | ||||
|   | ||||
| @@ -1876,6 +1876,7 @@ class WorkflowActionWebhookSerializer(serializers.ModelSerializer): | ||||
|             "id", | ||||
|             "url", | ||||
|             "use_params", | ||||
|             "as_json", | ||||
|             "params", | ||||
|             "body", | ||||
|             "headers", | ||||
|   | ||||
| @@ -573,14 +573,29 @@ def run_workflows_updated(sender, document: Document, logging_group=None, **kwar | ||||
|     max_retries=3, | ||||
|     throws=(httpx.HTTPError,), | ||||
| ) | ||||
| def send_webhook(url, data, headers, files): | ||||
| def send_webhook( | ||||
|     url: str, | ||||
|     data: str | dict, | ||||
|     headers: dict, | ||||
|     files: dict, | ||||
|     *, | ||||
|     as_json: bool = False, | ||||
| ): | ||||
|     try: | ||||
|         httpx.post( | ||||
|             url, | ||||
|             data=data, | ||||
|             files=files, | ||||
|             headers=headers, | ||||
|         ).raise_for_status() | ||||
|         if as_json: | ||||
|             httpx.post( | ||||
|                 url, | ||||
|                 json=data, | ||||
|                 files=files, | ||||
|                 headers=headers, | ||||
|             ).raise_for_status() | ||||
|         else: | ||||
|             httpx.post( | ||||
|                 url, | ||||
|                 data=data, | ||||
|                 files=files, | ||||
|                 headers=headers, | ||||
|             ).raise_for_status() | ||||
|         logger.info( | ||||
|             f"Webhook sent to {url}", | ||||
|         ) | ||||
| @@ -1092,6 +1107,7 @@ def run_workflows( | ||||
|                 data=data, | ||||
|                 headers=headers, | ||||
|                 files=files, | ||||
|                 as_json=action.webhook.as_json, | ||||
|             ) | ||||
|             logger.debug( | ||||
|                 f"Webhook to {action.webhook.url} queued", | ||||
|   | ||||
| @@ -11,6 +11,7 @@ from guardian.shortcuts import assign_perm | ||||
| from guardian.shortcuts import get_groups_with_perms | ||||
| from guardian.shortcuts import get_users_with_perms | ||||
| from httpx import HTTPStatusError | ||||
| from pytest_httpx import HTTPXMock | ||||
| from rest_framework.test import APITestCase | ||||
|  | ||||
| from documents.signals.handlers import run_workflows | ||||
| @@ -2407,6 +2408,7 @@ class TestWorkflows( | ||||
|             data=f"Test message: http://localhost:8000/documents/{doc.id}/", | ||||
|             headers={}, | ||||
|             files=None, | ||||
|             as_json=False, | ||||
|         ) | ||||
|  | ||||
|     @override_settings( | ||||
| @@ -2468,6 +2470,7 @@ class TestWorkflows( | ||||
|             data=f"Test message: http://localhost:8000/documents/{doc.id}/", | ||||
|             headers={}, | ||||
|             files={"file": ("simple.pdf", mock.ANY, "application/pdf")}, | ||||
|             as_json=False, | ||||
|         ) | ||||
|  | ||||
|     @override_settings( | ||||
| @@ -2669,3 +2672,43 @@ class TestWorkflows( | ||||
|                 ) | ||||
|  | ||||
|         mock_post.assert_called_once() | ||||
|  | ||||
|  | ||||
| class TestWebhookSend: | ||||
|     def test_send_webhook_data_or_json( | ||||
|         self, | ||||
|         httpx_mock: HTTPXMock, | ||||
|     ): | ||||
|         """ | ||||
|         GIVEN: | ||||
|             - Nothing | ||||
|         WHEN: | ||||
|             - send_webhook is called with data or dict | ||||
|         THEN: | ||||
|             - data is sent as form-encoded and json, respectively | ||||
|         """ | ||||
|         httpx_mock.add_response( | ||||
|             content=b"ok", | ||||
|         ) | ||||
|  | ||||
|         send_webhook( | ||||
|             url="http://paperless-ngx.com", | ||||
|             data="Test message", | ||||
|             headers={}, | ||||
|             files=None, | ||||
|             as_json=False, | ||||
|         ) | ||||
|         assert httpx_mock.get_request().headers.get("Content-Type") is None | ||||
|         httpx_mock.reset() | ||||
|  | ||||
|         httpx_mock.add_response( | ||||
|             json={"status": "ok"}, | ||||
|         ) | ||||
|         send_webhook( | ||||
|             url="http://paperless-ngx.com", | ||||
|             data={"message": "Test message"}, | ||||
|             headers={}, | ||||
|             files=None, | ||||
|             as_json=True, | ||||
|         ) | ||||
|         assert httpx_mock.get_request().headers["Content-Type"] == "application/json" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon