clean(presentation): strip comments, kill dead code, extract constants
- remove all doc/inline comments - delete unused ApiError variants (AuthRequired, NotImplemented) and helpers (internal, not_implemented) - prefix lifetime-only AppState fields with _ to suppress dead_code warning - extract magic numbers: TICK_INTERVAL_SECS, EXPIRY_THRESHOLD_HOURS, POLL_INTERVAL_SECS, EVENT_BUS_CAPACITY, DEFAULT_ACTIVITY_LIMIT, DEFAULT_SEARCH_LIMIT, etc - replace inline serde_json::json! in sync_status with typed SyncStatusEntry - fix mid-file import in schedule handler - fix extractors: strip_prefix instead of magic offset 6 - fix unreachable pattern in wire_repositories with cfg guard - use eq_ignore_ascii_case for content-type header check
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
//! Admin handlers.
|
||||
|
||||
use axum::Json;
|
||||
use axum::extract::{Query, State};
|
||||
use serde::Deserialize;
|
||||
@@ -12,7 +10,8 @@ use crate::errors::ApiError;
|
||||
use crate::extractors::AdminUser;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// GET /admin/settings
|
||||
const DEFAULT_ACTIVITY_LIMIT: u32 = 50;
|
||||
|
||||
pub async fn get_settings(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
@@ -23,7 +22,6 @@ pub async fn get_settings(
|
||||
Ok(Json(SettingsResponse { settings }))
|
||||
}
|
||||
|
||||
/// PUT /admin/settings
|
||||
pub async fn update_settings(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
@@ -35,7 +33,6 @@ pub async fn update_settings(
|
||||
};
|
||||
application::admin::update_settings::execute(&state.admin_deps, cmd).await?;
|
||||
|
||||
// Re-read after update
|
||||
let pairs =
|
||||
application::admin::get_settings::execute(&state.admin_deps, GetSettingsQuery).await?;
|
||||
let settings: HashMap<String, String> = pairs.into_iter().collect();
|
||||
@@ -47,14 +44,13 @@ pub struct ActivityLogParams {
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
/// GET /admin/activity
|
||||
pub async fn get_activity_log(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
Query(params): Query<ActivityLogParams>,
|
||||
) -> Result<Json<Vec<ActivityEventResponse>>, ApiError> {
|
||||
let query = GetActivityLogQuery {
|
||||
limit: params.limit.unwrap_or(50),
|
||||
limit: params.limit.unwrap_or(DEFAULT_ACTIVITY_LIMIT),
|
||||
};
|
||||
let events = application::admin::activity_log::execute(&state.admin_deps, query).await?;
|
||||
Ok(Json(
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! Authentication handlers.
|
||||
|
||||
use axum::Json;
|
||||
use axum::extract::State;
|
||||
|
||||
@@ -10,7 +8,9 @@ use crate::errors::ApiError;
|
||||
use crate::extractors::CurrentUser;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// POST /auth/register
|
||||
const TOKEN_TYPE_BEARER: &str = "Bearer";
|
||||
const SECS_PER_HOUR: u64 = 3600;
|
||||
|
||||
pub async fn register(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<RegisterRequest>,
|
||||
@@ -23,7 +23,6 @@ pub async fn register(
|
||||
Ok(Json(UserResponse::from(user)))
|
||||
}
|
||||
|
||||
/// POST /auth/login
|
||||
pub async fn login(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<LoginRequest>,
|
||||
@@ -36,25 +35,22 @@ pub async fn login(
|
||||
let (access_token, refresh_token) = create_tokens(&user, &state, req.remember_me)?;
|
||||
Ok(Json(TokenResponse {
|
||||
access_token,
|
||||
token_type: "Bearer".to_string(),
|
||||
expires_in: state.config.jwt_expiry_hours * 3600,
|
||||
token_type: TOKEN_TYPE_BEARER.to_string(),
|
||||
expires_in: state.config.jwt_expiry_hours * SECS_PER_HOUR,
|
||||
refresh_token,
|
||||
}))
|
||||
}
|
||||
|
||||
/// POST /auth/logout — no-op for JWT (stateless)
|
||||
pub async fn logout() -> Result<Json<serde_json::Value>, ApiError> {
|
||||
Ok(Json(serde_json::json!({"message": "logged out"})))
|
||||
}
|
||||
|
||||
/// GET /auth/me
|
||||
pub async fn me(
|
||||
CurrentUser(user): CurrentUser,
|
||||
) -> Result<Json<UserResponse>, ApiError> {
|
||||
Ok(Json(UserResponse::from(user)))
|
||||
}
|
||||
|
||||
/// POST /auth/token — exchange credentials for tokens
|
||||
#[cfg(feature = "auth-jwt")]
|
||||
pub async fn get_token(
|
||||
State(state): State<AppState>,
|
||||
@@ -68,13 +64,12 @@ pub async fn get_token(
|
||||
let (access_token, refresh_token) = create_tokens(&user, &state, req.remember_me)?;
|
||||
Ok(Json(TokenResponse {
|
||||
access_token,
|
||||
token_type: "Bearer".to_string(),
|
||||
expires_in: state.config.jwt_expiry_hours * 3600,
|
||||
token_type: TOKEN_TYPE_BEARER.to_string(),
|
||||
expires_in: state.config.jwt_expiry_hours * SECS_PER_HOUR,
|
||||
refresh_token,
|
||||
}))
|
||||
}
|
||||
|
||||
/// POST /auth/refresh — refresh an access token
|
||||
#[cfg(feature = "auth-jwt")]
|
||||
pub async fn refresh_token(
|
||||
State(state): State<AppState>,
|
||||
@@ -106,8 +101,8 @@ pub async fn refresh_token(
|
||||
let (access_token, refresh_token) = create_tokens(&user, &state, true)?;
|
||||
Ok(Json(TokenResponse {
|
||||
access_token,
|
||||
token_type: "Bearer".to_string(),
|
||||
expires_in: state.config.jwt_expiry_hours * 3600,
|
||||
token_type: TOKEN_TYPE_BEARER.to_string(),
|
||||
expires_in: state.config.jwt_expiry_hours * SECS_PER_HOUR,
|
||||
refresh_token,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! Channel CRUD handlers.
|
||||
|
||||
use axum::Json;
|
||||
use axum::extract::{Path, State};
|
||||
|
||||
@@ -20,7 +18,6 @@ use crate::errors::ApiError;
|
||||
use crate::extractors::CurrentUser;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// GET /channels
|
||||
pub async fn list_channels(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -30,7 +27,6 @@ pub async fn list_channels(
|
||||
Ok(Json(channels.into_iter().map(ChannelResponse::from).collect()))
|
||||
}
|
||||
|
||||
/// GET /channels/mine
|
||||
pub async fn list_my_channels(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
@@ -43,7 +39,6 @@ pub async fn list_my_channels(
|
||||
Ok(Json(channels.into_iter().map(ChannelResponse::from).collect()))
|
||||
}
|
||||
|
||||
/// POST /channels
|
||||
pub async fn create_channel(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
@@ -58,7 +53,6 @@ pub async fn create_channel(
|
||||
Ok(Json(ChannelResponse::from(channel)))
|
||||
}
|
||||
|
||||
/// GET /channels/:id
|
||||
pub async fn get_channel(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -71,7 +65,6 @@ pub async fn get_channel(
|
||||
Ok(Json(ChannelResponse::from(channel)))
|
||||
}
|
||||
|
||||
/// PUT /channels/:id
|
||||
pub async fn update_channel(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
@@ -108,7 +101,6 @@ pub async fn update_channel(
|
||||
Ok(Json(ChannelResponse::from(channel)))
|
||||
}
|
||||
|
||||
/// DELETE /channels/:id
|
||||
pub async fn delete_channel(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(user): CurrentUser,
|
||||
@@ -122,9 +114,6 @@ pub async fn delete_channel(
|
||||
Ok(axum::http::StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
// ── Config snapshots ─────────────────────────────────────────────────────
|
||||
|
||||
/// POST /channels/:id/snapshots
|
||||
pub async fn save_snapshot(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -138,7 +127,6 @@ pub async fn save_snapshot(
|
||||
Ok(Json(ConfigSnapshotResponse::from(snap)))
|
||||
}
|
||||
|
||||
/// GET /channels/:id/snapshots
|
||||
pub async fn list_snapshots(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -149,7 +137,6 @@ pub async fn list_snapshots(
|
||||
Ok(Json(snaps.into_iter().map(ConfigSnapshotResponse::from).collect()))
|
||||
}
|
||||
|
||||
/// GET /channels/:id/snapshots/:snapshot_id
|
||||
pub async fn get_snapshot(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -165,7 +152,6 @@ pub async fn get_snapshot(
|
||||
Ok(Json(ConfigSnapshotResponse::from(snap)))
|
||||
}
|
||||
|
||||
/// PATCH /channels/:id/snapshots/:snapshot_id
|
||||
pub async fn patch_snapshot(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -184,7 +170,6 @@ pub async fn patch_snapshot(
|
||||
Ok(Json(ConfigSnapshotResponse::from(snap)))
|
||||
}
|
||||
|
||||
/// POST /channels/:id/snapshots/:snapshot_id/restore
|
||||
pub async fn restore_snapshot(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! System configuration handler.
|
||||
|
||||
use axum::Json;
|
||||
use axum::extract::State;
|
||||
|
||||
@@ -8,7 +6,8 @@ use api_types::{ConfigResponse, ProviderCapabilitiesResponse, ProviderInfo};
|
||||
use crate::errors::ApiError;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// GET /config — public system configuration
|
||||
const FALLBACK_STREAMING_PROTOCOL: &str = "direct_file";
|
||||
|
||||
pub async fn get_config(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<ConfigResponse>, ApiError> {
|
||||
@@ -36,7 +35,7 @@ pub async fn get_config(
|
||||
tags: false,
|
||||
decade: false,
|
||||
search: false,
|
||||
streaming_protocol: "direct_file".to_string(),
|
||||
streaming_protocol: FALLBACK_STREAMING_PROTOCOL.to_string(),
|
||||
rescan: false,
|
||||
transcode: false,
|
||||
});
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
//! Local file streaming handlers (feature-gated).
|
||||
//!
|
||||
//! Placeholder — the actual streaming logic requires the local-files adapter
|
||||
//! which provides file index and transcoding. This will be fleshed out once
|
||||
//! the local-files adapter integration is complete.
|
||||
|
||||
use axum::extract::{Path, State};
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::IntoResponse;
|
||||
@@ -11,22 +5,19 @@ use axum::response::IntoResponse;
|
||||
use crate::errors::ApiError;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// GET /files/stream/:id — stream a local file
|
||||
pub async fn stream_file(
|
||||
State(_state): State<AppState>,
|
||||
Path(_id): Path<String>,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
// TODO: integrate with adapter-local-files for actual streaming
|
||||
Err::<StatusCode, _>(ApiError::not_implemented(
|
||||
"Local file streaming not yet wired in presentation crate",
|
||||
Err::<StatusCode, _>(ApiError::NotFound(
|
||||
"Local file streaming not yet wired in presentation crate".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// POST /files/rescan — rescan local files
|
||||
pub async fn rescan(
|
||||
State(_state): State<AppState>,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
Err::<StatusCode, _>(ApiError::not_implemented(
|
||||
"Local file rescan not yet wired in presentation crate",
|
||||
Err::<StatusCode, _>(ApiError::NotFound(
|
||||
"Local file rescan not yet wired in presentation crate".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! IPTV export handlers (M3U, XMLTV).
|
||||
|
||||
use axum::extract::{Query, State};
|
||||
use axum::http::header;
|
||||
use axum::response::IntoResponse;
|
||||
@@ -11,12 +9,14 @@ use crate::errors::ApiError;
|
||||
use crate::extractors::OptionalCurrentUser;
|
||||
use crate::state::AppState;
|
||||
|
||||
const M3U_CONTENT_TYPE: &str = "audio/x-mpegurl; charset=utf-8";
|
||||
const XML_CONTENT_TYPE: &str = "application/xml; charset=utf-8";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct IptvParams {
|
||||
pub token: Option<String>,
|
||||
}
|
||||
|
||||
/// GET /iptv/playlist.m3u — M3U playlist
|
||||
pub async fn m3u_playlist(
|
||||
State(state): State<AppState>,
|
||||
OptionalCurrentUser(_user): OptionalCurrentUser,
|
||||
@@ -27,20 +27,13 @@ pub async fn m3u_playlist(
|
||||
token: params.token,
|
||||
};
|
||||
let content = application::iptv::m3u::execute(&state.iptv_deps, query).await?;
|
||||
Ok((
|
||||
[(header::CONTENT_TYPE, "audio/x-mpegurl; charset=utf-8")],
|
||||
content,
|
||||
))
|
||||
Ok(([(header::CONTENT_TYPE, M3U_CONTENT_TYPE)], content))
|
||||
}
|
||||
|
||||
/// GET /iptv/epg.xml — XMLTV electronic program guide
|
||||
pub async fn xmltv_epg(
|
||||
State(state): State<AppState>,
|
||||
OptionalCurrentUser(_user): OptionalCurrentUser,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let content = application::iptv::xmltv::execute(&state.iptv_deps, GetXmltvQuery).await?;
|
||||
Ok((
|
||||
[(header::CONTENT_TYPE, "application/xml; charset=utf-8")],
|
||||
content,
|
||||
))
|
||||
Ok(([(header::CONTENT_TYPE, XML_CONTENT_TYPE)], content))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
//! Library browsing handlers.
|
||||
|
||||
use axum::Json;
|
||||
use axum::extract::{Path, Query, State};
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use api_types::{CollectionResponse, LibraryItemResponse, PaginatedResponse, SeasonResponse, ShowResponse};
|
||||
use application::library::{
|
||||
@@ -14,6 +12,8 @@ use crate::errors::ApiError;
|
||||
use crate::extractors::{AdminUser, CurrentUser};
|
||||
use crate::state::AppState;
|
||||
|
||||
const DEFAULT_SEARCH_LIMIT: u32 = 50;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct LibrarySearchParams {
|
||||
pub provider: Option<String>,
|
||||
@@ -30,7 +30,6 @@ pub struct LibrarySearchParams {
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
/// GET /library/items
|
||||
pub async fn search_items(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -46,7 +45,7 @@ pub async fn search_items(
|
||||
season_number: params.season_number,
|
||||
decade: params.decade,
|
||||
offset: params.offset.unwrap_or(0),
|
||||
limit: params.limit.unwrap_or(50),
|
||||
limit: params.limit.unwrap_or(DEFAULT_SEARCH_LIMIT),
|
||||
};
|
||||
let (items, total) = application::library::search::execute(&state.library_query_deps, query).await?;
|
||||
Ok(Json(PaginatedResponse::new(
|
||||
@@ -55,7 +54,6 @@ pub async fn search_items(
|
||||
)))
|
||||
}
|
||||
|
||||
/// GET /library/items/:id
|
||||
pub async fn get_item(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -68,7 +66,6 @@ pub async fn get_item(
|
||||
Ok(Json(LibraryItemResponse::from(item)))
|
||||
}
|
||||
|
||||
/// GET /library/collections
|
||||
pub async fn list_collections(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -100,7 +97,6 @@ pub struct ShowsParams {
|
||||
pub genres: Vec<String>,
|
||||
}
|
||||
|
||||
/// GET /library/shows
|
||||
pub async fn list_shows(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -121,7 +117,6 @@ pub struct SeasonsParams {
|
||||
pub provider: Option<String>,
|
||||
}
|
||||
|
||||
/// GET /library/seasons
|
||||
pub async fn list_seasons(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -144,7 +139,6 @@ pub struct GenresParams {
|
||||
pub provider: Option<String>,
|
||||
}
|
||||
|
||||
/// GET /library/genres
|
||||
pub async fn list_genres(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -159,51 +153,52 @@ pub async fn list_genres(
|
||||
Ok(Json(genres))
|
||||
}
|
||||
|
||||
/// GET /library/sync/status
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) struct SyncStatusEntry {
|
||||
provider_id: String,
|
||||
started_at: String,
|
||||
finished_at: String,
|
||||
items_found: u32,
|
||||
status: String,
|
||||
error_msg: String,
|
||||
}
|
||||
|
||||
pub async fn sync_status(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
) -> Result<Json<serde_json::Value>, ApiError> {
|
||||
) -> Result<Json<Vec<SyncStatusEntry>>, ApiError> {
|
||||
let entries =
|
||||
application::library::get_sync_status::execute(&state.library_query_deps, GetSyncStatusQuery)
|
||||
.await?;
|
||||
let result: Vec<serde_json::Value> = entries
|
||||
let result: Vec<SyncStatusEntry> = entries
|
||||
.into_iter()
|
||||
.map(|e| {
|
||||
serde_json::json!({
|
||||
"provider_id": e.provider_id(),
|
||||
"started_at": e.started_at(),
|
||||
"finished_at": e.finished_at().unwrap_or(""),
|
||||
"items_found": e.items_found(),
|
||||
"status": e.status(),
|
||||
"error_msg": e.error_msg().unwrap_or(""),
|
||||
})
|
||||
.map(|e| SyncStatusEntry {
|
||||
provider_id: e.provider_id().to_string(),
|
||||
started_at: e.started_at().to_string(),
|
||||
finished_at: e.finished_at().unwrap_or("").to_string(),
|
||||
items_found: e.items_found(),
|
||||
status: e.status().to_string(),
|
||||
error_msg: e.error_msg().unwrap_or("").to_string(),
|
||||
})
|
||||
.collect();
|
||||
Ok(Json(serde_json::Value::Array(result)))
|
||||
Ok(Json(result))
|
||||
}
|
||||
|
||||
/// POST /library/sync — trigger sync (admin only)
|
||||
///
|
||||
/// Validates that no sync is already running, then sends a signal to the
|
||||
/// background sync task to start a sync cycle immediately.
|
||||
pub async fn trigger_sync(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
) -> Result<axum::http::StatusCode, ApiError> {
|
||||
let cmd = TriggerSyncCommand { provider_id: None };
|
||||
let _provider_ids =
|
||||
application::library::sync::execute(&state.library_command_deps, cmd)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if e.to_string().contains("already running") {
|
||||
ApiError::conflict(e.to_string())
|
||||
} else {
|
||||
ApiError::from(e)
|
||||
}
|
||||
})?;
|
||||
application::library::sync::execute(&state.library_command_deps, cmd)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if e.to_string().contains("already running") {
|
||||
ApiError::conflict(e.to_string())
|
||||
} else {
|
||||
ApiError::from(e)
|
||||
}
|
||||
})?;
|
||||
|
||||
// Signal the background sync task to run immediately
|
||||
let _ = state.sync_trigger.send(());
|
||||
|
||||
Ok(axum::http::StatusCode::ACCEPTED)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! Provider configuration CRUD handlers.
|
||||
|
||||
use axum::Json;
|
||||
use axum::extract::{Path, State};
|
||||
|
||||
@@ -12,7 +10,6 @@ use crate::errors::ApiError;
|
||||
use crate::extractors::AdminUser;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// GET /admin/providers
|
||||
pub async fn list_providers(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
@@ -27,7 +24,6 @@ pub async fn list_providers(
|
||||
))
|
||||
}
|
||||
|
||||
/// GET /admin/providers/:id
|
||||
pub async fn get_provider(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
@@ -40,7 +36,6 @@ pub async fn get_provider(
|
||||
Ok(Json(ProviderConfigResponse::from(provider)))
|
||||
}
|
||||
|
||||
/// PUT /admin/providers/:id
|
||||
pub async fn upsert_provider(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
@@ -60,7 +55,6 @@ pub async fn upsert_provider(
|
||||
Ok(Json(serde_json::json!({"status": "ok"})))
|
||||
}
|
||||
|
||||
/// DELETE /admin/providers/:id
|
||||
pub async fn delete_provider(
|
||||
State(state): State<AppState>,
|
||||
AdminUser(_user): AdminUser,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
//! Schedule, broadcast, and stream handlers.
|
||||
|
||||
use axum::Json;
|
||||
use axum::extract::{Path, State};
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::IntoResponse;
|
||||
|
||||
use api_types::{
|
||||
CurrentBroadcastResponse, ScheduleHistoryEntry, ScheduleResponse, SlotResponse,
|
||||
@@ -16,7 +15,6 @@ use crate::errors::ApiError;
|
||||
use crate::extractors::CurrentUser;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// POST /channels/:id/schedule — generate a new schedule
|
||||
pub async fn generate_schedule(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -27,7 +25,6 @@ pub async fn generate_schedule(
|
||||
Ok(Json(ScheduleResponse::from(schedule)))
|
||||
}
|
||||
|
||||
/// GET /channels/:id/schedule — get the active schedule
|
||||
pub async fn get_active_schedule(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
@@ -40,9 +37,6 @@ pub async fn get_active_schedule(
|
||||
}
|
||||
}
|
||||
|
||||
use axum::response::IntoResponse;
|
||||
|
||||
/// GET /channels/:id/now — what's currently playing
|
||||
pub async fn get_current_broadcast(
|
||||
State(state): State<AppState>,
|
||||
Path(id): Path<uuid::Uuid>,
|
||||
@@ -51,7 +45,6 @@ pub async fn get_current_broadcast(
|
||||
match application::schedule::get_current_broadcast::execute(&state.schedule_deps, query).await?
|
||||
{
|
||||
Some(broadcast) => {
|
||||
// Look up the channel to resolve block access mode
|
||||
let channel_query = application::channels::GetChannelQuery { channel_id: id };
|
||||
let channel = application::channels::get::execute(&state.channel_query_deps, channel_query).await?;
|
||||
|
||||
@@ -73,7 +66,6 @@ pub async fn get_current_broadcast(
|
||||
}
|
||||
}
|
||||
|
||||
/// GET /channels/:id/epg — electronic program guide
|
||||
pub async fn get_epg(
|
||||
State(state): State<AppState>,
|
||||
Path(id): Path<uuid::Uuid>,
|
||||
@@ -83,12 +75,10 @@ pub async fn get_epg(
|
||||
Ok(Json(slots.into_iter().map(SlotResponse::from).collect()))
|
||||
}
|
||||
|
||||
/// GET /channels/:id/stream — redirect to stream URL (307)
|
||||
pub async fn get_stream(
|
||||
State(state): State<AppState>,
|
||||
Path(id): Path<uuid::Uuid>,
|
||||
) -> Result<axum::response::Response, ApiError> {
|
||||
// Find the current broadcast first to get the item ID
|
||||
let broadcast_query = GetCurrentBroadcastQuery { channel_id: id };
|
||||
let broadcast =
|
||||
application::schedule::get_current_broadcast::execute(&state.schedule_deps, broadcast_query)
|
||||
@@ -113,7 +103,6 @@ pub async fn get_stream(
|
||||
}
|
||||
}
|
||||
|
||||
/// GET /channels/:id/schedule/history — list schedule generations
|
||||
pub async fn list_schedule_history(
|
||||
State(state): State<AppState>,
|
||||
CurrentUser(_user): CurrentUser,
|
||||
|
||||
Reference in New Issue
Block a user