From 6ba897d27f71965454084737d3a1328d8d238e9d Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Wed, 25 Mar 2026 16:52:57 +0100 Subject: [PATCH] fixed missing attribute --- backend/src/main.rs | 107 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/backend/src/main.rs b/backend/src/main.rs index be59e9f..d6110e2 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,9 +1,9 @@ use axum::{ + Router, extract::{DefaultBodyLimit, Multipart, Path, State}, http::{HeaderMap, StatusCode}, response::{IntoResponse, Json}, - routing::{get, post, delete}, - Router, + routing::{delete, get, post}, }; use serde::{Deserialize, Serialize}; use std::{env, fs, path::PathBuf, sync::Arc}; @@ -45,6 +45,7 @@ impl Default for SiteConfig { #[derive(Serialize)] struct PostInfo { slug: String, + excerpt: String, } #[derive(Serialize)] @@ -125,13 +126,19 @@ async fn main() { axum::serve(listener, app).await.unwrap(); } -fn check_auth(headers: &HeaderMap, admin_token: &str) -> Result<(), (StatusCode, Json)> { +fn check_auth( + headers: &HeaderMap, + admin_token: &str, +) -> Result<(), (StatusCode, Json)> { let auth_header = headers.get("Authorization").and_then(|h| h.to_str().ok()); if auth_header != Some(&format!("Bearer {}", admin_token)) { warn!("Unauthorized access attempt detected"); return Err(( StatusCode::UNAUTHORIZED, - Json(ErrorResponse { error: "Unauthorized".to_string(), details: None }), + Json(ErrorResponse { + error: "Unauthorized".to_string(), + details: None, + }), )); } Ok(()) @@ -143,7 +150,7 @@ async fn get_config(State(state): State>) -> impl IntoResponse { .ok() .and_then(|c| serde_json::from_str::(&c).ok()) .unwrap_or_default(); - + Json(config) } @@ -157,12 +164,24 @@ async fn update_config( let config_path = state.data_dir.join("config.json"); let config_str = serde_json::to_string_pretty(&payload).map_err(|e| { error!("Serialization error: {}", e); - (StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { error: "Serialization error".to_string(), details: Some(e.to_string()) })) + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + error: "Serialization error".to_string(), + details: Some(e.to_string()), + }), + ) })?; fs::write(&config_path, config_str).map_err(|e| { error!("Write error for config: {}", e); - (StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { error: "Write error".to_string(), details: Some(e.to_string()) })) + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + error: "Write error".to_string(), + details: Some(e.to_string()), + }), + ) })?; Ok(Json(payload)) @@ -178,15 +197,27 @@ async fn create_post( if payload.slug.contains('/') || payload.slug.contains('\\') || payload.slug.contains("..") { return Err(( StatusCode::BAD_REQUEST, - Json(ErrorResponse { error: "Invalid slug".to_string(), details: None }), + Json(ErrorResponse { + error: "Invalid slug".to_string(), + details: None, + }), )); } - let file_path = state.data_dir.join("posts").join(format!("{}.md", payload.slug)); - + let file_path = state + .data_dir + .join("posts") + .join(format!("{}.md", payload.slug)); + fs::write(&file_path, &payload.content).map_err(|e| { error!("Write error for post {}: {}", payload.slug, e); - (StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { error: "Write error".to_string(), details: Some(e.to_string()) })) + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + error: "Write error".to_string(), + details: Some(e.to_string()), + }), + ) })?; info!("Post created/updated: {}", payload.slug); @@ -205,18 +236,27 @@ async fn delete_post( let file_path = state.data_dir.join("posts").join(format!("{}.md", slug)); info!("Attempting to delete post at: {:?}", file_path); - + if !file_path.exists() { warn!("Post not found for deletion: {}", slug); return Err(( StatusCode::NOT_FOUND, - Json(ErrorResponse { error: "Post not found".to_string(), details: None }), + Json(ErrorResponse { + error: "Post not found".to_string(), + details: None, + }), )); } fs::remove_file(file_path).map_err(|e| { error!("Delete error for post {}: {}", slug, e); - (StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { error: "Delete error".to_string(), details: Some(e.to_string()) })) + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + error: "Delete error".to_string(), + details: Some(e.to_string()), + }), + ) })?; info!("Post deleted: {}", slug); @@ -284,12 +324,15 @@ async fn get_post( Path(slug): Path, ) -> Result, (StatusCode, Json)> { let file_path = state.data_dir.join("posts").join(format!("{}.md", slug)); - + match fs::read_to_string(&file_path) { Ok(content) => Ok(Json(PostDetail { slug, content })), Err(_) => Err(( StatusCode::NOT_FOUND, - Json(ErrorResponse { error: "Post not found".to_string(), details: None }), + Json(ErrorResponse { + error: "Post not found".to_string(), + details: None, + }), )), } } @@ -311,13 +354,13 @@ async fn upload_file( info!("Processing upload for: {}", file_name); let slugified_name = slug::slugify(&file_name); - + // Handle extension correctly after slugifying let extension = std::path::Path::new(&file_name) .extension() .and_then(|e| e.to_str()) .unwrap_or(""); - + let final_name = if !extension.is_empty() { format!("{}.{}", slugified_name, extension) } else { @@ -334,19 +377,36 @@ async fn upload_file( file_path }; - let final_name_str = final_path.file_name().unwrap().to_str().unwrap().to_string(); + let final_name_str = final_path + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string(); let data = match field.bytes().await { Ok(bytes) => bytes, Err(e) => { error!("Failed to read multipart bytes: {}", e); - return Err((StatusCode::BAD_REQUEST, Json(ErrorResponse { error: "Read error".to_string(), details: Some(e.to_string()) }))); + return Err(( + StatusCode::BAD_REQUEST, + Json(ErrorResponse { + error: "Read error".to_string(), + details: Some(e.to_string()), + }), + )); } }; if let Err(e) = fs::write(&final_path, &data) { error!("Failed to write file to {:?}: {}", final_path, e); - return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { error: "Write error".to_string(), details: Some(e.to_string()) }))); + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + error: "Write error".to_string(), + details: Some(e.to_string()), + }), + )); } info!("File uploaded successfully to {:?}", final_path); @@ -358,6 +418,9 @@ async fn upload_file( warn!("Upload failed: no file found in multipart stream"); Err(( StatusCode::BAD_REQUEST, - Json(ErrorResponse { error: "No file found".to_string(), details: None }), + Json(ErrorResponse { + error: "No file found".to_string(), + details: None, + }), )) }