[[package]]
name = "cc"
-version = "1.2.5"
+version = "1.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
+checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
dependencies = [
"shlex",
]
[step_id] INTEGER NOT NULL,
- [name] TEXT NOT NULL,
+ [name] TEXT NOT NULL DEFAULT '',
[comment] TEXT NOT NULL DEFAULT '',
[quantity_value] REAL,
[quantity_unit] TEXT NOT NULL DEFAULT '',
.map_err(DBError::from)
}
+ pub async fn add_recipe_step(&self, group_id: i64) -> Result<i64> {
+ let db_result = sqlx::query("INSERT INTO [Step] ([group_id]) VALUES ($1)")
+ .bind(group_id)
+ .execute(&self.pool)
+ .await?;
+ Ok(db_result.last_insert_rowid())
+ }
+
+ pub async fn rm_recipe_step(&self, step_id: i64) -> Result<()> {
+ sqlx::query("DELETE FROM [Step] WHERE [id] = $1")
+ .bind(step_id)
+ .execute(&self.pool)
+ .await
+ .map(|_| ())
+ .map_err(DBError::from)
+ }
+
pub async fn set_step_action(&self, step_id: i64, action: &str) -> Result<()> {
sqlx::query("UPDATE [Step] SET [action] = $2 WHERE [id] = $1")
.bind(step_id)
.map_err(DBError::from)
}
+ pub async fn add_recipe_ingredient(&self, step_id: i64) -> Result<i64> {
+ let db_result = sqlx::query("INSERT INTO [Ingredient] ([step_id]) VALUES ($1)")
+ .bind(step_id)
+ .execute(&self.pool)
+ .await?;
+ Ok(db_result.last_insert_rowid())
+ }
+
+ pub async fn rm_recipe_ingredient(&self, ingredient_id: i64) -> Result<()> {
+ sqlx::query("DELETE FROM [Ingredient] WHERE [id] = $1")
+ .bind(ingredient_id)
+ .execute(&self.pool)
+ .await
+ .map(|_| ())
+ .map_err(DBError::from)
+ }
+
pub async fn set_ingredient_name(&self, ingredient_id: i64, name: &str) -> Result<()> {
sqlx::query("UPDATE [Ingredient] SET [name] = $2 WHERE [id] = $1")
.bind(ingredient_id)
pub id: i64,
pub name: String,
pub comment: String,
- pub quantity_value: f64,
+ pub quantity_value: Option<f64>,
pub quantity_unit: String,
}
"/recipe/set_group_comment",
put(services::ron::set_group_comment),
)
+ .route("/recipe/add_step", post(services::ron::add_step))
+ .route("/recipe/remove_step", delete(services::ron::rm_step))
.route(
"/recipe/set_step_action",
put(services::ron::set_step_action),
)
+ .route(
+ "/recipe/add_ingredient",
+ post(services::ron::add_ingredient),
+ )
+ .route(
+ "/recipe/remove_ingredient",
+ delete(services::ron::rm_ingredient),
+ )
.route(
"/recipe/set_ingredient_name",
put(services::ron::set_ingredient_name),
Ok(StatusCode::OK)
}
+#[debug_handler]
+pub async fn add_step(
+ State(connection): State<db::Connection>,
+ Extension(user): Extension<Option<model::User>>,
+ ExtractRon(ron): ExtractRon<common::ron_api::AddRecipeStep>,
+) -> Result<impl IntoResponse> {
+ check_user_rights_recipe_group(&connection, &user, ron.group_id).await?;
+ let step_id = connection.add_recipe_step(ron.group_id).await?;
+
+ Ok(ron_response(
+ StatusCode::OK,
+ common::ron_api::AddRecipeStepResult { step_id },
+ ))
+}
+
+#[debug_handler]
+pub async fn rm_step(
+ State(connection): State<db::Connection>,
+ Extension(user): Extension<Option<model::User>>,
+ ExtractRon(ron): ExtractRon<common::ron_api::RemoveRecipeStep>,
+) -> Result<impl IntoResponse> {
+ check_user_rights_recipe_step(&connection, &user, ron.step_id).await?;
+ connection.rm_recipe_step(ron.step_id).await?;
+ Ok(StatusCode::OK)
+}
+
#[debug_handler]
pub async fn set_step_action(
State(connection): State<db::Connection>,
Ok(StatusCode::OK)
}
+#[debug_handler]
+pub async fn add_ingredient(
+ State(connection): State<db::Connection>,
+ Extension(user): Extension<Option<model::User>>,
+ ExtractRon(ron): ExtractRon<common::ron_api::AddRecipeIngredient>,
+) -> Result<impl IntoResponse> {
+ check_user_rights_recipe_step(&connection, &user, ron.step_id).await?;
+ let ingredient_id = connection.add_recipe_ingredient(ron.step_id).await?;
+
+ Ok(ron_response(
+ StatusCode::OK,
+ common::ron_api::AddRecipeIngredientResult { ingredient_id },
+ ))
+}
+
+#[debug_handler]
+pub async fn rm_ingredient(
+ State(connection): State<db::Connection>,
+ Extension(user): Extension<Option<model::User>>,
+ ExtractRon(ron): ExtractRon<common::ron_api::RemoveRecipeIngredient>,
+) -> Result<impl IntoResponse> {
+ check_user_rights_recipe_ingredient(&connection, &user, ron.ingredient_id).await?;
+ connection.rm_recipe_ingredient(ron.ingredient_id).await?;
+ Ok(StatusCode::OK)
+}
+
#[debug_handler]
pub async fn set_ingredient_name(
State(connection): State<db::Connection>,
<div id="groups-container">
</div>
- <input id="button-add-group" type="button" value="Add a group" />
+ <input id="input-add-group" type="button" value="Add a group" />
<div id="hidden-templates">
<div class="group">
<div class="steps"></div>
- <input class="button-add-step" type="button" value="Add a step" />
+ <input class="input-add-step" type="button" value="Add a step" />
</div>
<div class="step">
<div class="ingredients"></div>
- <input class="button-add-ingedient" type="button" value="Add an ingredient"/>
+ <input class="input-add-ingredient" type="button" value="Add an ingredient"/>
</div>
<div class="ingredient">
pub comment: String,
}
+#[derive(Serialize, Deserialize, Clone)]
+pub struct AddRecipeStep {
+ pub group_id: i64,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct AddRecipeStepResult {
+ pub step_id: i64,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct RemoveRecipeStep {
+ pub step_id: i64,
+}
+
#[derive(Serialize, Deserialize, Clone)]
pub struct SetStepAction {
pub step_id: i64,
pub action: String,
}
+#[derive(Serialize, Deserialize, Clone)]
+pub struct AddRecipeIngredient {
+ pub step_id: i64,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct AddRecipeIngredientResult {
+ pub ingredient_id: i64,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct RemoveRecipeIngredient {
+ pub ingredient_id: i64,
+}
+
#[derive(Serialize, Deserialize, Clone)]
pub struct SetIngredientName {
pub ingredient_id: i64,
pub id: i64,
pub name: String,
pub comment: String,
- pub quantity_value: f64,
+ pub quantity_value: Option<f64>,
pub quantity_unit: String,
}
})
.forget();
+ // Add step button.
+ let add_step_button: HtmlInputElement = group_element.select(".input-add-step");
+ EventListener::new(&add_step_button, "click", move |_event| {
+ spawn_local(async move {
+ let body = ron_api::AddRecipeStep { group_id };
+ let response: ron_api::AddRecipeStepResult =
+ request::post("recipe/add_step", body).await.unwrap();
+ create_step_element(
+ &by_id::<Element>(&format!("group-{}", group_id)),
+ &ron_api::Step {
+ id: response.step_id,
+ action: "".to_string(),
+ ingredients: vec![],
+ },
+ );
+ });
+ })
+ .forget();
+
group_element
}
})
.forget();
+ // Add ingredient button.
+ let add_ingredient_button: HtmlInputElement = step_element.select(".input-add-ingredient");
+ EventListener::new(&add_ingredient_button, "click", move |_event| {
+ spawn_local(async move {
+ let body = ron_api::AddRecipeIngredient { step_id };
+ let response: ron_api::AddRecipeIngredientResult =
+ request::post("recipe/add_ingredient", body).await.unwrap();
+ create_ingredient_element(
+ &by_id::<Element>(&format!("step-{}", step_id)),
+ &ron_api::Ingredient {
+ id: response.ingredient_id,
+ name: "".to_string(),
+ comment: "".to_string(),
+ quantity_value: None,
+ quantity_unit: "".to_string(),
+ },
+ );
+ });
+ })
+ .forget();
+
step_element
}
let ingredient_id = ingredient.id;
let ingredient_element: Element = select_and_clone("#hidden-templates .ingredient");
ingredient_element
- .set_attribute("id", &format!("step-{}", ingredient.id))
+ .set_attribute("id", &format!("ingredient-{}", ingredient.id))
.unwrap();
step_element.append_child(&ingredient_element).unwrap();
// Ingredient quantity.
let quantity: HtmlInputElement = ingredient_element.select(".input-ingredient-quantity");
- quantity.set_value(&ingredient.quantity_value.to_string());
- let mut current_quantity = ingredient.quantity_value;
+ quantity.set_value(
+ &ingredient
+ .quantity_value
+ .map_or("".to_string(), |q| q.to_string()),
+ );
+ let mut current_quantity = quantity.value_as_number();
EventListener::new(&quantity.clone(), "blur", move |_event| {
let n = quantity.value_as_number();
if n.is_nan() {
// Add a new group.
{
- let button_add_group = document().get_element_by_id("button-add-group").unwrap();
+ let button_add_group: HtmlInputElement = by_id("input-add-group");
let on_click_add_group = EventListener::new(&button_add_group, "click", move |_event| {
- log!("Click!");
let body = ron_api::AddRecipeGroup { recipe_id };
-
spawn_local(async move {
let response: ron_api::AddRecipeGroupResult =
request::post("recipe/add_group", body).await.unwrap();
comment: "".to_string(),
steps: vec![],
});
- // group_html.set_attribute("id", "test").unwrap();
});
});
on_click_add_group.forget();