collapse 20 pass-through use cases; handlers call ports directly

delete get/list/list_by_owner channels, get_settings/activity_log admin,
get_item/get_sync_status/list_collections/list_seasons/list_shows/list_genres library,
get/list/delete providers, get/list/patch_label config_snapshots,
get_active/list_history/delete_after schedule — all single-delegation.

remove ChannelQueryDeps, LibraryQueryDeps, deleted query/command structs.
add direct port fields to AppState. update MCP crate accordingly.
This commit is contained in:
2026-07-12 07:18:26 +02:00
parent a6558e15b2
commit e2393be635
68 changed files with 191 additions and 1589 deletions

View File

@@ -3,7 +3,7 @@ use axum::extract::{Query, State};
use std::collections::HashMap;
use api_types::{ActivityEventResponse, ActivityLogParams, SettingsResponse};
use application::admin::{GetActivityLogQuery, UpdateSettingsCommand};
use application::admin::UpdateSettingsCommand;
use crate::errors::AppError;
use crate::extractors::AdminUser;
@@ -15,8 +15,7 @@ pub async fn get_settings(
State(state): State<AppState>,
AdminUser(_user): AdminUser,
) -> Result<Json<SettingsResponse>, AppError> {
let pairs =
application::admin::get_settings::execute(&state.admin_deps, application::admin::GetSettingsQuery).await?;
let pairs = state.settings_repo.get_all().await?;
let settings: HashMap<String, String> = pairs.into_iter().collect();
Ok(Json(SettingsResponse { settings }))
}
@@ -40,10 +39,8 @@ pub async fn get_activity_log(
AdminUser(_user): AdminUser,
Query(params): Query<ActivityLogParams>,
) -> Result<Json<Vec<ActivityEventResponse>>, AppError> {
let query = GetActivityLogQuery {
limit: params.limit.unwrap_or(DEFAULT_ACTIVITY_LIMIT),
};
let events = application::admin::activity_log::execute(&state.admin_deps, query).await?;
let limit = params.limit.unwrap_or(DEFAULT_ACTIVITY_LIMIT);
let events = state.activity_query.recent(limit).await?;
Ok(Json(
events
.into_iter()

View File

@@ -5,14 +5,8 @@ use api_types::{
ChannelResponse, ConfigSnapshotResponse, CreateChannelRequest, PatchSnapshotRequest,
UpdateChannelRequest,
};
use application::channels::{
CreateChannelCommand, DeleteChannelCommand, GetChannelQuery, ListByOwnerQuery,
ListChannelsQuery, UpdateChannelCommand,
};
use application::config_snapshots::{
GetSnapshotQuery, ListSnapshotsQuery, PatchLabelCommand, RestoreSnapshotCommand,
SaveSnapshotCommand,
};
use application::channels::{CreateChannelCommand, DeleteChannelCommand, UpdateChannelCommand};
use application::config_snapshots::{RestoreSnapshotCommand, SaveSnapshotCommand};
use domain::DomainError;
use crate::errors::AppError;
@@ -23,8 +17,7 @@ pub async fn list_channels(
State(state): State<AppState>,
CurrentUser(_user): CurrentUser,
) -> Result<Json<Vec<ChannelResponse>>, AppError> {
let channels =
application::channels::list::execute(&state.channel_query_deps, ListChannelsQuery).await?;
let channels = state.channel_query.find_all().await?;
Ok(Json(channels.into_iter().map(ChannelResponse::from).collect()))
}
@@ -32,11 +25,7 @@ pub async fn list_my_channels(
State(state): State<AppState>,
CurrentUser(user): CurrentUser,
) -> Result<Json<Vec<ChannelResponse>>, AppError> {
let query = ListByOwnerQuery {
owner_id: user.id(),
};
let channels =
application::channels::list_by_owner::execute(&state.channel_query_deps, query).await?;
let channels = state.channel_query.find_by_owner(user.id()).await?;
Ok(Json(channels.into_iter().map(ChannelResponse::from).collect()))
}
@@ -59,10 +48,9 @@ pub async fn get_channel(
CurrentUser(_user): CurrentUser,
Path(id): Path<uuid::Uuid>,
) -> Result<Json<ChannelResponse>, AppError> {
let query = GetChannelQuery {
channel_id: id.into(),
};
let channel = application::channels::get::execute(&state.channel_query_deps, query)
let channel = state
.channel_query
.find_by_id(id.into())
.await?
.ok_or_else(|| AppError(DomainError::NotFound(format!("Channel {id} not found"))))?;
Ok(Json(ChannelResponse::from(channel)))
@@ -119,10 +107,7 @@ pub async fn list_snapshots(
CurrentUser(_user): CurrentUser,
Path(id): Path<uuid::Uuid>,
) -> Result<Json<Vec<ConfigSnapshotResponse>>, AppError> {
let query = ListSnapshotsQuery {
channel_id: id.into(),
};
let snaps = application::config_snapshots::list::execute(&state.config_snapshot_deps, query).await?;
let snaps = state.channel_query.list_config_snapshots(id.into()).await?;
Ok(Json(snaps.into_iter().map(ConfigSnapshotResponse::from).collect()))
}
@@ -131,11 +116,9 @@ pub async fn get_snapshot(
CurrentUser(_user): CurrentUser,
Path((id, snapshot_id)): Path<(uuid::Uuid, uuid::Uuid)>,
) -> Result<Json<ConfigSnapshotResponse>, AppError> {
let query = GetSnapshotQuery {
channel_id: id.into(),
snapshot_id: snapshot_id.into(),
};
let snap = application::config_snapshots::get::execute(&state.config_snapshot_deps, query)
let snap = state
.channel_query
.get_config_snapshot(id.into(), snapshot_id.into())
.await?
.ok_or_else(|| AppError(DomainError::NotFound("Snapshot not found".into())))?;
Ok(Json(ConfigSnapshotResponse::from(snap)))
@@ -147,15 +130,12 @@ pub async fn patch_snapshot(
Path((id, snapshot_id)): Path<(uuid::Uuid, uuid::Uuid)>,
Json(req): Json<PatchSnapshotRequest>,
) -> Result<Json<ConfigSnapshotResponse>, AppError> {
let cmd = PatchLabelCommand {
channel_id: id.into(),
snapshot_id: snapshot_id.into(),
label: req.label,
};
let snap =
application::config_snapshots::patch_label::execute(&state.config_snapshot_deps, cmd)
.await?
.ok_or_else(|| AppError(DomainError::NotFound("Snapshot not found".into())))?;
let snap = state
.channel_command_deps
.channel_command
.patch_config_snapshot_label(id.into(), snapshot_id.into(), req.label)
.await?
.ok_or_else(|| AppError(DomainError::NotFound("Snapshot not found".into())))?;
Ok(Json(ConfigSnapshotResponse::from(snap)))
}

View File

@@ -5,10 +5,7 @@ use api_types::{
CollectionResponse, GenresParams, LibraryItemResponse, LibrarySearchParams, PaginatedResponse,
ProviderParam, SeasonResponse, SeasonsParams, ShowResponse, ShowsParams, SyncStatusEntry,
};
use application::library::{
GetItemQuery, GetSyncStatusQuery, ListCollectionsQuery, ListGenresQuery, ListSeasonsQuery,
ListShowsQuery, SearchItemsQuery, TriggerSyncCommand,
};
use application::library::{SearchItemsQuery, TriggerSyncCommand};
use domain::DomainError;
use crate::errors::AppError;
@@ -34,7 +31,7 @@ pub async fn search_items(
offset: params.offset.unwrap_or(0),
limit: params.limit.unwrap_or(DEFAULT_SEARCH_LIMIT),
};
let (items, total) = application::library::search::execute(&state.library_query_deps, query).await?;
let (items, total) = application::library::search::execute(&state.library_command_deps, query).await?;
Ok(Json(PaginatedResponse::new(
items.into_iter().map(LibraryItemResponse::from).collect(),
total as u64,
@@ -46,8 +43,9 @@ pub async fn get_item(
CurrentUser(_user): CurrentUser,
Path(id): Path<String>,
) -> Result<Json<LibraryItemResponse>, AppError> {
let query = GetItemQuery { item_id: id.clone() };
let item = application::library::get_item::execute(&state.library_query_deps, query)
let item = state
.library_query
.get_by_id(&id)
.await?
.ok_or_else(|| AppError(DomainError::NotFound(format!("Library item {id} not found"))))?;
Ok(Json(LibraryItemResponse::from(item)))
@@ -58,11 +56,10 @@ pub async fn list_collections(
CurrentUser(_user): CurrentUser,
Query(params): Query<ProviderParam>,
) -> Result<Json<Vec<CollectionResponse>>, AppError> {
let query = ListCollectionsQuery {
provider_id: params.provider,
};
let collections =
application::library::list_collections::execute(&state.library_query_deps, query).await?;
let collections = state
.library_query
.list_collections(params.provider.as_deref())
.await?;
Ok(Json(
collections
.into_iter()
@@ -76,12 +73,14 @@ pub async fn list_shows(
CurrentUser(_user): CurrentUser,
Query(params): Query<ShowsParams>,
) -> Result<Json<Vec<ShowResponse>>, AppError> {
let query = ListShowsQuery {
provider_id: params.provider,
search_term: params.search_term,
genres: params.genres,
};
let shows = application::library::list_shows::execute(&state.library_query_deps, query).await?;
let shows = state
.library_query
.list_shows(
params.provider.as_deref(),
params.search_term.as_deref(),
&params.genres,
)
.await?;
Ok(Json(shows.into_iter().map(ShowResponse::from).collect()))
}
@@ -90,12 +89,10 @@ pub async fn list_seasons(
CurrentUser(_user): CurrentUser,
Query(params): Query<SeasonsParams>,
) -> Result<Json<Vec<SeasonResponse>>, AppError> {
let query = ListSeasonsQuery {
series_name: params.series_name,
provider_id: params.provider,
};
let seasons =
application::library::list_seasons::execute(&state.library_query_deps, query).await?;
let seasons = state
.library_query
.list_seasons(&params.series_name, params.provider.as_deref())
.await?;
Ok(Json(
seasons.into_iter().map(SeasonResponse::from).collect(),
))
@@ -106,12 +103,15 @@ pub async fn list_genres(
CurrentUser(_user): CurrentUser,
Query(params): Query<GenresParams>,
) -> Result<Json<Vec<String>>, AppError> {
let query = ListGenresQuery {
content_type: params.content_type,
provider_id: params.provider,
};
let genres =
application::library::list_genres::execute(&state.library_query_deps, query).await?;
let content_type = params
.content_type
.as_deref()
.map(application::library::parse_content_type)
.transpose()?;
let genres = state
.library_query
.list_genres(content_type.as_ref(), params.provider.as_deref())
.await?;
Ok(Json(genres))
}
@@ -119,9 +119,7 @@ pub async fn sync_status(
State(state): State<AppState>,
CurrentUser(_user): CurrentUser,
) -> Result<Json<Vec<SyncStatusEntry>>, AppError> {
let entries =
application::library::get_sync_status::execute(&state.library_query_deps, GetSyncStatusQuery)
.await?;
let entries = state.library_query.latest_sync_status().await?;
Ok(Json(entries.into_iter().map(SyncStatusEntry::from).collect()))
}

View File

@@ -2,9 +2,7 @@ use axum::Json;
use axum::extract::{Path, State};
use api_types::{ProviderConfigRequest, ProviderConfigResponse};
use application::providers::{
DeleteProviderCommand, GetProviderQuery, ListProvidersQuery, UpsertProviderCommand,
};
use application::providers::UpsertProviderCommand;
use domain::DomainError;
use crate::errors::AppError;
@@ -15,8 +13,7 @@ pub async fn list_providers(
State(state): State<AppState>,
AdminUser(_user): AdminUser,
) -> Result<Json<Vec<ProviderConfigResponse>>, AppError> {
let providers =
application::providers::list::execute(&state.provider_deps, ListProvidersQuery).await?;
let providers = state.provider_config_query.get_all().await?;
Ok(Json(
providers
.into_iter()
@@ -30,8 +27,9 @@ pub async fn get_provider(
AdminUser(_user): AdminUser,
Path(id): Path<String>,
) -> Result<Json<ProviderConfigResponse>, AppError> {
let query = GetProviderQuery { id: id.clone() };
let provider = application::providers::get::execute(&state.provider_deps, query)
let provider = state
.provider_config_query
.get_by_id(&id)
.await?
.ok_or_else(|| AppError(DomainError::NotFound(format!("Provider {id} not found"))))?;
Ok(Json(ProviderConfigResponse::from(provider)))
@@ -58,7 +56,6 @@ pub async fn delete_provider(
AdminUser(_user): AdminUser,
Path(id): Path<String>,
) -> Result<axum::http::StatusCode, AppError> {
let cmd = DeleteProviderCommand { id };
application::providers::delete::execute(&state.provider_deps, cmd).await?;
state.provider_config_command.delete(&id).await?;
Ok(axum::http::StatusCode::NO_CONTENT)
}

View File

@@ -2,14 +2,15 @@ use axum::Json;
use axum::extract::{Path, State};
use axum::http::StatusCode;
use axum::response::IntoResponse;
use chrono::Utc;
use api_types::{
CurrentBroadcastResponse, ScheduleHistoryEntry, ScheduleResponse, SlotResponse,
};
use application::schedule::{
GenerateScheduleCommand, GetActiveScheduleQuery, GetCurrentBroadcastQuery, GetEpgQuery,
GetStreamUrlQuery, ListHistoryQuery,
GenerateScheduleCommand, GetCurrentBroadcastQuery, GetEpgQuery, GetStreamUrlQuery,
};
use domain::value_objects::ChannelId;
use crate::errors::AppError;
use crate::extractors::CurrentUser;
@@ -30,8 +31,8 @@ pub async fn get_active_schedule(
CurrentUser(_user): CurrentUser,
Path(id): Path<uuid::Uuid>,
) -> Result<axum::response::Response, AppError> {
let query = GetActiveScheduleQuery { channel_id: id };
match application::schedule::get_active::execute(&state.schedule_deps, query).await? {
let channel_id = ChannelId::from(id);
match state.schedule_query.find_active(channel_id, Utc::now()).await? {
Some(schedule) => Ok(Json(ScheduleResponse::from(schedule)).into_response()),
None => Ok(StatusCode::NO_CONTENT.into_response()),
}
@@ -85,9 +86,8 @@ pub async fn list_schedule_history(
CurrentUser(_user): CurrentUser,
Path(id): Path<uuid::Uuid>,
) -> Result<Json<Vec<ScheduleHistoryEntry>>, AppError> {
let query = ListHistoryQuery { channel_id: id };
let history =
application::schedule::list_history::execute(&state.schedule_deps, query).await?;
let channel_id = ChannelId::from(id);
let history = state.schedule_query.list_schedule_history(channel_id).await?;
Ok(Json(
history
.into_iter()