Finish Schoolhouse programming submission flow

This commit is contained in:
Fizzlepoof
2026-05-16 19:13:10 +00:00
parent 1aa4b16eef
commit 754e98c6a5
15 changed files with 753 additions and 74 deletions

View File

@@ -6,8 +6,7 @@ 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}"
def _multipart_parts_for_fields(self, boundary: str, fields: dict[str, str]) -> list[bytes]:
parts: list[bytes] = []
for key, value in fields.items():
parts.extend([
@@ -16,16 +15,32 @@ class WebhookService:
str(value).encode(),
b"\r\n",
])
return parts
def _multipart_parts_for_file(self, boundary: str, file_field: str, file_path: str) -> list[bytes]:
path = Path(file_path)
mime = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
parts.extend([
return [
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(),
])
]
def _multipart_body(self, fields: dict[str, str], file_field: str, file_path: str) -> tuple[bytes, str]:
boundary = f"----DorisSchoolhouse{uuid.uuid4().hex}"
parts = self._multipart_parts_for_fields(boundary, fields)
parts.extend(self._multipart_parts_for_file(boundary, file_field, file_path))
parts.append(f"--{boundary}--\r\n".encode())
return b"".join(parts), boundary
def _multipart_body_many(self, fields: dict[str, str], file_field: str, file_paths: list[str]) -> tuple[bytes, str]:
boundary = f"----DorisSchoolhouse{uuid.uuid4().hex}"
parts = self._multipart_parts_for_fields(boundary, fields)
for file_path in file_paths:
parts.extend(self._multipart_parts_for_file(boundary, file_field, file_path))
parts.append(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:
@@ -50,3 +65,26 @@ class WebhookService:
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)}
def post_multipart_many(self, url: str, fields: dict[str, str], file_field: str, file_paths: list[str]) -> dict:
body, boundary = self._multipart_body_many(fields, file_field, file_paths)
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)}