Couple the household & user
This commit is contained in:
parent
eacd89119f
commit
b52443f833
5 changed files with 84 additions and 83 deletions
|
|
@ -12,11 +12,14 @@ use serde::{Deserialize, Serialize};
|
|||
use tower_sessions::Session;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::entity::{household, household_members, prelude::*};
|
||||
use crate::entity::{household, household_members, prelude::*, user};
|
||||
|
||||
use super::{base_page_with_head, AppState, AuthenticatedUser, RedirectOrError, RouteError};
|
||||
|
||||
pub(super) struct CurrentHousehold(pub household::Model);
|
||||
pub(super) struct CurrentHousehold {
|
||||
pub(super) user: user::Model,
|
||||
pub(super) household: household::Model,
|
||||
}
|
||||
|
||||
pub(super) fn routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
|
|
@ -44,19 +47,30 @@ where
|
|||
.await
|
||||
.map_err(|_| RouteError::SessionExtract)?;
|
||||
|
||||
let id: Uuid = session
|
||||
let user_id: Uuid = session
|
||||
.get("id")
|
||||
.await
|
||||
.map_err(RouteError::from)?
|
||||
.ok_or_else(|| Redirect::to("/login"))?;
|
||||
|
||||
let household_id: Uuid = session
|
||||
.get("household")
|
||||
.await
|
||||
.map_err(RouteError::from)?
|
||||
.ok_or_else(|| Redirect::to("/household/select"))?;
|
||||
|
||||
Ok(Self(
|
||||
Household::find_by_id(id)
|
||||
let (household, user) = Household::find_by_id(household_id)
|
||||
.find_also_related(user::Entity)
|
||||
.filter(user::Column::Id.eq(user_id))
|
||||
.one(&app_state.db)
|
||||
.await
|
||||
.map_err(RouteError::from)?
|
||||
.unwrap(),
|
||||
))
|
||||
.ok_or_else(|| RouteError::RessourceNotFound)?;
|
||||
|
||||
Ok(CurrentHousehold {
|
||||
household,
|
||||
user: user.ok_or_else(|| RouteError::RessourceNotFound)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,11 +161,11 @@ struct HouseholdName {
|
|||
}
|
||||
|
||||
async fn rename(
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
state: State<AppState>,
|
||||
Form(form): Form<HouseholdName>,
|
||||
) -> Result<Redirect, RouteError> {
|
||||
let mut household: household::ActiveModel = household.0.into();
|
||||
let mut household: household::ActiveModel = current.household.into();
|
||||
|
||||
household.name = ActiveValue::Set(form.name);
|
||||
|
||||
|
|
@ -218,8 +232,7 @@ async fn delete_household(
|
|||
}
|
||||
|
||||
async fn leave(
|
||||
household: CurrentHousehold,
|
||||
user: AuthenticatedUser,
|
||||
current: CurrentHousehold,
|
||||
session: Session,
|
||||
state: State<AppState>,
|
||||
) -> Result<Redirect, RouteError> {
|
||||
|
|
@ -227,13 +240,12 @@ async fn leave(
|
|||
.db
|
||||
.transaction(|txn| {
|
||||
Box::pin(async move {
|
||||
HouseholdMembers::delete_by_id((household.0.id, user.model.id))
|
||||
HouseholdMembers::delete_by_id((current.household.id, current.user.id))
|
||||
.exec(txn)
|
||||
.await?;
|
||||
|
||||
let Some(household) = Household::find_by_id(household.0.id)
|
||||
.one(txn)
|
||||
.await? else {
|
||||
let Some(household) = Household::find_by_id(current.household.id).one(txn).await?
|
||||
else {
|
||||
return Err(RouteError::InvalidRequest("No such household".into()));
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use super::{
|
|||
confirm_danger_modal, error_alert,
|
||||
household::CurrentHousehold,
|
||||
sidebar::{sidebar, SidebarLocation},
|
||||
AppState, AuthenticatedUser, RouteError,
|
||||
AppState, RouteError,
|
||||
};
|
||||
|
||||
pub(super) fn routes() -> Router<AppState> {
|
||||
|
|
@ -118,12 +118,11 @@ fn render_ingredients(error: Option<String>, ingredient_list: &[ingredient::Mode
|
|||
|
||||
async fn ingredients_view(
|
||||
error: Option<String>,
|
||||
household: &CurrentHousehold,
|
||||
user: &AuthenticatedUser,
|
||||
current: &CurrentHousehold,
|
||||
db: &DatabaseConnection,
|
||||
) -> Result<Markup, RouteError> {
|
||||
let list = household
|
||||
.0
|
||||
let list = current
|
||||
.household
|
||||
.find_related(Ingredient)
|
||||
.order_by_asc(ingredient::Column::Id)
|
||||
.all(db)
|
||||
|
|
@ -131,27 +130,25 @@ async fn ingredients_view(
|
|||
|
||||
Ok(sidebar(
|
||||
SidebarLocation::Ingredients,
|
||||
household,
|
||||
user,
|
||||
current,
|
||||
render_ingredients(error, &list),
|
||||
))
|
||||
}
|
||||
|
||||
async fn ingredients(
|
||||
state: State<AppState>,
|
||||
user: AuthenticatedUser,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
) -> Result<Markup, RouteError> {
|
||||
ingredients_view(None, &household, &user, &state.db).await
|
||||
ingredients_view(None, ¤t, &state.db).await
|
||||
}
|
||||
|
||||
async fn do_ingredient_delete(
|
||||
household: &CurrentHousehold,
|
||||
current: &CurrentHousehold,
|
||||
db: &DatabaseConnection,
|
||||
id: i64,
|
||||
) -> Result<Option<String>, RouteError> {
|
||||
if household
|
||||
.0
|
||||
if current
|
||||
.household
|
||||
.find_related(Ingredient)
|
||||
.filter(ingredient::Column::Id.eq(id))
|
||||
.count(db)
|
||||
|
|
@ -182,14 +179,12 @@ async fn do_ingredient_delete(
|
|||
|
||||
async fn delete_ingredient(
|
||||
state: State<AppState>,
|
||||
user: AuthenticatedUser,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
ig: Path<i64>,
|
||||
) -> Result<Markup, RouteError> {
|
||||
ingredients_view(
|
||||
do_ingredient_delete(&household, &state.db, ig.0).await?,
|
||||
&household,
|
||||
&user,
|
||||
do_ingredient_delete(¤t, &state.db, ig.0).await?,
|
||||
¤t,
|
||||
&state.db,
|
||||
)
|
||||
.await
|
||||
|
|
@ -203,12 +198,12 @@ struct IngredientDesc {
|
|||
|
||||
async fn edit_ingredient(
|
||||
state: State<AppState>,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
ig: Path<i64>,
|
||||
form: Form<IngredientDesc>,
|
||||
) -> Result<Redirect, RouteError> {
|
||||
let ingredient = household
|
||||
.0
|
||||
let ingredient = current
|
||||
.household
|
||||
.find_related(Ingredient)
|
||||
.filter(ingredient::Column::Id.eq(ig.0))
|
||||
.one(&state.db)
|
||||
|
|
@ -228,7 +223,7 @@ async fn edit_ingredient(
|
|||
|
||||
async fn add_ingredient(
|
||||
state: State<AppState>,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
form: Form<IngredientDesc>,
|
||||
) -> Result<Redirect, RouteError> {
|
||||
let mut ingredient = ingredient::ActiveModel::new();
|
||||
|
|
@ -237,7 +232,7 @@ async fn add_ingredient(
|
|||
true => None,
|
||||
false => Some(form.0.unit),
|
||||
});
|
||||
ingredient.household = ActiveValue::Set(household.0.id);
|
||||
ingredient.household = ActiveValue::Set(current.household.id);
|
||||
|
||||
ingredient.insert(&state.db).await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -345,13 +345,12 @@ fn confirm_danger_modal(id: &str, inner: &str, action: &str, title: &str) -> Mar
|
|||
}
|
||||
}
|
||||
|
||||
async fn index(user: AuthenticatedUser, household: CurrentHousehold) -> Markup {
|
||||
async fn index(current: CurrentHousehold) -> Markup {
|
||||
sidebar::sidebar(
|
||||
SidebarLocation::Home,
|
||||
&household,
|
||||
&user,
|
||||
¤t,
|
||||
html! {
|
||||
"Hello world in " (household.0.name) "!"
|
||||
"Hello world in " (current.household.name) "!"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use super::{
|
|||
base_page,
|
||||
household::CurrentHousehold,
|
||||
sidebar::{sidebar, SidebarLocation},
|
||||
AppState, AuthenticatedUser, RouteError,
|
||||
AppState, RouteError,
|
||||
};
|
||||
|
||||
pub(super) fn routes() -> Router<AppState> {
|
||||
|
|
@ -72,11 +72,10 @@ fn recipe_list(recipes: &[recipe::Model], household: Option<Uuid>) -> Markup {
|
|||
|
||||
async fn list_recipes(
|
||||
state: State<AppState>,
|
||||
user: AuthenticatedUser,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
) -> Result<Markup, RouteError> {
|
||||
let recipes = household
|
||||
.0
|
||||
let recipes = current
|
||||
.household
|
||||
.find_related(Recipe)
|
||||
.order_by_asc(recipe::Column::Name)
|
||||
.all(&state.db)
|
||||
|
|
@ -84,8 +83,7 @@ async fn list_recipes(
|
|||
|
||||
Ok(sidebar(
|
||||
SidebarLocation::RecipeList,
|
||||
&household,
|
||||
&user,
|
||||
¤t,
|
||||
recipe_list(&recipes, None),
|
||||
))
|
||||
}
|
||||
|
|
@ -222,12 +220,11 @@ async fn recipe_view(
|
|||
|
||||
async fn view_recipe(
|
||||
state: State<AppState>,
|
||||
user: AuthenticatedUser,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
id: Path<i32>,
|
||||
) -> Result<Markup, RouteError> {
|
||||
let recipe = household
|
||||
.0
|
||||
let recipe = current
|
||||
.household
|
||||
.find_related(Recipe)
|
||||
.filter(recipe::Column::Id.eq(id.0))
|
||||
.one(&state.db)
|
||||
|
|
@ -236,9 +233,8 @@ async fn view_recipe(
|
|||
|
||||
Ok(sidebar(
|
||||
SidebarLocation::RecipeList,
|
||||
&household,
|
||||
&user,
|
||||
recipe_view(&recipe, household.0.id, true, &state.db).await?,
|
||||
¤t,
|
||||
recipe_view(&recipe, current.household.id, true, &state.db).await?,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -290,12 +286,11 @@ struct CreateAddIngredient {
|
|||
|
||||
async fn create_recipe_ingredient(
|
||||
state: State<AppState>,
|
||||
_user: AuthenticatedUser,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
Form(form): Form<CreateAddIngredient>,
|
||||
) -> Result<Markup, RouteError> {
|
||||
let ingredient = ingredient::ActiveModel {
|
||||
household: sea_orm::ActiveValue::Set(household.0.id),
|
||||
household: sea_orm::ActiveValue::Set(current.household.id),
|
||||
name: sea_orm::ActiveValue::Set(form.name),
|
||||
unit: sea_orm::ActiveValue::Set(form.unit),
|
||||
id: sea_orm::ActiveValue::NotSet,
|
||||
|
|
@ -363,9 +358,13 @@ fn create_ingredient_modal() -> Markup {
|
|||
|
||||
async fn ingredient_list(
|
||||
state: &State<AppState>,
|
||||
household: &CurrentHousehold,
|
||||
current: &CurrentHousehold,
|
||||
) -> Result<Markup, RouteError> {
|
||||
let list = household.0.find_related(Ingredient).all(&state.db).await?;
|
||||
let list = current
|
||||
.household
|
||||
.find_related(Ingredient)
|
||||
.all(&state.db)
|
||||
.await?;
|
||||
|
||||
Ok(html! {
|
||||
@for ig in list {
|
||||
|
|
@ -376,10 +375,10 @@ async fn ingredient_list(
|
|||
|
||||
async fn select_ingredient(
|
||||
state: &State<AppState>,
|
||||
household: &CurrentHousehold,
|
||||
current: &CurrentHousehold,
|
||||
extra_controls: Markup,
|
||||
) -> Result<Markup, RouteError> {
|
||||
let ingredients = ingredient_list(state, household).await?;
|
||||
let ingredients = ingredient_list(state, current).await?;
|
||||
|
||||
Ok(html! {
|
||||
.d-flex.flex-column.align-items-start {
|
||||
|
|
@ -469,8 +468,7 @@ igAdd.addEventListener("click", function(event) {
|
|||
|
||||
async fn do_create_recipe(
|
||||
state: State<AppState>,
|
||||
_user: AuthenticatedUser,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
Form(form): Form<Vec<(String, String)>>,
|
||||
) -> Result<Redirect, RouteError> {
|
||||
let mut name = None;
|
||||
|
|
@ -527,7 +525,7 @@ async fn do_create_recipe(
|
|||
person_count: extract("person_count", person_count)?,
|
||||
ranking: extract("rating", rating)?,
|
||||
steps: extract("steps", steps)?,
|
||||
household: sea_orm::ActiveValue::Set(household.0.id),
|
||||
household: sea_orm::ActiveValue::Set(current.household.id),
|
||||
}
|
||||
.insert(tx)
|
||||
.await?;
|
||||
|
|
@ -552,8 +550,7 @@ async fn do_create_recipe(
|
|||
|
||||
async fn create_recipe(
|
||||
state: State<AppState>,
|
||||
user: AuthenticatedUser,
|
||||
household: CurrentHousehold,
|
||||
current: CurrentHousehold,
|
||||
) -> Result<Markup, RouteError> {
|
||||
let create_ig = html! {
|
||||
button .btn.btn-primary
|
||||
|
|
@ -564,8 +561,7 @@ async fn create_recipe(
|
|||
|
||||
Ok(sidebar(
|
||||
SidebarLocation::RecipeCreator,
|
||||
&household,
|
||||
&user,
|
||||
¤t,
|
||||
html! {
|
||||
script { (PreEscaped(r#"
|
||||
function removeIngredient (self) {
|
||||
|
|
@ -603,7 +599,7 @@ function removeIngredient (self) {
|
|||
|
||||
.d-flex.flex-column.justify-content-start {
|
||||
h2 { "Ingredients" }
|
||||
(select_ingredient(&state, &household, create_ig).await?)
|
||||
(select_ingredient(&state, ¤t, create_ig).await?)
|
||||
ul .list-group.list-group-flush.text-start #recipeIngredients {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use maud::{html, Markup};
|
||||
|
||||
use super::{base_page, confirm_danger_modal, household::CurrentHousehold, AuthenticatedUser};
|
||||
use super::{base_page, confirm_danger_modal, household::CurrentHousehold};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub(super) enum SidebarLocation {
|
||||
|
|
@ -80,9 +80,8 @@ fn rename_hs_modal(current: &str) -> Markup {
|
|||
}
|
||||
|
||||
pub(super) fn sidebar(
|
||||
current: SidebarLocation,
|
||||
household: &CurrentHousehold,
|
||||
user: &AuthenticatedUser,
|
||||
current_page: SidebarLocation,
|
||||
current: &CurrentHousehold,
|
||||
inner: Markup,
|
||||
) -> Markup {
|
||||
let entries = &[
|
||||
|
|
@ -118,7 +117,7 @@ pub(super) fn sidebar(
|
|||
li .nav-item."w-100" {
|
||||
a href=(entry.location.to())
|
||||
class={"nav-link text-white" (
|
||||
(entry.location == current).then_some(" active").unwrap_or("")
|
||||
(entry.location == current_page).then_some(" active").unwrap_or("")
|
||||
)} {
|
||||
i class={"fs-4 " (entry.icon)} {}
|
||||
span ."ms-2".d-none.d-sm-inline { (entry.label) }
|
||||
|
|
@ -129,17 +128,17 @@ pub(super) fn sidebar(
|
|||
hr ."w-100";
|
||||
(confirm_danger_modal(
|
||||
"leaveModal",
|
||||
&format!("Are you sure you want to leave the household {}", household.0.name),
|
||||
&format!("Are you sure you want to leave the household {}", current.household.name),
|
||||
"/household/leave",
|
||||
"Leave Household",
|
||||
))
|
||||
(rename_hs_modal(&household.0.name))
|
||||
(rename_hs_modal(¤t.household.name))
|
||||
.dropdown {
|
||||
a href="#" "data-bs-toggle"="dropdown" "aria-expanded"="false"
|
||||
.d-flex.align-items-center.text-white.text-decoration-none.dropdown-toggle {
|
||||
i ."fs-4".bi-house-door-fill {}
|
||||
strong ."ms-2".d-none.d-sm-inline {
|
||||
(household.0.name) " (" (user.model.name) ")"
|
||||
(current.household.name) " (" (current.user.name) ")"
|
||||
}
|
||||
}
|
||||
ul .dropdown-menu {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue