feat(exam): template source PDF at create + GET /templates/{id}/source-pdf (S4-8.1)
Recovered from cc-worker WIP that was left uncommitted in the dev-centre clone (card t_0055b89b). Multipart source_pdf upload at create -> source_file_id; source-pdf download endpoint resolves from exam_id (catalogue) or source_file_id. NOT yet human-reviewed/merged; preserving + verifying so it isn't clobbered. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9c1aee28e2
commit
c58df6715c
@@ -136,6 +136,19 @@ class FakeSupabase:
|
||||
return FakeQuery(self.store, name)
|
||||
|
||||
|
||||
class _FakeStorageAdmin:
|
||||
def upload_file(self, *args, **kwargs):
|
||||
return None
|
||||
|
||||
def download_file(self, bucket_id, file_path):
|
||||
return b"%PDF-1.7 fake"
|
||||
|
||||
|
||||
class _FakeServiceRoleClient:
|
||||
def __init__(self, store):
|
||||
self.supabase = FakeSupabase(store)
|
||||
|
||||
|
||||
def make_client(user_id=TEACHER, institute_ids=(INST_A,), store=None):
|
||||
store = store if store is not None else {}
|
||||
app = FastAPI()
|
||||
@@ -169,6 +182,44 @@ def test_create_template_sets_owner_and_institute():
|
||||
assert row["status"] == "draft"
|
||||
|
||||
|
||||
def test_create_template_accepts_uploaded_source_pdf(monkeypatch):
|
||||
store = {}
|
||||
client, store = make_client(store=store)
|
||||
monkeypatch.setattr(templates_mod, "StorageAdmin", _FakeStorageAdmin)
|
||||
monkeypatch.setattr(templates_mod, "SupabaseServiceRoleClient", lambda: _FakeServiceRoleClient(store))
|
||||
|
||||
resp = client.post(
|
||||
"/api/exam/templates",
|
||||
data={"title": "AQA Physics 1H", "subject": "Physics"},
|
||||
files={"source_pdf": ("paper.pdf", b"%PDF-1.7 test", "application/pdf")},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
row = resp.json()
|
||||
assert row["source_file_id"] is not None
|
||||
assert store["files"][0]["id"] == row["source_file_id"]
|
||||
assert store["files"][0]["uploaded_by"] == TEACHER
|
||||
|
||||
|
||||
def test_get_template_source_pdf_from_uploaded_file(monkeypatch):
|
||||
store = {
|
||||
"exam_templates": [{
|
||||
"id": "t1",
|
||||
"title": "p",
|
||||
"status": "draft",
|
||||
"institute_id": INST_A,
|
||||
"teacher_id": TEACHER,
|
||||
"source_file_id": "f1",
|
||||
}],
|
||||
"files": [{"id": "f1", "bucket": "cc.users", "path": "exam-marker/cab1/f1/paper.pdf", "name": "paper.pdf"}],
|
||||
}
|
||||
client, _ = make_client(store=store)
|
||||
monkeypatch.setattr(templates_mod, "StorageAdmin", _FakeStorageAdmin)
|
||||
resp = client.get("/api/exam/templates/t1/source-pdf")
|
||||
assert resp.status_code == 200
|
||||
assert resp.headers["content-type"].startswith("application/pdf")
|
||||
assert resp.content.startswith(b"%PDF-1.7")
|
||||
|
||||
|
||||
def test_create_template_rejects_foreign_institute():
|
||||
client, _ = make_client(institute_ids=(INST_A,))
|
||||
resp = client.post("/api/exam/templates", json={"title": "X", "institute_id": INST_B})
|
||||
|
||||
Reference in New Issue
Block a user