fix(web): serve closed-case recordings page instead of 404
Following "Aufnahmen anzeigen" on a closed case returned HTTP 404
{"error":"Case not found"} — an apparently empty page. handle_case_recordings
unconditionally resolved the case via locate_case_or_404, which rejects any
case carrying the .closed marker, so the recordings (which stay on disk after
a close — only a marker is written) became unreachable.
Fix mirrors handle_case_page: the handler now takes Query<CaseListQuery> and
branches to locate_closed_case_or_404 when show_closed=1 is requested, falling
back to the IDOR-guarded locate_case_or_404 otherwise. The in-app link in
case_page.html now carries ?show_closed=1 for closed cases (mirroring
my_cases.html), so navigation from a closed case's detail page no longer drops
the flag and 404s.
Reuses the existing CaseListQuery/include_closed() extractor; no parallel type.
Minimal fix, no surrounding refactor.
RED+GREEN combined: regression test case_recordings_honours_show_closed_for_closed_case
in server/tests/case_page_test.rs seeds a closed case with a recording and
asserts the route returns 200 with the recording listed, not 404. Full
case_page_test suite green (18 passed); cargo clippy clean; cargo fmt clean.
closes #17
This commit is contained in:
@@ -7,7 +7,8 @@ use doctate_common::oneliners::OnelinerState;
|
||||
|
||||
use common::{
|
||||
TestConfig, body_string, get_with_cookie, paths, seed_case, seed_oneliner_ready,
|
||||
seed_oneliner_state, seed_recording, test_admin, test_user, write_document_for_test,
|
||||
seed_oneliner_state, seed_recording, test_admin, test_user, write_closed_marker,
|
||||
write_document_for_test,
|
||||
};
|
||||
|
||||
/// Password "s" is the shared test default; wrap `login` so call sites
|
||||
@@ -351,6 +352,45 @@ async fn case_recordings_shows_all_recordings() {
|
||||
assert!(body.contains("Transkription ausstehend"));
|
||||
}
|
||||
|
||||
/// Property: the recordings sub-page must honour `?show_closed=1` exactly
|
||||
/// like the case detail page does. Closing a case only sets a `.closed`
|
||||
/// marker — the `.m4a` recordings stay on disk — so a user who opted into
|
||||
/// viewing closed cases must still be able to open the recordings list.
|
||||
///
|
||||
/// Regression for issue #17: `handle_case_recordings` resolves the case via
|
||||
/// `locate_case_or_404`, which returns `None` for any case carrying the
|
||||
/// `.closed` marker, yielding 404 `{"error":"Case not found"}` and an
|
||||
/// apparently empty page — even when `show_closed=1` is requested.
|
||||
#[tokio::test]
|
||||
async fn case_recordings_honours_show_closed_for_closed_case() {
|
||||
let cfg = TestConfig::new()
|
||||
.with_label("rec-closed")
|
||||
.with_user(test_user("dr_a"))
|
||||
.with_llm("http://unused")
|
||||
.build();
|
||||
let case_id = "11111111-1111-1111-1111-111111111111";
|
||||
let case_dir = seed_case(&cfg.data_path, "dr_a", case_id);
|
||||
seed_recording(&case_dir, "2026-04-15T10-00-00Z", Some("erste Aufnahme"));
|
||||
// Close the case: only a marker is written; the recording stays put.
|
||||
write_closed_marker(&case_dir, "2026-04-15T12:00:00Z");
|
||||
|
||||
let app = doctate_server::create_router(cfg);
|
||||
let cookie = login_dr_a(&app).await;
|
||||
|
||||
let url = format!("{}?show_closed=1", paths::case_recordings(case_id));
|
||||
let resp = app.oneshot(get_with_cookie(&url, &cookie)).await.unwrap();
|
||||
assert_eq!(
|
||||
resp.status(),
|
||||
StatusCode::OK,
|
||||
"recordings page must render for a closed case under show_closed=1, not 404",
|
||||
);
|
||||
let body = body_string(resp).await;
|
||||
assert!(
|
||||
body.contains("2026-04-15T10-00-00Z.m4a"),
|
||||
"recording still on disk must be listed for the closed case"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn case_recordings_back_link_targets_case_page() {
|
||||
let cfg = TestConfig::new()
|
||||
|
||||
Reference in New Issue
Block a user