fix: recursive bloat in html
the meta, title and style tags are being replicated in the list on '/'
This commit is contained in:
parent
76d27dfcec
commit
aaaed7ce62
@ -10,6 +10,7 @@ chrono = { version = "0.4.41", features = ["serde"] }
|
||||
serde = { version = "1.0.219", features = ["derive", "rc"] }
|
||||
serde_json = "1.0.140"
|
||||
tokio = { version = "1.45.1", features = ["full", "tracing"] }
|
||||
tower-http = { version = "0.6.6", features = ["trace"] }
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.19"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
||||
uuid = { version = "1.17.0", features = ["serde", "v4"] }
|
||||
|
56
src/lib.rs
56
src/lib.rs
@ -3,39 +3,75 @@ use askama::Template;
|
||||
use axum::{
|
||||
Router,
|
||||
extract::{Path, State},
|
||||
http::HeaderMap,
|
||||
http::StatusCode,
|
||||
response::{Html, IntoResponse},
|
||||
routing::get,
|
||||
serve,
|
||||
};
|
||||
use person::PersonID;
|
||||
use stammbaum::Stammbaum;
|
||||
use person::{PersonID, PersonTemplate, PersonTemplateFull};
|
||||
use stammbaum::{Stammbaum, StammbaumFull};
|
||||
use std::io::BufReader;
|
||||
use tokio::runtime::Runtime;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing::{error, instrument, warn};
|
||||
|
||||
mod person;
|
||||
mod stammbaum;
|
||||
|
||||
#[instrument(skip(stammbaum))]
|
||||
async fn get_person(
|
||||
Path(id): Path<String>,
|
||||
headers: HeaderMap,
|
||||
State(stammbaum): State<Stammbaum>,
|
||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||
let id = match PersonID::try_from(id) {
|
||||
Ok(id) => id,
|
||||
Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR),
|
||||
Err(e) => {
|
||||
error!(error = ?e);
|
||||
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
};
|
||||
match stammbaum.get(id) {
|
||||
None => Err(StatusCode::NOT_FOUND),
|
||||
Some(p) => Ok(Html(
|
||||
p.render().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||
)),
|
||||
None => {
|
||||
warn!(id = ?id, "not_found");
|
||||
Err(StatusCode::NOT_FOUND)
|
||||
}
|
||||
Some(p) => match headers.get("HX-Request") {
|
||||
Some(_) => Ok(Html(PersonTemplate::from(p.to_owned()).render().map_err(
|
||||
|e| {
|
||||
error!(error=?e, id = ?id);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
},
|
||||
)?)),
|
||||
_ => Ok(Html(
|
||||
PersonTemplateFull::from(p.to_owned())
|
||||
.render()
|
||||
.map_err(|e| {
|
||||
error!(error=?e, id = ?id);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?,
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn list_stammbaum(
|
||||
headers: HeaderMap,
|
||||
State(stammbaum): State<Stammbaum>,
|
||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||
Ok::<axum::response::Html<std::string::String>, StatusCode>(Html(stammbaum.render()))
|
||||
match headers.get("HX-Request") {
|
||||
Some(_) => Ok::<axum::response::Html<std::string::String>, StatusCode>(Html(
|
||||
stammbaum
|
||||
.render()
|
||||
.expect("should have rendered the template"),
|
||||
)),
|
||||
None => Ok::<axum::response::Html<std::string::String>, StatusCode>(Html(
|
||||
StammbaumFull::from(stammbaum)
|
||||
.render()
|
||||
.expect("should have rendered the template"),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() -> Result<(), String> {
|
||||
@ -50,7 +86,9 @@ pub fn run() -> Result<(), String> {
|
||||
let app = Router::new()
|
||||
.route("/", get(list_stammbaum))
|
||||
.route("/{id}", get(get_person))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.with_state(stammbaum);
|
||||
|
||||
let addr = tokio::net::TcpListener::bind("0.0.0.0:3000")
|
||||
.await
|
||||
.expect("faild to bind port");
|
||||
|
10
src/main.rs
10
src/main.rs
@ -1,5 +1,13 @@
|
||||
use stammbaum::run;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
#[allow(clippy::unwrap_used)]
|
||||
fn main() {
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
EnvFilter::try_from_default_env()
|
||||
.or_else(|_| EnvFilter::try_new("stammbaum=debug"))
|
||||
.unwrap(),
|
||||
)
|
||||
.init();
|
||||
run().unwrap();
|
||||
}
|
||||
|
@ -7,8 +7,30 @@ use uuid::Uuid;
|
||||
|
||||
pub type PersonID = Uuid;
|
||||
|
||||
#[derive(Template, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Template)]
|
||||
#[template(path = "person.html")]
|
||||
pub struct PersonTemplate {
|
||||
person: Person,
|
||||
}
|
||||
|
||||
impl From<Person> for PersonTemplate {
|
||||
fn from(value: Person) -> Self {
|
||||
Self { person: value }
|
||||
}
|
||||
}
|
||||
#[derive(Template)]
|
||||
#[template(path = "person_full.html")]
|
||||
pub struct PersonTemplateFull {
|
||||
person: Person,
|
||||
}
|
||||
|
||||
impl From<Person> for PersonTemplateFull {
|
||||
fn from(value: Person) -> Self {
|
||||
Self { person: value }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Person {
|
||||
id: PersonID,
|
||||
first_name: Arc<str>,
|
||||
@ -44,6 +66,29 @@ impl Person {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sex(&self) -> &Sex {
|
||||
&self.sex
|
||||
}
|
||||
|
||||
pub fn date_of_birth(&self) -> DateTime<Utc> {
|
||||
self.date_of_birth
|
||||
}
|
||||
|
||||
pub fn maiden_name(&self) -> Option<Arc<str>> {
|
||||
self.maiden_name.clone()
|
||||
}
|
||||
|
||||
pub fn last_name(&self) -> Arc<str> {
|
||||
self.last_name.clone()
|
||||
}
|
||||
pub fn first_name(&self) -> Arc<str> {
|
||||
self.first_name.clone()
|
||||
}
|
||||
|
||||
pub fn parents(&self) -> &Vec<PersonID> {
|
||||
&self.parents
|
||||
}
|
||||
|
||||
pub fn add_parent(&mut self, parent: PersonID) {
|
||||
self.parents.push(parent);
|
||||
}
|
||||
|
@ -1,14 +1,29 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::person::{Person, PersonID};
|
||||
use crate::person::{Person, PersonID, Sex};
|
||||
|
||||
use askama::Template;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Template)]
|
||||
#[template(path = "stammbaum.html")]
|
||||
pub struct Stammbaum {
|
||||
members: Vec<Person>,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "stammbaum_full.html")]
|
||||
pub struct StammbaumFull {
|
||||
members: Vec<Person>,
|
||||
}
|
||||
|
||||
impl From<Stammbaum> for StammbaumFull {
|
||||
fn from(value: Stammbaum) -> Self {
|
||||
Self {
|
||||
members: value.members,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Stammbaum {
|
||||
pub fn new(members: Vec<Person>) -> Self {
|
||||
@ -18,13 +33,6 @@ impl Stammbaum {
|
||||
pub fn get(&self, id: PersonID) -> Option<&Person> {
|
||||
self.members.iter().find(|p| p.id() == id)
|
||||
}
|
||||
|
||||
pub fn render(&self) -> String {
|
||||
self.members
|
||||
.iter()
|
||||
.flat_map(|p: &Person| p.render())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
mod test {
|
||||
|
@ -1,31 +1,28 @@
|
||||
{% extends "_layout.html" %}
|
||||
|
||||
{%- block content -%}
|
||||
<div class="family-node">
|
||||
<div class="name">
|
||||
<span class="first-name">{{ first_name }}</span>
|
||||
<span class="last-name">{{ last_name }}</span>
|
||||
{% if maiden_name.is_some() %}
|
||||
<span class="maiden-name">({{ maiden_name.as_ref().unwrap() }})</span>
|
||||
<span class="first-name">{{ person.first_name }}</span>
|
||||
<span class="last-name">{{ person.last_name }}</span>
|
||||
{% if person.maiden_name.is_some() %}
|
||||
<span class="maiden-name">({{ person.maiden_name.as_ref().unwrap() }})</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="details">
|
||||
<div>Sex:
|
||||
{% match sex %}
|
||||
{% match person.sex %}
|
||||
{% when Sex::Male %}Male
|
||||
{% when Sex::Female %}Female
|
||||
{% when Sex::Other(desc) %}{{ desc }}
|
||||
{% endmatch %}
|
||||
</div>
|
||||
<div>Birthday: {{ date_of_birth.format("%Y-%m-%d") }}</div>
|
||||
<a href="/{{ id }}">ID: {{ id }}</a>
|
||||
<div>Birthday: {{ person.date_of_birth.format("%Y-%m-%d") }}</div>
|
||||
<a href="/{{ person.id }}">ID: {{ person.id }}</a>
|
||||
<div class="parents">
|
||||
Parents:
|
||||
{% if parents.is_empty() %}
|
||||
{% if person.parents.is_empty() %}
|
||||
<ul></ul>
|
||||
{% else %}
|
||||
<ul>
|
||||
{% for parent_id in &parents %}
|
||||
{% for parent_id in &person.parents %}
|
||||
<li>
|
||||
<a href="/{{ parent_id }}">{{ parent_id }}</a>
|
||||
|
||||
@ -35,4 +32,3 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endblock -%}
|
||||
|
38
templates/person_full.html
Normal file
38
templates/person_full.html
Normal file
@ -0,0 +1,38 @@
|
||||
{% extends "_layout.html" %}
|
||||
|
||||
{%- block content -%}
|
||||
<div class="family-node">
|
||||
<div class="name">
|
||||
<span class="first-name">{{ person.first_name }}</span>
|
||||
<span class="last-name">{{ person.last_name }}</span>
|
||||
{% if person.maiden_name.is_some() %}
|
||||
<span class="maiden-name">({{ person.maiden_name.as_ref().unwrap() }})</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="details">
|
||||
<div>Sex:
|
||||
{% match person.sex %}
|
||||
{% when Sex::Male %}Male
|
||||
{% when Sex::Female %}Female
|
||||
{% when Sex::Other(desc) %}{{ desc }}
|
||||
{% endmatch %}
|
||||
</div>
|
||||
<div>Birthday: {{ person.date_of_birth.format("%Y-%m-%d") }}</div>
|
||||
<a href="/{{ person.id }}">ID: {{ person.id }}</a>
|
||||
<div class="parents">
|
||||
Parents:
|
||||
{% if person.parents.is_empty() %}
|
||||
<ul></ul>
|
||||
{% else %}
|
||||
<ul>
|
||||
{% for parent_id in &person.parents %}
|
||||
<li>
|
||||
<a href="/{{ parent_id }}">{{ parent_id }}</a>
|
||||
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endblock -%}
|
36
templates/stammbaum.html
Normal file
36
templates/stammbaum.html
Normal file
@ -0,0 +1,36 @@
|
||||
{% for person in members %}
|
||||
<div class="family-node">
|
||||
<div class="name">
|
||||
<span class="first-name">{{ person.first_name() }}</span>
|
||||
<span class="last-name">{{ person.last_name() }}</span>
|
||||
{% if person.maiden_name().is_some() %}
|
||||
<span class="maiden-name">({{ person.maiden_name().as_ref().unwrap() }})</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="details">
|
||||
<div>Sex:
|
||||
{% match person.sex() %}
|
||||
{% when Sex::Male %}Male
|
||||
{% when Sex::Female %}Female
|
||||
{% when Sex::Other(desc) %}{{ desc }}
|
||||
{% endmatch %}
|
||||
</div>
|
||||
<div>Birthday: {{ person.date_of_birth().format("%Y-%m-%d") }}</div>
|
||||
<a href="/{{ person.id() }}">ID: {{ person.id() }}</a>
|
||||
<div class="parents">
|
||||
Parents:
|
||||
{% if person.parents().is_empty() %}
|
||||
<ul></ul>
|
||||
{% else %}
|
||||
<ul>
|
||||
{% for parent_id in &person.parents() %}
|
||||
<li>
|
||||
<a href="/{{ parent_id }}">{{ parent_id }}</a>
|
||||
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
40
templates/stammbaum_full.html
Normal file
40
templates/stammbaum_full.html
Normal file
@ -0,0 +1,40 @@
|
||||
{% extends "_layout.html" %}
|
||||
|
||||
{%- block content -%}
|
||||
{% for person in members %}
|
||||
<div class="family-node">
|
||||
<div class="name">
|
||||
<span class="first-name">{{ person.first_name() }}</span>
|
||||
<span class="last-name">{{ person.last_name() }}</span>
|
||||
{% if person.maiden_name().is_some() %}
|
||||
<span class="maiden-name">({{ person.maiden_name().as_ref().unwrap() }})</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="details">
|
||||
<div>Sex:
|
||||
{% match person.sex() %}
|
||||
{% when Sex::Male %}Male
|
||||
{% when Sex::Female %}Female
|
||||
{% when Sex::Other(desc) %}{{ desc }}
|
||||
{% endmatch %}
|
||||
</div>
|
||||
<div>Birthday: {{ person.date_of_birth().format("%Y-%m-%d") }}</div>
|
||||
<a href="/{{ person.id() }}">ID: {{ person.id() }}</a>
|
||||
<div class="parents">
|
||||
Parents:
|
||||
{% if person.parents().is_empty() %}
|
||||
<ul></ul>
|
||||
{% else %}
|
||||
<ul>
|
||||
{% for parent_id in &person.parents() %}
|
||||
<li>
|
||||
<a href="/{{ parent_id }}">{{ parent_id }}</a>
|
||||
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{%- endblock -%}
|
Loading…
x
Reference in New Issue
Block a user