feat(exam): persist S4-9 region kinds + Part geometry; keep metadata out of graph
api-ci-deploy / test-build-deploy (push) Has been cancelled
api-ci-deploy / test-build-deploy (push) Has been cancelled
Backend follow-on to migration 73: - schemas: ResponseAreaPayload.kind extended to response|context|question_number| mark_area|reference|furniture + context_type; QuestionPayload gains bounds+page. - PUT serialization persists Part bounds/page and region context_type. - Neo4j projection only emits Region nodes for response/context regions; the metadata kinds (question_number/mark_area/reference/furniture) are physical-layer only and stay out of cc.public.exams. - Unit test: new kinds + Part geometry + context_type round-trip. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
93972a62f7
commit
9c1aee28e2
@@ -234,6 +234,33 @@ def test_put_replace_persists_children_with_client_ids():
|
||||
assert body["boundaries"][0]["id"] == "b-uuid-1"
|
||||
|
||||
|
||||
def test_put_persists_region_kinds_and_part_geometry():
|
||||
# S4-9 taxonomy: Part box geometry on the question; new region kinds + context_type.
|
||||
store = {"exam_templates": [{"id": "t1", "title": "p", "status": "draft", "institute_id": INST_A, "teacher_id": TEACHER}]}
|
||||
client, store = make_client(store=store)
|
||||
resp = client.put("/api/exam/templates/t1", json={
|
||||
"questions": [
|
||||
{"id": "q1", "label": "01", "order": 0, "is_container": True},
|
||||
{"id": "p1", "parent_id": "q1", "label": "01.1", "order": 0, "max_marks": 3,
|
||||
"bounds": {"x": 1, "y": 2, "w": 3, "h": 4}, "page": 1},
|
||||
],
|
||||
"response_areas": [
|
||||
{"id": "r1", "question_id": "p1", "page": 1, "bounds": {"x": 1}, "kind": "response", "response_form": "lines"},
|
||||
{"id": "c1", "question_id": "p1", "page": 1, "bounds": {"x": 1}, "kind": "context", "context_type": "data_table"},
|
||||
{"id": "qn1", "question_id": "p1", "page": 1, "bounds": {"x": 1}, "kind": "question_number"},
|
||||
{"id": "m1", "question_id": "p1", "page": 1, "bounds": {"x": 1}, "kind": "mark_area"},
|
||||
{"id": "f1", "question_id": "p1", "page": 1, "bounds": {"x": 1}, "kind": "furniture"},
|
||||
],
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
part = next(q for q in store["exam_questions"] if q["id"] == "p1")
|
||||
assert part["bounds"] == {"x": 1, "y": 2, "w": 3, "h": 4} and part["page"] == 1
|
||||
ras = {r["id"]: r for r in store["exam_response_areas"]}
|
||||
assert {ras["r1"]["kind"], ras["c1"]["kind"], ras["qn1"]["kind"], ras["m1"]["kind"], ras["f1"]["kind"]} == \
|
||||
{"response", "context", "question_number", "mark_area", "furniture"}
|
||||
assert ras["c1"]["context_type"] == "data_table"
|
||||
|
||||
|
||||
def test_put_replace_clears_previous_children():
|
||||
store = {
|
||||
"exam_templates": [{"id": "t1", "title": "p", "status": "draft", "institute_id": INST_A, "teacher_id": TEACHER}],
|
||||
|
||||
Reference in New Issue
Block a user