feat: add per-user retention settings to users.toml
New [user.retention] TOML sub-block with auto_close_days and auto_delete_days. Both default to 0, which disables the respective sweep — a conservative default that preserves current behaviour for existing deployments and lets admins test auto-close in isolation. Only parsing + the test User literals are touched here; the actual lazy sweep consuming these values lands in the next commit.
This commit is contained in:
@@ -12,6 +12,20 @@ pub struct WhisperUserSettings {
|
||||
pub initial_prompt: Option<String>,
|
||||
}
|
||||
|
||||
/// Per-user retention settings from users.toml.
|
||||
///
|
||||
/// `auto_close_days = 0` disables the auto-close sweep (a case is never
|
||||
/// closed for age alone). `auto_delete_days = 0` disables the auto-purge
|
||||
/// sweep (closed cases stay forever until manual purge) — important for
|
||||
/// admin / dev setups where data must survive across restarts.
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
pub struct RetentionUserSettings {
|
||||
#[serde(default)]
|
||||
pub auto_close_days: u32,
|
||||
#[serde(default)]
|
||||
pub auto_delete_days: u32,
|
||||
}
|
||||
|
||||
/// A single user entry from users.toml.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct User {
|
||||
@@ -21,6 +35,8 @@ pub struct User {
|
||||
pub role: String,
|
||||
#[serde(default)]
|
||||
pub whisper: WhisperUserSettings,
|
||||
#[serde(default)]
|
||||
pub retention: RetentionUserSettings,
|
||||
}
|
||||
|
||||
/// Wrapper for deserializing the [[user]] array from TOML.
|
||||
@@ -258,6 +274,7 @@ mod tests {
|
||||
web_password: String::new(),
|
||||
role: "doctor".into(),
|
||||
whisper: WhisperUserSettings::default(),
|
||||
retention: RetentionUserSettings::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,6 +294,60 @@ mod tests {
|
||||
assert!(u.whisper.initial_prompt.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_user_without_retention_block_defaults_to_zero() {
|
||||
let toml_str = r#"
|
||||
[[user]]
|
||||
slug = "a"
|
||||
api_key = "k1"
|
||||
web_password = ""
|
||||
role = "doctor"
|
||||
"#;
|
||||
let parsed: UsersFile = toml::from_str(toml_str).unwrap();
|
||||
let r = &parsed.user[0].retention;
|
||||
// Both zero means "feature disabled", matching the pre-migration
|
||||
// status quo — no case is ever auto-closed or auto-purged.
|
||||
assert_eq!(r.auto_close_days, 0);
|
||||
assert_eq!(r.auto_delete_days, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_user_with_retention_block() {
|
||||
let toml_str = r#"
|
||||
[[user]]
|
||||
slug = "a"
|
||||
api_key = "k1"
|
||||
web_password = ""
|
||||
role = "doctor"
|
||||
[user.retention]
|
||||
auto_close_days = 7
|
||||
auto_delete_days = 30
|
||||
"#;
|
||||
let parsed: UsersFile = toml::from_str(toml_str).unwrap();
|
||||
let r = &parsed.user[0].retention;
|
||||
assert_eq!(r.auto_close_days, 7);
|
||||
assert_eq!(r.auto_delete_days, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_user_with_partial_retention_block() {
|
||||
let toml_str = r#"
|
||||
[[user]]
|
||||
slug = "a"
|
||||
api_key = "k1"
|
||||
web_password = ""
|
||||
role = "doctor"
|
||||
[user.retention]
|
||||
auto_close_days = 5
|
||||
"#;
|
||||
let parsed: UsersFile = toml::from_str(toml_str).unwrap();
|
||||
let r = &parsed.user[0].retention;
|
||||
assert_eq!(r.auto_close_days, 5);
|
||||
// Missing field defaults to 0 = disabled — lets admins test auto-close
|
||||
// in isolation without losing data to auto-purge.
|
||||
assert_eq!(r.auto_delete_days, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_user_with_full_whisper_block() {
|
||||
let toml_str = r#"
|
||||
|
||||
Reference in New Issue
Block a user