server: Add a route to add a recipe
This commit is contained in:
parent
82b466f52c
commit
e49a5829c4
3 changed files with 83 additions and 0 deletions
|
|
@ -83,3 +83,16 @@ pub struct EditIngredientRequest {
|
|||
#[serde(default)]
|
||||
pub has_unit: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct CreateRecipeRequest {
|
||||
pub name: String,
|
||||
pub rating: u8,
|
||||
pub ingredients: Vec<(i64, f64)>,
|
||||
pub steps: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct CreateRecipeResponse {
|
||||
pub id: i64,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use crate::entity::{prelude::*, user};
|
|||
|
||||
mod household;
|
||||
mod ingredients;
|
||||
mod recipe;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
enum RouteError {
|
||||
|
|
@ -42,6 +43,8 @@ enum RouteError {
|
|||
PathRejection(#[from] axum::extract::rejection::PathRejection),
|
||||
#[error("The supplied ressource does not exist")]
|
||||
RessourceNotFound,
|
||||
#[error("The request was malformed")]
|
||||
InvalidRequest(String),
|
||||
#[error("Error in DB transaction")]
|
||||
TxnError(#[from] TransactionError<Box<RouteError>>),
|
||||
}
|
||||
|
|
@ -73,6 +76,7 @@ impl IntoResponse for RouteError {
|
|||
)
|
||||
.into_response(),
|
||||
RouteError::RessourceNotFound => StatusCode::NOT_FOUND.into_response(),
|
||||
RouteError::InvalidRequest(reason) => (StatusCode::BAD_REQUEST, reason).into_response(),
|
||||
e => {
|
||||
tracing::error!("Internal error: {e:?}");
|
||||
StatusCode::INTERNAL_SERVER_ERROR.into_response()
|
||||
|
|
@ -212,4 +216,8 @@ pub(crate) fn router(api_allowed: Option<HeaderValue>) -> Router<AppState> {
|
|||
.get(ingredients::list_ingredients)
|
||||
.layer(mk_service(vec![Method::GET, Method::POST])),
|
||||
)
|
||||
.route(
|
||||
"/household/:house_id/recipe",
|
||||
post(recipe::create_recipe).layer(mk_service(vec![Method::POST])),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
62
src/routes/recipe.rs
Normal file
62
src/routes/recipe.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use api::{CreateRecipeRequest, CreateRecipeResponse};
|
||||
use axum::{extract::State, Json};
|
||||
use sea_orm::{prelude::*, ActiveValue, TransactionTrait};
|
||||
|
||||
use crate::entity::{ingredient, prelude::*, recipe, recipe_ingerdients, recipe_steps};
|
||||
|
||||
use super::{household::AuthorizedHousehold, AppState, JsonResult, RouteError};
|
||||
|
||||
pub(super) async fn create_recipe(
|
||||
AuthorizedHousehold(household): AuthorizedHousehold,
|
||||
State(state): State<AppState>,
|
||||
Json(request): Json<CreateRecipeRequest>,
|
||||
) -> JsonResult<CreateRecipeResponse> {
|
||||
let id = state
|
||||
.db
|
||||
.transaction(|txn| {
|
||||
Box::pin(async move {
|
||||
let model = recipe::ActiveModel {
|
||||
name: ActiveValue::Set(request.name),
|
||||
ranking: ActiveValue::Set(request.rating as i32),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let recipe = model.insert(txn).await?;
|
||||
for (num, text) in request.steps.into_iter().enumerate() {
|
||||
let model = recipe_steps::ActiveModel {
|
||||
num: ActiveValue::Set(num as _),
|
||||
recipe_id: ActiveValue::Set(recipe.id),
|
||||
text: ActiveValue::Set(text),
|
||||
};
|
||||
|
||||
model.insert(txn).await?;
|
||||
}
|
||||
|
||||
for (ig, amount) in request.ingredients {
|
||||
if 0 == household
|
||||
.find_related(Ingredient)
|
||||
.filter(ingredient::Column::Id.eq(ig))
|
||||
.count(txn)
|
||||
.await?
|
||||
{
|
||||
Err(RouteError::InvalidRequest(format!(
|
||||
"No such ingredient {ig}"
|
||||
)))?;
|
||||
}
|
||||
|
||||
let model = recipe_ingerdients::ActiveModel {
|
||||
recipe_id: ActiveValue::Set(recipe.id),
|
||||
ingredient_id: ActiveValue::Set(ig),
|
||||
amount: ActiveValue::Set(amount),
|
||||
};
|
||||
|
||||
model.insert(txn).await?;
|
||||
}
|
||||
|
||||
Ok(recipe.id)
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(CreateRecipeResponse { id }.into())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue