diff --git a/crates/pinakes-server/src/routes/audit.rs b/crates/pinakes-server/src/routes/audit.rs index b39cf8f..191c93f 100644 --- a/crates/pinakes-server/src/routes/audit.rs +++ b/crates/pinakes-server/src/routes/audit.rs @@ -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, diff --git a/crates/pinakes-server/src/routes/collections.rs b/crates/pinakes-server/src/routes/collections.rs index 723c800..9ca72c3 100644 --- a/crates/pinakes-server/src/routes/collections.rs +++ b/crates/pinakes-server/src/routes/collections.rs @@ -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, diff --git a/crates/pinakes-server/src/routes/config.rs b/crates/pinakes-server/src/routes/config.rs index 1124a89..2311178 100644 --- a/crates/pinakes-server/src/routes/config.rs +++ b/crates/pinakes-server/src/routes/config.rs @@ -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, @@ -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, diff --git a/crates/pinakes-server/src/routes/enrichment.rs b/crates/pinakes-server/src/routes/enrichment.rs index a7f3a91..0229d55 100644 --- a/crates/pinakes-server/src/routes/enrichment.rs +++ b/crates/pinakes-server/src/routes/enrichment.rs @@ -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, diff --git a/crates/pinakes-server/src/routes/health.rs b/crates/pinakes-server/src/routes/health.rs index 9eb0fa8..cffabb3 100644 --- a/crates/pinakes-server/src/routes/health.rs +++ b/crates/pinakes-server/src/routes/health.rs @@ -65,7 +65,7 @@ pub async fn health(State(state): State) -> Json { 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; diff --git a/crates/pinakes-server/src/routes/integrity.rs b/crates/pinakes-server/src/routes/integrity.rs index bdf9f49..d6a84ea 100644 --- a/crates/pinakes-server/src/routes/integrity.rs +++ b/crates/pinakes-server/src/routes/integrity.rs @@ -56,7 +56,7 @@ pub async fn generate_all_thumbnails( State(state): State, body: Option>, ) -> Result, 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) diff --git a/crates/pinakes-server/src/routes/notes.rs b/crates/pinakes-server/src/routes/notes.rs index b682db9..0fca5a3 100644 --- a/crates/pinakes-server/src/routes/notes.rs +++ b/crates/pinakes-server/src/routes/notes.rs @@ -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); diff --git a/crates/pinakes-server/src/routes/photos.rs b/crates/pinakes-server/src/routes/photos.rs index 02f7a50..edf04b6 100644 --- a/crates/pinakes-server/src/routes/photos.rs +++ b/crates/pinakes-server/src/routes/photos.rs @@ -33,7 +33,7 @@ pub struct TimelineQuery { pub limit: u64, } -fn default_timeline_limit() -> u64 { +const fn default_timeline_limit() -> u64 { 10000 } diff --git a/crates/pinakes-server/src/routes/playlists.rs b/crates/pinakes-server/src/routes/playlists.rs index b36a441..15df830 100644 --- a/crates/pinakes-server/src/routes/playlists.rs +++ b/crates/pinakes-server/src/routes/playlists.rs @@ -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, 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 diff --git a/crates/pinakes-server/src/routes/plugins.rs b/crates/pinakes-server/src/routes/plugins.rs index a2a21a2..77a03a7 100644 --- a/crates/pinakes-server/src/routes/plugins.rs +++ b/crates/pinakes-server/src/routes/plugins.rs @@ -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}"), )) })?; diff --git a/crates/pinakes-server/src/routes/scan.rs b/crates/pinakes-server/src/routes/scan.rs index 6fc9f2c..b9aef1b 100644 --- a/crates/pinakes-server/src/routes/scan.rs +++ b/crates/pinakes-server/src/routes/scan.rs @@ -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( diff --git a/crates/pinakes-server/src/routes/search.rs b/crates/pinakes-server/src/routes/search.rs index 7db6231..3201047 100644 --- a/crates/pinakes-server/src/routes/search.rs +++ b/crates/pinakes-server/src/routes/search.rs @@ -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 { diff --git a/crates/pinakes-server/src/routes/social.rs b/crates/pinakes-server/src/routes/social.rs index ae9a66e..b270ae0 100644 --- a/crates/pinakes-server/src/routes/social.rs +++ b/crates/pinakes-server/src/routes/social.rs @@ -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}" )), )); } diff --git a/crates/pinakes-server/src/routes/streaming.rs b/crates/pinakes-server/src/routes/streaming.rs index e3d1aa0..92ae897 100644 --- a/crates/pinakes-server/src/routes/streaming.rs +++ b/crates/pinakes-server/src/routes/streaming.rs @@ -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}"), )) })?; diff --git a/crates/pinakes-server/src/routes/subtitles.rs b/crates/pinakes-server/src/routes/subtitles.rs index 230dc4d..3e94770 100644 --- a/crates/pinakes-server/src/routes/subtitles.rs +++ b/crates/pinakes-server/src/routes/subtitles.rs @@ -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, diff --git a/crates/pinakes-server/src/routes/tags.rs b/crates/pinakes-server/src/routes/tags.rs index 20dbba0..449c78d 100644 --- a/crates/pinakes-server/src/routes/tags.rs +++ b/crates/pinakes-server/src/routes/tags.rs @@ -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, diff --git a/crates/pinakes-server/src/routes/transcode.rs b/crates/pinakes-server/src/routes/transcode.rs index a4af624..b98ad4f 100644 --- a/crates/pinakes-server/src/routes/transcode.rs +++ b/crates/pinakes-server/src/routes/transcode.rs @@ -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, diff --git a/crates/pinakes-server/src/routes/users.rs b/crates/pinakes-server/src/routes/users.rs index 8b2a828..65dfbd2 100644 --- a/crates/pinakes-server/src/routes/users.rs +++ b/crates/pinakes-server/src/routes/users.rs @@ -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, diff --git a/crates/pinakes-server/tests/api.rs b/crates/pinakes-server/tests/api.rs index 5fe46f0..379b07f 100644 --- a/crates/pinakes-server/tests/api.rs +++ b/crates/pinakes-server/tests/api.rs @@ -19,6 +19,7 @@ use pinakes_core::{ ManagedStorageConfig, PhotoConfig, PluginsConfig, + RateLimitConfig, ScanningConfig, ServerConfig, SharingConfig, @@ -41,19 +42,19 @@ use pinakes_core::{ use tokio::sync::RwLock; use tower::ServiceExt; -/// Fake socket address for tests (governor needs ConnectInfo) +/// Fake socket address for tests (governor needs `ConnectInfo`) fn test_addr() -> ConnectInfo { ConnectInfo("127.0.0.1:9999".parse().unwrap()) } -/// Build a GET request with ConnectInfo for rate limiter compatibility +/// Build a GET request with `ConnectInfo` for rate limiter compatibility fn get(uri: &str) -> Request { let mut req = Request::builder().uri(uri).body(Body::empty()).unwrap(); req.extensions_mut().insert(test_addr()); req } -/// Build a POST request with ConnectInfo +/// Build a POST request with `ConnectInfo` fn post_json(uri: &str, body: &str) -> Request { let mut req = Request::builder() .method("POST") @@ -69,7 +70,7 @@ fn post_json(uri: &str, body: &str) -> Request { fn get_authed(uri: &str, token: &str) -> Request { let mut req = Request::builder() .uri(uri) - .header("authorization", format!("Bearer {}", token)) + .header("authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(); req.extensions_mut().insert(test_addr()); @@ -82,7 +83,7 @@ fn post_json_authed(uri: &str, body: &str, token: &str) -> Request { .method("POST") .uri(uri) .header("content-type", "application/json") - .header("authorization", format!("Bearer {}", token)) + .header("authorization", format!("Bearer {token}")) .body(Body::from(body.to_string())) .unwrap(); req.extensions_mut().insert(test_addr()); @@ -94,7 +95,7 @@ fn delete_authed(uri: &str, token: &str) -> Request { let mut req = Request::builder() .method("DELETE") .uri(uri) - .header("authorization", format!("Bearer {}", token)) + .header("authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(); req.extensions_mut().insert(test_addr()); @@ -107,7 +108,7 @@ fn patch_json_authed(uri: &str, body: &str, token: &str) -> Request { .method("PATCH") .uri(uri) .header("content-type", "application/json") - .header("authorization", format!("Bearer {}", token)) + .header("authorization", format!("Bearer {token}")) .body(Body::from(body.to_string())) .unwrap(); req.extensions_mut().insert(test_addr()); @@ -136,7 +137,10 @@ fn default_config() -> Config { api_key: None, tls: TlsConfig::default(), authentication_disabled: true, + cors_enabled: false, + cors_origins: vec![], }, + rate_limits: RateLimitConfig::default(), ui: UiConfig::default(), accounts: AccountsConfig::default(), jobs: JobsConfig::default(), @@ -164,7 +168,7 @@ async fn setup_app() -> axum::Router { let config = default_config(); let job_queue = - JobQueue::new(1, |_id, _kind, _cancel, _jobs| tokio::spawn(async {})); + JobQueue::new(1, 0, |_id, _kind, _cancel, _jobs| tokio::spawn(async {})); let config = Arc::new(RwLock::new(config)); let scheduler = pinakes_core::scheduler::TaskScheduler::new( job_queue.clone(), @@ -186,9 +190,10 @@ async fn setup_app() -> axum::Router { managed_storage: None, chunked_upload_manager: None, session_semaphore: Arc::new(tokio::sync::Semaphore::new(64)), + webhook_dispatcher: None, }; - pinakes_server::app::create_router(state) + pinakes_server::app::create_router(state, &RateLimitConfig::default()) } /// Hash a password for test user accounts @@ -197,7 +202,7 @@ fn hash_password(password: &str) -> String { } /// Set up an app with accounts enabled and three pre-seeded users. -/// Returns (Router, admin_token, editor_token, viewer_token). +/// Returns (Router, `admin_token`, `editor_token`, `viewer_token`). async fn setup_app_with_auth() -> (axum::Router, String, String, String) { let backend = SqliteBackend::in_memory().expect("in-memory SQLite"); backend.run_migrations().await.expect("migrations"); @@ -239,7 +244,7 @@ async fn setup_app_with_auth() -> (axum::Router, String, String, String) { ]; let job_queue = - JobQueue::new(1, |_id, _kind, _cancel, _jobs| tokio::spawn(async {})); + JobQueue::new(1, 0, |_id, _kind, _cancel, _jobs| tokio::spawn(async {})); let config = Arc::new(RwLock::new(config)); let scheduler = pinakes_core::scheduler::TaskScheduler::new( job_queue.clone(), @@ -261,9 +266,11 @@ async fn setup_app_with_auth() -> (axum::Router, String, String, String) { managed_storage: None, chunked_upload_manager: None, session_semaphore: Arc::new(tokio::sync::Semaphore::new(64)), + webhook_dispatcher: None, }; - let app = pinakes_server::app::create_router(state); + let app = + pinakes_server::app::create_router(state, &RateLimitConfig::default()); // Login each user to get tokens let admin_token = login_user(app.clone(), "admin", "adminpass").await; @@ -278,8 +285,7 @@ async fn login_user( username: &str, password: &str, ) -> String { - let body = - format!(r#"{{"username":"{}","password":"{}"}}"#, username, password); + let body = format!(r#"{{"username":"{username}","password":"{password}"}}"#); let response = app .oneshot(post_json("/api/v1/auth/login", &body)) .await @@ -287,8 +293,7 @@ async fn login_user( assert_eq!( response.status(), StatusCode::OK, - "login failed for user {}", - username + "login failed for user {username}" ); let body = response.into_body().collect().await.unwrap().to_bytes(); let result: serde_json::Value = serde_json::from_slice(&body).unwrap(); @@ -449,7 +454,7 @@ async fn test_user_management_crud() { // Get specific user let response = app .clone() - .oneshot(get(&format!("/api/v1/users/{}", user_id))) + .oneshot(get(&format!("/api/v1/users/{user_id}"))) .await .unwrap(); @@ -462,7 +467,7 @@ async fn test_user_management_crud() { // Delete user let mut req = Request::builder() .method("DELETE") - .uri(&format!("/api/v1/users/{}", user_id)) + .uri(format!("/api/v1/users/{user_id}")) .body(Body::empty()) .unwrap(); req.extensions_mut().insert(test_addr()); @@ -472,7 +477,7 @@ async fn test_user_management_crud() { // Verify user is deleted let response = app - .oneshot(get(&format!("/api/v1/users/{}", user_id))) + .oneshot(get(&format!("/api/v1/users/{user_id}"))) .await .unwrap(); assert_eq!(response.status(), StatusCode::NOT_FOUND); @@ -796,7 +801,7 @@ async fn test_playlist_crud() { let response = app .clone() .oneshot(get_authed( - &format!("/api/v1/playlists/{}", playlist_id), + &format!("/api/v1/playlists/{playlist_id}"), &editor_token, )) .await @@ -807,7 +812,7 @@ async fn test_playlist_crud() { let response = app .clone() .oneshot(patch_json_authed( - &format!("/api/v1/playlists/{}", playlist_id), + &format!("/api/v1/playlists/{playlist_id}"), r#"{"name":"Updated Playlist","description":"A test description"}"#, &editor_token, )) @@ -821,7 +826,7 @@ async fn test_playlist_crud() { let response = app .clone() .oneshot(delete_authed( - &format!("/api/v1/playlists/{}", playlist_id), + &format!("/api/v1/playlists/{playlist_id}"), &editor_token, )) .await @@ -972,7 +977,7 @@ async fn test_oversized_comment() { let (app, _, editor_token, _) = setup_app_with_auth().await; let long_text: String = "x".repeat(10_001); - let body = format!(r#"{{"text":"{}"}}"#, long_text); + let body = format!(r#"{{"text":"{long_text}"}}"#); let response = app .oneshot(post_json_authed( "/api/v1/media/00000000-0000-0000-0000-000000000000/comments", diff --git a/crates/pinakes-server/tests/plugin.rs b/crates/pinakes-server/tests/plugin.rs index 0a07462..c9d1560 100644 --- a/crates/pinakes-server/tests/plugin.rs +++ b/crates/pinakes-server/tests/plugin.rs @@ -19,6 +19,7 @@ use pinakes_core::{ ManagedStorageConfig, PhotoConfig, PluginsConfig, + RateLimitConfig, ScanningConfig, ServerConfig, SharingConfig, @@ -40,12 +41,12 @@ use pinakes_core::{ use tokio::sync::RwLock; use tower::ServiceExt; -/// Fake socket address for tests (governor needs ConnectInfo) +/// Fake socket address for tests (governor needs `ConnectInfo`) fn test_addr() -> ConnectInfo { ConnectInfo("127.0.0.1:9999".parse().unwrap()) } -/// Build a GET request with ConnectInfo for rate limiter compatibility +/// Build a GET request with `ConnectInfo` for rate limiter compatibility fn get(uri: &str) -> Request { let mut req = Request::builder().uri(uri).body(Body::empty()).unwrap(); req.extensions_mut().insert(test_addr()); @@ -103,7 +104,10 @@ async fn setup_app_with_plugins() api_key: None, tls: TlsConfig::default(), authentication_disabled: true, + cors_enabled: false, + cors_origins: vec![], }, + rate_limits: RateLimitConfig::default(), ui: UiConfig::default(), accounts: AccountsConfig::default(), jobs: JobsConfig::default(), @@ -123,7 +127,7 @@ async fn setup_app_with_plugins() }; let job_queue = - JobQueue::new(1, |_id, _kind, _cancel, _jobs| tokio::spawn(async {})); + JobQueue::new(1, 0, |_id, _kind, _cancel, _jobs| tokio::spawn(async {})); let config = Arc::new(RwLock::new(config)); let scheduler = pinakes_core::scheduler::TaskScheduler::new( job_queue.clone(), @@ -145,9 +149,11 @@ async fn setup_app_with_plugins() managed_storage: None, chunked_upload_manager: None, session_semaphore: Arc::new(tokio::sync::Semaphore::new(64)), + webhook_dispatcher: None, }; - let router = pinakes_server::app::create_router(state); + let router = + pinakes_server::app::create_router(state, &RateLimitConfig::default()); (router, plugin_manager, temp_dir) }