[verified] round-trip S5 exam layout fields
This commit is contained in:
@@ -315,11 +315,19 @@ async def get_template(
|
||||
boundaries = _rows(
|
||||
ctx.supabase.table("exam_boundaries").select("*").eq("template_id", template_id).execute()
|
||||
)
|
||||
layout = _rows(
|
||||
ctx.supabase.table("exam_template_layout")
|
||||
.select("*")
|
||||
.eq("template_id", template_id)
|
||||
.order("page_index")
|
||||
.execute()
|
||||
)
|
||||
return {
|
||||
**template,
|
||||
"questions": questions,
|
||||
"response_areas": response_areas,
|
||||
"boundaries": boundaries,
|
||||
"layout": layout,
|
||||
}
|
||||
|
||||
|
||||
@@ -412,6 +420,7 @@ async def replace_template(
|
||||
# remove them first (we delete by template_id rather than rely on cascade for predictability).
|
||||
sb.table("exam_response_areas").delete().eq("template_id", template_id).execute()
|
||||
sb.table("exam_boundaries").delete().eq("template_id", template_id).execute()
|
||||
sb.table("exam_template_layout").delete().eq("template_id", template_id).execute()
|
||||
sb.table("exam_questions").delete().eq("template_id", template_id).execute()
|
||||
|
||||
# Re-insert, preserving client-supplied UUIDs (Neo4j join keys, spec §2).
|
||||
@@ -431,6 +440,10 @@ async def replace_template(
|
||||
"spec_ref": q.spec_ref,
|
||||
"bounds": q.bounds, # drawn Part box (73); null for derived main questions
|
||||
"page": q.page,
|
||||
"source": q.source,
|
||||
"confirmed": q.confirmed,
|
||||
"confidence": q.confidence,
|
||||
"derivation": q.derivation,
|
||||
}
|
||||
if q.id:
|
||||
r["id"] = q.id
|
||||
@@ -451,6 +464,8 @@ async def replace_template(
|
||||
"source": ra.source,
|
||||
"confirmed": ra.confirmed,
|
||||
"confidence": ra.confidence,
|
||||
"mark_subtype": ra.mark_subtype,
|
||||
"derivation": ra.derivation,
|
||||
}
|
||||
if ra.id:
|
||||
r["id"] = ra.id
|
||||
@@ -469,15 +484,41 @@ async def replace_template(
|
||||
"bounds": b.bounds,
|
||||
"source": b.source,
|
||||
"confirmed": b.confirmed,
|
||||
"confidence": b.confidence,
|
||||
"derivation": b.derivation,
|
||||
}
|
||||
if b.id:
|
||||
r["id"] = b.id
|
||||
b_rows.append({k: v for k, v in r.items() if v is not None})
|
||||
sb.table("exam_boundaries").insert(b_rows).execute()
|
||||
|
||||
if body.layout:
|
||||
layout_rows = []
|
||||
for item in body.layout:
|
||||
r = {
|
||||
"template_id": template_id,
|
||||
"page_index": item.page_index,
|
||||
"role": item.role,
|
||||
"margin_left": item.margin_left,
|
||||
"margin_right": item.margin_right,
|
||||
"margin_top": item.margin_top,
|
||||
"margin_bottom": item.margin_bottom,
|
||||
"margins_enabled": item.margins_enabled,
|
||||
"source": item.source,
|
||||
"confirmed": item.confirmed,
|
||||
"confidence": item.confidence,
|
||||
"derivation": item.derivation,
|
||||
"meta": item.meta,
|
||||
}
|
||||
if item.id:
|
||||
r["id"] = item.id
|
||||
layout_rows.append({k: v for k, v in r.items() if v is not None})
|
||||
sb.table("exam_template_layout").insert(layout_rows).execute()
|
||||
|
||||
logger.info(
|
||||
f"Exam template {template_id} replaced: {len(body.questions)} questions, "
|
||||
f"{len(body.response_areas)} regions, {len(body.boundaries)} boundaries"
|
||||
f"{len(body.response_areas)} regions, {len(body.boundaries)} boundaries, "
|
||||
f"{len(body.layout)} layout rows"
|
||||
)
|
||||
# R3.5.4: a successful save enqueues a graph projection into cc.public.exams. BackgroundTasks
|
||||
# is acceptable for Sprint 4 (durability via a real queue is a later step); failures are
|
||||
|
||||
Reference in New Issue
Block a user