pinakes-server: update remaining route imports and handlers
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I67206fd813d514f8903041eea0a4cd266a6a6964
This commit is contained in:
parent
2b2c1830a1
commit
eb6c0a3577
20 changed files with 169 additions and 87 deletions
|
|
@ -4,7 +4,11 @@ use axum::{
|
|||
};
|
||||
use pinakes_core::model::Pagination;
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{AuditEntryResponse, PaginationParams},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub async fn list_audit(
|
||||
State(state): State<AppState>,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,16 @@ use axum::{
|
|||
use pinakes_core::model::{CollectionKind, MediaId};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{
|
||||
AddMemberRequest,
|
||||
CollectionResponse,
|
||||
CreateCollectionRequest,
|
||||
MediaResponse,
|
||||
},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub async fn create_collection(
|
||||
State(state): State<AppState>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,18 @@
|
|||
use axum::{Json, extract::State};
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{
|
||||
ConfigResponse,
|
||||
RootDirRequest,
|
||||
ScanningConfigResponse,
|
||||
ServerConfigResponse,
|
||||
UiConfigResponse,
|
||||
UpdateScanningRequest,
|
||||
UpdateUiConfigRequest,
|
||||
},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub async fn get_config(
|
||||
State(state): State<AppState>,
|
||||
|
|
@ -15,18 +27,11 @@ pub async fn get_config(
|
|||
let config_writable = match &state.config_path {
|
||||
Some(path) => {
|
||||
if path.exists() {
|
||||
std::fs::metadata(path)
|
||||
.map(|m| !m.permissions().readonly())
|
||||
.unwrap_or(false)
|
||||
std::fs::metadata(path).is_ok_and(|m| !m.permissions().readonly())
|
||||
} else {
|
||||
path
|
||||
.parent()
|
||||
.map(|parent| {
|
||||
std::fs::metadata(parent)
|
||||
.map(|m| !m.permissions().readonly())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
path.parent().is_some_and(|parent| {
|
||||
std::fs::metadata(parent).is_ok_and(|m| !m.permissions().readonly())
|
||||
})
|
||||
}
|
||||
},
|
||||
None => false,
|
||||
|
|
@ -128,18 +133,11 @@ pub async fn update_scanning_config(
|
|||
let config_writable = match &state.config_path {
|
||||
Some(path) => {
|
||||
if path.exists() {
|
||||
std::fs::metadata(path)
|
||||
.map(|m| !m.permissions().readonly())
|
||||
.unwrap_or(false)
|
||||
std::fs::metadata(path).is_ok_and(|m| !m.permissions().readonly())
|
||||
} else {
|
||||
path
|
||||
.parent()
|
||||
.map(|parent| {
|
||||
std::fs::metadata(parent)
|
||||
.map(|m| !m.permissions().readonly())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
path.parent().is_some_and(|parent| {
|
||||
std::fs::metadata(parent).is_ok_and(|m| !m.permissions().readonly())
|
||||
})
|
||||
}
|
||||
},
|
||||
None => false,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ use axum::{
|
|||
use pinakes_core::model::MediaId;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{BatchDeleteRequest, ExternalMetadataResponse},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub async fn trigger_enrichment(
|
||||
State(state): State<AppState>,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ pub async fn health(State(state): State<AppState>) -> Json<HealthResponse> {
|
|||
Err(e) => {
|
||||
response.status = "degraded".to_string();
|
||||
DatabaseHealth {
|
||||
status: format!("error: {}", e),
|
||||
status: format!("error: {e}"),
|
||||
latency_ms: db_start.elapsed().as_millis() as u64,
|
||||
media_count: None,
|
||||
}
|
||||
|
|
@ -168,7 +168,7 @@ pub async fn health_detailed(
|
|||
let db_start = Instant::now();
|
||||
let (db_status, media_count) = match state.storage.count_media().await {
|
||||
Ok(count) => ("ok".to_string(), Some(count)),
|
||||
Err(e) => (format!("error: {}", e), None),
|
||||
Err(e) => (format!("error: {e}"), None),
|
||||
};
|
||||
let db_latency = db_start.elapsed().as_millis() as u64;
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub async fn generate_all_thumbnails(
|
|||
State(state): State<AppState>,
|
||||
body: Option<Json<GenerateThumbnailsRequest>>,
|
||||
) -> Result<Json<serde_json::Value>, ApiError> {
|
||||
let only_missing = body.map(|b| b.only_missing).unwrap_or(false);
|
||||
let only_missing = body.is_some_and(|b| b.only_missing);
|
||||
let media_ids = state
|
||||
.storage
|
||||
.list_media_ids_for_thumbnails(only_missing)
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ pub struct GraphQuery {
|
|||
pub depth: u32,
|
||||
}
|
||||
|
||||
fn default_depth() -> u32 {
|
||||
const fn default_depth() -> u32 {
|
||||
2
|
||||
}
|
||||
|
||||
|
|
@ -280,7 +280,7 @@ pub async fn reindex_links(
|
|||
// Read the file content
|
||||
let content = tokio::fs::read_to_string(&media.path)
|
||||
.await
|
||||
.map_err(|e| ApiError::internal(format!("Failed to read file: {}", e)))?;
|
||||
.map_err(|e| ApiError::internal(format!("Failed to read file: {e}")))?;
|
||||
|
||||
// Extract links
|
||||
let links = pinakes_core::links::extract_links(media_id, &content);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub struct TimelineQuery {
|
|||
pub limit: u64,
|
||||
}
|
||||
|
||||
fn default_timeline_limit() -> u64 {
|
||||
const fn default_timeline_limit() -> u64 {
|
||||
10000
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,19 @@ use axum::{
|
|||
use pinakes_core::{model::MediaId, playlists::Playlist, users::UserId};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{auth::resolve_user_id, dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
auth::resolve_user_id,
|
||||
dto::{
|
||||
CreatePlaylistRequest,
|
||||
MediaResponse,
|
||||
PlaylistItemRequest,
|
||||
PlaylistResponse,
|
||||
ReorderPlaylistRequest,
|
||||
UpdatePlaylistRequest,
|
||||
},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
/// Check whether a user has access to a playlist.
|
||||
///
|
||||
|
|
@ -138,12 +150,11 @@ pub async fn add_item(
|
|||
) -> Result<Json<serde_json::Value>, ApiError> {
|
||||
let user_id = resolve_user_id(&state.storage, &username).await?;
|
||||
check_playlist_access(&state.storage, id, user_id, true).await?;
|
||||
let position = match req.position {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
let items = state.storage.get_playlist_items(id).await?;
|
||||
items.len() as i32
|
||||
},
|
||||
let position = if let Some(p) = req.position {
|
||||
p
|
||||
} else {
|
||||
let items = state.storage.get_playlist_items(id).await?;
|
||||
items.len() as i32
|
||||
};
|
||||
state
|
||||
.storage
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use axum::{
|
|||
extract::{Path, State},
|
||||
};
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{InstallPluginRequest, PluginResponse, TogglePluginRequest},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
/// List all installed plugins
|
||||
pub async fn list_plugins(
|
||||
|
|
@ -37,8 +41,7 @@ pub async fn get_plugin(
|
|||
|
||||
let plugin = plugin_manager.get_plugin(&id).await.ok_or_else(|| {
|
||||
ApiError(pinakes_core::error::PinakesError::NotFound(format!(
|
||||
"Plugin not found: {}",
|
||||
id
|
||||
"Plugin not found: {id}"
|
||||
)))
|
||||
})?;
|
||||
|
||||
|
|
@ -63,7 +66,7 @@ pub async fn install_plugin(
|
|||
.await
|
||||
.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("Failed to install plugin: {}", e),
|
||||
format!("Failed to install plugin: {e}"),
|
||||
))
|
||||
})?;
|
||||
|
||||
|
|
@ -91,7 +94,7 @@ pub async fn uninstall_plugin(
|
|||
|
||||
plugin_manager.uninstall_plugin(&id).await.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("Failed to uninstall plugin: {}", e),
|
||||
format!("Failed to uninstall plugin: {e}"),
|
||||
))
|
||||
})?;
|
||||
|
||||
|
|
@ -113,13 +116,13 @@ pub async fn toggle_plugin(
|
|||
if req.enabled {
|
||||
plugin_manager.enable_plugin(&id).await.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("Failed to enable plugin: {}", e),
|
||||
format!("Failed to enable plugin: {e}"),
|
||||
))
|
||||
})?;
|
||||
} else {
|
||||
plugin_manager.disable_plugin(&id).await.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("Failed to disable plugin: {}", e),
|
||||
format!("Failed to disable plugin: {e}"),
|
||||
))
|
||||
})?;
|
||||
}
|
||||
|
|
@ -143,7 +146,7 @@ pub async fn reload_plugin(
|
|||
|
||||
plugin_manager.reload_plugin(&id).await.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("Failed to reload plugin: {}", e),
|
||||
format!("Failed to reload plugin: {e}"),
|
||||
))
|
||||
})?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
use axum::{Json, extract::State};
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{ScanJobResponse, ScanRequest, ScanStatusResponse},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
/// Trigger a scan as a background job. Returns the job ID immediately.
|
||||
pub async fn trigger_scan(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ use pinakes_core::{
|
|||
search::{SearchRequest, SortOrder, parse_search_query},
|
||||
};
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{MediaResponse, SearchParams, SearchRequestBody, SearchResponse},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
fn resolve_sort(sort: Option<&str>) -> SortOrder {
|
||||
match sort {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,21 @@ use pinakes_core::model::{MediaId, Pagination};
|
|||
use serde::Deserialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{auth::resolve_user_id, dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
auth::resolve_user_id,
|
||||
dto::{
|
||||
CommentResponse,
|
||||
CreateCommentRequest,
|
||||
CreateRatingRequest,
|
||||
CreateShareLinkRequest,
|
||||
FavoriteRequest,
|
||||
MediaResponse,
|
||||
RatingResponse,
|
||||
ShareLinkResponse,
|
||||
},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ShareLinkQuery {
|
||||
|
|
@ -133,8 +147,7 @@ pub async fn create_share_link(
|
|||
{
|
||||
return Err(ApiError(
|
||||
pinakes_core::error::PinakesError::InvalidOperation(format!(
|
||||
"expires_in_hours cannot exceed {}",
|
||||
MAX_EXPIRY_HOURS
|
||||
"expires_in_hours cannot exceed {MAX_EXPIRY_HOURS}"
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ pub async fn hls_variant_playlist(
|
|||
);
|
||||
for i in 0..num_segments.max(1) {
|
||||
let seg_dur = if i == num_segments.saturating_sub(1) && duration > 0.0 {
|
||||
duration - (i as f64 * segment_duration)
|
||||
(i as f64).mul_add(-segment_duration, duration)
|
||||
} else {
|
||||
segment_duration
|
||||
};
|
||||
|
|
@ -143,7 +143,7 @@ pub async fn hls_segment(
|
|||
if segment_path.exists() {
|
||||
let data = tokio::fs::read(&segment_path).await.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("failed to read segment: {}", e),
|
||||
format!("failed to read segment: {e}"),
|
||||
))
|
||||
})?;
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ pub async fn dash_segment(
|
|||
if segment_path.exists() {
|
||||
let data = tokio::fs::read(&segment_path).await.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("failed to read segment: {}", e),
|
||||
format!("failed to read segment: {e}"),
|
||||
))
|
||||
})?;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ use pinakes_core::{
|
|||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{AddSubtitleRequest, SubtitleResponse, UpdateSubtitleOffsetRequest},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub async fn list_subtitles(
|
||||
State(state): State<AppState>,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ use axum::{
|
|||
use pinakes_core::model::MediaId;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{CreateTagRequest, TagMediaRequest, TagResponse},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub async fn create_tag(
|
||||
State(state): State<AppState>,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ use axum::{
|
|||
use pinakes_core::model::MediaId;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{CreateTranscodeRequest, PaginationParams, TranscodeSessionResponse},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
pub async fn start_transcode(
|
||||
State(state): State<AppState>,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,16 @@ use axum::{
|
|||
};
|
||||
use pinakes_core::users::{CreateUserRequest, UpdateUserRequest, UserId};
|
||||
|
||||
use crate::{dto::*, error::ApiError, state::AppState};
|
||||
use crate::{
|
||||
dto::{
|
||||
GrantLibraryAccessRequest,
|
||||
RevokeLibraryAccessRequest,
|
||||
UserLibraryResponse,
|
||||
UserResponse,
|
||||
},
|
||||
error::ApiError,
|
||||
state::AppState,
|
||||
};
|
||||
|
||||
/// List all users (admin only)
|
||||
pub async fn list_users(
|
||||
|
|
@ -175,7 +184,7 @@ pub async fn grant_library_access(
|
|||
|
||||
/// Revoke library access from a user (admin only)
|
||||
///
|
||||
/// Uses a JSON body instead of a path parameter because root_path may contain
|
||||
/// Uses a JSON body instead of a path parameter because `root_path` may contain
|
||||
/// slashes that conflict with URL routing.
|
||||
pub async fn revoke_library_access(
|
||||
State(state): State<AppState>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue