Add parse recipe parts

This commit is contained in:
eraden 2024-10-31 05:33:51 +01:00
parent afc77b5c3d
commit a3a8e32f14
6 changed files with 155 additions and 8 deletions

44
Cargo.lock generated
View File

@ -1133,6 +1133,7 @@ dependencies = [
"humantime",
"humantime-serde",
"migration",
"pulldown-cmark",
"redis 0.27.5",
"rswind",
"rswind_cli",
@ -1141,6 +1142,7 @@ dependencies = [
"serde_json",
"tantivy",
"tempfile",
"thiserror",
"tracing",
"tracing-subscriber",
"tracing-test",
@ -1811,6 +1813,15 @@ dependencies = [
"version_check",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.2.15"
@ -3207,6 +3218,25 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "pulldown-cmark"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
dependencies = [
"bitflags 2.6.0",
"getopts",
"memchr",
"pulldown-cmark-escape",
"unicase",
]
[[package]]
name = "pulldown-cmark-escape"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
[[package]]
name = "quote"
version = "1.0.37"
@ -4699,18 +4729,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.64"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.64"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
dependencies = [
"proc-macro2",
"quote",
@ -5022,6 +5052,12 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-xid"
version = "0.2.6"

View File

@ -27,6 +27,8 @@ actix-session = { version = "0.10.1", features = ["redis-session-rustls"] }
actix-identity = "0.8.0"
tantivy = "0.22.0"
tempfile = "3.13.0"
pulldown-cmark = "0.12.2"
thiserror = "1.0.65"
[build-dependencies]

View File

@ -1,3 +1,5 @@
#![feature(iterator_try_collect)]
use actix::SyncArbiter;
use actix_files::Files;
use actix_identity::IdentityMiddleware;
@ -13,6 +15,7 @@ pub mod entities;
pub mod filters;
pub mod routes;
pub mod types;
pub mod utils;
const SESSION_KEY: &'static str = "session";

View File

@ -54,7 +54,7 @@ struct SignInForm {
page: Page,
}
#[derive(Debug, Template)]
#[derive(Debug, Template, Deserialize, Clone)]
#[template(path = "recipies/create_form.jinja", ext = "html")]
struct RecipeForm {
title: String,
@ -293,6 +293,33 @@ async fn recipe_form(admin: Identity) -> RecipeForm {
}
}
#[post("/create")]
async fn create_recipe(
admin: Identity,
form: Form<RecipeForm>,
db: Data<DatabaseConnection>,
) -> RecipeForm {
let form = form.into_inner();
let mut failure = form.clone();
let title = form.title;
let mut summary = String::new();
let parser = pulldown_cmark::Parser::new(&form.summary);
pulldown_cmark::html::push_html(&mut summary, parser);
let Ok(steps) = crate::utils::parse_steps(&form.steps, 0) else {
failure.error = Some("Invalid steps list".into());
return failure;
};
let Ok(ingeredients) = crate::utils::parse_steps(&form.ingeredients, 0) else {
failure.error = Some("Invalid ingeredients list".into());
return failure;
};
failure
}
#[get("/styles.css")]
async fn styles_css() -> HttpResponse {
HttpResponse::Ok()
@ -309,5 +336,6 @@ pub fn configure(config: &mut actix_web::web::ServiceConfig) {
.service(show)
.service(search_page)
.service(search_results)
.service(recipe_form);
.service(recipe_form)
.service(create_recipe);
}

View File

@ -1,8 +1,18 @@
use std::str::FromStr;
use serde::Deserialize;
pub type User = String;
#[derive(Debug, PartialEq, Clone, Copy)]
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Invalid step list")]
InvalidStepList,
#[error("Invalid ingeredients list")]
InvalidIngeredientList,
}
#[derive(Debug, PartialEq, Clone, Copy, Deserialize)]
pub enum Page {
Index,
Recipe,
@ -10,7 +20,7 @@ pub enum Page {
SignIn,
}
#[derive(Debug)]
#[derive(Debug, Deserialize)]
pub struct Admin {
pub email: String,
pub pass: String,

68
src/utils.rs Normal file
View File

@ -0,0 +1,68 @@
use crate::entities::recipe_ingeredients::ActiveModel as RIAM;
use crate::entities::recipe_steps::ActiveModel as RSAM;
use crate::types::Error::*;
use sea_orm::prelude::*;
use sea_orm::ActivrValue::*;
pub fn parse_steps(s: &str, recipe_id: u64) -> Result<Vec<RSAM>, InvalidStepList> {
s.lines()
.filter(|s| !s.trim().is_empty())
.try_fold(Vec::new(), |mut v, line| {
let line = line.trim();
match line.chars().next() {
Some('*') => {
let line = line.replacen("*", "", 1).trim();
v.push(RSAM {
body: Set(line.to_string()),
recipe_id: Set(recipe_id),
..Default::default()
});
}
Some('>') => {
let line = line.replacen(">", "", 1).trim();
v.last_mut().ok_or(InvalidStepList)?.hint = Set(line.to_string());
}
_ => return Err(InvalidStepList),
};
Ok(v)
})
}
pub fn parse_ingenedients(s: &str, recipe_id: u64) -> Result<Vec<RIAM>, InvalidIngeredientList> {
s.lines()
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.map(|s| {
let mut pieces = s
.split_whitespace()
.filter(|s| !s.is_empty())
.collect::<Vec<_>>();
match pieces.len() {
0 | 1 => return Err(InvalidIngeredientList),
// no unit
2 => {
let qty = pieces.remove(0).parse().map_err(|_| InvalidIngeredientList);
Ok(RIAM {
recipe_id: Set(recipe_id),
name: Set(pieces.join(" ")),
qty: Set(qty),
..Default::default()
})
}
_ => {
let qty = pieces.remove(0).parse().map_err(|_| InvalidIngeredientList);
let unit = pieces.remove(0);
Ok(RIAM {
recipe_id: Set(recipe_id),
name: Set(pieces.join(" ")),
unit: Set(unit),
qty: Set(qty),
..Default::default()
})
}
}
})
.try_collect()
}