first commit

This commit is contained in:
2026-07-11 23:54:36 +07:00
commit b07562921b
40 changed files with 3813 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
from reporting.transports.file import FileTransport
from reporting.transports.webhook import WebhookTransport
__all__ = ["FileTransport", "WebhookTransport"]

View 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)

View 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