fix: Inline recording-delete confirm + stable redirects

- Replace native confirm() in the recording list with an inline
  two-step confirm row; hide the player via visibility:hidden
  while open so the row height stays stable.
- Hard-redirect recording delete back to /web/cases/{id}/recordings
  instead of relying on the Referer header (which silently fell
  back to /web/cases when stripped).
- Switch analyze/reset to a hidden return_to form field so the
  source page (case detail vs. case list) is preserved reliably,
  with same-origin /web/ prefix validation.
- Tighten delete_recording_test on the concrete Location header;
  adjust analyze/reset redirect expectations to the new
  case-detail fallback.
This commit is contained in:
2026-04-26 17:52:29 +02:00
parent 03736b6993
commit eaed8f0dcd
7 changed files with 132 additions and 19 deletions
+5 -2
View File
@@ -216,7 +216,7 @@ async fn analyze_case_happy_path_writes_input_and_redirects() {
.unwrap()
.to_str()
.unwrap(),
"/web/cases"
format!("/web/cases/{case_id}")
);
let input_path = case_dir.join(ANALYSIS_INPUT_FILE);
@@ -1190,7 +1190,10 @@ async fn reset_case_clears_derived_and_unfails_audio() {
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::SEE_OTHER);
assert_eq!(resp.headers().get(header::LOCATION).unwrap(), "/web/cases");
assert_eq!(
resp.headers().get(header::LOCATION).unwrap(),
&format!("/web/cases/{case_id}")
);
// Audio preserved, .failed renamed to .m4a.
assert!(dir.join("2026-04-15T09-00-00Z.m4a").exists());
+16
View File
@@ -54,6 +54,14 @@ async fn delete_recording_removes_file_and_sidecars_and_invalidates_derived() {
"delete should redirect (3xx), got {}",
resp.status()
);
let expected_location = format!("/web/cases/{case_id}/recordings");
assert_eq!(
resp.headers()
.get(axum::http::header::LOCATION)
.and_then(|v| v.to_str().ok()),
Some(expected_location.as_str()),
"delete should redirect back to the recording list, not the case list"
);
// Victim + its sidecars are gone.
assert!(!case_dir.join(&victim).exists(), "m4a should be deleted");
@@ -212,6 +220,14 @@ async fn delete_last_recording_clears_case() {
"last-recording delete should still redirect, got {}",
resp.status()
);
let expected_location = format!("/web/cases/{case_id}/recordings");
assert_eq!(
resp.headers()
.get(axum::http::header::LOCATION)
.and_then(|v| v.to_str().ok()),
Some(expected_location.as_str()),
"last-recording delete should still redirect to the recording list"
);
assert!(!case_dir.join(&only).exists());
assert!(!case_dir.join(ONELINER_FILENAME).exists());