mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
Refuse an export nobody scoped, and stop naming UCUM without a code
Two findings from the deferred-audit list, both live since July. A FHIR lab quantity stamped the UCUM system unconditionally while the code was only added when the analyte map resolved a symbol for exactly that unit. A receiver was told the unit came from UCUM and then handed no UCUM code, which is a coding claim the bundle cannot back. System and code now travel together, on the value and on both reference-range bounds. The doctor-report export accepted a selection that admits nothing. The panel disables its own submit in that state, so only a hand-built request reached it, and it rendered an empty artefact while spending a rate-limit slot. This route has no documents-only mode that would make an empty leaf list a legitimate scope, so it refuses with 422. The share-link route, which does have that mode, is untouched.
This commit is contained in:
1 parent
d2491d5589
commit
09446846b1
4 files changed
+60
-16
No files matched your search
@@ -205,6 +205,18 @@ describe("POST /api/export/health-record — validation", () => {
|
||||
expect(res.status).toBe(422);
|
||||
});
|
||||
|
||||
it("rejects a selection that admits nothing with 422", async () => {
|
||||
// The panel disables its own submit in that state, so only a hand-built
|
||||
// request gets here. Rendering an empty report and spending a rate-limit
|
||||
// slot on it would be the wrong answer; this route has no documents-only
|
||||
// mode that would make an empty leaf list a legitimate scope.
|
||||
const { POST } = await import("../route");
|
||||
const res = await POST(mkReq({ format: "pdf", selection: sel() }));
|
||||
expect(res.status).toBe(422);
|
||||
const body = (await res.json()) as { meta?: { errorCode?: string } };
|
||||
expect(body.meta?.errorCode).toBe("export.selection.empty");
|
||||
});
|
||||
|
||||
it("rejects a userId smuggled into the body with 422", async () => {
|
||||
const { POST } = await import("../route");
|
||||
const res = await POST(
|
||||
@@ -540,15 +552,11 @@ describe("POST /api/export/health-record — the selection reaches every format"
|
||||
// leaves: the totals must stay in the database.
|
||||
expect(await observationCodes(sel("LAB_RESULTS"))).toEqual([]);
|
||||
// And an empty selection — the "I said nothing" case, which used to mean
|
||||
// "give me everything".
|
||||
// "give me everything" and is now refused outright, so the totals cannot
|
||||
// ride out on a scope nobody chose.
|
||||
const { POST } = await import("../route");
|
||||
const res = await POST(mkReq({ format: "fhir", selection: sel() }));
|
||||
const bundle = (await res.json()) as {
|
||||
entry: { resource: { resourceType: string } }[];
|
||||
};
|
||||
expect(
|
||||
bundle.entry.filter((e) => e.resource.resourceType === "Observation"),
|
||||
).toEqual([]);
|
||||
expect(res.status).toBe(422);
|
||||
|
||||
// Asked for by name, they are emitted — the data is withheld, not lost.
|
||||
const asked = await observationCodes(sel("PHQ9_SCORE", "GAD7_SCORE"));
|
||||
|
||||
@@ -129,6 +129,17 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
);
|
||||
}
|
||||
const selection = minted.selection;
|
||||
// A selection that admits nothing would render an empty report and still
|
||||
// spend a rate-limit slot on it. The panel disables its own submit button
|
||||
// in that state; a hand-built request has to be refused here, because this
|
||||
// route has no documents-only mode that would make an empty leaf list a
|
||||
// legitimate scope (the share-link route, which does, mints EMPTY itself).
|
||||
if (selection.leaves.length === 0) {
|
||||
annotate({ meta: { empty_selection: true } });
|
||||
return apiError("Select at least one section to export", 422, {
|
||||
errorCode: "export.selection.empty",
|
||||
});
|
||||
}
|
||||
|
||||
const range = normaliseDateRange(input.range ?? undefined);
|
||||
const practiceName = sanitisePracticeName(input.practiceName);
|
||||
|
||||
Reference in new issue
Block a user