feat: Add API endpoint for listing oneliners

This commit introduces a new API endpoint `/api/oneliners` that allows
authenticated users to retrieve a list of their recent oneliners.

The endpoint supports conditional GET requests using the `ETag` header
for efficient caching. It also allows specifying a time window for the
oneliners via the `hours` query parameter, with sensible defaults and
clamping.

The implementation includes:
- A new route handler `handle_oneliners`.
- A new type `OnelinerWatermark` for tracking user-specific timestamps.
- Logic for scanning user data directories, filtering by time, and
  handling deleted cases.
- Test cases to cover various scenarios, including caching, time
  windowing, and edge cases.
This commit is contained in:
2026-04-18 09:27:23 +02:00
parent 6fbb549ddf
commit 94392e72d8
10 changed files with 658 additions and 16 deletions
+8 -2
View File
@@ -288,7 +288,10 @@ async fn worker_renames_audio_to_failed_on_whisper_error() {
let client = reqwest::Client::new();
let busy = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let vocab = std::sync::Arc::new(doctate_server::gazetteer::Gazetteer::empty());
transcribe::worker::run(rx, config, client, busy, vocab).await;
let watermark: doctate_server::OnelinerWatermark = std::sync::Arc::new(
tokio::sync::RwLock::new(std::collections::HashMap::new()),
);
transcribe::worker::run(rx, config, client, busy, vocab, watermark).await;
// Audio must have been renamed so recovery skips it next time.
assert!(!audio.exists(), "original .m4a still present");
@@ -337,7 +340,10 @@ async fn transcribe_worker_normalizes_whisper_output() {
let client = reqwest::Client::new();
let busy = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
transcribe::worker::run(rx, config, client, busy, vocab).await;
let watermark: doctate_server::OnelinerWatermark = std::sync::Arc::new(
tokio::sync::RwLock::new(std::collections::HashMap::new()),
);
transcribe::worker::run(rx, config, client, busy, vocab, watermark).await;
let transcript_path = case_dir.join("2026-04-13T10-30-00Z.transcript.txt");
assert!(transcript_path.exists(), "transcript missing");