calathea/src/server/plants.rs

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)?))
}