From d7e44a84d5de93e7b9669f481762135dea787e3a Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Fri, 27 Mar 2026 14:27:01 +0100 Subject: [PATCH] added asset manegement --- backend/src/handlers/upload.rs | 39 ++++- backend/src/main.rs | 1 + frontend/src/components/AssetManager.astro | 178 +++++++++++++++++++++ frontend/src/pages/admin/assets.astro | 10 ++ frontend/src/pages/admin/editor.astro | 172 ++++---------------- frontend/src/pages/admin/index.astro | 30 ++-- 6 files changed, 279 insertions(+), 151 deletions(-) create mode 100644 frontend/src/components/AssetManager.astro create mode 100644 frontend/src/pages/admin/assets.astro diff --git a/backend/src/handlers/upload.rs b/backend/src/handlers/upload.rs index 49ebf12..7aa45d7 100644 --- a/backend/src/handlers/upload.rs +++ b/backend/src/handlers/upload.rs @@ -1,8 +1,9 @@ use axum::{ Json, - extract::{Multipart, State}, - http::HeaderMap, + extract::{Multipart, State, Path, Query}, + http::{HeaderMap, StatusCode}, }; +use serde::Deserialize; use std::{fs, sync::Arc}; use tracing::{error, info, warn}; @@ -13,6 +14,37 @@ use crate::{ models::{FileInfo, UploadResponse}, }; +#[derive(Deserialize)] +pub struct UploadQuery { + pub replace: Option, +} + +pub async fn delete_upload( + State(state): State>, + headers: HeaderMap, + Path(filename): Path, +) -> Result { + check_auth(&headers, &state.admin_token)?; + + let file_path = state.data_dir.join("uploads").join(&filename); + + // Security check to prevent directory traversal + if file_path.parent() != Some(&state.data_dir.join("uploads")) { + return Err(AppError::BadRequest("Invalid filename".to_string())); + } + + if file_path.exists() { + fs::remove_file(file_path).map_err(|e| { + error!("Delete error for file {}: {}", filename, e); + AppError::Internal("Delete error".to_string(), Some(e.to_string())) + })?; + info!("Deleted file: {}", filename); + Ok(StatusCode::NO_CONTENT) + } else { + Err(AppError::NotFound("File not found".to_string())) + } +} + pub async fn list_uploads( State(state): State>, headers: HeaderMap, @@ -42,6 +74,7 @@ pub async fn list_uploads( pub async fn upload_file( State(state): State>, headers: HeaderMap, + Query(query): Query, mut multipart: Multipart, ) -> Result, AppError> { check_auth(&headers, &state.admin_token)?; @@ -71,7 +104,7 @@ pub async fn upload_file( let uploads_dir = state.data_dir.join("uploads"); let file_path = uploads_dir.join(&final_name); - let final_path = if file_path.exists() { + let final_path = if file_path.exists() && !query.replace.unwrap_or(false) { let timestamp = chrono::Utc::now().timestamp(); uploads_dir.join(format!("{}_{}", timestamp, final_name)) } else { diff --git a/backend/src/main.rs b/backend/src/main.rs index 4f18c29..5599aab 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -67,6 +67,7 @@ async fn main() { get(handlers::posts::get_post).delete(handlers::posts::delete_post), ) .route("/api/uploads", get(handlers::upload::list_uploads)) + .route("/api/uploads/{filename}", delete(handlers::upload::delete_upload)) .route("/api/upload", post(handlers::upload::upload_file)) .nest_service("/uploads", ServeDir::new(uploads_dir)) .layer(DefaultBodyLimit::max(50 * 1024 * 1024)) diff --git a/frontend/src/components/AssetManager.astro b/frontend/src/components/AssetManager.astro new file mode 100644 index 0000000..0ebd94c --- /dev/null +++ b/frontend/src/components/AssetManager.astro @@ -0,0 +1,178 @@ +--- +interface Props { + mode?: 'select' | 'manage'; +} + +const { mode = 'manage' } = Astro.props; +--- + +
+ + + +
+ +
+ +

Click or drag to upload assets

+

Any file type up to 50MB

+
+
+ + +
+ +
+ +
+ + diff --git a/frontend/src/pages/admin/assets.astro b/frontend/src/pages/admin/assets.astro new file mode 100644 index 0000000..21f4e7a --- /dev/null +++ b/frontend/src/pages/admin/assets.astro @@ -0,0 +1,10 @@ +--- +import AdminLayout from '../../layouts/AdminLayout.astro'; +import AssetManager from '../../components/AssetManager.astro'; +--- + + +

Manage your uploaded images and files.

+ + +
diff --git a/frontend/src/pages/admin/editor.astro b/frontend/src/pages/admin/editor.astro index d99af13..aa65145 100644 --- a/frontend/src/pages/admin/editor.astro +++ b/frontend/src/pages/admin/editor.astro @@ -1,5 +1,6 @@ --- import AdminLayout from '../../layouts/AdminLayout.astro'; +import AssetManager from '../../components/AssetManager.astro'; --- @@ -54,24 +55,13 @@ import AdminLayout from '../../layouts/AdminLayout.astro';
-
- - - - -
+