Render edit
This commit is contained in:
parent
510376bb81
commit
a3ccefb118
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -1179,6 +1179,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"humantime",
|
"humantime",
|
||||||
"humantime-serde",
|
"humantime-serde",
|
||||||
|
"itertools 0.13.0",
|
||||||
"migration",
|
"migration",
|
||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
"redis 0.27.5",
|
"redis 0.27.5",
|
||||||
@ -2274,6 +2275,15 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
@ -37,6 +37,7 @@ serde_qs = { version = "0.13.0", features = ["actix4", "tracing"] }
|
|||||||
futures-core = "0.3.31"
|
futures-core = "0.3.31"
|
||||||
futures-util = "0.3.31"
|
futures-util = "0.3.31"
|
||||||
encoding_rs = "0.8.35"
|
encoding_rs = "0.8.35"
|
||||||
|
itertools = "0.13.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ use actix_web::HttpMessage;
|
|||||||
use actix_web::{get, post, HttpRequest, HttpResponse, Responder};
|
use actix_web::{get, post, HttpRequest, HttpResponse, Responder};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use askama_actix::TemplateToResponse;
|
use askama_actix::TemplateToResponse;
|
||||||
|
use itertools::Itertools;
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
prelude::*, DatabaseTransaction, JoinType, QueryOrder, QuerySelect, TransactionTrait,
|
prelude::*, DatabaseTransaction, JoinType, QueryOrder, QuerySelect, TransactionTrait,
|
||||||
};
|
};
|
||||||
@ -568,7 +569,7 @@ async fn save_recipe(form: RecipeForm, t: &mut DatabaseTransaction) -> Result<i3
|
|||||||
|
|
||||||
// Ingredients
|
// Ingredients
|
||||||
{
|
{
|
||||||
let ingredients = crate::utils::parse_ingenedients(&form.ingeredients)?;
|
let ingredients = crate::utils::parse_ingredients(&form.ingeredients)?;
|
||||||
let known = Ingredients::find()
|
let known = Ingredients::find()
|
||||||
.filter(
|
.filter(
|
||||||
entities::ingredients::Column::Name.is_in(
|
entities::ingredients::Column::Name.is_in(
|
||||||
@ -654,40 +655,43 @@ async fn edit_recipe(
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// steps
|
||||||
|
let recipe_steps = RecipeSteps::find()
|
||||||
|
.filter(entities::recipe_steps::Column::RecipeId.eq(id))
|
||||||
|
.all(&**db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| tracing::error!("Failed to load recipe steps for edit recipe: {e}"))
|
||||||
|
.map_err(|_| Error::DatabaseError)?;
|
||||||
|
|
||||||
|
// tags
|
||||||
let recipe_tags = RecipeTags::find()
|
let recipe_tags = RecipeTags::find()
|
||||||
.filter(entities::recipe_tags::Column::RecipeId.eq(id))
|
.filter(entities::recipe_tags::Column::RecipeId.eq(id))
|
||||||
.all(&**db)
|
.all(&**db)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
|
||||||
.inspect_err(|e| tracing::error!("Failed to load recipe tags for edit recipe: {e}"))
|
.inspect_err(|e| tracing::error!("Failed to load recipe tags for edit recipe: {e}"))
|
||||||
.map_err(|_| Error::DatabaseError)?;
|
.map_err(|_| Error::DatabaseError)?;
|
||||||
let tags = Tags::find()
|
let tags = Tags::find()
|
||||||
.join(
|
|
||||||
JoinType::InnerJoin,
|
|
||||||
entities::tags::Relation::RecipeTags.def(),
|
|
||||||
)
|
|
||||||
.filter(entities::recipe_tags::Column::RecipeId.eq(id))
|
|
||||||
.all(&**db)
|
.all(&**db)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.inspect_err(|e| tracing::error!("Failed to load tags for edit recipe: {e}"))
|
||||||
.inspect_err(|e| tracing::error!("Failed to load ingredients for edit recipe: {e}"))
|
|
||||||
.map_err(|_| Error::DatabaseError)?;
|
.map_err(|_| Error::DatabaseError)?;
|
||||||
|
|
||||||
|
// ingredients
|
||||||
let recipe_ingredients = RecipeIngredients::find()
|
let recipe_ingredients = RecipeIngredients::find()
|
||||||
.filter(entities::recipe_ingredients::Column::RecipeId.eq(id))
|
.filter(entities::recipe_ingredients::Column::RecipeId.eq(id))
|
||||||
.all(&**db)
|
.all(&**db)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.inspect_err(|e| tracing::error!("Failed to load recipe ingredients for edit recipe: {e}"))
|
||||||
.inspect_err(|e| tracing::error!("Failed to load ingredients for edit recipe: {e}"))
|
|
||||||
.map_err(|_| Error::DatabaseError)?;
|
.map_err(|_| Error::DatabaseError)?;
|
||||||
let ingredients = Ingredients::find()
|
let ingredients = Ingredients::find()
|
||||||
.join_rev(
|
.join(
|
||||||
JoinType::InnerJoin,
|
JoinType::InnerJoin,
|
||||||
entities::ingredients::Relation::RecipeIngredients.def(),
|
entities::ingredients::Relation::RecipeIngredients.def(),
|
||||||
)
|
)
|
||||||
.filter(entities::recipe_ingredients::Column::RecipeId.eq(id))
|
.filter(entities::recipe_ingredients::Column::RecipeId.eq(id))
|
||||||
.all(&**db)
|
.all(&**db)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
|
||||||
.inspect_err(|e| tracing::error!("Failed to load ingredients for edit recipe: {e}"))
|
.inspect_err(|e| tracing::error!("Failed to load ingredients for edit recipe: {e}"))
|
||||||
.map_err(|_| Error::DatabaseError)?
|
.map_err(|_| Error::DatabaseError)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -695,39 +699,59 @@ async fn edit_recipe(
|
|||||||
agg.insert(ing.id, ing);
|
agg.insert(ing.id, ing);
|
||||||
agg
|
agg
|
||||||
});
|
});
|
||||||
|
let tags_by_id = tags.iter().fold(HashMap::new(), |mut agg, tag| {
|
||||||
|
agg.insert(tag.id, tag);
|
||||||
|
agg
|
||||||
|
});
|
||||||
|
let steps = recipe_steps
|
||||||
|
.iter()
|
||||||
|
.map(|recipe| match recipe.hint {
|
||||||
|
Some(ref hint) => format!("* {body}\n> {hint}", body = recipe.body, hint = hint),
|
||||||
|
None => format!("* {body}", body = recipe.body),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
Ok(EditRecipeForm {
|
Ok(EditRecipeForm {
|
||||||
id,
|
id,
|
||||||
title: recipe.title,
|
title: recipe.title,
|
||||||
summary: recipe.summary,
|
summary: recipe.summary.unwrap_or_default(),
|
||||||
ingredients: recipe_ingredients
|
ingredients: recipe_ingredients
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|ingredient| {
|
.filter_map(|ingredient| {
|
||||||
format!(
|
Some(format!(
|
||||||
"{} {} {}",
|
"{} {} {}",
|
||||||
ingredient.qty,
|
ingredient.qty,
|
||||||
ingredient.unit,
|
ingredient.unit,
|
||||||
ingredients.get(&ingredient.id)?.name
|
ingredients.get(&ingredient.id)?.name
|
||||||
)
|
))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n"),
|
.join("\n"),
|
||||||
steps,
|
steps,
|
||||||
tags,
|
tags: recipe_tags
|
||||||
selected_tags,
|
.iter()
|
||||||
|
.filter_map(|recipe_tag| Some(tags_by_id.get(&recipe_tag.tag_id)?.name.clone()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(","),
|
||||||
|
selected_tags: recipe_tags
|
||||||
|
.iter()
|
||||||
|
.map(|rt| rt.recipe_id.to_string())
|
||||||
|
.collect(),
|
||||||
image_url: recipe.image_url,
|
image_url: recipe.image_url,
|
||||||
time: recipe.time,
|
time: recipe.time.map(|i| i.to_string()),
|
||||||
author: recipe.author,
|
author: recipe.author,
|
||||||
error: None,
|
error: None,
|
||||||
known_tags: recipe_tags.iter().map(|tag| tag.tag_id)).collect(),
|
known_tags: tags.clone(),
|
||||||
known_ingredients: recipe_ingredients.iter().map(|ing| ing.ingredient_id).collect(),
|
known_ingredients: ingredients.values().cloned().collect(),
|
||||||
session: admin.id(),
|
session: admin.id().ok(),
|
||||||
page: Page::Index,
|
page: Page::Index,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/recipe/{id}/edit")]
|
#[post("/recipe/{id}/edit")]
|
||||||
async fn update_recipe(
|
async fn update_recipe(
|
||||||
id: actix_web::web::Path<i32>,
|
_id: actix_web::web::Path<i32>,
|
||||||
admin: Identity,
|
admin: Identity,
|
||||||
db: Data<DatabaseConnection>,
|
db: Data<DatabaseConnection>,
|
||||||
form: QsForm<RecipeForm>,
|
form: QsForm<RecipeForm>,
|
||||||
|
@ -22,7 +22,7 @@ pub fn parse_steps(s: &str) -> Result<Vec<(String, Option<String>)>, Error> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_ingenedients(s: &str) -> Result<Vec<(String, Option<String>, i32)>, Error> {
|
pub fn parse_ingredients(s: &str) -> Result<Vec<(String, Option<String>, i32)>, Error> {
|
||||||
s.lines()
|
s.lines()
|
||||||
.map(|s| s.trim())
|
.map(|s| s.trim())
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user