Skip to content

Commit 225026a

Browse files
committed
Squashed commit of the following:
commit 8aa15db Author: Trenton Holmes <[email protected]> Date: Thu Jan 11 08:42:01 2024 -0800 Adds support for the Gotenberg webhooks
1 parent 996c650 commit 225026a

File tree

5 files changed

+117
-4
lines changed

5 files changed

+117
-4
lines changed

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ repos:
3939
exclude: "(^Pipfile\\.lock$)"
4040
# Python hooks
4141
- repo: https://github.com/astral-sh/ruff-pre-commit
42-
rev: 'v0.1.6'
42+
rev: 'v0.1.11'
4343
hooks:
4444
- id: ruff
45-
- repo: https://github.com/psf/black
46-
rev: 23.11.0
45+
- repo: https://github.com/psf/black-pre-commit-mirror
46+
rev: 23.12.1
4747
hooks:
4848
- id: black

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Documentation site built with Github Pages and Material for MkDocs
1313
- New method `.run_with_retry` for routes, which allows the route to be rerun as configured, with progressive backoff if the server returns a server error
14+
- Support for Gotenberg [Webhooks](https://gotenberg.dev/docs/webhook)
15+
16+
### Deprecated
17+
18+
- Support for Gotenberg 7.x. This will likely be the last release to support 7.x, as the options for PDF/A have been changed
1419

1520
## [0.4.1] - 2023-12-11
1621

src/gotenberg_client/_client.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from gotenberg_client._health import HealthCheckApi
1616
from gotenberg_client._merge import MergeApi
1717
from gotenberg_client._typing_compat import Self
18+
from gotenberg_client.options import HttpMethods
1819

1920

2021
class GotenbergClient:
@@ -44,12 +45,44 @@ def __init__(
4445
self.merge = MergeApi(self._client)
4546
self.health = HealthCheckApi(self._client)
4647

47-
def add_headers(self, header: Dict[str, str]) -> None: # pragma: no cover
48+
def add_headers(self, header: Dict[str, str]) -> None:
4849
"""
4950
Updates the httpx Client headers with the given values
5051
"""
5152
self._client.headers.update(header)
5253

54+
def add_webhook_url(self, url: str) -> None:
55+
"""
56+
Adds the webhook URL to the headers
57+
"""
58+
self.add_headers({"Gotenberg-Webhook-Url": url})
59+
60+
def add_error_webhook_url(self, url: str) -> None:
61+
"""
62+
Adds the webhook error URL to the headers
63+
"""
64+
self.add_headers({"Gotenberg-Webhook-Error-Url": url})
65+
66+
def set_webhook_http_method(self, method: HttpMethods = "PUT") -> None:
67+
"""
68+
Sets the HTTP method Gotenberg will use to call the hooks
69+
"""
70+
self.add_headers({"Gotenberg-Webhook-Method": method})
71+
72+
def set_error_webhook_http_method(self, method: HttpMethods = "PUT") -> None:
73+
"""
74+
Sets the HTTP method Gotenberg will use to call the hooks
75+
"""
76+
self.add_headers({"Gotenberg-Webhook-Error-Method": method})
77+
78+
def set_webhook_extra_headers(self, extra_headers: Dict[str, str]) -> None:
79+
"""
80+
Sets the HTTP method Gotenberg will use to call the hooks
81+
"""
82+
from json import dumps
83+
84+
self.add_headers({"Gotenberg-Webhook-Extra-Http-Headers": dumps(extra_headers)})
85+
5386
def __enter__(self) -> Self:
5487
return self
5588

src/gotenberg_client/options.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import enum
66
from typing import Dict
77
from typing import Final
8+
from typing import Literal
89
from typing import Optional
910
from typing import Union
1011

@@ -102,3 +103,6 @@ def to_form(self) -> Dict[str, str]:
102103
return {"emulatedMediaType": "screen"}
103104
else: # pragma: no cover
104105
raise NotImplementedError(self.value)
106+
107+
108+
HttpMethods = Literal["POST", "PATCH", "PUT"]

tests/test_misc_stuff.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import shutil
22
import tempfile
33
import uuid
4+
from json import dumps
5+
from json import loads
46
from pathlib import Path
57

68
import pytest
79
from httpx import HTTPStatusError
10+
from httpx import Request
811
from httpx import codes
912
from pytest_httpx import HTTPXMock
1013

@@ -105,3 +108,71 @@ def test_not_a_server_error(self, client: GotenbergClient, httpx_mock: HTTPXMock
105108
with pytest.raises(HTTPStatusError) as exc_info:
106109
_ = route.index(test_file).run_with_retry(initial_retry_wait=0.1, retry_scale=0.1)
107110
assert exc_info.value.response.status_code == codes.NOT_FOUND
111+
112+
113+
class TestWebhookHeaders:
114+
def test_webhook_basic_headers(self, client: GotenbergClient, httpx_mock: HTTPXMock):
115+
httpx_mock.add_response(method="POST", status_code=codes.OK)
116+
117+
client.add_webhook_url("http://myapi:3000/on-success")
118+
client.add_error_webhook_url("http://myapi:3000/on-error")
119+
120+
test_file = SAMPLE_DIR / "basic.html"
121+
with client.chromium.html_to_pdf() as route:
122+
_ = route.index(test_file).run_with_retry()
123+
124+
requests = httpx_mock.get_requests()
125+
126+
assert len(requests) == 1
127+
128+
request: Request = requests[0]
129+
130+
assert "Gotenberg-Webhook-Url" in request.headers
131+
assert request.headers["Gotenberg-Webhook-Url"] == "http://myapi:3000/on-success"
132+
assert "Gotenberg-Webhook-Error-Url" in request.headers
133+
assert request.headers["Gotenberg-Webhook-Error-Url"] == "http://myapi:3000/on-error"
134+
135+
def test_webhook_http_methods(self, client: GotenbergClient, httpx_mock: HTTPXMock):
136+
httpx_mock.add_response(method="POST", status_code=codes.OK)
137+
138+
client.add_webhook_url("http://myapi:3000/on-success")
139+
client.set_webhook_http_method("POST")
140+
client.add_error_webhook_url("http://myapi:3000/on-error")
141+
client.set_error_webhook_http_method("GET")
142+
143+
test_file = SAMPLE_DIR / "basic.html"
144+
with client.chromium.html_to_pdf() as route:
145+
_ = route.index(test_file).run_with_retry()
146+
147+
requests = httpx_mock.get_requests()
148+
149+
assert len(requests) == 1
150+
151+
request: Request = requests[0]
152+
153+
assert "Gotenberg-Webhook-Method" in request.headers
154+
assert request.headers["Gotenberg-Webhook-Method"] == "POST"
155+
assert "Gotenberg-Webhook-Error-Method" in request.headers
156+
assert request.headers["Gotenberg-Webhook-Error-Method"] == "GET"
157+
158+
def test_webhook_extra_headers(self, client: GotenbergClient, httpx_mock: HTTPXMock):
159+
httpx_mock.add_response(method="POST", status_code=codes.OK)
160+
161+
headers = {"Token": "mytokenvalue"}
162+
headers_str = dumps(headers)
163+
164+
client.set_webhook_extra_headers(headers)
165+
166+
test_file = SAMPLE_DIR / "basic.html"
167+
with client.chromium.html_to_pdf() as route:
168+
_ = route.index(test_file).run_with_retry()
169+
170+
requests = httpx_mock.get_requests()
171+
172+
assert len(requests) == 1
173+
174+
request: Request = requests[0]
175+
176+
assert "Gotenberg-Webhook-Extra-Http-Headers" in request.headers
177+
assert request.headers["Gotenberg-Webhook-Extra-Http-Headers"] == headers_str
178+
assert loads(request.headers["Gotenberg-Webhook-Extra-Http-Headers"]) == headers

0 commit comments

Comments
 (0)