53 lines
2.0 KiB
Python
53 lines
2.0 KiB
Python
import json
|
|
import mimetypes
|
|
import uuid
|
|
from pathlib import Path
|
|
from urllib import error, request
|
|
|
|
|
|
class WebhookService:
|
|
def _multipart_body(self, fields: dict[str, str], file_field: str, file_path: str) -> tuple[bytes, str]:
|
|
boundary = f"----DorisSchoolhouse{uuid.uuid4().hex}"
|
|
parts: list[bytes] = []
|
|
for key, value in fields.items():
|
|
parts.extend([
|
|
f"--{boundary}\r\n".encode(),
|
|
f'Content-Disposition: form-data; name="{key}"\r\n\r\n'.encode(),
|
|
str(value).encode(),
|
|
b"\r\n",
|
|
])
|
|
path = Path(file_path)
|
|
mime = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
|
|
parts.extend([
|
|
f"--{boundary}\r\n".encode(),
|
|
f'Content-Disposition: form-data; name="{file_field}"; filename="{path.name}"\r\n'.encode(),
|
|
f"Content-Type: {mime}\r\n\r\n".encode(),
|
|
path.read_bytes(),
|
|
b"\r\n",
|
|
f"--{boundary}--\r\n".encode(),
|
|
])
|
|
return b"".join(parts), boundary
|
|
|
|
def post_multipart(self, url: str, fields: dict[str, str], file_field: str, file_path: str) -> dict:
|
|
body, boundary = self._multipart_body(fields, file_field, file_path)
|
|
req = request.Request(
|
|
url,
|
|
data=body,
|
|
headers={"Content-Type": f"multipart/form-data; boundary={boundary}"},
|
|
method="POST",
|
|
)
|
|
|
|
def parse_raw(raw: str):
|
|
try:
|
|
return json.loads(raw)
|
|
except Exception:
|
|
return {"raw": raw}
|
|
|
|
try:
|
|
with request.urlopen(req, timeout=120) as response:
|
|
raw = response.read().decode("utf-8", errors="replace")
|
|
return {"ok": True, "status_code": response.status, "body": parse_raw(raw)}
|
|
except error.HTTPError as exc:
|
|
raw = exc.read().decode("utf-8", errors="replace")
|
|
return {"ok": False, "status_code": exc.code, "body": parse_raw(raw), "error": str(exc)}
|