added asset manegement
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user