added asset manegement

This commit is contained in:
2026-03-27 14:27:01 +01:00
parent 8e10cb9d17
commit d7e44a84d5
6 changed files with 279 additions and 151 deletions

View File

@@ -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<bool>,
}
pub async fn delete_upload(
State(state): State<Arc<AppState>>,
headers: HeaderMap,
Path(filename): Path<String>,
) -> Result<StatusCode, AppError> {
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<Arc<AppState>>,
headers: HeaderMap,
@@ -42,6 +74,7 @@ pub async fn list_uploads(
pub async fn upload_file(
State(state): State<Arc<AppState>>,
headers: HeaderMap,
Query(query): Query<UploadQuery>,
mut multipart: Multipart,
) -> Result<Json<UploadResponse>, 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 {

View File

@@ -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))