Files
packager/rust/src/routing/routes.rs

1179 lines
34 KiB
Rust
Raw Normal View History

2023-08-29 21:34:00 +02:00
use axum::{
extract::{Extension, Path, Query, State},
http::header::{self, HeaderMap, HeaderName},
response::{IntoResponse, Redirect},
Form,
};
use serde::Deserialize;
use uuid::Uuid;
2023-08-29 21:34:00 +02:00
use crate::htmx;
2023-08-29 21:34:00 +02:00
use crate::models;
use crate::view;
2023-08-29 21:34:00 +02:00
use crate::{AppState, Context, Error, RequestError, TopLevelPage};
2023-08-29 21:34:00 +02:00
2023-08-29 21:34:00 +02:00
use super::{get_referer, html};
2023-08-29 21:34:00 +02:00
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Default, Debug)]
2023-08-29 21:34:00 +02:00
pub struct InventoryQuery {
edit_item: Option<Uuid>,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct NewItem {
#[serde(rename = "new-item-name")]
name: String,
#[serde(rename = "new-item-weight")]
weight: u32,
// damn i just love how serde is integrated everywhere, just add a feature to the uuid in
// cargo.toml and go
#[serde(rename = "new-item-category-id")]
category_id: Uuid,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct NewItemName {
#[serde(rename = "new-item-name")]
name: String,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct EditItem {
#[serde(rename = "edit-item-name")]
name: String,
#[serde(rename = "edit-item-weight")]
weight: u32,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct NewTrip {
#[serde(rename = "new-trip-name")]
name: String,
#[serde(rename = "new-trip-start-date")]
date_start: time::Date,
#[serde(rename = "new-trip-end-date")]
date_end: time::Date,
}
#[derive(Debug, Deserialize)]
pub struct TripQuery {
edit: Option<models::trips::TripAttribute>,
category: Option<Uuid>,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct CommentUpdate {
#[serde(rename = "new-comment")]
new_comment: String,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct TripUpdate {
#[serde(rename = "new-value")]
new_value: String,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct NewCategory {
#[serde(rename = "new-category-name")]
name: String,
}
#[derive(Debug, Deserialize)]
pub struct TripTypeQuery {
edit: Option<Uuid>,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct NewTripType {
#[serde(rename = "new-trip-type-name")]
name: String,
}
2023-08-29 21:34:01 +02:00
#[derive(Deserialize, Debug)]
2023-08-29 21:34:00 +02:00
pub struct TripTypeUpdate {
#[serde(rename = "new-value")]
new_value: String,
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn root(Extension(current_user): Extension<models::user::User>) -> impl IntoResponse {
view::Root::build(
&Context::build(current_user),
&view::home::Home::build(),
None,
)
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn icon() -> impl IntoResponse {
(
[(header::CONTENT_TYPE, "image/svg+xml")],
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/luggage.svg")),
)
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn debug(headers: HeaderMap) -> impl IntoResponse {
2023-08-29 21:34:01 +02:00
let mut out = String::new();
for (key, value) in headers.iter() {
out.push_str(&format!("{}: {}\n", key, value.to_str().unwrap()));
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
out
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_active(
Extension(current_user): Extension<models::user::User>,
State(mut state): State<AppState>,
Path(id): Path<Uuid>,
Query(inventory_query): Query<InventoryQuery>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
state.client_state.edit_item = inventory_query.edit_item;
state.client_state.active_category_id = Some(id);
2023-08-29 21:34:00 +02:00
let inventory = models::inventory::Inventory::load(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
let active_category: Option<&models::inventory::Category> = state
.client_state
.active_category_id
.map(|id| {
inventory
.categories
.iter()
.find(|category| category.id == id)
.ok_or(Error::Request(RequestError::NotFound {
message: format!("a category with id {id} does not exist"),
}))
})
.transpose()?;
Ok(view::Root::build(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&view::inventory::Inventory::build(
active_category,
&inventory.categories,
state.client_state.edit_item,
),
Some(&TopLevelPage::Inventory),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_inactive(
Extension(current_user): Extension<models::user::User>,
State(mut state): State<AppState>,
Query(inventory_query): Query<InventoryQuery>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
state.client_state.edit_item = inventory_query.edit_item;
state.client_state.active_category_id = None;
2023-08-29 21:34:00 +02:00
let inventory = models::inventory::Inventory::load(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
Ok(view::Root::build(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&view::inventory::Inventory::build(
None,
&inventory.categories,
state.client_state.edit_item,
),
Some(&TopLevelPage::Inventory),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_item_validate_name(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Form(new_item): Form<NewItemName>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
let exists =
2023-08-29 21:34:00 +02:00
models::inventory::InventoryItem::name_exists(&ctx, &state.database_pool, &new_item.name)
.await?;
2023-08-29 21:34:00 +02:00
Ok(view::inventory::InventoryNewItemFormName::build(
Some(&new_item.name),
exists,
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_item_create(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
headers: HeaderMap,
Form(new_item): Form<NewItem>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
if new_item.name.is_empty() {
return Err(Error::Request(RequestError::EmptyFormElement {
name: "name".to_string(),
}));
}
let _new_id = models::inventory::InventoryItem::save(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state.database_pool,
&new_item.name,
new_item.category_id,
new_item.weight,
)
.await?;
2023-08-29 21:34:00 +02:00
if htmx::is_htmx(&headers) {
2023-08-29 21:34:00 +02:00
let inventory = models::inventory::Inventory::load(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
// it's impossible to NOT find the item here, as we literally just added
// it.
let active_category: Option<&models::inventory::Category> = Some(
inventory
.categories
.iter()
.find(|category| category.id == new_item.category_id)
.unwrap(),
);
Ok(view::inventory::Inventory::build(
active_category,
&inventory.categories,
state.client_state.edit_item,
)
.into_response())
} else {
Ok(Redirect::to(&format!(
"/inventory/category/{id}/",
id = new_item.category_id
))
.into_response())
}
}
2023-08-29 21:34:01 +02:00
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_item_delete(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
headers: HeaderMap,
Path(id): Path<Uuid>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let deleted = models::inventory::InventoryItem::delete(&ctx, &state.database_pool, id).await?;
2023-08-29 21:34:00 +02:00
2023-08-29 21:34:01 +02:00
if deleted {
Ok(Redirect::to(get_referer(&headers)?))
} else {
2023-08-29 21:34:00 +02:00
Err(Error::Request(RequestError::NotFound {
message: format!("item with id {id} not found"),
}))
}
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_item_edit(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path(id): Path<Uuid>,
Form(edit_item): Form<EditItem>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
if edit_item.name.is_empty() {
return Err(Error::Request(RequestError::EmptyFormElement {
name: "name".to_string(),
}));
}
let id = models::inventory::InventoryItem::update(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state.database_pool,
id,
&edit_item.name,
edit_item.weight,
)
.await?;
2023-08-29 21:34:01 +02:00
Ok(Redirect::to(&format!("/inventory/category/{id}/")))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_item_cancel(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path(id): Path<Uuid>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let id = models::inventory::InventoryItem::find(&ctx, &state.database_pool, id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("item with id {id} not found"),
}))?;
Ok(Redirect::to(&format!(
"/inventory/category/{id}/",
id = id.category.id
)))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_create(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Form(new_trip): Form<NewTrip>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
if new_trip.name.is_empty() {
return Err(Error::Request(RequestError::EmptyFormElement {
name: "name".to_string(),
}));
}
let new_id = models::trips::Trip::save(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state.database_pool,
&new_trip.name,
new_trip.date_start,
new_trip.date_end,
)
.await?;
Ok(Redirect::to(&format!("/trips/{new_id}/")))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trips(
Extension(current_user): Extension<models::user::User>,
State(state): State<AppState>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let trips = models::trips::Trip::all(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
Ok(view::Root::build(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&view::trip::TripManager::build(trips),
Some(&TopLevelPage::Trips),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip(
Extension(current_user): Extension<models::user::User>,
State(mut state): State<AppState>,
Path(id): Path<Uuid>,
Query(trip_query): Query<TripQuery>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
state.client_state.trip_edit_attribute = trip_query.edit;
state.client_state.active_category_id = trip_query.category;
2023-08-29 21:34:00 +02:00
let mut trip: models::trips::Trip = models::trips::Trip::find(&ctx, &state.database_pool, id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("trip with id {id} not found"),
}))?;
2023-08-29 21:34:00 +02:00
trip.load_trips_types(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
2023-08-29 21:34:00 +02:00
trip.sync_trip_items_with_inventory(&ctx, &state.database_pool)
2023-08-29 21:34:00 +02:00
.await?;
2023-08-29 21:34:00 +02:00
trip.load_categories(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
let active_category: Option<&models::trips::TripCategory> = state
.client_state
.active_category_id
.map(|id| {
trip.categories()
.iter()
.find(|category| category.category.id == id)
.ok_or(Error::Request(RequestError::NotFound {
message: format!("an active category with id {id} does not exist"),
}))
})
.transpose()?;
Ok(view::Root::build(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&view::trip::Trip::build(
&trip,
2023-08-29 21:34:01 +02:00
state.client_state.trip_edit_attribute.as_ref(),
2023-08-29 21:34:00 +02:00
active_category,
),
Some(&TopLevelPage::Trips),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_type_remove(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
let found =
2023-08-29 21:34:00 +02:00
models::trips::Trip::trip_type_remove(&ctx, &state.database_pool, trip_id, type_id).await?;
2023-08-29 21:34:00 +02:00
2023-08-29 21:34:01 +02:00
if found {
Ok(Redirect::to(&format!("/trips/{trip_id}/")))
} else {
2023-08-29 21:34:00 +02:00
Err(Error::Request(RequestError::NotFound {
message: format!("type {type_id} is not active for trip {trip_id}"),
}))
}
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_type_add(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
models::trips::Trip::trip_type_add(&ctx, &state.database_pool, trip_id, type_id).await?;
2023-08-29 21:34:00 +02:00
Ok(Redirect::to(&format!("/trips/{trip_id}/")))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_comment_set(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path(trip_id): Path<Uuid>,
Form(comment_update): Form<CommentUpdate>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
let found = models::trips::Trip::set_comment(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state.database_pool,
trip_id,
&comment_update.new_comment,
)
.await?;
2023-08-29 21:34:01 +02:00
if found {
Ok(Redirect::to(&format!("/trips/{trip_id}/")))
} else {
2023-08-29 21:34:00 +02:00
Err(Error::Request(RequestError::NotFound {
message: format!("trip with id {trip_id} not found"),
}))
}
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_edit_attribute(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, attribute)): Path<(Uuid, models::trips::TripAttribute)>,
Form(trip_update): Form<TripUpdate>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:01 +02:00
if attribute == models::trips::TripAttribute::Name && trip_update.new_value.is_empty() {
return Err(Error::Request(RequestError::EmptyFormElement {
name: "name".to_string(),
}));
2023-08-29 21:34:00 +02:00
}
models::trips::Trip::set_attribute(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state.database_pool,
trip_id,
attribute,
&trip_update.new_value,
)
.await?;
Ok(Redirect::to(&format!("/trips/{trip_id}/")))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_state(
2023-08-29 21:34:00 +02:00
ctx: &Context,
2023-08-29 21:34:00 +02:00
state: &AppState,
trip_id: Uuid,
item_id: Uuid,
key: models::trips::TripItemStateKey,
value: bool,
) -> Result<(), Error> {
2023-08-29 21:34:01 +02:00
models::trips::TripItem::set_state(ctx, &state.database_pool, trip_id, item_id, key, value)
2023-08-29 21:34:00 +02:00
.await?;
2023-08-29 21:34:00 +02:00
Ok(())
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_row(
2023-08-29 21:34:00 +02:00
ctx: &Context,
2023-08-29 21:34:00 +02:00
state: &AppState,
trip_id: Uuid,
item_id: Uuid,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let item = models::trips::TripItem::find(ctx, &state.database_pool, trip_id, item_id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or_else(|| {
Error::Request(RequestError::NotFound {
message: format!("item with id {item_id} not found for trip {trip_id}"),
})
})?;
let item_row = view::trip::TripItemListRow::build(
trip_id,
&item,
models::inventory::InventoryItem::get_category_max_weight(
2023-08-29 21:34:01 +02:00
ctx,
2023-08-29 21:34:00 +02:00
&state.database_pool,
item.item.category_id,
)
.await?,
);
2023-08-29 21:34:00 +02:00
let category = models::trips::TripCategory::find(
ctx,
&state.database_pool,
trip_id,
item.item.category_id,
)
.await?
.ok_or_else(|| {
Error::Request(RequestError::NotFound {
message: format!("category with id {} not found", item.item.category_id),
})
})?;
2023-08-29 21:34:00 +02:00
// TODO biggest_category_weight?
let category_row = view::trip::TripCategoryListRow::build(trip_id, &category, true, 0, true);
2023-08-29 21:34:01 +02:00
Ok(html::concat(&item_row, &category_row))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_pick(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
headers: HeaderMap,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
Ok::<_, Error>(
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pick,
true,
)
.await?,
)
.map(|_| -> Result<Redirect, Error> { Ok(Redirect::to(get_referer(&headers)?)) })?
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_pick_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pick,
true,
)
.await?;
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::Trigger.into(),
htmx::Event::TripItemEdited.into(),
2023-08-29 21:34:00 +02:00
);
2023-08-29 21:34:00 +02:00
Ok((headers, trip_row(&ctx, &state, trip_id, item_id).await?))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_unpick(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
headers: HeaderMap,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
Ok::<_, Error>(
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pick,
false,
)
.await?,
)
.map(|_| -> Result<Redirect, Error> { Ok(Redirect::to(get_referer(&headers)?)) })?
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_unpick_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pick,
false,
)
.await?;
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::Trigger.into(),
htmx::Event::TripItemEdited.into(),
2023-08-29 21:34:00 +02:00
);
2023-08-29 21:34:00 +02:00
Ok((headers, trip_row(&ctx, &state, trip_id, item_id).await?))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_pack(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
headers: HeaderMap,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
Ok::<_, Error>(
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pack,
true,
)
.await?,
)
.map(|_| -> Result<Redirect, Error> { Ok(Redirect::to(get_referer(&headers)?)) })?
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_pack_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pack,
true,
)
.await?;
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::Trigger.into(),
htmx::Event::TripItemEdited.into(),
2023-08-29 21:34:00 +02:00
);
2023-08-29 21:34:00 +02:00
Ok((headers, trip_row(&ctx, &state, trip_id, item_id).await?))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_unpack(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
headers: HeaderMap,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
Ok::<_, Error>(
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pack,
false,
)
.await?,
)
.map(|_| -> Result<Redirect, Error> { Ok(Redirect::to(get_referer(&headers)?)) })?
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_unpack_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pack,
false,
)
.await?;
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::Trigger.into(),
htmx::Event::TripItemEdited.into(),
2023-08-29 21:34:00 +02:00
);
2023-08-29 21:34:00 +02:00
Ok((headers, trip_row(&ctx, &state, trip_id, item_id).await?))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_ready(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
headers: HeaderMap,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
Ok::<_, Error>(
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Ready,
true,
)
.await?,
)
.map(|_| -> Result<Redirect, Error> { Ok(Redirect::to(get_referer(&headers)?)) })?
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_ready_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Ready,
true,
)
.await?;
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::Trigger.into(),
htmx::Event::TripItemEdited.into(),
2023-08-29 21:34:00 +02:00
);
2023-08-29 21:34:00 +02:00
Ok((headers, trip_row(&ctx, &state, trip_id, item_id).await?))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_unready(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
headers: HeaderMap,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
Ok::<_, Error>(
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Ready,
false,
)
.await?,
)
.map(|_| -> Result<Redirect, Error> { Ok(Redirect::to(get_referer(&headers)?)) })?
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_set_unready_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Ready,
false,
)
.await?;
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::Trigger.into(),
htmx::Event::TripItemEdited.into(),
2023-08-29 21:34:00 +02:00
);
2023-08-29 21:34:00 +02:00
Ok((headers, trip_row(&ctx, &state, trip_id, item_id).await?))
2023-08-29 21:34:00 +02:00
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_total_weight_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path(trip_id): Path<Uuid>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
let total_weight =
2023-08-29 21:34:00 +02:00
models::trips::Trip::find_total_picked_weight(&ctx, &state.database_pool, trip_id).await?;
2023-08-29 21:34:00 +02:00
Ok(view::trip::TripInfoTotalWeightRow::build(
trip_id,
total_weight,
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_category_create(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Form(new_category): Form<NewCategory>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
if new_category.name.is_empty() {
return Err(Error::Request(RequestError::EmptyFormElement {
name: "name".to_string(),
}));
}
let _new_id =
2023-08-29 21:34:00 +02:00
models::inventory::Category::save(&ctx, &state.database_pool, &new_category.name).await?;
2023-08-29 21:34:00 +02:00
Ok(Redirect::to("/inventory/"))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_state_set(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
headers: HeaderMap,
Path((trip_id, new_state)): Path<(Uuid, models::trips::TripState)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let exists =
models::trips::Trip::set_state(&ctx, &state.database_pool, trip_id, &new_state).await?;
2023-08-29 21:34:00 +02:00
if !exists {
return Err(Error::Request(RequestError::NotFound {
message: format!("trip with id {trip_id} not found"),
}));
}
2023-08-29 21:34:00 +02:00
if htmx::is_htmx(&headers) {
2023-08-29 21:34:00 +02:00
Ok(view::trip::TripInfoStateRow::build(&new_state).into_response())
} else {
2023-08-29 21:34:01 +02:00
Ok(Redirect::to(&format!("/trips/{trip_id}/")).into_response())
2023-08-29 21:34:00 +02:00
}
}
2023-08-29 21:34:01 +02:00
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trips_types(
Extension(current_user): Extension<models::user::User>,
State(mut state): State<AppState>,
Query(trip_type_query): Query<TripTypeQuery>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
state.client_state.trip_type_edit = trip_type_query.edit;
let trip_types: Vec<models::trips::TripsType> =
2023-08-29 21:34:00 +02:00
models::trips::TripsType::all(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
Ok(view::Root::build(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&view::trip::types::TypeList::build(&state.client_state, trip_types),
Some(&TopLevelPage::Trips),
))
}
2023-08-29 21:34:01 +02:00
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_type_create(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Form(new_trip_type): Form<NewTripType>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
if new_trip_type.name.is_empty() {
return Err(Error::Request(RequestError::EmptyFormElement {
name: "name".to_string(),
}));
}
2023-08-29 21:34:00 +02:00
let _new_id =
models::trips::TripsType::save(&ctx, &state.database_pool, &new_trip_type.name).await?;
2023-08-29 21:34:00 +02:00
Ok(Redirect::to("/trips/types/"))
}
2023-08-29 21:34:01 +02:00
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trips_types_edit_name(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path(trip_type_id): Path<Uuid>,
Form(trip_update): Form<TripTypeUpdate>,
) -> Result<Redirect, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
if trip_update.new_value.is_empty() {
return Err(Error::Request(RequestError::EmptyFormElement {
name: "name".to_string(),
}));
}
let exists = models::trips::TripsType::set_name(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state.database_pool,
trip_type_id,
&trip_update.new_value,
)
.await?;
2023-08-29 21:34:01 +02:00
if exists {
Ok(Redirect::to("/trips/types/"))
} else {
2023-08-29 21:34:00 +02:00
Err(Error::Request(RequestError::NotFound {
2023-08-29 21:34:00 +02:00
message: format!("trip type with id {trip_type_id} not found"),
2023-08-29 21:34:00 +02:00
}))
2023-08-29 21:34:00 +02:00
}
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_item(
Extension(current_user): Extension<models::user::User>,
State(state): State<AppState>,
Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let item = models::inventory::InventoryItem::find(&ctx, &state.database_pool, id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("inventory item with id {id} not found"),
}))?;
Ok(view::Root::build(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&view::inventory::InventoryItem::build(&state.client_state, &item),
Some(&TopLevelPage::Inventory),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_category_select(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, category_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let mut trip = models::trips::Trip::find(&ctx, &state.database_pool, trip_id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("trip with id {trip_id} not found"),
}))?;
2023-08-29 21:34:00 +02:00
trip.load_categories(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
let active_category = trip
.categories()
.iter()
.find(|c| c.category.id == category_id)
.ok_or(Error::Request(RequestError::NotFound {
message: format!("category with id {category_id} not found"),
}))?;
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::PushUrl.into(),
2023-08-29 21:34:00 +02:00
format!("?={category_id}").parse().unwrap(),
);
Ok((
headers,
view::trip::TripItems::build(Some(active_category), &trip),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn inventory_category_select(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path(category_id): Path<Uuid>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let inventory = models::inventory::Inventory::load(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
let active_category: Option<&models::inventory::Category> = Some(
inventory
.categories
.iter()
.find(|category| category.id == category_id)
.ok_or(Error::Request(RequestError::NotFound {
message: format!("a category with id {category_id} not found"),
}))?,
);
let mut headers = HeaderMap::new();
headers.insert::<HeaderName>(
2023-08-29 21:34:00 +02:00
htmx::ResponseHeaders::PushUrl.into(),
2023-08-29 21:34:00 +02:00
format!("/inventory/category/{category_id}/")
.parse()
.unwrap(),
);
Ok((
headers,
view::inventory::Inventory::build(
active_category,
&inventory.categories,
state.client_state.edit_item,
),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_packagelist(
Extension(current_user): Extension<models::user::User>,
State(state): State<AppState>,
Path(trip_id): Path<Uuid>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
let mut trip = models::trips::Trip::find(&ctx, &state.database_pool, trip_id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("trip with id {trip_id} not found"),
}))?;
2023-08-29 21:34:00 +02:00
trip.load_categories(&ctx, &state.database_pool).await?;
2023-08-29 21:34:00 +02:00
Ok(view::Root::build(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&view::trip::packagelist::TripPackageList::build(&trip),
Some(&TopLevelPage::Trips),
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_packagelist_set_pack_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pack,
true,
)
.await?;
2023-08-29 21:34:00 +02:00
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("an item with id {item_id} does not exist"),
}))?;
Ok(view::trip::packagelist::TripPackageListRowReady::build(
trip_id, &item,
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_packagelist_set_unpack_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Pack,
false,
)
.await?;
// note that this cannot fail due to a missing item, as trip_item_set_state would already
// return 404. but error handling cannot hurt ;)
2023-08-29 21:34:00 +02:00
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("an item with id {item_id} does not exist"),
}))?;
Ok(view::trip::packagelist::TripPackageListRowReady::build(
trip_id, &item,
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_packagelist_set_ready_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Ready,
true,
)
.await?;
2023-08-29 21:34:00 +02:00
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("an item with id {item_id} does not exist"),
}))?;
Ok(view::trip::packagelist::TripPackageListRowUnready::build(
trip_id, &item,
))
}
2023-08-29 21:34:01 +02:00
//#[tracing::instrument]
2023-08-29 21:34:00 +02:00
pub async fn trip_item_packagelist_set_unready_htmx(
2023-08-29 21:34:00 +02:00
Extension(current_user): Extension<models::user::User>,
2023-08-29 21:34:00 +02:00
State(state): State<AppState>,
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
2023-08-29 21:34:00 +02:00
let ctx = Context::build(current_user);
2023-08-29 21:34:00 +02:00
trip_item_set_state(
2023-08-29 21:34:00 +02:00
&ctx,
2023-08-29 21:34:00 +02:00
&state,
trip_id,
item_id,
models::trips::TripItemStateKey::Ready,
false,
)
.await?;
// note that this cannot fail due to a missing item, as trip_item_set_state would already
// return 404. but error handling cannot hurt ;)
2023-08-29 21:34:00 +02:00
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
2023-08-29 21:34:00 +02:00
.await?
.ok_or(Error::Request(RequestError::NotFound {
message: format!("an item with id {item_id} does not exist"),
}))?;
Ok(view::trip::packagelist::TripPackageListRowUnready::build(
trip_id, &item,
))
}