Cover use case of manually inserted recipes; allow recipe names instead of URLs in CSV
This commit is contained in:
parent
fe363c0e26
commit
7495682e41
|
@ -128,7 +128,7 @@
|
||||||
"2022-05-07","sabato",,"https://ricette.giallozafferano.it/Moussaka.html"
|
"2022-05-07","sabato",,"https://ricette.giallozafferano.it/Moussaka.html"
|
||||||
"2022-05-08","domenica",,
|
"2022-05-08","domenica",,
|
||||||
"2022-05-09","lunedì",,
|
"2022-05-09","lunedì",,
|
||||||
"2022-05-10","martedì",,
|
"2022-05-10","martedì",,"https://ricette.giallozafferano.it/Torta-salata-di-melanzane.html"
|
||||||
"2022-05-11","mercoledì",,"https://ricette.giallozafferano.it/Mezze-maniche-al-tonno.html"
|
"2022-05-11","mercoledì",,"https://ricette.giallozafferano.it/Mezze-maniche-al-tonno.html"
|
||||||
"2022-05-12","giovedì",,
|
"2022-05-12","giovedì",,
|
||||||
"2022-05-13","venerdì",,"https://ricette.giallozafferano.it/Spiedini-di-pollo.html"
|
"2022-05-13","venerdì",,"https://ricette.giallozafferano.it/Spiedini-di-pollo.html"
|
||||||
|
@ -193,7 +193,7 @@
|
||||||
"2022-07-11","lunedì",,"https://ricette.giallozafferano.it/Insalata-con-uova-strapazzate.html"
|
"2022-07-11","lunedì",,"https://ricette.giallozafferano.it/Insalata-con-uova-strapazzate.html"
|
||||||
"2022-07-12","martedì",,
|
"2022-07-12","martedì",,
|
||||||
"2022-07-13","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
"2022-07-13","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||||
"2022-07-14","giovedì",,
|
"2022-07-14","giovedì",,"Tomatenpita"
|
||||||
"2022-07-15","venerdì",,"https://ricette.giallozafferano.it/Salmorejo.html"
|
"2022-07-15","venerdì",,"https://ricette.giallozafferano.it/Salmorejo.html"
|
||||||
"2022-07-16","sabato",,
|
"2022-07-16","sabato",,
|
||||||
"2022-07-17","domenica",,"https://ricette.giallozafferano.it/Insalata-di-quinoa-alla-greca.html"
|
"2022-07-17","domenica",,"https://ricette.giallozafferano.it/Insalata-di-quinoa-alla-greca.html"
|
||||||
|
@ -213,17 +213,17 @@
|
||||||
"2022-07-31","domenica",,
|
"2022-07-31","domenica",,
|
||||||
"2022-08-01","lunedì",,"https://ricette.giallozafferano.it/Riso-freddo-con-tonno-zucchine-e-limone.html"
|
"2022-08-01","lunedì",,"https://ricette.giallozafferano.it/Riso-freddo-con-tonno-zucchine-e-limone.html"
|
||||||
"2022-08-02","martedì",,"https://ricette.giallozafferano.it/Insalata-Shirazi.html"
|
"2022-08-02","martedì",,"https://ricette.giallozafferano.it/Insalata-Shirazi.html"
|
||||||
"2022-08-03","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
"2022-08-03","mercoledì",,"https://ricette.giallozafferano.it/Insalata-di-pasta-Mediterranea.html"
|
||||||
"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ì",,"https://ricette.giallozafferano.it/Pasta-con-pomodorini-e-stracchino.html"
|
"2022-08-05","venerdì",,
|
||||||
"2022-08-06","sabato","https://ricette.giallozafferano.it/Spaghetti-di-riso-con-carne-e-verdure.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",,
|
"2022-08-07","domenica",,"https://ricette.giallozafferano.it/Insalata-di-riso-vegetariana.html"
|
||||||
"2022-08-08","lunedì",,
|
"2022-08-08","lunedì",,"https://ricette.giallozafferano.it/Torta-salata-di-melanzane.html"
|
||||||
"2022-08-09","martedì",,"https://ricette.giallozafferano.it/Insalata-di-pasta-Mediterranea.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"
|
||||||
"2022-08-11","giovedì",,"https://ricette.giallozafferano.it/Verdure-gratinate-al-forno.html"
|
"2022-08-11","giovedì",,"https://ricette.giallozafferano.it/Verdure-gratinate-al-forno.html"
|
||||||
"2022-08-12","venerdì",,"https://ricette.giallozafferano.it/Garganelli-con-pesto-di-zucchine-e-gamberetti.html"
|
"2022-08-12","venerdì",,"https://ricette.giallozafferano.it/Garganelli-con-pesto-di-zucchine-e-gamberetti.html"
|
||||||
"2022-08-13","sabato","https://ricette.giallozafferano.it/Insalata-di-bulgur-vegana.html",
|
"2022-08-13","sabato","https://ricette.giallozafferano.it/Insalata-di-bulgur-vegana.html","Tomatenpita"
|
||||||
"2022-08-14","domenica",,
|
"2022-08-14","domenica",,
|
||||||
"2022-08-15","lunedì",,"https://ricette.giallozafferano.it/Pasta-con-le-melanzane.html"
|
"2022-08-15","lunedì",,"https://ricette.giallozafferano.it/Pasta-con-le-melanzane.html"
|
||||||
"2022-08-16","martedì",,"https://ricette.giallozafferano.it/Tempeh-alle-verdure.html"
|
"2022-08-16","martedì",,"https://ricette.giallozafferano.it/Tempeh-alle-verdure.html"
|
||||||
|
@ -254,7 +254,7 @@
|
||||||
"2022-09-10","sabato","https://ricette.giallozafferano.it/Maccheroncini-al-fume.html",
|
"2022-09-10","sabato","https://ricette.giallozafferano.it/Maccheroncini-al-fume.html",
|
||||||
"2022-09-11","domenica","https://ricette.giallozafferano.it/Polpo-alla-Luciana.html",
|
"2022-09-11","domenica","https://ricette.giallozafferano.it/Polpo-alla-Luciana.html",
|
||||||
"2022-09-12","lunedì",,"https://ricette.giallozafferano.it/Pennette-con-speck-e-zucchine.html"
|
"2022-09-12","lunedì",,"https://ricette.giallozafferano.it/Pennette-con-speck-e-zucchine.html"
|
||||||
"2022-09-13","martedì",,
|
"2022-09-13","martedì",,"https://ricette.giallozafferano.it/Torta-salata-di-melanzane.html"
|
||||||
"2022-09-14","mercoledì",,"https://ricette.giallozafferano.it/Scaloppine-ai-funghi.html"
|
"2022-09-14","mercoledì",,"https://ricette.giallozafferano.it/Scaloppine-ai-funghi.html"
|
||||||
"2022-09-15","giovedì",,
|
"2022-09-15","giovedì",,
|
||||||
"2022-09-16","venerdì",,"https://ricette.giallozafferano.it/Cordon-bleu-di-melanzane.html"
|
"2022-09-16","venerdì",,"https://ricette.giallozafferano.it/Cordon-bleu-di-melanzane.html"
|
||||||
|
|
|
|
@ -9,10 +9,10 @@ use {
|
||||||
|
|
||||||
pub struct ApiClient {
|
pub struct ApiClient {
|
||||||
rest: reqwest::Client,
|
rest: reqwest::Client,
|
||||||
pub(crate) rest_semaphore: Arc<Semaphore>, // TODO: wrap in dereferentiable struct
|
rest_semaphore: Arc<Semaphore>,
|
||||||
base_url: Url,
|
base_url: Url,
|
||||||
caldav_base_url: Url,
|
caldav_base_url: Url,
|
||||||
username: String,
|
webdav_base_url: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApiClient {
|
impl ApiClient {
|
||||||
|
@ -30,6 +30,8 @@ impl ApiClient {
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let username = server.login_name.clone();
|
||||||
|
|
||||||
use reqwest::header;
|
use reqwest::header;
|
||||||
let mut default_headers = header::HeaderMap::new();
|
let mut default_headers = header::HeaderMap::new();
|
||||||
let mut auth_header = b"Basic ".to_vec();
|
let mut auth_header = b"Basic ".to_vec();
|
||||||
|
@ -53,12 +55,14 @@ impl ApiClient {
|
||||||
.send(),
|
.send(),
|
||||||
)?
|
)?
|
||||||
.url()
|
.url()
|
||||||
.clone();
|
.join(&format!("calendars/{}/", &username))?;
|
||||||
|
|
||||||
|
let webdav_base_url = base_url.join(&format!("remote.php/dav/files/{}/", username))?;
|
||||||
|
|
||||||
Ok(ApiClient {
|
Ok(ApiClient {
|
||||||
base_url,
|
base_url,
|
||||||
caldav_base_url,
|
caldav_base_url,
|
||||||
username: server.login_name.clone(),
|
webdav_base_url,
|
||||||
rest: rest_client,
|
rest: rest_client,
|
||||||
rest_semaphore: Arc::new(Semaphore::new(5)),
|
rest_semaphore: Arc::new(Semaphore::new(5)),
|
||||||
})
|
})
|
||||||
|
@ -94,10 +98,6 @@ impl ApiClient {
|
||||||
&self.caldav_base_url
|
&self.caldav_base_url
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn username(&self) -> &str {
|
|
||||||
&self.username
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_events<Tz>(
|
pub async fn get_events<Tz>(
|
||||||
&self,
|
&self,
|
||||||
calendar_name: &str,
|
calendar_name: &str,
|
||||||
|
@ -113,10 +113,8 @@ impl ApiClient {
|
||||||
let response = client
|
let response = client
|
||||||
.request(
|
.request(
|
||||||
report_method.clone(),
|
report_method.clone(),
|
||||||
// TODO extract into helper method
|
|
||||||
self.caldav_base_url.join(&format!(
|
self.caldav_base_url.join(&format!(
|
||||||
"calendars/{}/{}",
|
"{}/",
|
||||||
self.username(),
|
|
||||||
calendar_name.to_lowercase().replace(" ", "-")
|
calendar_name.to_lowercase().replace(" ", "-")
|
||||||
))?,
|
))?,
|
||||||
)
|
)
|
||||||
|
@ -195,4 +193,8 @@ impl ApiClient {
|
||||||
|
|
||||||
Ok(events.collect::<Vec<_>>())
|
Ok(events.collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn webdav_base_url(&self) -> &Url {
|
||||||
|
&self.webdav_base_url
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use {
|
||||||
chrono::{Duration, Local},
|
chrono::{Duration, Local},
|
||||||
icalendar::Component,
|
icalendar::Component,
|
||||||
regex::Regex,
|
regex::Regex,
|
||||||
reqwest::{Method, StatusCode},
|
reqwest::{Method, StatusCode, Url},
|
||||||
std::collections::HashSet,
|
std::collections::HashSet,
|
||||||
std::ops::Range,
|
std::ops::Range,
|
||||||
};
|
};
|
||||||
|
@ -109,43 +109,16 @@ fn prepare_grocery_list(ingredients: &Vec<Ingredient>) -> Result<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_grocery_list(api_client: &ApiClient, filename: &str, contents: &str) -> Result<()> {
|
async fn save_grocery_list(api_client: &ApiClient, filename: &str, contents: &str) -> Result<()> {
|
||||||
let dav_base_url = api_client
|
|
||||||
.base_url()
|
|
||||||
.join(&format!("remote.php/dav/files/{}/", api_client.username()))?;
|
|
||||||
|
|
||||||
let filename_components = filename.split('/').collect::<Vec<_>>();
|
let filename_components = filename.split('/').collect::<Vec<_>>();
|
||||||
filename_components
|
filename_components
|
||||||
.iter()
|
.iter()
|
||||||
.take(filename_components.len() - 1)
|
.take(filename_components.len() - 1)
|
||||||
.fold(Ok(dav_base_url.clone()), |url, dir| {
|
.fold(Ok(api_client.webdav_base_url().clone()), |url, dir| {
|
||||||
url.map(|u| u.join(&format!("{dir}/")).unwrap())
|
url.map(|u| u.join(&format!("{dir}/")).unwrap())
|
||||||
.and_then(|url| {
|
.and_then(|url| ensure_collection_exist(api_client, url))
|
||||||
futures::executor::block_on(async {
|
|
||||||
let response = api_client
|
|
||||||
.rest(|client| async {
|
|
||||||
let r = client
|
|
||||||
.request(Method::from_bytes(b"MKCOL").unwrap(), url.clone())
|
|
||||||
.send()
|
|
||||||
.await;
|
|
||||||
Ok(r?)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match response.map(|r| r.status()) {
|
|
||||||
Ok(StatusCode::OK)
|
|
||||||
| Ok(StatusCode::METHOD_NOT_ALLOWED /* already exists */) => Ok(url),
|
|
||||||
Ok(status) => Err(anyhow!(
|
|
||||||
"Could not create WebDAV collection {}, server responded with {}",
|
|
||||||
&url,
|
|
||||||
status
|
|
||||||
)),
|
|
||||||
Err(e) => Err(anyhow!(e)),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let file_url = dav_base_url.join(filename).unwrap();
|
let file_url = api_client.webdav_base_url().join(filename).unwrap();
|
||||||
log::info!("Saving grocery list to {}", &file_url);
|
log::info!("Saving grocery list to {}", &file_url);
|
||||||
let response = api_client
|
let response = api_client
|
||||||
.rest(|client| async {
|
.rest(|client| async {
|
||||||
|
@ -168,3 +141,27 @@ async fn save_grocery_list(api_client: &ApiClient, filename: &str, contents: &st
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ensure_collection_exist(api_client: &ApiClient, url: Url) -> Result<Url> {
|
||||||
|
futures::executor::block_on(async {
|
||||||
|
let response = api_client
|
||||||
|
.rest(|client| async {
|
||||||
|
let r = client
|
||||||
|
.request(Method::from_bytes(b"MKCOL").unwrap(), url.clone())
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
Ok(r?)
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match response.map(|r| r.status()) {
|
||||||
|
Ok(StatusCode::OK) | Ok(StatusCode::METHOD_NOT_ALLOWED /* already exists */) => Ok(url),
|
||||||
|
Ok(status) => Err(anyhow!(
|
||||||
|
"Could not create WebDAV collection {}, server responded with {}",
|
||||||
|
&url,
|
||||||
|
status
|
||||||
|
)),
|
||||||
|
Err(e) => Err(anyhow!(e)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -10,10 +10,8 @@ pub async fn with(api_client: &ApiClient, calendar_name: &str) -> Result<()> {
|
||||||
let response = client
|
let response = client
|
||||||
.request(
|
.request(
|
||||||
report_method.clone(),
|
report_method.clone(),
|
||||||
// TODO extract into helper method
|
|
||||||
api_client.caldav_base_url().join(&format!(
|
api_client.caldav_base_url().join(&format!(
|
||||||
"calendars/{}/{}/",
|
"{}/",
|
||||||
api_client.username(),
|
|
||||||
calendar_name.to_lowercase().replace(" ", "-")
|
calendar_name.to_lowercase().replace(" ", "-")
|
||||||
))?,
|
))?,
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,7 +11,7 @@ use {
|
||||||
chrono::naive::NaiveDate,
|
chrono::naive::NaiveDate,
|
||||||
futures::future::try_join_all,
|
futures::future::try_join_all,
|
||||||
icalendar::Event,
|
icalendar::Event,
|
||||||
reqwest::StatusCode,
|
reqwest::{StatusCode, Url},
|
||||||
std::collections::{HashMap, HashSet},
|
std::collections::{HashMap, HashSet},
|
||||||
std::fmt::Write,
|
std::fmt::Write,
|
||||||
std::iter::Iterator,
|
std::iter::Iterator,
|
||||||
|
@ -61,17 +61,17 @@ pub async fn with(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn urls_from_csv<'a, RecordsIter>(records: RecordsIter) -> Result<HashSet<String>>
|
fn urls_from_csv<'a, RecordsIter>(records: RecordsIter) -> Result<HashSet<Url>>
|
||||||
where
|
where
|
||||||
RecordsIter: Iterator<Item = &'a CsvRecord>,
|
RecordsIter: Iterator<Item = &'a CsvRecord>,
|
||||||
{
|
{
|
||||||
Ok(
|
Ok(
|
||||||
records.fold(std::collections::HashSet::new(), |mut set, r| {
|
records.fold(std::collections::HashSet::new(), |mut set, r| {
|
||||||
if !r.lunch.is_empty() {
|
if let Ok(lunch) = Url::try_from(r.lunch.as_str()) {
|
||||||
set.insert(r.lunch.clone());
|
set.insert(lunch);
|
||||||
}
|
}
|
||||||
if !r.dinner.is_empty() {
|
if let Ok(dinner) = Url::try_from(r.dinner.as_str()) {
|
||||||
set.insert(r.dinner.clone());
|
set.insert(dinner);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
}),
|
}),
|
||||||
|
@ -93,13 +93,9 @@ async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, Rc<re
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let recipes = metadata.iter().map(|rm| async {
|
let recipes = metadata.iter().map(|rm| async {
|
||||||
// TODO: wrap this, heavily refactor this mess
|
let response = api_client
|
||||||
let _ = api_client.rest_semaphore.acquire().await.unwrap();
|
|
||||||
let mut retries = 0;
|
|
||||||
let response = loop {
|
|
||||||
let result = api_client
|
|
||||||
.rest(|client| async {
|
.rest(|client| async {
|
||||||
let response = client
|
let r = client
|
||||||
.get(
|
.get(
|
||||||
api_client
|
api_client
|
||||||
.base_url()
|
.base_url()
|
||||||
|
@ -108,20 +104,9 @@ async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, Rc<re
|
||||||
)
|
)
|
||||||
.send()
|
.send()
|
||||||
.await;
|
.await;
|
||||||
Ok(response?)
|
Ok(r?)
|
||||||
})
|
})
|
||||||
.await;
|
.await?;
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(response) => break response,
|
|
||||||
Err(_) if retries < 10 => {
|
|
||||||
retries += 1;
|
|
||||||
std::thread::sleep(retries * std::time::Duration::from_millis(500));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => bail!("Cannot fetch recipe {} with id {}", rm.name, rm.id),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
response
|
response
|
||||||
.json::<recipe::Recipe>()
|
.json::<recipe::Recipe>()
|
||||||
|
@ -131,9 +116,17 @@ async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, Rc<re
|
||||||
});
|
});
|
||||||
|
|
||||||
let recipes = try_join_all(recipes).await?;
|
let recipes = try_join_all(recipes).await?;
|
||||||
Ok(HashMap::from_iter(
|
|
||||||
recipes.into_iter().map(|r| (r.url.clone(), r)),
|
Ok(HashMap::from_iter(recipes.into_iter().map(|r| {
|
||||||
))
|
// Fallback to recipe name as ID if URL is empty
|
||||||
|
let id = match &r.url {
|
||||||
|
Some(u) if !u.is_empty() => u,
|
||||||
|
_ => &r.name,
|
||||||
|
}
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
(id, r)
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn publish_events<'a, SchedulingsIter>(
|
async fn publish_events<'a, SchedulingsIter>(
|
||||||
|
@ -146,8 +139,7 @@ where
|
||||||
SchedulingsIter: Iterator<Item = Scheduling>,
|
SchedulingsIter: Iterator<Item = Scheduling>,
|
||||||
{
|
{
|
||||||
let calendar_url = api_client.caldav_base_url().join(&format!(
|
let calendar_url = api_client.caldav_base_url().join(&format!(
|
||||||
"calendars/{}/{}/",
|
"{}/",
|
||||||
&api_client.username(),
|
|
||||||
calendar.to_lowercase().as_str().replace(" ", "-")
|
calendar.to_lowercase().as_str().replace(" ", "-")
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct Metadata {
|
||||||
#[serde(rename = "recipe_id")]
|
#[serde(rename = "recipe_id")]
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub keywords: String,
|
pub keywords: Option<String>,
|
||||||
pub date_created: DateTime,
|
pub date_created: DateTime,
|
||||||
pub date_modified: DateTime,
|
pub date_modified: DateTime,
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ pub struct Recipe {
|
||||||
pub id: isize,
|
pub id: isize,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub url: String,
|
pub url: Option<String>,
|
||||||
pub keywords: String,
|
pub keywords: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "dateCreated")]
|
#[serde(rename = "dateCreated")]
|
||||||
pub created: DateTime,
|
pub created: DateTime,
|
||||||
|
|
|
@ -49,16 +49,20 @@ impl From<Scheduling> for Event {
|
||||||
use icalendar::Component;
|
use icalendar::Component;
|
||||||
let start_time = ev.ends_at - ev.recipe.total_time();
|
let start_time = ev.ends_at - ev.recipe.total_time();
|
||||||
|
|
||||||
let cal_event = Event::new()
|
let mut cal_event = Event::new();
|
||||||
|
|
||||||
|
cal_event
|
||||||
.uid(&ev.uid)
|
.uid(&ev.uid)
|
||||||
.summary(&ev.recipe.name)
|
.summary(&ev.recipe.name)
|
||||||
.description(&format!("cookbook@{}", ev.recipe.id))
|
.description(&format!("cookbook@{}", ev.recipe.id))
|
||||||
.location(&ev.recipe.url)
|
|
||||||
.timestamp(Utc::now())
|
.timestamp(Utc::now())
|
||||||
.starts(start_time)
|
.starts(start_time)
|
||||||
.ends(ev.ends_at)
|
.ends(ev.ends_at);
|
||||||
.done();
|
|
||||||
|
|
||||||
cal_event
|
if let Some(ref location) = ev.recipe.url.clone() {
|
||||||
|
cal_event.location(&location);
|
||||||
|
}
|
||||||
|
|
||||||
|
cal_event.done()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue