Collect ingredients from recipes for grocery list

This commit is contained in:
Matteo Settenvini 2022-07-30 17:33:29 +02:00
parent c649fbf88c
commit ed5a6d2306
Signed by: matteo
GPG key ID: 8576CC1AD97D42DF
7 changed files with 168 additions and 239 deletions

View file

@ -3,16 +3,17 @@
use {
crate::api_client::ApiClient,
crate::constants,
crate::recipe::{Ingredient, Recipe},
anyhow::{anyhow, Result},
chrono::{Duration, Local, NaiveDateTime},
anyhow::Result,
chrono::{Duration, Local},
icalendar::Component,
regex::Regex,
std::collections::HashSet,
std::ops::Range,
};
pub async fn with(api_client: &ApiClient, calendar_name: &str, days: u32) -> Result<()> {
let ids = map_events_to_recipe_ids(api_client, calendar_name, days)?;
let ids = map_events_to_recipe_ids(api_client, calendar_name, days).await?;
let ingredients = get_ingredients(api_client, ids).await?;
todo!("Recipe ingredients: {:?}", ingredients)
@ -22,57 +23,25 @@ pub async fn with(api_client: &ApiClient, calendar_name: &str, days: u32) -> Res
// save_grocery_list(api_client, "", md).await?;
}
fn map_events_to_recipe_ids(
async fn map_events_to_recipe_ids(
api_client: &ApiClient,
calendar_name: &str,
days: u32,
) -> Result<HashSet<usize>> {
// minicaldav is quite hamfisted in retrieving events (it gets everything, every time).
// Consider crafting an XML request and use something else for ical parsing.
let date_range = Range {
start: Local::now(),
end: Local::now() + Duration::days(days as i64),
};
let calendars = api_client
.get_calendars()
.map_err(|err| convert_caldav_err(err))?;
let calendar = calendars
.into_iter()
.filter(|c| c.name() == calendar_name)
.next()
.ok_or(anyhow!(
"Unable to find calendar '{}' on server",
calendar_name
))?;
let all_events = api_client
.get_events(&calendar)
.map_err(|err| convert_caldav_err(err))?
.0;
let relevant_events = all_events.into_iter().filter(|ev| {
ev.get("PRODID")
.map(|p| p == constants::CALENDAR_PROVIDER)
.unwrap_or(false)
&& {
let start_time = NaiveDateTime::parse_from_str(
ev.property("DTSTART").unwrap().value(),
"%Y%m%dT%H%M%S",
)
.unwrap_or(NaiveDateTime::from_timestamp(0, 0));
let now = Local::now().naive_local();
start_time >= now && start_time < now + Duration::days(days as i64)
}
});
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_ids = relevant_events
.flat_map(|event| {
event
.property("DESCRIPTION")
.iter()
.flat_map(|descr| recipe_id_regex.captures(descr.value()))
.flat_map(|c| c.get(1))
.flat_map(|m| m.as_str().parse::<usize>())
.collect::<Vec<usize>>()
})
let recipe_ids = all_events
.iter()
.flat_map(|event| event.property_value("DESCRIPTION"))
.flat_map(|descr| recipe_id_regex.captures(descr))
.flat_map(|c| c.get(1))
.flat_map(|m| m.as_str().parse::<usize>())
.collect::<HashSet<_>>();
Ok(recipe_ids)
@ -101,7 +70,3 @@ where
let ingredients = futures::future::try_join_all(ingredients).await?;
Ok(ingredients.into_iter().flatten().collect())
}
fn convert_caldav_err(err: minicaldav::Error) -> anyhow::Error {
anyhow!(format!("{:?}", err))
}