Grocery list: Fix filtering of recipes
This commit is contained in:
parent
5e796365f1
commit
e69d8fc24c
|
@ -18,7 +18,7 @@
|
||||||
"kind": "bin"
|
"kind": "bin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"args": ["groceries", "Cucina"],
|
"args": ["groceries", "Cucina", "Note/Spesa/Groceries.md"],
|
||||||
"env": {
|
"env": {
|
||||||
"RUST_LOG": "debug",
|
"RUST_LOG": "debug",
|
||||||
},
|
},
|
||||||
|
|
|
@ -217,7 +217,7 @@
|
||||||
"2022-08-04","giovedì",,"https://ricette.giallozafferano.it/Petto-di-pollo-ai-peperoni.html"
|
"2022-08-04","giovedì",,"https://ricette.giallozafferano.it/Petto-di-pollo-ai-peperoni.html"
|
||||||
"2022-08-05","venerdì",,
|
"2022-08-05","venerdì",,
|
||||||
"2022-08-06","sabato","https://ricette.giallozafferano.it/Spaghetti-di-riso-con-carne-e-verdure.html","https://ricette.giallozafferano.it/Pasta-con-pomodorini-e-stracchino.html"
|
"2022-08-06","sabato","https://ricette.giallozafferano.it/Spaghetti-di-riso-con-carne-e-verdure.html","https://ricette.giallozafferano.it/Pasta-con-pomodorini-e-stracchino.html"
|
||||||
"2022-08-07","domenica",,"https://ricette.giallozafferano.it/Insalata-di-riso-vegetariana.html"
|
"2022-08-07","domenica","https://ricette.giallozafferano.it/Insalata-di-riso-vegetariana.html",
|
||||||
"2022-08-08","lunedì",,"https://ricette.giallozafferano.it/Torta-salata-di-melanzane.html"
|
"2022-08-08","lunedì",,"https://ricette.giallozafferano.it/Torta-salata-di-melanzane.html"
|
||||||
"2022-08-09","martedì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
"2022-08-09","martedì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||||
"2022-08-10","mercoledì",,"https://ricette.giallozafferano.it/Insalata-con-uova-strapazzate.html"
|
"2022-08-10","mercoledì",,"https://ricette.giallozafferano.it/Insalata-con-uova-strapazzate.html"
|
||||||
|
|
|
|
@ -108,6 +108,18 @@ impl ApiClient {
|
||||||
Tz::Offset: std::fmt::Display,
|
Tz::Offset: std::fmt::Display,
|
||||||
{
|
{
|
||||||
let report_method = reqwest::Method::from_bytes(b"REPORT").unwrap();
|
let report_method = reqwest::Method::from_bytes(b"REPORT").unwrap();
|
||||||
|
|
||||||
|
let start = date_range
|
||||||
|
.start
|
||||||
|
.naive_utc()
|
||||||
|
.format(constants::ICAL_UTCTIME_FMT)
|
||||||
|
.to_string();
|
||||||
|
let end = date_range
|
||||||
|
.end
|
||||||
|
.naive_utc()
|
||||||
|
.format(constants::ICAL_UTCTIME_FMT)
|
||||||
|
.to_string();
|
||||||
|
|
||||||
let events_xml = self
|
let events_xml = self
|
||||||
.rest(|client| async {
|
.rest(|client| async {
|
||||||
let response = client
|
let response = client
|
||||||
|
@ -121,37 +133,29 @@ impl ApiClient {
|
||||||
.header("Prefer", "return-minimal")
|
.header("Prefer", "return-minimal")
|
||||||
.header("Content-Type", "application/xml; charset=utf-8")
|
.header("Content-Type", "application/xml; charset=utf-8")
|
||||||
.header("Depth", 1)
|
.header("Depth", 1)
|
||||||
.body(format!(
|
.body(format!("<?xml version=\"1.0\" encoding=\"utf-8\" ?>
|
||||||
"<c:calendar-query xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">
|
<c:calendar-query xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">
|
||||||
<d:prop>
|
<d:prop>
|
||||||
<c:calendar-data />
|
<c:calendar-data />
|
||||||
</d:prop>
|
</d:prop>
|
||||||
<c:filter>
|
<c:filter>
|
||||||
<c:comp-filter name=\"VCALENDAR\">
|
<c:comp-filter name=\"VCALENDAR\">
|
||||||
<c:prop-filter name=\"PRODID\">
|
<c:prop-filter name=\"PRODID\">
|
||||||
<c:text-match>{}</c:text-match>
|
<c:text-match>{}</c:text-match>
|
||||||
</c:prop-filter>
|
</c:prop-filter>
|
||||||
<c:comp-filter name=\"VEVENT\">
|
<c:comp-filter name=\"VEVENT\">
|
||||||
<c:prop-filter name=\"DTSTART\">
|
<c:prop-filter name=\"DTSTART\">
|
||||||
<time-range start=\"{}\" end=\"{}\" />
|
<c:time-range start=\"{}\" end=\"{}\" />
|
||||||
</c:prop-filter>
|
</c:prop-filter>
|
||||||
</c:comp-filter>
|
</c:comp-filter>
|
||||||
</c:comp-filter>
|
</c:comp-filter>
|
||||||
</c:filter>
|
</c:filter>
|
||||||
</c:calendar-query>
|
</c:calendar-query>
|
||||||
",
|
",
|
||||||
constants::CALENDAR_PROVIDER,
|
constants::CALENDAR_PROVIDER,
|
||||||
date_range
|
start,
|
||||||
.start
|
end
|
||||||
.naive_utc()
|
))
|
||||||
.format(constants::ICAL_UTCTIME_FMT)
|
|
||||||
.to_string(),
|
|
||||||
date_range
|
|
||||||
.end
|
|
||||||
.naive_utc()
|
|
||||||
.format(constants::ICAL_UTCTIME_FMT)
|
|
||||||
.to_string()
|
|
||||||
))
|
|
||||||
.send()
|
.send()
|
||||||
.await;
|
.await;
|
||||||
Ok(response?)
|
Ok(response?)
|
||||||
|
|
|
@ -40,7 +40,7 @@ async fn map_events_to_recipe_ids(
|
||||||
|
|
||||||
let all_events = api_client.get_events(calendar_name, date_range).await?;
|
let all_events = api_client.get_events(calendar_name, date_range).await?;
|
||||||
|
|
||||||
let recipe_id_regex: Regex = Regex::new(r"cookbook@(\d+)").unwrap();
|
let recipe_id_regex: Regex = Regex::new(r"^cookbook@(\d+)$").unwrap();
|
||||||
let recipe_ids = all_events
|
let recipe_ids = all_events
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|event| event.property_value("DESCRIPTION"))
|
.flat_map(|event| event.property_value("DESCRIPTION"))
|
||||||
|
@ -55,7 +55,7 @@ async fn map_events_to_recipe_ids(
|
||||||
async fn get_ingredients<RecipeIds>(
|
async fn get_ingredients<RecipeIds>(
|
||||||
api_client: &ApiClient,
|
api_client: &ApiClient,
|
||||||
recipe_ids: RecipeIds,
|
recipe_ids: RecipeIds,
|
||||||
) -> Result<Vec<Ingredient>>
|
) -> Result<Vec<(Ingredient, String)>>
|
||||||
where
|
where
|
||||||
RecipeIds: IntoIterator<Item = usize>,
|
RecipeIds: IntoIterator<Item = usize>,
|
||||||
{
|
{
|
||||||
|
@ -74,7 +74,10 @@ where
|
||||||
|
|
||||||
response.json::<Recipe>().await.map(|r| {
|
response.json::<Recipe>().await.map(|r| {
|
||||||
log::info!("Retrieved ingredients for '{}'", r.name);
|
log::info!("Retrieved ingredients for '{}'", r.name);
|
||||||
|
let recipe_name = r.name.clone();
|
||||||
r.ingredients
|
r.ingredients
|
||||||
|
.into_iter()
|
||||||
|
.map(move |i| (i, recipe_name.clone()))
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -82,7 +85,7 @@ where
|
||||||
Ok(ingredients.into_iter().flatten().collect())
|
Ok(ingredients.into_iter().flatten().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_ingredients(mut ingredients: Vec<Ingredient>) -> Vec<Ingredient> {
|
fn merge_ingredients(mut ingredients: Vec<(Ingredient, String)>) -> Vec<(Ingredient, String)> {
|
||||||
ingredients.sort();
|
ingredients.sort();
|
||||||
|
|
||||||
// TODO actual merging
|
// TODO actual merging
|
||||||
|
@ -90,7 +93,7 @@ fn merge_ingredients(mut ingredients: Vec<Ingredient>) -> Vec<Ingredient> {
|
||||||
ingredients
|
ingredients
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_grocery_list(ingredients: &Vec<Ingredient>) -> Result<String> {
|
fn prepare_grocery_list(ingredients: &Vec<(Ingredient, String)>) -> Result<String> {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
@ -101,8 +104,8 @@ fn prepare_grocery_list(ingredients: &Vec<Ingredient>) -> Result<String> {
|
||||||
)?;
|
)?;
|
||||||
writeln!(out)?; // leave an empty line
|
writeln!(out)?; // leave an empty line
|
||||||
for ingredient in ingredients {
|
for ingredient in ingredients {
|
||||||
let ingredient = ingredient.0.as_str();
|
let ingredient_s = ingredient.0 .0.as_str();
|
||||||
writeln!(out, "- [ ] {}", ingredient)?;
|
writeln!(out, "- [ ] {} ({})", ingredient_s, ingredient.1)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
|
|
Loading…
Reference in New Issue