app,server: Allow to edit recipe ingredients

This commit is contained in:
traxys 2023-06-25 17:25:42 +02:00
parent 47b547caf4
commit 6004520fb9
6 changed files with 307 additions and 35 deletions

View file

@ -1,5 +1,7 @@
use axum::{
extract::{Path, State},
async_trait,
extract::{FromRef, FromRequestParts, Path, State},
http::request::Parts,
Json,
};
@ -10,7 +12,7 @@ use api::{
use sea_orm::{prelude::*, ActiveValue};
use serde::Deserialize;
use super::{household::AuthorizedHousehold, AppState, JsonResult};
use super::{household::AuthorizedHousehold, AppState, JsonResult, RouteError};
use crate::entity::{ingredient, prelude::*};
pub(super) async fn create_ingredient(
@ -52,37 +54,57 @@ pub(super) async fn list_ingredients(
}))
}
#[derive(Deserialize)]
pub struct IngredientId {
iid: i64,
pub(super) struct IngredientExtractor(pub(super) ingredient::Model);
#[async_trait]
impl<S> FromRequestParts<S> for IngredientExtractor
where
S: Send + Sync,
AppState: FromRef<S>,
{
type Rejection = RouteError;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let State(app_state): State<AppState> = State::from_request_parts(parts, state)
.await
.expect("No state");
#[derive(Deserialize)]
pub struct IngredientId {
iid: i64,
}
let household = AuthorizedHousehold::from_request_parts(parts, state).await?;
let Path(ingredient_id): Path<IngredientId> =
Path::from_request_parts(parts, state).await?;
match household
.0
.find_related(Ingredient)
.filter(ingredient::Column::Id.eq(ingredient_id.iid))
.one(&app_state.db)
.await?
{
None => Err(RouteError::RessourceNotFound),
Some(r) => Ok(Self(r)),
}
}
}
pub(super) async fn remove_ingredient(
AuthorizedHousehold(household): AuthorizedHousehold,
State(state): State<AppState>,
Path(IngredientId { iid }): Path<IngredientId>,
IngredientExtractor(ingredient): IngredientExtractor,
) -> JsonResult<EmptyResponse> {
Ingredient::delete_by_id(iid)
.filter(ingredient::Column::Household.eq(household.id))
.exec(&state.db)
.await?;
ingredient.delete(&state.db).await?;
Ok(Json(EmptyResponse {}))
}
pub(super) async fn edit_ingredient(
AuthorizedHousehold(household): AuthorizedHousehold,
State(state): State<AppState>,
Path(IngredientId { iid }): Path<IngredientId>,
IngredientExtractor(ingredient): IngredientExtractor,
Json(request): Json<EditIngredientRequest>,
) -> JsonResult<EmptyResponse> {
let Some(ingredient) = Ingredient::find_by_id(iid)
.filter(ingredient::Column::Household.eq(household.id))
.one(&state.db)
.await? else {
return Err(super::RouteError::RessourceNotFound);
};
let mut ingredient: ingredient::ActiveModel = ingredient.into();
if let Some(name) = request.name {

View file

@ -11,7 +11,7 @@ use axum::{
HeaderValue, Method, StatusCode,
},
response::IntoResponse,
routing::{delete, get, post, put},
routing::{delete, get, patch, post, put},
Json, Router, TypedHeader,
};
use jwt_simple::prelude::*;
@ -228,4 +228,10 @@ pub(crate) fn router(api_allowed: Option<HeaderValue>) -> Router<AppState> {
.patch(recipe::edit_name)
.layer(mk_service(vec![Method::GET, Method::PATCH])),
)
.route(
"/household/:house_id/recipe/:recipe_id/ingredients/:iid",
patch(recipe::edit_ig_amount)
.delete(recipe::delete_ig)
.layer(mk_service(vec![Method::PATCH, Method::DELETE])),
)
}

View file

@ -1,6 +1,6 @@
use api::{
CreateRecipeRequest, CreateRecipeResponse, EmptyResponse, IngredientInfo, ListRecipesResponse,
RecipeInfo, RecipeRenameRequest,
RecipeInfo, RecipeIngredientEditRequest, RecipeRenameRequest,
};
use axum::{
async_trait,
@ -12,7 +12,10 @@ use sea_orm::{prelude::*, ActiveValue, TransactionTrait};
use crate::entity::{ingredient, prelude::*, recipe, recipe_ingerdients, recipe_steps};
use super::{household::AuthorizedHousehold, AppState, JsonResult, RouteError};
use super::{
household::AuthorizedHousehold, ingredients::IngredientExtractor, AppState, JsonResult,
RouteError,
};
pub(super) async fn create_recipe(
AuthorizedHousehold(household): AuthorizedHousehold,
@ -176,3 +179,32 @@ pub(super) async fn edit_name(
Ok(EmptyResponse {}.into())
}
pub(super) async fn edit_ig_amount(
State(state): State<AppState>,
RecipeExtractor(recipe): RecipeExtractor,
IngredientExtractor(ingredient): IngredientExtractor,
Json(req): Json<RecipeIngredientEditRequest>,
) -> JsonResult<EmptyResponse> {
let active_model = recipe_ingerdients::ActiveModel {
recipe_id: ActiveValue::Set(recipe.id),
ingredient_id: ActiveValue::Set(ingredient.id),
amount: ActiveValue::Set(req.amount),
};
active_model.update(&state.db).await?;
Ok(EmptyResponse {}.into())
}
pub(super) async fn delete_ig(
State(state): State<AppState>,
RecipeExtractor(recipe): RecipeExtractor,
IngredientExtractor(ingredient): IngredientExtractor,
) -> JsonResult<EmptyResponse> {
RecipeIngerdients::delete_by_id((recipe.id, ingredient.id))
.exec(&state.db)
.await?;
Ok(EmptyResponse {}.into())
}