diff --git a/server/src/config.rs b/server/src/config.rs index c604f73..3e43b1d 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -3,6 +3,15 @@ use std::path::PathBuf; use serde::Deserialize; +/// Per-user Whisper transcription settings from users.toml. +/// All fields optional — missing `[user.whisper]` block yields defaults (None). +#[derive(Debug, Default, Clone, Deserialize)] +pub struct WhisperUserSettings { + pub language: Option, + pub hotwords: Option, + pub initial_prompt: Option, +} + /// A single user entry from users.toml. #[derive(Debug, Deserialize)] pub struct User { @@ -10,6 +19,8 @@ pub struct User { pub api_key: String, pub web_password: String, pub role: String, + #[serde(default)] + pub whisper: WhisperUserSettings, } /// Wrapper for deserializing the [[user]] array from TOML. @@ -158,9 +169,59 @@ mod tests { api_key: api_key.into(), web_password: String::new(), role: "doctor".into(), + whisper: WhisperUserSettings::default(), } } + #[test] + fn parses_user_without_whisper_block() { + let toml_str = r#" + [[user]] + slug = "a" + api_key = "k1" + web_password = "" + role = "doctor" + "#; + let parsed: UsersFile = toml::from_str(toml_str).unwrap(); + let u = &parsed.user[0]; + assert!(u.whisper.language.is_none()); + assert!(u.whisper.hotwords.is_none()); + assert!(u.whisper.initial_prompt.is_none()); + } + + #[test] + fn parses_user_with_full_whisper_block() { + let toml_str = r#" + [[user]] + slug = "a" + api_key = "k1" + web_password = "" + role = "doctor" + [user.whisper] + language = "de" + hotwords = "HOCM Valsalva" + initial_prompt = "Kardiologie" + "#; + let parsed: UsersFile = toml::from_str(toml_str).unwrap(); + let w = &parsed.user[0].whisper; + assert_eq!(w.language.as_deref(), Some("de")); + assert_eq!(w.hotwords.as_deref(), Some("HOCM Valsalva")); + assert_eq!(w.initial_prompt.as_deref(), Some("Kardiologie")); + } + + #[test] + fn accepts_admin_role() { + let toml_str = r#" + [[user]] + slug = "root" + api_key = "k1" + web_password = "" + role = "admin" + "#; + let parsed: UsersFile = toml::from_str(toml_str).unwrap(); + assert_eq!(parsed.user[0].role, "admin"); + } + #[test] fn accepts_distinct_users() { let users = vec![u("a", "k1"), u("b", "k2")]; diff --git a/server/tests/auth_test.rs b/server/tests/auth_test.rs index ea4ae6a..2a4cba3 100644 --- a/server/tests/auth_test.rs +++ b/server/tests/auth_test.rs @@ -19,6 +19,7 @@ fn test_config() -> Arc { api_key: "test-key-123".into(), web_password: "unused".into(), role: "doctor".into(), + whisper: Default::default(), }], api_keys: HashMap::from([("test-key-123".into(), "dr_test".into())]), retention_audio_days: 30, diff --git a/server/tests/upload_test.rs b/server/tests/upload_test.rs index 7c834ea..afa0664 100644 --- a/server/tests/upload_test.rs +++ b/server/tests/upload_test.rs @@ -24,6 +24,7 @@ fn test_config() -> Arc { api_key: "test-key-123".into(), web_password: "unused".into(), role: "doctor".into(), + whisper: Default::default(), }], api_keys: HashMap::from([("test-key-123".into(), "dr_test".into())]), retention_audio_days: 30, diff --git a/server/tests/web_test.rs b/server/tests/web_test.rs index dab070b..a9a36bd 100644 --- a/server/tests/web_test.rs +++ b/server/tests/web_test.rs @@ -24,6 +24,7 @@ fn test_config() -> Arc { api_key: "test-key".into(), web_password: "unused".into(), role: "doctor".into(), + whisper: Default::default(), }], api_keys: HashMap::from([("test-key".into(), "dr_test".into())]), retention_audio_days: 30,