Enhancement: allow specifying JSON encoding for webhooks (#8799)

This commit is contained in:
shamoon
2025-01-18 12:19:50 -08:00
committed by GitHub
parent cd50f20a20
commit ed1775e689
9 changed files with 99 additions and 8 deletions

View File

@@ -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"),
),
]

View File

@@ -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,

View File

@@ -1876,6 +1876,7 @@ class WorkflowActionWebhookSerializer(serializers.ModelSerializer):
"id",
"url",
"use_params",
"as_json",
"params",
"body",
"headers",

View File

@@ -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",

View File

@@ -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"