Refactor timestamp handling for activity sorting
Introduce `last_recording_at` to `OnelinerEntry` and use it as the primary sort key for cases. This ensures that cases with recent dictation activity are prioritized, even if their initial creation date is older. The logic for determining a case's activity has been updated to consider the most recent `.m4a` file's modification time (`last_recording_at`), falling back to `updated_at` or `created_at` if necessary. This change also refactors the timestamp formatting and handling within the web interface to correctly display and sort cases based on their actual last activity time, improving user experience and data relevance. The `now_rfc3339` function is updated to strip sub-second precision for consistent filename generation.
This commit is contained in:
@@ -363,3 +363,57 @@ async fn multiple_cases_sorted_newest_first() {
|
||||
|
||||
let _ = std::fs::remove_dir_all(&dp);
|
||||
}
|
||||
|
||||
/// Regression guard: if a case was first created long ago but got a
|
||||
/// follow-up recording today, it must sort ahead of a case whose single
|
||||
/// (older) recording happens to be newer than the first one. Sorting
|
||||
/// must use `last_recording_at`, not `created_at`.
|
||||
#[tokio::test]
|
||||
async fn sorts_by_last_recording_not_created() {
|
||||
let (config, dp) = test_config();
|
||||
|
||||
// Case A: first recording 20h ago (old created_at), second 1 min ago
|
||||
// (new last_recording_at).
|
||||
let case_a = "550e8400-e29b-41d4-a716-000000000020";
|
||||
let dir_a = dp.join(TEST_SLUG).join(case_a);
|
||||
tokio::fs::create_dir_all(&dir_a).await.unwrap();
|
||||
let old_m4a = dir_a.join("2026-04-17T12-00-00Z.m4a");
|
||||
tokio::fs::write(&old_m4a, b"x").await.unwrap();
|
||||
filetime::set_file_mtime(
|
||||
&old_m4a,
|
||||
FileTime::from_system_time(SystemTime::now() - Duration::from_secs(20 * 3600)),
|
||||
)
|
||||
.unwrap();
|
||||
let fresh_m4a = dir_a.join("2026-04-18T07-59-00Z.m4a");
|
||||
tokio::fs::write(&fresh_m4a, b"x").await.unwrap();
|
||||
filetime::set_file_mtime(
|
||||
&fresh_m4a,
|
||||
FileTime::from_system_time(SystemTime::now() - Duration::from_secs(60)),
|
||||
)
|
||||
.unwrap();
|
||||
tokio::fs::write(dir_a.join("oneliner.txt"), "A (fresh addendum)")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Case B: single recording 10h ago — created_at newer than A's, but
|
||||
// last_recording_at older than A's fresh addendum.
|
||||
seed_case(
|
||||
&dp,
|
||||
"550e8400-e29b-41d4-a716-000000000021",
|
||||
Duration::from_secs(10 * 3600),
|
||||
Some("B (single, middle-aged)"),
|
||||
)
|
||||
.await;
|
||||
|
||||
let app = doctate_server::create_router(config);
|
||||
let body = body_json(
|
||||
app.oneshot(get("/api/oneliners?hours=48")).await.unwrap(),
|
||||
)
|
||||
.await;
|
||||
let arr = body["oneliners"].as_array().unwrap();
|
||||
assert_eq!(arr.len(), 2);
|
||||
assert_eq!(arr[0]["case_id"], case_a, "A must sort first");
|
||||
assert!(arr[0]["last_recording_at"].is_string());
|
||||
|
||||
let _ = std::fs::remove_dir_all(&dp);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user