diff --git a/api/src/main.rs b/api/src/main.rs index 64581b8..93708be 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -45,7 +45,7 @@ async fn main() { .nest("/events", events::router()) .nest("/ingredients", ingredients::router()) .nest("/places", places::router()) - .nest("/reciepes", reciepes::router()) + .nest("/recipes", reciepes::router()) .nest("/calc", mealcalc::router()) .with_state(ApiState { food_base }) .layer(TraceLayer::new_for_http()) diff --git a/api/src/reciepes.rs b/api/src/reciepes.rs index 2c48e1f..0945016 100644 --- a/api/src/reciepes.rs +++ b/api/src/reciepes.rs @@ -1,15 +1,20 @@ use axum::{ + extract::{Path, State}, http::StatusCode, response::IntoResponse, routing::{delete, get, post, put}, - Router, + Json, Router, }; +use foodlib::Recipe; +use serde::{Deserialize, Serialize}; + +use crate::ApiState; pub fn router() -> Router { Router::new() .route("/", get(list_reciepes)) .route("/", put(add_reciepe)) - .route("/:recipe_id/", get(calc_reciepe)) + .route("/:recipe_id/", get(get_recipe)) .route("/:recipe_id/", post(update_reciepe)) .route("/:recipe_id/", delete(update_reciepe)) .route("/:recipe_id/steps/", get(update_reciepe)) @@ -18,12 +23,69 @@ pub fn router() -> Router { .route("/:recipe_id/ingredients/", post(calc_reciepe)) } -async fn list_reciepes() -> impl IntoResponse { - StatusCode::NOT_IMPLEMENTED +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +struct RecipeBody { + id: Option, + name: String, + comment: Option, } -async fn add_reciepe() -> impl IntoResponse { - StatusCode::NOT_IMPLEMENTED +fn recipe_to_body(recipe: Recipe) -> RecipeBody { + RecipeBody { + id: Some(recipe.recipe_id), + name: recipe.name, + comment: recipe.comment, + } +} + +async fn list_reciepes(State(state): State) -> impl IntoResponse { + match state.food_base.get_recipes().await { + Ok(recipes) => ( + StatusCode::OK, + Json(recipes.into_iter().map(recipe_to_body).collect::>()), + ) + .into_response(), + Err(_) => (StatusCode::INTERNAL_SERVER_ERROR).into_response(), + } +} + +async fn add_reciepe( + State(state): State, + Json(body): Json, +) -> impl IntoResponse { + match state.food_base.add_recipe(&body.name, &body.comment).await { + Ok(recipe) => (StatusCode::OK, Json(recipe_to_body(recipe))).into_response(), + Err(_) => (StatusCode::INTERNAL_SERVER_ERROR).into_response(), + } +} + +async fn get_recipe( + State(state): State, + Path(recipe_id): Path, +) -> impl IntoResponse { + match state.food_base.get_recipe(recipe_id).await { + Ok(recipe) => (StatusCode::OK, Json(recipe_to_body(recipe))).into_response(), + Err(_) => StatusCode::NOT_FOUND.into_response(), + } +} + +async fn update_recipe( + State(state): State, + Path(recipe_id): Path, + Json(body): Json, +) -> impl IntoResponse { + match state + .food_base + .update_recipe(&Recipe { + recipe_id, + name: body.name, + comment: body.comment, + }) + .await + { + Ok(recipe) => (StatusCode::OK, Json(recipe_to_body(recipe))).into_response(), + Err(_) => StatusCode::NOT_FOUND.into_response(), + } } async fn calc_reciepe() -> impl IntoResponse { diff --git a/foodlib/src/recipes.rs b/foodlib/src/recipes.rs index 1d735f5..0969912 100644 --- a/foodlib/src/recipes.rs +++ b/foodlib/src/recipes.rs @@ -491,7 +491,11 @@ impl FoodBase { Ok(recipe) } - pub async fn insert_recipe(&self, recipe: &Recipe) -> eyre::Result { + pub async fn add_recipe( + &self, + name: &String, + comment: &Option, + ) -> eyre::Result { let recipe = sqlx::query_as!( Recipe, r#" @@ -499,14 +503,18 @@ impl FoodBase { VALUES ($1, $2) RETURNING * "#, - recipe.name, - recipe.comment, + name.clone(), + comment.clone(), ) .fetch_one(&*self.pg_pool) .await?; Ok(recipe) } + pub async fn insert_recipe(&self, recipe: &Recipe) -> eyre::Result { + self.add_recipe(&recipe.name, &recipe.comment).await + } + // TODO: Human race condition, add proper locking / edit notifications pub async fn update_recipe_entries( &self,