diff --git a/src/router.rs b/src/router.rs index d436ca4..5fd9bd3 100644 --- a/src/router.rs +++ b/src/router.rs @@ -2,7 +2,14 @@ use axum::{routing::get, Router}; use crate::{syntax::serial::Format, types::Graph}; -mod handlers; +mod handlers { + pub mod graph; + pub mod template; + pub mod raw; + pub mod navigation; + pub mod fixed; + pub mod error; +} pub fn new(graph: &Graph) -> Router { let mut router = Router::default() @@ -11,6 +18,7 @@ pub fn new(graph: &Graph) -> Router { get(|| handlers::navigation::page("index.html")) .post(handlers::navigation::search), ) + .route("/redirect", get(handlers::navigation::redirect)) .route( "/static/style.css", get(|| handlers::fixed::file("./static/style.css", "text/css")), @@ -38,6 +46,8 @@ pub fn new(graph: &Graph) -> Router { } if graph.meta.config.raw { + router = router + .route("/data", get(|| handlers::navigation::page("data.html"))); if graph.meta.config.raw_json { router = router.route( "/graph/json", diff --git a/src/router/handlers.rs b/src/router/handlers.rs deleted file mode 100644 index 3757eae..0000000 --- a/src/router/handlers.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod graph; -pub mod template; -pub mod raw; -pub mod navigation; -pub mod fixed; -pub mod error; diff --git a/src/router/handlers/graph.rs b/src/router/handlers/graph.rs index 39ae2a8..e48ff17 100644 --- a/src/router/handlers/graph.rs +++ b/src/router/handlers/graph.rs @@ -1,4 +1,3 @@ -use crate::prelude::*; use axum::response::IntoResponse as _; use axum::{body::Body, extract::Path, http::Response, response::Redirect}; @@ -8,9 +7,12 @@ use crate::{syntax::serial::populate_graph, router::handlers, types::Node}; pub async fn node(Path(id): Path) -> Response { let graph = populate_graph(); - let empty_node = Node::new(Some(format!("Could not find node ID {id}."))); - let (node_match, exact) = graph.find_node(&id); - let node = node_match.unwrap_or(empty_node.clone()); + let result = graph.find_node(&id); + let nodes: Vec = graph.nodes.into_values().collect(); + let not_found = result.node.is_none(); + let node = result + .node + .unwrap_or(Node::new(Some(format!("Could not find node ID {id}.")))); if !node.redirect.is_empty() { return Redirect::permanent( @@ -19,20 +21,18 @@ pub async fn node(Path(id): Path) -> Response { .into_response(); } - if !exact { - log!("Redirecting non-exact match to {}", node.id); + if result.redirect { return Redirect::permanent(format!("/node/{}", node.id).as_str()) .into_response(); } let mut context = tera::Context::default(); context.insert("node", &node); + context.insert("nodes", &nodes); context.insert("text", &content::parse(&node.text, &graph.meta.config)); context.insert("incoming", &graph.incoming.get(&id)); context.insert("config", &graph.meta.config); - let not_found = node == empty_node; - handlers::template::by_filename( "node.html", &context, diff --git a/src/router/handlers/navigation.rs b/src/router/handlers/navigation.rs index 357ecb8..919c49c 100644 --- a/src/router/handlers/navigation.rs +++ b/src/router/handlers/navigation.rs @@ -25,6 +25,10 @@ pub async fn search(Form(query): Form) -> Redirect { Redirect::permanent(format!("/node/{}", query.node).as_str()) } +pub async fn redirect(Form(query): Form) -> Redirect { + Redirect::permanent(format!("/node/{}", query.node).as_str()) +} + #[derive(serde::Deserialize)] pub struct Query { node: String, @@ -63,4 +67,13 @@ mod tests { let response = page("HBvcwqT8wLk6hxk1GdvNcEzJ6IiZ2Fod").await; assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR); } + + #[tokio::test] + async fn id_redirect() { + let query = Form(Query { + node: String::from("ancHOr syntaX"), + }); + let response = search(query).await; + assert!(response.status_code() == StatusCode::PERMANENT_REDIRECT); + } } diff --git a/src/types.rs b/src/types.rs index 1e38191..f99f268 100644 --- a/src/types.rs +++ b/src/types.rs @@ -121,6 +121,11 @@ fn mk8() -> u16 { 8 } +pub struct QueryResult { + pub node: Option, + pub redirect: bool, +} + impl Graph { pub fn new(message: Option<&str>) -> Graph { Graph { @@ -136,17 +141,26 @@ impl Graph { } } - pub fn find_node(&self, query: &str) -> (Option, bool) { + pub fn find_node(&self, query: &str) -> QueryResult { let collapsed_query = query.trim().replace(" ", ""); if let Some(exact_match) = self.nodes.get(query) { - (Some(exact_match.clone()), true) + QueryResult { + node: Some(exact_match.clone()), + redirect: false, + } } else if let Some(lower_key) = - self.lowercase_keymap.get(&collapsed_query) + self.lowercase_keymap.get(&collapsed_query.to_lowercase()) { - (self.nodes.get(lower_key).cloned(), false) + QueryResult { + node: self.nodes.get(lower_key).cloned(), + redirect: true, + } } else { - (None, false) + QueryResult { + node: None, + redirect: false, + } } } @@ -162,7 +176,7 @@ impl Node { title: "Not Found".to_string(), text: match message { Some(s) => s, - None => "Node is empty, missing or wasn't found.".to_string(), + None => "Node not found.".to_string(), }, connections: None, links: vec![], @@ -233,7 +247,7 @@ mod tests { #[test] fn empty_node_message() { let node = Node::new(None); - assert_eq!(node.text, "Node is empty, missing or wasn't found."); + assert_eq!(node.text, "Node not found."); } #[test]