- TokenService port + JwtTokenService adapter; login/refresh return LoginResult - delete get_token (dup of login); create_tokens helper removed - type UpdateChannelRequest schedule_config/recycle_policy (no serde_json::Value) - update_settings returns updated Vec; handler calls one use case - config use case in application::config; handler maps DTO only - SyncStatusEntry moved to api-types w/ From<LibrarySyncLogEntry> - trigger_sync: Conflict error, drop sync_trigger.send from handler - UpsertProviderCommand.config accepts Value; serialization in use case - get_current_broadcast returns BroadcastWithChannel; one call - get_stream_url resolves broadcast internally; handler single call
175 lines
6.0 KiB
Rust
175 lines
6.0 KiB
Rust
use axum::Json;
|
|
use axum::extract::{Path, State};
|
|
|
|
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 domain::DomainError;
|
|
|
|
use crate::errors::AppError;
|
|
use crate::extractors::CurrentUser;
|
|
use crate::state::AppState;
|
|
|
|
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?;
|
|
Ok(Json(channels.into_iter().map(ChannelResponse::from).collect()))
|
|
}
|
|
|
|
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?;
|
|
Ok(Json(channels.into_iter().map(ChannelResponse::from).collect()))
|
|
}
|
|
|
|
pub async fn create_channel(
|
|
State(state): State<AppState>,
|
|
CurrentUser(user): CurrentUser,
|
|
Json(req): Json<CreateChannelRequest>,
|
|
) -> Result<Json<ChannelResponse>, AppError> {
|
|
let cmd = CreateChannelCommand {
|
|
owner_id: user.id(),
|
|
name: req.name,
|
|
timezone: req.timezone,
|
|
};
|
|
let channel = application::channels::create::execute(&state.channel_command_deps, cmd).await?;
|
|
Ok(Json(ChannelResponse::from(channel)))
|
|
}
|
|
|
|
pub async fn get_channel(
|
|
State(state): State<AppState>,
|
|
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)
|
|
.await?
|
|
.ok_or_else(|| AppError(DomainError::NotFound(format!("Channel {id} not found"))))?;
|
|
Ok(Json(ChannelResponse::from(channel)))
|
|
}
|
|
|
|
pub async fn update_channel(
|
|
State(state): State<AppState>,
|
|
CurrentUser(user): CurrentUser,
|
|
Path(id): Path<uuid::Uuid>,
|
|
Json(req): Json<UpdateChannelRequest>,
|
|
) -> Result<Json<ChannelResponse>, AppError> {
|
|
let cmd = UpdateChannelCommand {
|
|
channel_id: id.into(),
|
|
owner_id: user.id(),
|
|
name: req.name,
|
|
description: req.description.map(Some),
|
|
timezone: req.timezone,
|
|
schedule_config: req.schedule_config.map(Into::into),
|
|
recycle_policy: req.recycle_policy,
|
|
auto_schedule: req.auto_schedule,
|
|
};
|
|
let channel = application::channels::update::execute(&state.channel_command_deps, cmd).await?;
|
|
Ok(Json(ChannelResponse::from(channel)))
|
|
}
|
|
|
|
pub async fn delete_channel(
|
|
State(state): State<AppState>,
|
|
CurrentUser(user): CurrentUser,
|
|
Path(id): Path<uuid::Uuid>,
|
|
) -> Result<axum::http::StatusCode, AppError> {
|
|
let cmd = DeleteChannelCommand {
|
|
channel_id: id.into(),
|
|
owner_id: user.id(),
|
|
};
|
|
application::channels::delete::execute(&state.channel_command_deps, cmd).await?;
|
|
Ok(axum::http::StatusCode::NO_CONTENT)
|
|
}
|
|
|
|
pub async fn save_snapshot(
|
|
State(state): State<AppState>,
|
|
CurrentUser(_user): CurrentUser,
|
|
Path(id): Path<uuid::Uuid>,
|
|
) -> Result<Json<ConfigSnapshotResponse>, AppError> {
|
|
let cmd = SaveSnapshotCommand {
|
|
channel_id: id.into(),
|
|
label: None,
|
|
};
|
|
let snap = application::config_snapshots::save::execute(&state.config_snapshot_deps, cmd).await?;
|
|
Ok(Json(ConfigSnapshotResponse::from(snap)))
|
|
}
|
|
|
|
pub async fn list_snapshots(
|
|
State(state): State<AppState>,
|
|
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?;
|
|
Ok(Json(snaps.into_iter().map(ConfigSnapshotResponse::from).collect()))
|
|
}
|
|
|
|
pub async fn get_snapshot(
|
|
State(state): State<AppState>,
|
|
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)
|
|
.await?
|
|
.ok_or_else(|| AppError(DomainError::NotFound("Snapshot not found".into())))?;
|
|
Ok(Json(ConfigSnapshotResponse::from(snap)))
|
|
}
|
|
|
|
pub async fn patch_snapshot(
|
|
State(state): State<AppState>,
|
|
CurrentUser(_user): CurrentUser,
|
|
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())))?;
|
|
Ok(Json(ConfigSnapshotResponse::from(snap)))
|
|
}
|
|
|
|
pub async fn restore_snapshot(
|
|
State(state): State<AppState>,
|
|
CurrentUser(_user): CurrentUser,
|
|
Path((id, snapshot_id)): Path<(uuid::Uuid, uuid::Uuid)>,
|
|
) -> Result<Json<ChannelResponse>, AppError> {
|
|
let cmd = RestoreSnapshotCommand {
|
|
channel_id: id.into(),
|
|
snapshot_id: snapshot_id.into(),
|
|
};
|
|
let channel =
|
|
application::config_snapshots::restore::execute(&state.config_snapshot_deps, cmd).await?;
|
|
Ok(Json(ChannelResponse::from(channel)))
|
|
}
|