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,