diff --git a/src/main.rs b/src/main.rs index ce07ec5..36b2470 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use axum::{ extract::Path, http::{header, StatusCode}, - response::{ Html, IntoResponse, Redirect }, + response::{IntoResponse, Redirect}, routing::get, Form, Router, @@ -74,40 +74,62 @@ fn make_body( } }; - let render_result = match tera.render(name, &context) { - Ok(t) => t, + match tera.render(name, context) { + Ok(t) => (t, 200), Err(e) => { let mut error_context = tera::Context::new(); - let error = StatusCode::from_u16(error_code) - .unwrap_or(StatusCode::NOT_IMPLEMENTED); - error_context.insert("title", &error.to_string()); - error_context.insert( - "message", - &format!( - r#"Error while filling template {name}: {} - User message: {error_message}"#, - e.to_string(), + + let out_error_message = match error_message { + Some(s) => &format!( + "Template render failed.\n\ + User message: {s}, + Engine message:\n
{e:#?}
\n\ + Context:\n
{context:#?}
" ), - ); + None => { + &format!( + "Template render failed.\n\ + Engine message:\n
{e:#?}
\n\ + Context:\n
{context:#?}
" + ) + } + }; - tera.render("error.html", &error_context) - .unwrap_or(error_message.to_string()) + error_context.insert("message", out_error_message); + error_context.insert("title", + &StatusCode::INTERNAL_SERVER_ERROR.to_string()); + + (tera.render("error.html", &error_context) + .unwrap_or(out_error_message.clone()), 500) } - }; - - render_result + } } - fn template_handler( name: &str, context: tera::Context, error_code: u16, - error_message: &str, -) -> Html { - let body = make_body(name, context, error_code, error_message); - Html(body) + error_message: Option, + is_error: bool, +) -> impl IntoResponse { + + let (body, render_status) = make_body( + name, &context, error_message.as_deref()); + + let status_code = if render_status != 200 { + StatusCode::from_u16(render_status) + .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) + } else if is_error { + StatusCode::from_u16(error_code) + .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) + } else { StatusCode::OK }; + + ( + status_code, + [(header::CONTENT_TYPE, "text/html")], + body.clone(), + ) } async fn node_view(Path(id): Path) -> impl IntoResponse { @@ -128,23 +150,22 @@ async fn node_view(Path(id): Path) -> impl IntoResponse { context.insert("connections", &node.connections.clone()); context.insert("incoming", &graph.incoming.get(&id)); + let not_found = node.clone() == empty_node; + template_handler( "node.html", context, - 500, - &format!( - r#"Failed to generate page for node {} (ID {}) with {} outgoing, - {} incoming connections and text "{}""#, - node.title, - id, - node.connections.iter().len(), - graph.incoming.get(&id).iter().len(), - node.text, - ), + if not_found { 404 } else { 500 }, + Some(format!( + "Failed to generate page for node {} (ID {}).\n\ + Node struct:
{:#?}
", + node.title, id, node + ).to_owned()), + not_found, ) } -async fn index() -> Html { +async fn index() -> impl IntoResponse { let mut context = tera::Context::new(); let graph = populate_graph(); @@ -154,10 +175,10 @@ async fn index() -> Html { context.insert("nodes", &nodes); context.insert("root_node", &root_node); - template_handler("index.html", context, 500, "Failed to render template.") + template_handler("index.html", context.clone(), 500, None, false) } -async fn tree() -> Html { +async fn tree() -> impl IntoResponse { let mut context = tera::Context::new(); let graph = populate_graph(); @@ -167,7 +188,8 @@ async fn tree() -> Html { context.insert("nodes", &nodes); context.insert("root_node", &root_node); - template_handler("tree.html", context, 500, "Failed to render template") + template_handler("tree.html", context, 500, None, false) +} #[expect(clippy::unused_async)] async fn static_template_handler(name: &str) -> impl IntoResponse { diff --git a/src/types.rs b/src/types.rs index 4b96d08..69b7509 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,7 @@ use serde::{Serialize, Deserialize}; use std::collections::HashMap; -#[derive(Serialize, Deserialize, Clone, Default, Debug)] +#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, Debug)] pub struct Graph { pub nodes: HashMap, pub root_node: String, @@ -9,7 +9,7 @@ pub struct Graph { #[serde(skip)] pub incoming: HashMap>, } -#[derive(Serialize, Deserialize, Clone, Default, Debug)] +#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, Debug)] pub struct Node { pub text: String, #[serde(default)] pub title: String, @@ -20,7 +20,7 @@ pub struct Node { pub connections: Option>, } -#[derive(Serialize, Clone, Default, PartialEq, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, Debug)] pub struct Edge { pub to: String, #[serde(default)] pub anchor: String,