first commit
This commit is contained in:
4
reporting/transports/__init__.py
Normal file
4
reporting/transports/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from reporting.transports.file import FileTransport
|
||||
from reporting.transports.webhook import WebhookTransport
|
||||
|
||||
__all__ = ["FileTransport", "WebhookTransport"]
|
||||
25
reporting/transports/file.py
Normal file
25
reporting/transports/file.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from core.base import TypedTransport
|
||||
from reporting.models import RenderedReport
|
||||
|
||||
|
||||
class FileTransportConfig(BaseModel):
|
||||
path: str = Field()
|
||||
append_extension: bool = Field(True)
|
||||
|
||||
|
||||
class FileTransport(TypedTransport[FileTransportConfig]):
|
||||
transport_type = "file"
|
||||
config_model = FileTransportConfig
|
||||
|
||||
def publish_typed(self, rendered_report: RenderedReport, transport: FileTransportConfig) -> str:
|
||||
destination = Path(transport.path)
|
||||
if transport.append_extension and not destination.suffix:
|
||||
destination = destination.with_suffix(rendered_report.file_extension)
|
||||
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
destination.write_text(rendered_report.content, encoding="utf-8")
|
||||
return str(destination)
|
||||
69
reporting/transports/webhook.py
Normal file
69
reporting/transports/webhook.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import json
|
||||
from enum import StrEnum
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from pydantic import AnyHttpUrl, BaseModel, Field
|
||||
|
||||
from core.base import TypedTransport
|
||||
from reporting.models import RenderedReport
|
||||
|
||||
|
||||
class WebhookMethod(StrEnum):
|
||||
POST = "POST"
|
||||
PUT = "PUT"
|
||||
PATCH = "PATCH"
|
||||
|
||||
|
||||
class WebhookPayloadMode(StrEnum):
|
||||
RENDERED = "rendered"
|
||||
ENVELOPE = "envelope"
|
||||
|
||||
|
||||
class WebhookTransportConfig(BaseModel):
|
||||
url: AnyHttpUrl = Field()
|
||||
method: WebhookMethod = Field(WebhookMethod.POST)
|
||||
headers: dict[str, str] = Field(default_factory=dict)
|
||||
timeout_seconds: float = Field(10.0, gt=0)
|
||||
payload_mode: WebhookPayloadMode = Field(WebhookPayloadMode.RENDERED)
|
||||
|
||||
|
||||
class WebhookTransport(TypedTransport[WebhookTransportConfig]):
|
||||
transport_type = "webhook"
|
||||
config_model = WebhookTransportConfig
|
||||
|
||||
def publish_typed(
|
||||
self, rendered_report: RenderedReport, transport: WebhookTransportConfig
|
||||
) -> str:
|
||||
body, headers = self._build_request(rendered_report, transport)
|
||||
request = Request(
|
||||
url=str(transport.url),
|
||||
data=body,
|
||||
headers=headers,
|
||||
method=transport.method.value,
|
||||
)
|
||||
|
||||
with urlopen(request, timeout=transport.timeout_seconds) as response:
|
||||
return f"{response.status} {transport.url}"
|
||||
|
||||
def _build_request(
|
||||
self,
|
||||
rendered_report: RenderedReport,
|
||||
transport: WebhookTransportConfig,
|
||||
) -> tuple[bytes, dict[str, str]]:
|
||||
headers = dict(transport.headers)
|
||||
|
||||
if transport.payload_mode is WebhookPayloadMode.ENVELOPE:
|
||||
payload = json.dumps(
|
||||
{
|
||||
"format": rendered_report.format_name,
|
||||
"content_type": rendered_report.media_type,
|
||||
"file_extension": rendered_report.file_extension,
|
||||
"content": rendered_report.content,
|
||||
},
|
||||
ensure_ascii=True,
|
||||
).encode("utf-8")
|
||||
headers.setdefault("Content-Type", "application/json")
|
||||
return payload, headers
|
||||
|
||||
headers.setdefault("Content-Type", rendered_report.media_type)
|
||||
return rendered_report.content.encode("utf-8"), headers
|
||||
Reference in New Issue
Block a user