feat: add explicit media review workflow
CI / backend-and-migrations (push) Canceled after 0s
CI / astro-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
CI / compose-e2e (push) Canceled after 0s

This commit is contained in:
ik
2026-09-12 15:55:39 +07:00
parent 26724c7675
commit 215af73388
5 changed files with 54 additions and 4 deletions
+25
View File
@@ -95,6 +95,31 @@ def reclassify_manifest(path: Path) -> dict:
return manifest
def review_asset(
path: Path, *, asset_url: str, decision: str, entity_type: str | None = None,
entity_key: str | None = None, note: str | None = None,
) -> dict:
if decision not in {"approved", "rejected"}:
raise ValueError("decision must be approved or rejected")
manifest = json.loads(path.read_text(encoding="utf-8"))
item = next((asset for asset in manifest.get("assets", []) if asset["asset_url"] == asset_url), None)
if item is None:
raise ValueError("asset URL is not present in manifest")
if decision == "approved":
if item.get("status") != "stored":
raise ValueError("only a stored asset can be approved")
if entity_type not in {"fish", "waterbody", "tackle", "reference"} or not entity_key:
raise ValueError("approved asset requires entity type and canonical key")
item.update({"entity_type": entity_type, "entity_key": entity_key})
item.update({
"status": decision,
"reviewed_at": datetime.now(timezone.utc).isoformat(),
"review_note": note or None,
})
path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
return item
def inspect_image(body: bytes) -> tuple[int, int, str]:
try:
with Image.open(io.BytesIO(body)) as image: