fix(api): group create read product from multipart form (bug: 'provide product info' when no file attached)

The GroupBuilder sends the create form as multipart/form-data (FormData). The code
decided JSON vs form by checking  — when no file was attached,
request.files was empty/falsy, so it tried get_json() on a multipart body and lost the
product field -> 400 'provide product info' even though the user filled the product name.

Fix: branch on the Content-Type (multipart/form-data -> request.form) instead of
request.files. Added a regression test (multipart create with product only -> 201).
Verified live: multipart product-only create now returns 201.
This commit is contained in:
Macky
2026-08-08 09:49:24 +07:00
parent 88892be1d9
commit 55759a3a50
2 changed files with 19 additions and 3 deletions

View File

@@ -88,7 +88,10 @@ def create_group():
file.save(dest) file.save(dest)
saved_files.append(dest.name) saved_files.append(dest.name)
data = request.form.to_dict() if request.files else (request.get_json(silent=True) or {}) if request.content_type and "multipart/form-data" in request.content_type:
data = request.form.to_dict()
else:
data = request.get_json(silent=True) or {}
from ..services.file_parser import parse_document from ..services.file_parser import parse_document

View File

@@ -47,6 +47,18 @@ def main():
assert r.get_json()["group"]["status"] == "draft" assert r.get_json()["group"]["status"] == "draft"
print("[ok] group created (draft)") print("[ok] group created (draft)")
# Regression: multipart (like the frontend FormData) with product field but NO file
# attached must still create the group (was 400 'provide product info' before fix).
r = client.post(
"/api/groups",
data={"product": "Multipart Product"},
content_type="multipart/form-data",
headers=H,
)
assert r.status_code == 201, f"multipart create failed: {r.get_json()}"
assert r.get_json()["group"]["title"] == "Multipart Product"
print("[ok] group created via multipart (product only) — regression fixed")
# analyze should fail cleanly (LLM None) # analyze should fail cleanly (LLM None)
r = client.post(f"/api/groups/{gid}/analyze", headers=H) r = client.post(f"/api/groups/{gid}/analyze", headers=H)
assert r.status_code == 500, r.get_json() assert r.status_code == 500, r.get_json()
@@ -54,8 +66,9 @@ def main():
# list groups as admin # list groups as admin
r = client.get("/api/groups", headers=H) r = client.get("/api/groups", headers=H)
assert r.status_code == 200 and len(r.get_json()["groups"]) == 1 assert r.status_code == 200 and len(r.get_json()["groups"]) >= 1
print("[ok] admin lists 1 group") assert all(g["status"] == "draft" for g in r.get_json()["groups"])
print("[ok] admin lists groups")
# personas empty until analyze # personas empty until analyze
r = client.get(f"/api/groups/{gid}", headers=H) r = client.get(f"/api/groups/{gid}", headers=H)