application: config_snapshots, admin, providers, iptv

This commit is contained in:
2026-07-12 02:14:07 +02:00
parent ebf0614fdf
commit 466d34b5d0
37 changed files with 895 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
use domain::models::ActivityEvent;
use domain::DomainResult;
use super::deps::AdminDeps;
use super::queries::GetActivityLogQuery;
/// Get recent activity log entries.
pub async fn execute(
deps: &AdminDeps,
query: GetActivityLogQuery,
) -> DomainResult<Vec<ActivityEvent>> {
deps.activity_query.recent(query.limit).await
}

View File

@@ -0,0 +1,4 @@
/// Update one or more admin settings (key-value pairs).
pub struct UpdateSettingsCommand {
pub settings: Vec<(String, String)>,
}

View File

@@ -0,0 +1,9 @@
use std::sync::Arc;
use domain::ports::{ActivityLogQuery, AppSettingsRepository};
/// Dependencies for admin use cases.
pub struct AdminDeps {
pub settings_repo: Arc<dyn AppSettingsRepository>,
pub activity_query: Arc<dyn ActivityLogQuery>,
}

View File

@@ -0,0 +1,16 @@
use domain::DomainResult;
use super::deps::AdminDeps;
use super::queries::GetSettingsQuery;
/// Get all admin settings as key-value pairs.
pub async fn execute(
deps: &AdminDeps,
_query: GetSettingsQuery,
) -> DomainResult<Vec<(String, String)>> {
deps.settings_repo.get_all().await
}
#[cfg(test)]
#[path = "tests/get_settings.rs"]
mod tests;

View File

@@ -0,0 +1,10 @@
pub mod activity_log;
pub mod commands;
pub mod deps;
pub mod get_settings;
pub mod queries;
pub mod update_settings;
pub use commands::UpdateSettingsCommand;
pub use deps::AdminDeps;
pub use queries::{GetActivityLogQuery, GetSettingsQuery};

View File

@@ -0,0 +1,7 @@
/// Get all admin settings.
pub struct GetSettingsQuery;
/// Get recent activity log entries.
pub struct GetActivityLogQuery {
pub limit: u32,
}

View File

@@ -0,0 +1,46 @@
use std::sync::Arc;
use domain::testing::{InMemoryActivityLog, InMemoryAppSettings};
use crate::admin::commands::UpdateSettingsCommand;
use crate::admin::deps::AdminDeps;
use crate::admin::queries::GetSettingsQuery;
use crate::admin::{get_settings, update_settings};
fn make_deps() -> AdminDeps {
AdminDeps {
settings_repo: Arc::new(InMemoryAppSettings::new()),
activity_query: Arc::new(InMemoryActivityLog::new()),
}
}
#[tokio::test]
async fn get_empty_settings() {
let deps = make_deps();
let settings = get_settings::execute(&deps, GetSettingsQuery).await.unwrap();
assert!(settings.is_empty());
}
#[tokio::test]
async fn get_returns_stored_settings() {
let deps = make_deps();
update_settings::execute(
&deps,
UpdateSettingsCommand {
settings: vec![
("a".into(), "1".into()),
("b".into(), "2".into()),
],
},
)
.await
.unwrap();
let settings = get_settings::execute(&deps, GetSettingsQuery).await.unwrap();
assert_eq!(settings.len(), 2);
let keys: Vec<&str> = settings.iter().map(|(k, _)| k.as_str()).collect();
assert!(keys.contains(&"a"));
assert!(keys.contains(&"b"));
}

View File

@@ -0,0 +1,63 @@
use std::sync::Arc;
use domain::testing::{InMemoryActivityLog, InMemoryAppSettings};
use crate::admin::commands::UpdateSettingsCommand;
use crate::admin::deps::AdminDeps;
use crate::admin::update_settings;
fn make_deps() -> AdminDeps {
AdminDeps {
settings_repo: Arc::new(InMemoryAppSettings::new()),
activity_query: Arc::new(InMemoryActivityLog::new()),
}
}
#[tokio::test]
async fn update_stores_settings() {
let deps = make_deps();
update_settings::execute(
&deps,
UpdateSettingsCommand {
settings: vec![
("library_sync_interval_hours".into(), "12".into()),
("theme".into(), "dark".into()),
],
},
)
.await
.unwrap();
let val = deps.settings_repo.get("library_sync_interval_hours").await.unwrap();
assert_eq!(val, Some("12".into()));
let val2 = deps.settings_repo.get("theme").await.unwrap();
assert_eq!(val2, Some("dark".into()));
}
#[tokio::test]
async fn update_overwrites_existing() {
let deps = make_deps();
update_settings::execute(
&deps,
UpdateSettingsCommand {
settings: vec![("key".into(), "old".into())],
},
)
.await
.unwrap();
update_settings::execute(
&deps,
UpdateSettingsCommand {
settings: vec![("key".into(), "new".into())],
},
)
.await
.unwrap();
let val = deps.settings_repo.get("key").await.unwrap();
assert_eq!(val, Some("new".into()));
}

View File

@@ -0,0 +1,18 @@
use domain::DomainResult;
use super::commands::UpdateSettingsCommand;
use super::deps::AdminDeps;
/// Update one or more admin settings.
///
/// Iterates key/value pairs and upserts each one.
pub async fn execute(deps: &AdminDeps, cmd: UpdateSettingsCommand) -> DomainResult<()> {
for (key, value) in &cmd.settings {
deps.settings_repo.set(key, value).await?;
}
Ok(())
}
#[cfg(test)]
#[path = "tests/update_settings.rs"]
mod tests;