95 lines
2.4 KiB
Rust
95 lines
2.4 KiB
Rust
use axum::{
|
|
extract::{Path, Query, State},
|
|
http::HeaderMap,
|
|
response::Html,
|
|
routing::get,
|
|
Form, Router,
|
|
};
|
|
use tera::Context;
|
|
|
|
use crate::{
|
|
db::{self, DbError, Event, Pagination, Plant},
|
|
template::{Template, Update, View},
|
|
};
|
|
|
|
use super::{error::AppError, query::ToQuery};
|
|
|
|
pub fn app() -> axum::Router<crate::Context> {
|
|
Router::new()
|
|
.route("/{id}", get(get_plant_page))
|
|
.route("/", get(get_plants).post(post_plant))
|
|
}
|
|
|
|
async fn get_plant_page(
|
|
State(ctx): State<crate::Context>,
|
|
headers: HeaderMap,
|
|
Path(plant_id): Path<i32>,
|
|
) -> super::Result<Html<String>> {
|
|
let res = tokio::task::spawn_blocking(move || {
|
|
let plant = Plant::by_id(&ctx.pool, plant_id)?;
|
|
|
|
if let Some(plant) = plant {
|
|
let events = Event::for_plant(&ctx.pool, plant.id)?;
|
|
|
|
Ok::<_, DbError>(Some((plant, events)))
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
})
|
|
.await
|
|
.unwrap()?;
|
|
|
|
match res {
|
|
Some((plant, events)) => {
|
|
let mut context = Context::new();
|
|
context.insert("plant", &plant);
|
|
context.insert("events", &events);
|
|
context.insert("event_types", &db::EVENT_TYPES);
|
|
|
|
Ok(Html(
|
|
View::Plant.headers(&headers).render(&ctx.tera, &context)?,
|
|
))
|
|
}
|
|
None => Err(AppError::NotFound),
|
|
}
|
|
}
|
|
|
|
async fn get_plants(
|
|
State(ctx): State<crate::Context>,
|
|
Query(mut page): Query<Pagination>,
|
|
headers: HeaderMap,
|
|
) -> super::Result<Html<String>> {
|
|
let plants = tokio::task::spawn_blocking(move || db::Plant::page(&ctx.pool, page))
|
|
.await
|
|
.unwrap()?;
|
|
|
|
let mut context = Context::new();
|
|
context.insert("plants", &plants);
|
|
|
|
let is_final_page = plants.len() < page.per_page.try_into().unwrap();
|
|
context.insert("is_final_page", &is_final_page);
|
|
|
|
if !is_final_page {
|
|
page.page += 1;
|
|
|
|
context.insert("query", &page.to_query().encode());
|
|
}
|
|
|
|
Ok(Html(
|
|
View::Plants.headers(&headers).render(&ctx.tera, &context)?,
|
|
))
|
|
}
|
|
|
|
async fn post_plant(
|
|
State(ctx): State<crate::Context>,
|
|
Form(plant): Form<db::NewPlant>,
|
|
) -> super::Result<Html<String>> {
|
|
let plant = tokio::task::spawn_blocking(move || plant.insert(&ctx.pool))
|
|
.await
|
|
.unwrap()?;
|
|
|
|
let mut context = Context::new();
|
|
context.insert("plant", &plant);
|
|
Ok(Html(Update::PlantLi.render(&ctx.tera, &context)?))
|
|
}
|