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)
|
||||
path.parent().is_some_and(|parent| {
|
||||
std::fs::metadata(parent).is_ok_and(|m| !m.permissions().readonly())
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
},
|
||||
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)
|
||||
path.parent().is_some_and(|parent| {
|
||||
std::fs::metadata(parent).is_ok_and(|m| !m.permissions().readonly())
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
},
|
||||
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 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>,
|
||||
|
|
|
|||
|
|
@ -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<SocketAddr>)
|
||||
/// Fake socket address for tests (governor needs `ConnectInfo`<SocketAddr>)
|
||||
fn test_addr() -> ConnectInfo<SocketAddr> {
|
||||
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<Body> {
|
||||
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<Body> {
|
||||
let mut req = Request::builder()
|
||||
.method("POST")
|
||||
|
|
@ -69,7 +70,7 @@ fn post_json(uri: &str, body: &str) -> Request<Body> {
|
|||
fn get_authed(uri: &str, token: &str) -> Request<Body> {
|
||||
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<Body> {
|
|||
.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<Body> {
|
|||
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<Body> {
|
|||
.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",
|
||||
|
|
|
|||
|
|
@ -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<SocketAddr>)
|
||||
/// Fake socket address for tests (governor needs `ConnectInfo`<SocketAddr>)
|
||||
fn test_addr() -> ConnectInfo<SocketAddr> {
|
||||
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<Body> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue