application: config_snapshots, admin, providers, iptv
This commit is contained in:
13
crates/application/src/admin/activity_log.rs
Normal file
13
crates/application/src/admin/activity_log.rs
Normal 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
|
||||
}
|
||||
4
crates/application/src/admin/commands.rs
Normal file
4
crates/application/src/admin/commands.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
/// Update one or more admin settings (key-value pairs).
|
||||
pub struct UpdateSettingsCommand {
|
||||
pub settings: Vec<(String, String)>,
|
||||
}
|
||||
9
crates/application/src/admin/deps.rs
Normal file
9
crates/application/src/admin/deps.rs
Normal 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>,
|
||||
}
|
||||
16
crates/application/src/admin/get_settings.rs
Normal file
16
crates/application/src/admin/get_settings.rs
Normal 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;
|
||||
10
crates/application/src/admin/mod.rs
Normal file
10
crates/application/src/admin/mod.rs
Normal 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};
|
||||
7
crates/application/src/admin/queries.rs
Normal file
7
crates/application/src/admin/queries.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
/// Get all admin settings.
|
||||
pub struct GetSettingsQuery;
|
||||
|
||||
/// Get recent activity log entries.
|
||||
pub struct GetActivityLogQuery {
|
||||
pub limit: u32,
|
||||
}
|
||||
46
crates/application/src/admin/tests/get_settings.rs
Normal file
46
crates/application/src/admin/tests/get_settings.rs
Normal 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"));
|
||||
}
|
||||
63
crates/application/src/admin/tests/update_settings.rs
Normal file
63
crates/application/src/admin/tests/update_settings.rs
Normal 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()));
|
||||
}
|
||||
18
crates/application/src/admin/update_settings.rs
Normal file
18
crates/application/src/admin/update_settings.rs
Normal 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;
|
||||
Reference in New Issue
Block a user