Refactor: Use doctate-common for shared logic
Moves shared types and utility functions to a new `doctate-common` crate. This includes: - API key header constant - AckResponse and AckStatus types - Timestamp formatting and parsing utilities This change centralizes common functionality, reducing duplication and improving maintainability. The `server` crate now depends on `doctate-common`.
This commit is contained in:
@@ -10,6 +10,8 @@ use time::OffsetDateTime;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tracing::{info, warn};
|
||||
|
||||
use doctate_common::timestamp::{filename_stem_to_recorded_at, now_rfc3339};
|
||||
|
||||
use crate::analyze::{
|
||||
AnalysisInput, AnalyzeJob, AnalyzeSender, RecordingInput, ANALYSIS_INPUT_FILE, DOCUMENT_FILE,
|
||||
};
|
||||
@@ -229,16 +231,6 @@ pub(crate) async fn write_input_create_new(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reverse the filesystem-safe timestamp mapping applied in `upload.rs`:
|
||||
/// `:` in the time portion was replaced with `-`. Split at `T`, undo hyphens
|
||||
/// only in the time part to avoid touching date hyphens.
|
||||
fn filename_stem_to_recorded_at(stem: &str) -> String {
|
||||
match stem.split_once('T') {
|
||||
Some((date, time)) => format!("{}T{}", date, time.replace('-', ":")),
|
||||
None => stem.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Read `case_dir/document.md`. Returns `None` if no document exists.
|
||||
pub(crate) async fn read_document(case_dir: &Path) -> Option<String> {
|
||||
tokio::fs::read_to_string(case_dir.join(DOCUMENT_FILE)).await.ok()
|
||||
@@ -295,7 +287,7 @@ pub async fn handle_delete_case(
|
||||
|
||||
let marker = DeleteMarker {
|
||||
batch: uuid::Uuid::new_v4(),
|
||||
deleted_at: now_rfc3339()?,
|
||||
deleted_at: now_rfc3339(),
|
||||
};
|
||||
write_delete_marker(&case_dir, &marker).await?;
|
||||
|
||||
@@ -444,28 +436,3 @@ async fn restore_batch(user_root: &Path, batch: uuid::Uuid) -> usize {
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn now_rfc3339() -> Result<String, AppError> {
|
||||
OffsetDateTime::now_utc()
|
||||
.format(&Rfc3339)
|
||||
.map_err(|e| AppError::Internal(format!("format timestamp: {e}")))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn filename_stem_roundtrip() {
|
||||
assert_eq!(
|
||||
filename_stem_to_recorded_at("2026-04-15T10-32-00Z"),
|
||||
"2026-04-15T10:32:00Z"
|
||||
);
|
||||
// Date-only hyphens are preserved.
|
||||
assert_eq!(
|
||||
filename_stem_to_recorded_at("2026-04-15T10-32-00.123Z"),
|
||||
"2026-04-15T10:32:00.123Z"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use axum::extract::{Multipart, State};
|
||||
use axum::Json;
|
||||
use doctate_common::timestamp::recorded_at_to_filename_stem;
|
||||
use tokio::sync::mpsc::error::TrySendError;
|
||||
use tracing::{info, warn};
|
||||
|
||||
@@ -72,7 +73,7 @@ pub async fn handle_upload(
|
||||
let case_dir = resolve_case_dir(&user.data_dir, &case_id).await?;
|
||||
|
||||
// Build a filesystem-safe filename from the timestamp (colons → hyphens).
|
||||
let safe_timestamp = recorded_at.replace(':', "-");
|
||||
let safe_timestamp = recorded_at_to_filename_stem(&recorded_at);
|
||||
let file_path = case_dir.join(format!("{safe_timestamp}.m4a"));
|
||||
|
||||
tokio::fs::write(&file_path, &audio).await?;
|
||||
|
||||
Reference in New Issue
Block a user