use axum::{ Json, extract::{Path, State}, }; use pinakes_core::model::{CollectionKind, MediaId}; use uuid::Uuid; use crate::{ dto::{ AddMemberRequest, CollectionResponse, CreateCollectionRequest, MediaResponse, }, error::ApiError, state::AppState, }; pub async fn create_collection( State(state): State, Json(req): Json, ) -> Result, ApiError> { if req.name.is_empty() || req.name.len() > 255 { return Err(ApiError( pinakes_core::error::PinakesError::InvalidOperation( "collection name must be 1-255 characters".into(), ), )); } if let Some(ref desc) = req.description && desc.len() > 10_000 { return Err(ApiError( pinakes_core::error::PinakesError::InvalidOperation( "description exceeds 10000 characters".into(), ), )); } let kind = match req.kind.as_str() { "virtual" => CollectionKind::Virtual, _ => CollectionKind::Manual, }; let col = pinakes_core::collections::create_collection( &state.storage, &req.name, kind, req.description.as_deref(), req.filter_query.as_deref(), ) .await?; state.emit_plugin_event( "CollectionCreated", &serde_json::json!({ "id": col.id.to_string(), "name": col.name, }), ); Ok(Json(CollectionResponse::from(col))) } pub async fn list_collections( State(state): State, ) -> Result>, ApiError> { let cols = state.storage.list_collections().await?; Ok(Json( cols.into_iter().map(CollectionResponse::from).collect(), )) } pub async fn get_collection( State(state): State, Path(id): Path, ) -> Result, ApiError> { let col = state.storage.get_collection(id).await?; Ok(Json(CollectionResponse::from(col))) } pub async fn delete_collection( State(state): State, Path(id): Path, ) -> Result, ApiError> { state.storage.delete_collection(id).await?; state.emit_plugin_event( "CollectionDeleted", &serde_json::json!({"id": id.to_string()}), ); Ok(Json(serde_json::json!({"deleted": true}))) } pub async fn add_member( State(state): State, Path(collection_id): Path, Json(req): Json, ) -> Result, ApiError> { pinakes_core::collections::add_member( &state.storage, collection_id, MediaId(req.media_id), req.position.unwrap_or(0), ) .await?; Ok(Json(serde_json::json!({"added": true}))) } pub async fn remove_member( State(state): State, Path((collection_id, media_id)): Path<(Uuid, Uuid)>, ) -> Result, ApiError> { pinakes_core::collections::remove_member( &state.storage, collection_id, MediaId(media_id), ) .await?; Ok(Json(serde_json::json!({"removed": true}))) } pub async fn get_members( State(state): State, Path(collection_id): Path, ) -> Result>, ApiError> { let items = pinakes_core::collections::get_members(&state.storage, collection_id) .await?; let roots = state.config.read().await.directories.roots.clone(); Ok(Json( items .into_iter() .map(|item| MediaResponse::new(item, &roots)) .collect(), )) }