implement user handling for trips
This commit is contained in:
@@ -6,6 +6,8 @@ use super::{
|
||||
inventory,
|
||||
};
|
||||
|
||||
use crate::Context;
|
||||
|
||||
use futures::{TryFutureExt, TryStreamExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_variant::to_variant_name;
|
||||
@@ -126,12 +128,14 @@ impl TripCategory {
|
||||
}
|
||||
|
||||
pub async fn find(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
trip_id: Uuid,
|
||||
category_id: Uuid,
|
||||
) -> Result<Option<TripCategory>, Error> {
|
||||
let mut category: Option<TripCategory> = None;
|
||||
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let trip_id_param = trip_id.to_string();
|
||||
let category_id_param = category_id.to_string();
|
||||
|
||||
@@ -170,12 +174,15 @@ impl TripCategory {
|
||||
ON item.id = trip.item_id
|
||||
INNER JOIN inventory_items_categories as category
|
||||
ON category.id = item.category_id
|
||||
WHERE trip.trip_id = ?
|
||||
WHERE
|
||||
trip.trip_id = ?
|
||||
AND trip.user_id = ?
|
||||
) AS inner
|
||||
ON inner.category_id = category.id
|
||||
WHERE category.id = ?
|
||||
",
|
||||
trip_id_param,
|
||||
user_id,
|
||||
category_id_param
|
||||
)
|
||||
.fetch(pool)
|
||||
@@ -280,10 +287,12 @@ impl TryFrom<DbTripsItemsRow> for TripItem {
|
||||
|
||||
impl TripItem {
|
||||
pub async fn find(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
trip_id: Uuid,
|
||||
item_id: Uuid,
|
||||
) -> Result<Option<Self>, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let item_id_param = item_id.to_string();
|
||||
let trip_id_param = trip_id.to_string();
|
||||
sqlx::query_as!(
|
||||
@@ -304,9 +313,11 @@ impl TripItem {
|
||||
ON i_item.id = t_item.item_id
|
||||
WHERE t_item.item_id = ?
|
||||
AND t_item.trip_id = ?
|
||||
AND t_item.user_id = ?
|
||||
",
|
||||
item_id_param,
|
||||
trip_id_param,
|
||||
user_id,
|
||||
)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
@@ -315,22 +326,26 @@ impl TripItem {
|
||||
}
|
||||
|
||||
pub async fn set_state(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
trip_id: Uuid,
|
||||
item_id: Uuid,
|
||||
key: TripItemStateKey,
|
||||
value: bool,
|
||||
) -> Result<(), Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let result = sqlx::query(&format!(
|
||||
"UPDATE trips_items
|
||||
SET {key} = ?
|
||||
WHERE trip_id = ?
|
||||
AND item_id = ?",
|
||||
AND item_id = ?
|
||||
AND user_id = ?",
|
||||
key = to_variant_name(&key).unwrap()
|
||||
))
|
||||
.bind(value)
|
||||
.bind(trip_id.to_string())
|
||||
.bind(item_id.to_string())
|
||||
.bind(user_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
@@ -342,7 +357,7 @@ impl TripItem {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DbTripRow {
|
||||
pub struct DbTripRow {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub date_start: String,
|
||||
@@ -409,34 +424,8 @@ pub(crate) struct DbTripWeightRow {
|
||||
}
|
||||
|
||||
impl Trip {
|
||||
pub async fn all(pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<Vec<Trip>, Error> {
|
||||
sqlx::query_as!(
|
||||
DbTripRow,
|
||||
"SELECT
|
||||
id,
|
||||
name,
|
||||
CAST (date_start AS TEXT) date_start,
|
||||
CAST (date_end AS TEXT) date_end,
|
||||
state,
|
||||
location,
|
||||
temp_min,
|
||||
temp_max,
|
||||
comment
|
||||
FROM trips",
|
||||
)
|
||||
.fetch(pool)
|
||||
.map_ok(|row| row.try_into())
|
||||
.try_collect::<Vec<Result<Trip, Error>>>()
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<Trip>, Error>>()
|
||||
}
|
||||
|
||||
pub async fn find(
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
trip_id: Uuid,
|
||||
) -> Result<Option<Self>, Error> {
|
||||
let trip_id_param = trip_id.to_string();
|
||||
pub async fn all(ctx: &Context, pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<Vec<Trip>, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
sqlx::query_as!(
|
||||
DbTripRow,
|
||||
"SELECT
|
||||
@@ -450,8 +439,40 @@ impl Trip {
|
||||
temp_max,
|
||||
comment
|
||||
FROM trips
|
||||
WHERE id = ?",
|
||||
trip_id_param
|
||||
WHERE user_id = ?",
|
||||
user_id
|
||||
)
|
||||
.fetch(pool)
|
||||
.map_ok(|row| row.try_into())
|
||||
.try_collect::<Vec<Result<Trip, Error>>>()
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<Trip>, Error>>()
|
||||
}
|
||||
|
||||
pub async fn find(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
trip_id: Uuid,
|
||||
) -> Result<Option<Self>, Error> {
|
||||
let trip_id_param = trip_id.to_string();
|
||||
let user_id = ctx.user.id.to_string();
|
||||
sqlx::query_as!(
|
||||
DbTripRow,
|
||||
"SELECT
|
||||
id,
|
||||
name,
|
||||
CAST (date_start AS TEXT) date_start,
|
||||
CAST (date_end AS TEXT) date_end,
|
||||
state,
|
||||
location,
|
||||
temp_min,
|
||||
temp_max,
|
||||
comment
|
||||
FROM trips
|
||||
WHERE id = ? and user_id = ?",
|
||||
trip_id_param,
|
||||
user_id,
|
||||
)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
@@ -460,10 +481,12 @@ impl Trip {
|
||||
}
|
||||
|
||||
pub async fn trip_type_remove(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
id: Uuid,
|
||||
type_id: Uuid,
|
||||
) -> Result<bool, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let id_param = id.to_string();
|
||||
let type_id_param = type_id.to_string();
|
||||
|
||||
@@ -471,9 +494,15 @@ impl Trip {
|
||||
"DELETE FROM trips_to_trips_types AS ttt
|
||||
WHERE ttt.trip_id = ?
|
||||
AND ttt.trip_type_id = ?
|
||||
AND EXISTS(SELECT * FROM trips WHERE id = ? AND user_id = ?)
|
||||
AND EXISTS(SELECT * FROM trips_types WHERE id = ? AND user_id = ?)
|
||||
",
|
||||
id_param,
|
||||
type_id_param,
|
||||
id_param,
|
||||
user_id,
|
||||
type_id_param,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -482,20 +511,31 @@ impl Trip {
|
||||
}
|
||||
|
||||
pub async fn trip_type_add(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
id: Uuid,
|
||||
type_id: Uuid,
|
||||
) -> Result<(), Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
// TODO user handling?
|
||||
let trip_id_param = id.to_string();
|
||||
let type_id_param = type_id.to_string();
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO trips_to_trips_types
|
||||
(trip_id, trip_type_id)
|
||||
VALUES
|
||||
(?, ?)
|
||||
",
|
||||
"INSERT INTO
|
||||
trips_to_trips_types (trip_id, trip_type_id)
|
||||
SELECT trips.id as trip_id, trips_types.id as trip_type_id
|
||||
FROM trips
|
||||
INNER JOIN trips_types
|
||||
WHERE
|
||||
trips.id = ?
|
||||
AND trips.user_id = ?
|
||||
AND trips_types.id = ?
|
||||
AND trips_types.user_id = ?",
|
||||
trip_id_param,
|
||||
user_id,
|
||||
type_id_param,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -504,17 +544,20 @@ impl Trip {
|
||||
}
|
||||
|
||||
pub async fn set_state(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
id: Uuid,
|
||||
new_state: &TripState,
|
||||
) -> Result<bool, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let trip_id_param = id.to_string();
|
||||
let result = sqlx::query!(
|
||||
"UPDATE trips
|
||||
SET state = ?
|
||||
WHERE id = ?",
|
||||
WHERE id = ? and user_id = ?",
|
||||
new_state,
|
||||
trip_id_param,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -523,17 +566,20 @@ impl Trip {
|
||||
}
|
||||
|
||||
pub async fn set_comment(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
id: Uuid,
|
||||
new_comment: &str,
|
||||
) -> Result<bool, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let trip_id_param = id.to_string();
|
||||
let result = sqlx::query!(
|
||||
"UPDATE trips
|
||||
SET comment = ?
|
||||
WHERE id = ?",
|
||||
WHERE id = ? AND user_id = ?",
|
||||
new_comment,
|
||||
trip_id_param,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -542,19 +588,22 @@ impl Trip {
|
||||
}
|
||||
|
||||
pub async fn set_attribute(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
trip_id: Uuid,
|
||||
attribute: TripAttribute,
|
||||
value: &str,
|
||||
) -> Result<(), Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let result = sqlx::query(&format!(
|
||||
"UPDATE trips
|
||||
SET {attribute} = ?
|
||||
WHERE id = ?",
|
||||
WHERE id = ? AND user_id = ?",
|
||||
attribute = to_variant_name(&attribute).unwrap()
|
||||
))
|
||||
.bind(value)
|
||||
.bind(trip_id.to_string())
|
||||
.bind(user_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
@@ -566,11 +615,13 @@ impl Trip {
|
||||
}
|
||||
|
||||
pub async fn save(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
name: &str,
|
||||
date_start: time::Date,
|
||||
date_end: time::Date,
|
||||
) -> Result<Uuid, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let id = Uuid::new_v4();
|
||||
let id_param = id.to_string();
|
||||
let date_start = date_start.format(consts::DATE_FORMAT)?;
|
||||
@@ -580,14 +631,15 @@ impl Trip {
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO trips
|
||||
(id, name, date_start, date_end, state)
|
||||
(id, name, date_start, date_end, state, user_id)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?)",
|
||||
(?, ?, ?, ?, ?, ?)",
|
||||
id_param,
|
||||
name,
|
||||
date_start,
|
||||
date_end,
|
||||
trip_state,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -596,9 +648,11 @@ impl Trip {
|
||||
}
|
||||
|
||||
pub async fn find_total_picked_weight(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
trip_id: Uuid,
|
||||
) -> Result<i64, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let trip_id_param = trip_id.to_string();
|
||||
let weight = sqlx::query_as!(
|
||||
DbTripWeightRow,
|
||||
@@ -611,10 +665,11 @@ impl Trip {
|
||||
INNER JOIN inventory_items AS i_item
|
||||
ON t_item.item_id = i_item.id
|
||||
WHERE
|
||||
trip.id = ?
|
||||
trip.id = ? AND trip.user_id = ?
|
||||
AND t_item.pick = true
|
||||
",
|
||||
trip_id_param
|
||||
trip_id_param,
|
||||
user_id,
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.map_ok(|row| row.total_weight.unwrap() as i64)
|
||||
@@ -650,7 +705,12 @@ impl Trip {
|
||||
.sum::<i64>()
|
||||
}
|
||||
|
||||
pub async fn load_trips_types(&mut self, pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<(), Error> {
|
||||
pub async fn load_trips_types(
|
||||
&mut self,
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
) -> Result<(), Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let id = self.id.to_string();
|
||||
let types = sqlx::query!(
|
||||
"
|
||||
@@ -660,17 +720,20 @@ impl Trip {
|
||||
inner.id IS NOT NULL AS active
|
||||
FROM trips_types AS type
|
||||
LEFT JOIN (
|
||||
SELECT type.id as id, type.name as name
|
||||
SELECT type.id as id, trip.user_id as user_id
|
||||
FROM trips as trip
|
||||
INNER JOIN trips_to_trips_types as ttt
|
||||
ON ttt.trip_id = trip.id
|
||||
INNER JOIN trips_types AS type
|
||||
ON type.id == ttt.trip_type_id
|
||||
WHERE trip.id = ?
|
||||
WHERE trip.id = ? AND trip.user_id = ?
|
||||
) AS inner
|
||||
ON inner.id = type.id
|
||||
WHERE type.user_id = ?
|
||||
",
|
||||
id
|
||||
id,
|
||||
user_id,
|
||||
user_id,
|
||||
)
|
||||
.fetch(pool)
|
||||
.map_ok(|row| -> Result<TripType, Error> {
|
||||
@@ -695,6 +758,7 @@ impl Trip {
|
||||
|
||||
pub async fn sync_trip_items_with_inventory(
|
||||
&mut self,
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
) -> Result<(), Error> {
|
||||
// we need to get all items that are part of the inventory but not
|
||||
@@ -708,6 +772,7 @@ impl Trip {
|
||||
// * if the trip is new, we have to make these new items prominently
|
||||
// visible so the user knows that there might be new items to
|
||||
// consider
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let trip_id = self.id.to_string();
|
||||
let unsynced_items: Vec<Uuid> = sqlx::query!(
|
||||
"
|
||||
@@ -715,14 +780,15 @@ impl Trip {
|
||||
i_item.id AS item_id
|
||||
FROM inventory_items AS i_item
|
||||
LEFT JOIN (
|
||||
SELECT t_item.item_id as item_id
|
||||
SELECT t_item.item_id AS item_id, t_item.user_id AS user_id
|
||||
FROM trips_items AS t_item
|
||||
WHERE t_item.trip_id = ?
|
||||
WHERE t_item.trip_id = ? AND t_item.user_id = ?
|
||||
) AS t_item
|
||||
ON t_item.item_id = i_item.id
|
||||
WHERE t_item.item_id IS NULL
|
||||
",
|
||||
trip_id
|
||||
WHERE t_item.item_id IS NULL AND i_item.user_id = ?",
|
||||
trip_id,
|
||||
user_id,
|
||||
user_id,
|
||||
)
|
||||
.fetch(pool)
|
||||
.map_ok(|row| -> Result<Uuid, Error> { Ok(Uuid::try_parse(&row.item_id)?) })
|
||||
@@ -748,9 +814,10 @@ impl Trip {
|
||||
pick,
|
||||
pack,
|
||||
ready,
|
||||
new
|
||||
new,
|
||||
user_id
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
",
|
||||
item_id,
|
||||
trip_id,
|
||||
@@ -758,6 +825,7 @@ impl Trip {
|
||||
false,
|
||||
false,
|
||||
mark_as_new,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -768,11 +836,16 @@ impl Trip {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn load_categories(&mut self, pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<(), Error> {
|
||||
pub async fn load_categories(
|
||||
&mut self,
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
) -> Result<(), Error> {
|
||||
let mut categories: Vec<TripCategory> = vec![];
|
||||
// we can ignore the return type as we collect into `categories`
|
||||
// in the `map_ok()` closure
|
||||
let id = self.id.to_string();
|
||||
let user_id = ctx.user.id.to_string();
|
||||
sqlx::query!(
|
||||
"
|
||||
SELECT
|
||||
@@ -802,17 +875,21 @@ impl Trip {
|
||||
trip.pick as item_is_picked,
|
||||
trip.pack as item_is_packed,
|
||||
trip.ready as item_is_ready,
|
||||
trip.new as item_is_new
|
||||
trip.new as item_is_new,
|
||||
trip.user_id as user_id
|
||||
FROM trips_items as trip
|
||||
INNER JOIN inventory_items as item
|
||||
ON item.id = trip.item_id
|
||||
INNER JOIN inventory_items_categories as category
|
||||
ON category.id = item.category_id
|
||||
WHERE trip.trip_id = ?
|
||||
WHERE trip.trip_id = ? AND trip.user_id = ?
|
||||
) AS inner
|
||||
ON inner.category_id = category.id
|
||||
WHERE category.user_id = ?
|
||||
",
|
||||
id
|
||||
id,
|
||||
user_id,
|
||||
user_id,
|
||||
)
|
||||
.fetch(pool)
|
||||
.map_ok(|row| -> Result<(), Error> {
|
||||
@@ -883,13 +960,16 @@ pub struct TripType {
|
||||
}
|
||||
|
||||
impl TripsType {
|
||||
pub async fn all(pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<Vec<Self>, Error> {
|
||||
pub async fn all(ctx: &Context, pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<Vec<Self>, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
sqlx::query_as!(
|
||||
DbTripsTypesRow,
|
||||
"SELECT
|
||||
id,
|
||||
name
|
||||
FROM trips_types",
|
||||
FROM trips_types
|
||||
WHERE user_id = ?",
|
||||
user_id,
|
||||
)
|
||||
.fetch(pool)
|
||||
.map_ok(|row| row.try_into())
|
||||
@@ -899,16 +979,22 @@ impl TripsType {
|
||||
.collect::<Result<Vec<Self>, Error>>()
|
||||
}
|
||||
|
||||
pub async fn save(pool: &sqlx::Pool<sqlx::Sqlite>, name: &str) -> Result<Uuid, Error> {
|
||||
pub async fn save(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
name: &str,
|
||||
) -> Result<Uuid, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let id = Uuid::new_v4();
|
||||
let id_param = id.to_string();
|
||||
sqlx::query!(
|
||||
"INSERT INTO trips_types
|
||||
(id, name)
|
||||
(id, name, user_id)
|
||||
VALUES
|
||||
(?, ?)",
|
||||
(?, ?, ?)",
|
||||
id_param,
|
||||
name,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@@ -917,18 +1003,21 @@ impl TripsType {
|
||||
}
|
||||
|
||||
pub async fn set_name(
|
||||
ctx: &Context,
|
||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||
id: Uuid,
|
||||
new_name: &str,
|
||||
) -> Result<bool, Error> {
|
||||
let user_id = ctx.user.id.to_string();
|
||||
let id_param = id.to_string();
|
||||
|
||||
let result = sqlx::query!(
|
||||
"UPDATE trips_types
|
||||
SET name = ?
|
||||
WHERE id = ?",
|
||||
WHERE id = ? and user_id = ?",
|
||||
new_name,
|
||||
id_param,
|
||||
user_id,
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
@@ -308,9 +308,11 @@ pub async fn inventory_item_cancel(
|
||||
}
|
||||
|
||||
pub async fn trip_create(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Form(new_trip): Form<NewTrip>,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
if new_trip.name.is_empty() {
|
||||
return Err(Error::Request(RequestError::EmptyFormElement {
|
||||
name: "name".to_string(),
|
||||
@@ -318,6 +320,7 @@ pub async fn trip_create(
|
||||
}
|
||||
|
||||
let new_id = models::trips::Trip::save(
|
||||
&ctx,
|
||||
&state.database_pool,
|
||||
&new_trip.name,
|
||||
new_trip.date_start,
|
||||
@@ -332,10 +335,11 @@ pub async fn trips(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let trips = models::trips::Trip::all(&state.database_pool).await?;
|
||||
let ctx = Context::build(current_user);
|
||||
let trips = models::trips::Trip::all(&ctx, &state.database_pool).await?;
|
||||
|
||||
Ok(view::Root::build(
|
||||
&Context::build(current_user),
|
||||
&ctx,
|
||||
&view::trip::TripManager::build(trips),
|
||||
Some(&TopLevelPage::Trips),
|
||||
))
|
||||
@@ -347,21 +351,22 @@ pub async fn trip(
|
||||
Path(id): Path<Uuid>,
|
||||
Query(trip_query): Query<TripQuery>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
state.client_state.trip_edit_attribute = trip_query.edit;
|
||||
state.client_state.active_category_id = trip_query.category;
|
||||
|
||||
let mut trip: models::trips::Trip = models::trips::Trip::find(&state.database_pool, id)
|
||||
let mut trip: models::trips::Trip = models::trips::Trip::find(&ctx, &state.database_pool, id)
|
||||
.await?
|
||||
.ok_or(Error::Request(RequestError::NotFound {
|
||||
message: format!("trip with id {id} not found"),
|
||||
}))?;
|
||||
|
||||
trip.load_trips_types(&state.database_pool).await?;
|
||||
trip.load_trips_types(&ctx, &state.database_pool).await?;
|
||||
|
||||
trip.sync_trip_items_with_inventory(&state.database_pool)
|
||||
trip.sync_trip_items_with_inventory(&ctx, &state.database_pool)
|
||||
.await?;
|
||||
|
||||
trip.load_categories(&state.database_pool).await?;
|
||||
trip.load_categories(&ctx, &state.database_pool).await?;
|
||||
|
||||
let active_category: Option<&models::trips::TripCategory> = state
|
||||
.client_state
|
||||
@@ -377,7 +382,7 @@ pub async fn trip(
|
||||
.transpose()?;
|
||||
|
||||
Ok(view::Root::build(
|
||||
&Context::build(current_user),
|
||||
&ctx,
|
||||
&view::trip::Trip::build(
|
||||
&trip,
|
||||
state.client_state.trip_edit_attribute,
|
||||
@@ -388,11 +393,13 @@ pub async fn trip(
|
||||
}
|
||||
|
||||
pub async fn trip_type_remove(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
let found =
|
||||
models::trips::Trip::trip_type_remove(&state.database_pool, trip_id, type_id).await?;
|
||||
models::trips::Trip::trip_type_remove(&ctx, &state.database_pool, trip_id, type_id).await?;
|
||||
|
||||
if !found {
|
||||
Err(Error::Request(RequestError::NotFound {
|
||||
@@ -404,20 +411,25 @@ pub async fn trip_type_remove(
|
||||
}
|
||||
|
||||
pub async fn trip_type_add(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
|
||||
) -> Result<Redirect, Error> {
|
||||
models::trips::Trip::trip_type_add(&state.database_pool, trip_id, type_id).await?;
|
||||
let ctx = Context::build(current_user);
|
||||
models::trips::Trip::trip_type_add(&ctx, &state.database_pool, trip_id, type_id).await?;
|
||||
|
||||
Ok(Redirect::to(&format!("/trips/{trip_id}/")))
|
||||
}
|
||||
|
||||
pub async fn trip_comment_set(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path(trip_id): Path<Uuid>,
|
||||
Form(comment_update): Form<CommentUpdate>,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
let found = models::trips::Trip::set_comment(
|
||||
&ctx,
|
||||
&state.database_pool,
|
||||
trip_id,
|
||||
&comment_update.new_comment,
|
||||
@@ -434,10 +446,12 @@ pub async fn trip_comment_set(
|
||||
}
|
||||
|
||||
pub async fn trip_edit_attribute(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, attribute)): Path<(Uuid, models::trips::TripAttribute)>,
|
||||
Form(trip_update): Form<TripUpdate>,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
if attribute == models::trips::TripAttribute::Name {
|
||||
if trip_update.new_value.is_empty() {
|
||||
return Err(Error::Request(RequestError::EmptyFormElement {
|
||||
@@ -446,6 +460,7 @@ pub async fn trip_edit_attribute(
|
||||
}
|
||||
}
|
||||
models::trips::Trip::set_attribute(
|
||||
&ctx,
|
||||
&state.database_pool,
|
||||
trip_id,
|
||||
attribute,
|
||||
@@ -457,13 +472,15 @@ pub async fn trip_edit_attribute(
|
||||
}
|
||||
|
||||
pub async fn trip_item_set_state(
|
||||
ctx: &Context,
|
||||
state: &AppState,
|
||||
trip_id: Uuid,
|
||||
item_id: Uuid,
|
||||
key: models::trips::TripItemStateKey,
|
||||
value: bool,
|
||||
) -> Result<(), Error> {
|
||||
models::trips::TripItem::set_state(&state.database_pool, trip_id, item_id, key, value).await?;
|
||||
models::trips::TripItem::set_state(&ctx, &state.database_pool, trip_id, item_id, key, value)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -473,7 +490,7 @@ pub async fn trip_row(
|
||||
trip_id: Uuid,
|
||||
item_id: Uuid,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let item = models::trips::TripItem::find(&state.database_pool, trip_id, item_id)
|
||||
let item = models::trips::TripItem::find(ctx, &state.database_pool, trip_id, item_id)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
Error::Request(RequestError::NotFound {
|
||||
@@ -492,14 +509,18 @@ pub async fn trip_row(
|
||||
.await?,
|
||||
);
|
||||
|
||||
let category =
|
||||
models::trips::TripCategory::find(&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),
|
||||
})
|
||||
})?;
|
||||
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),
|
||||
})
|
||||
})?;
|
||||
|
||||
// TODO biggest_category_weight?
|
||||
let category_row = view::trip::TripCategoryListRow::build(trip_id, &category, true, 0, true);
|
||||
@@ -508,12 +529,15 @@ pub async fn trip_row(
|
||||
}
|
||||
|
||||
pub async fn trip_item_set_pick(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
Ok::<_, Error>(
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -532,6 +556,7 @@ pub async fn trip_item_set_pick_htmx(
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -548,12 +573,15 @@ pub async fn trip_item_set_pick_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_set_unpick(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
Ok::<_, Error>(
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -572,6 +600,7 @@ pub async fn trip_item_set_unpick_htmx(
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -588,12 +617,15 @@ pub async fn trip_item_set_unpick_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_set_pack(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
Ok::<_, Error>(
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -612,6 +644,7 @@ pub async fn trip_item_set_pack_htmx(
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -628,12 +661,15 @@ pub async fn trip_item_set_pack_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_set_unpack(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
Ok::<_, Error>(
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -652,6 +688,7 @@ pub async fn trip_item_set_unpack_htmx(
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -668,12 +705,15 @@ pub async fn trip_item_set_unpack_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_set_ready(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
Ok::<_, Error>(
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -692,6 +732,7 @@ pub async fn trip_item_set_ready_htmx(
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -708,12 +749,15 @@ pub async fn trip_item_set_ready_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_set_unready(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
Ok::<_, Error>(
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -732,6 +776,7 @@ pub async fn trip_item_set_unready_htmx(
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -748,11 +793,13 @@ pub async fn trip_item_set_unready_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_total_weight_htmx(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path(trip_id): Path<Uuid>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
let total_weight =
|
||||
models::trips::Trip::find_total_picked_weight(&state.database_pool, trip_id).await?;
|
||||
models::trips::Trip::find_total_picked_weight(&ctx, &state.database_pool, trip_id).await?;
|
||||
Ok(view::trip::TripInfoTotalWeightRow::build(
|
||||
trip_id,
|
||||
total_weight,
|
||||
@@ -778,11 +825,14 @@ pub async fn inventory_category_create(
|
||||
}
|
||||
|
||||
pub async fn trip_state_set(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Path((trip_id, new_state)): Path<(Uuid, models::trips::TripState)>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let exists = models::trips::Trip::set_state(&state.database_pool, trip_id, &new_state).await?;
|
||||
let ctx = Context::build(current_user);
|
||||
let exists =
|
||||
models::trips::Trip::set_state(&ctx, &state.database_pool, trip_id, &new_state).await?;
|
||||
|
||||
if !exists {
|
||||
return Err(Error::Request(RequestError::NotFound {
|
||||
@@ -801,36 +851,42 @@ pub async fn trips_types(
|
||||
State(mut state): State<AppState>,
|
||||
Query(trip_type_query): Query<TripTypeQuery>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
state.client_state.trip_type_edit = trip_type_query.edit;
|
||||
|
||||
let trip_types: Vec<models::trips::TripsType> =
|
||||
models::trips::TripsType::all(&state.database_pool).await?;
|
||||
models::trips::TripsType::all(&ctx, &state.database_pool).await?;
|
||||
|
||||
Ok(view::Root::build(
|
||||
&Context::build(current_user),
|
||||
&ctx,
|
||||
&view::trip::types::TypeList::build(&state.client_state, trip_types),
|
||||
Some(&TopLevelPage::Trips),
|
||||
))
|
||||
}
|
||||
pub async fn trip_type_create(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Form(new_trip_type): Form<NewTripType>,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
if new_trip_type.name.is_empty() {
|
||||
return Err(Error::Request(RequestError::EmptyFormElement {
|
||||
name: "name".to_string(),
|
||||
}));
|
||||
}
|
||||
|
||||
let _new_id = models::trips::TripsType::save(&state.database_pool, &new_trip_type.name).await?;
|
||||
let _new_id =
|
||||
models::trips::TripsType::save(&ctx, &state.database_pool, &new_trip_type.name).await?;
|
||||
|
||||
Ok(Redirect::to("/trips/types/"))
|
||||
}
|
||||
pub async fn trips_types_edit_name(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path(trip_type_id): Path<Uuid>,
|
||||
Form(trip_update): Form<TripTypeUpdate>,
|
||||
) -> Result<Redirect, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
if trip_update.new_value.is_empty() {
|
||||
return Err(Error::Request(RequestError::EmptyFormElement {
|
||||
name: "name".to_string(),
|
||||
@@ -838,6 +894,7 @@ pub async fn trips_types_edit_name(
|
||||
}
|
||||
|
||||
let exists = models::trips::TripsType::set_name(
|
||||
&ctx,
|
||||
&state.database_pool,
|
||||
trip_type_id,
|
||||
&trip_update.new_value,
|
||||
@@ -873,16 +930,18 @@ pub async fn inventory_item(
|
||||
}
|
||||
|
||||
pub async fn trip_category_select(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, category_id)): Path<(Uuid, Uuid)>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut trip = models::trips::Trip::find(&state.database_pool, trip_id)
|
||||
let ctx = Context::build(current_user);
|
||||
let mut trip = models::trips::Trip::find(&ctx, &state.database_pool, trip_id)
|
||||
.await?
|
||||
.ok_or(Error::Request(RequestError::NotFound {
|
||||
message: format!("trip with id {trip_id} not found"),
|
||||
}))?;
|
||||
|
||||
trip.load_categories(&state.database_pool).await?;
|
||||
trip.load_categories(&ctx, &state.database_pool).await?;
|
||||
|
||||
let active_category = trip
|
||||
.categories()
|
||||
@@ -945,26 +1004,30 @@ pub async fn trip_packagelist(
|
||||
State(state): State<AppState>,
|
||||
Path(trip_id): Path<Uuid>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut trip = models::trips::Trip::find(&state.database_pool, trip_id)
|
||||
let ctx = Context::build(current_user);
|
||||
let mut trip = models::trips::Trip::find(&ctx, &state.database_pool, trip_id)
|
||||
.await?
|
||||
.ok_or(Error::Request(RequestError::NotFound {
|
||||
message: format!("trip with id {trip_id} not found"),
|
||||
}))?;
|
||||
|
||||
trip.load_categories(&state.database_pool).await?;
|
||||
trip.load_categories(&ctx, &state.database_pool).await?;
|
||||
|
||||
Ok(view::Root::build(
|
||||
&Context::build(current_user),
|
||||
&ctx,
|
||||
&view::trip::packagelist::TripPackageList::build(&trip),
|
||||
Some(&TopLevelPage::Trips),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn trip_item_packagelist_set_pack_htmx(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -973,7 +1036,7 @@ pub async fn trip_item_packagelist_set_pack_htmx(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let item = models::trips::TripItem::find(&state.database_pool, trip_id, item_id)
|
||||
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
|
||||
.await?
|
||||
.ok_or(Error::Request(RequestError::NotFound {
|
||||
message: format!("an item with id {item_id} does not exist"),
|
||||
@@ -985,10 +1048,13 @@ pub async fn trip_item_packagelist_set_pack_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_packagelist_set_unpack_htmx(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -999,7 +1065,7 @@ pub async fn trip_item_packagelist_set_unpack_htmx(
|
||||
|
||||
// note that this cannot fail due to a missing item, as trip_item_set_state would already
|
||||
// return 404. but error handling cannot hurt ;)
|
||||
let item = models::trips::TripItem::find(&state.database_pool, trip_id, item_id)
|
||||
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
|
||||
.await?
|
||||
.ok_or(Error::Request(RequestError::NotFound {
|
||||
message: format!("an item with id {item_id} does not exist"),
|
||||
@@ -1011,10 +1077,13 @@ pub async fn trip_item_packagelist_set_unpack_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_packagelist_set_ready_htmx(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -1023,7 +1092,7 @@ pub async fn trip_item_packagelist_set_ready_htmx(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let item = models::trips::TripItem::find(&state.database_pool, trip_id, item_id)
|
||||
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
|
||||
.await?
|
||||
.ok_or(Error::Request(RequestError::NotFound {
|
||||
message: format!("an item with id {item_id} does not exist"),
|
||||
@@ -1035,10 +1104,13 @@ pub async fn trip_item_packagelist_set_ready_htmx(
|
||||
}
|
||||
|
||||
pub async fn trip_item_packagelist_set_unready_htmx(
|
||||
Extension(current_user): Extension<models::user::User>,
|
||||
State(state): State<AppState>,
|
||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let ctx = Context::build(current_user);
|
||||
trip_item_set_state(
|
||||
&ctx,
|
||||
&state,
|
||||
trip_id,
|
||||
item_id,
|
||||
@@ -1049,7 +1121,7 @@ pub async fn trip_item_packagelist_set_unready_htmx(
|
||||
|
||||
// note that this cannot fail due to a missing item, as trip_item_set_state would already
|
||||
// return 404. but error handling cannot hurt ;)
|
||||
let item = models::trips::TripItem::find(&state.database_pool, trip_id, item_id)
|
||||
let item = models::trips::TripItem::find(&ctx, &state.database_pool, trip_id, item_id)
|
||||
.await?
|
||||
.ok_or(Error::Request(RequestError::NotFound {
|
||||
message: format!("an item with id {item_id} does not exist"),
|
||||
|
||||
Reference in New Issue
Block a user