use crate::{ handlers::{ albums, assets, auth, duplicates, health, processing, sharing, sidecar, stacks, storage, }, middleware::auth::require_auth, openapi::openapi_router, state::AppState, }; use axum::{ Router, middleware::from_fn_with_state, routing::{delete, get, post, put}, }; fn public_routes() -> Router { Router::new() .route("/auth/register", post(auth::register)) .route("/auth/login", post(auth::login)) .route("/auth/refresh", post(auth::refresh)) .route("/sharing/access/{token}", get(sharing::access_by_token)) } fn protected_routes(state: &AppState) -> Router { Router::new() // auth .route("/auth/me", get(auth::me)) .route("/auth/logout", post(auth::logout)) // albums .route( "/albums", get(albums::list_albums).post(albums::create_album), ) .route( "/albums/{id}", get(albums::get_album).put(albums::update_album), ) .route("/albums/{id}/entries", post(albums::add_entry)) .route( "/albums/{id}/entries/{asset_id}", delete(albums::remove_entry), ) // assets .route("/assets", get(assets::search_assets)) .route("/assets/ingest", post(assets::ingest)) .route("/assets/register", post(assets::register_asset)) .route("/assets/timeline", get(assets::timeline)) .route( "/assets/{id}", get(assets::get_asset).delete(assets::delete_asset), ) .route("/assets/{id}/metadata", put(assets::update_metadata)) .route("/assets/{id}/file", get(assets::serve_file)) .route( "/assets/{id}/derivatives/{profile}", get(assets::serve_derivative), ) .route("/assets/{id}/tags", post(assets::tag_asset)) .route("/assets/bulk-delete", post(assets::bulk_delete)) .route("/assets/bulk-tag", post(assets::bulk_tag)) // stacks .route( "/stacks", get(stacks::list_stacks).post(stacks::create_stack), ) .route( "/stacks/detect-live-photos", post(stacks::detect_live_photos), ) .route( "/stacks/{id}", get(stacks::get_stack).delete(stacks::delete_stack), ) // duplicates .route("/duplicates", get(duplicates::list_duplicates)) .route( "/duplicates/{id}/resolve", post(duplicates::resolve_duplicate), ) // sharing .route("/sharing", post(sharing::share_resource)) .route("/sharing/links", post(sharing::generate_link)) .route("/sharing/{id}", delete(sharing::revoke)) // storage .route("/storage/volumes", post(storage::register_volume)) .route( "/storage/library-paths", post(storage::register_library_path), ) .route("/storage/quota", get(storage::check_quota)) // sidecar .route("/sidecar/export/{asset_id}", post(sidecar::export_sidecar)) .route("/sidecar/detect-changes", post(sidecar::detect_changes)) .route("/sidecar/import/{asset_id}", post(sidecar::import_sidecar)) .route( "/sidecar/resolve/{asset_id}", post(sidecar::resolve_conflict), ) .route("/sidecar/full-export", post(sidecar::full_export)) .route("/sidecar/full-import", post(sidecar::full_import)) // processing .route( "/jobs", get(processing::list_jobs).post(processing::enqueue_job), ) .route("/jobs/{id}/start", post(processing::start_job)) .route("/jobs/{id}/complete", post(processing::complete_job)) .route("/jobs/{id}/fail", post(processing::fail_job)) .route("/jobs/batches/{id}", get(processing::batch_progress)) .route("/plugins", post(processing::manage_plugin)) .route("/pipelines", post(processing::configure_pipeline)) .route_layer(from_fn_with_state(state.clone(), require_auth)) } pub fn app_router(state: &AppState) -> Router { Router::new() .route("/health", get(health::health)) .nest("/api/v1", public_routes().merge(protected_routes(state))) .merge(openapi_router()) }