application: config_snapshots, admin, providers, iptv
This commit is contained in:
12
crates/application/src/providers/commands.rs
Normal file
12
crates/application/src/providers/commands.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
/// Insert or update a provider configuration.
|
||||
pub struct UpsertProviderCommand {
|
||||
pub id: String,
|
||||
pub provider_type: String,
|
||||
pub config_json: String,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
/// Delete a provider configuration.
|
||||
pub struct DeleteProviderCommand {
|
||||
pub id: String,
|
||||
}
|
||||
9
crates/application/src/providers/delete.rs
Normal file
9
crates/application/src/providers/delete.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use domain::DomainResult;
|
||||
|
||||
use super::commands::DeleteProviderCommand;
|
||||
use super::deps::ProviderDeps;
|
||||
|
||||
/// Delete a provider configuration by ID.
|
||||
pub async fn execute(deps: &ProviderDeps, cmd: DeleteProviderCommand) -> DomainResult<()> {
|
||||
deps.provider_config_command.delete(&cmd.id).await
|
||||
}
|
||||
9
crates/application/src/providers/deps.rs
Normal file
9
crates/application/src/providers/deps.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::ports::{ProviderConfigCommand, ProviderConfigQuery};
|
||||
|
||||
/// Dependencies for provider config use cases.
|
||||
pub struct ProviderDeps {
|
||||
pub provider_config_command: Arc<dyn ProviderConfigCommand>,
|
||||
pub provider_config_query: Arc<dyn ProviderConfigQuery>,
|
||||
}
|
||||
13
crates/application/src/providers/get.rs
Normal file
13
crates/application/src/providers/get.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use domain::models::ProviderConfigRow;
|
||||
use domain::DomainResult;
|
||||
|
||||
use super::deps::ProviderDeps;
|
||||
use super::queries::GetProviderQuery;
|
||||
|
||||
/// Get a provider configuration by ID.
|
||||
pub async fn execute(
|
||||
deps: &ProviderDeps,
|
||||
query: GetProviderQuery,
|
||||
) -> DomainResult<Option<ProviderConfigRow>> {
|
||||
deps.provider_config_query.get_by_id(&query.id).await
|
||||
}
|
||||
17
crates/application/src/providers/list.rs
Normal file
17
crates/application/src/providers/list.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use domain::models::ProviderConfigRow;
|
||||
use domain::DomainResult;
|
||||
|
||||
use super::deps::ProviderDeps;
|
||||
use super::queries::ListProvidersQuery;
|
||||
|
||||
/// List all provider configurations.
|
||||
pub async fn execute(
|
||||
deps: &ProviderDeps,
|
||||
_query: ListProvidersQuery,
|
||||
) -> DomainResult<Vec<ProviderConfigRow>> {
|
||||
deps.provider_config_query.get_all().await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/list.rs"]
|
||||
mod tests;
|
||||
11
crates/application/src/providers/mod.rs
Normal file
11
crates/application/src/providers/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
pub mod commands;
|
||||
pub mod delete;
|
||||
pub mod deps;
|
||||
pub mod get;
|
||||
pub mod list;
|
||||
pub mod queries;
|
||||
pub mod upsert;
|
||||
|
||||
pub use commands::{DeleteProviderCommand, UpsertProviderCommand};
|
||||
pub use deps::ProviderDeps;
|
||||
pub use queries::{GetProviderQuery, ListProvidersQuery};
|
||||
7
crates/application/src/providers/queries.rs
Normal file
7
crates/application/src/providers/queries.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
/// List all provider configurations.
|
||||
pub struct ListProvidersQuery;
|
||||
|
||||
/// Get a provider configuration by ID.
|
||||
pub struct GetProviderQuery {
|
||||
pub id: String,
|
||||
}
|
||||
45
crates/application/src/providers/tests/list.rs
Normal file
45
crates/application/src/providers/tests/list.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::testing::InMemoryProviderConfig;
|
||||
|
||||
use crate::providers::commands::UpsertProviderCommand;
|
||||
use crate::providers::deps::ProviderDeps;
|
||||
use crate::providers::queries::ListProvidersQuery;
|
||||
use crate::providers::{list, upsert};
|
||||
|
||||
fn make_deps() -> ProviderDeps {
|
||||
let repo = Arc::new(InMemoryProviderConfig::new());
|
||||
ProviderDeps {
|
||||
provider_config_command: repo.clone(),
|
||||
provider_config_query: repo,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn list_empty() {
|
||||
let deps = make_deps();
|
||||
let providers = list::execute(&deps, ListProvidersQuery).await.unwrap();
|
||||
assert!(providers.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn list_returns_all_providers() {
|
||||
let deps = make_deps();
|
||||
|
||||
for id in ["jf-1", "local-1"] {
|
||||
upsert::execute(
|
||||
&deps,
|
||||
UpsertProviderCommand {
|
||||
id: id.into(),
|
||||
provider_type: "jellyfin".into(),
|
||||
config_json: "{}".into(),
|
||||
enabled: true,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let providers = list::execute(&deps, ListProvidersQuery).await.unwrap();
|
||||
assert_eq!(providers.len(), 2);
|
||||
}
|
||||
76
crates/application/src/providers/tests/upsert.rs
Normal file
76
crates/application/src/providers/tests/upsert.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::testing::InMemoryProviderConfig;
|
||||
|
||||
use crate::providers::commands::UpsertProviderCommand;
|
||||
use crate::providers::deps::ProviderDeps;
|
||||
use crate::providers::upsert;
|
||||
|
||||
fn make_deps() -> ProviderDeps {
|
||||
let repo = Arc::new(InMemoryProviderConfig::new());
|
||||
ProviderDeps {
|
||||
provider_config_command: repo.clone(),
|
||||
provider_config_query: repo,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn upsert_stores_provider() {
|
||||
let deps = make_deps();
|
||||
|
||||
upsert::execute(
|
||||
&deps,
|
||||
UpsertProviderCommand {
|
||||
id: "jf-1".into(),
|
||||
provider_type: "jellyfin".into(),
|
||||
config_json: r#"{"url":"http://localhost:8096"}"#.into(),
|
||||
enabled: true,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let row = deps.provider_config_query.get_by_id("jf-1").await.unwrap();
|
||||
assert!(row.is_some());
|
||||
let row = row.unwrap();
|
||||
assert_eq!(row.provider_type(), "jellyfin");
|
||||
assert!(row.enabled());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn upsert_overwrites_existing() {
|
||||
let deps = make_deps();
|
||||
|
||||
upsert::execute(
|
||||
&deps,
|
||||
UpsertProviderCommand {
|
||||
id: "jf-1".into(),
|
||||
provider_type: "jellyfin".into(),
|
||||
config_json: r#"{"url":"http://old"}"#.into(),
|
||||
enabled: true,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
upsert::execute(
|
||||
&deps,
|
||||
UpsertProviderCommand {
|
||||
id: "jf-1".into(),
|
||||
provider_type: "jellyfin".into(),
|
||||
config_json: r#"{"url":"http://new"}"#.into(),
|
||||
enabled: false,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let row = deps
|
||||
.provider_config_query
|
||||
.get_by_id("jf-1")
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(row.config_json().contains("new"));
|
||||
assert!(!row.enabled());
|
||||
}
|
||||
21
crates/application/src/providers/upsert.rs
Normal file
21
crates/application/src/providers/upsert.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use domain::models::ProviderConfigRow;
|
||||
use domain::DomainResult;
|
||||
|
||||
use super::commands::UpsertProviderCommand;
|
||||
use super::deps::ProviderDeps;
|
||||
|
||||
/// Insert or update a provider configuration.
|
||||
pub async fn execute(deps: &ProviderDeps, cmd: UpsertProviderCommand) -> DomainResult<()> {
|
||||
let row = ProviderConfigRow::from_persistence(
|
||||
cmd.id,
|
||||
cmd.provider_type,
|
||||
cmd.config_json,
|
||||
cmd.enabled,
|
||||
String::new(),
|
||||
);
|
||||
deps.provider_config_command.upsert(&row).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/upsert.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user