Publish cal events to server
This commit is contained in:
parent
dce761b0f9
commit
8e1547750e
|
@ -157,6 +157,7 @@ dependencies = [
|
|||
"strum_macros",
|
||||
"tokio",
|
||||
"toml",
|
||||
"uuid",
|
||||
"webbrowser",
|
||||
]
|
||||
|
||||
|
@ -889,6 +890,12 @@ version = "0.3.25"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.1.3"
|
||||
|
@ -917,6 +924,36 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.13"
|
||||
|
@ -1371,6 +1408,16 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
|
|
@ -66,5 +66,9 @@ version = "0.5"
|
|||
version = "1"
|
||||
features = ["rt-multi-thread", "net", "macros"]
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "1.1"
|
||||
features = ["v4", "fast-rng"]
|
||||
|
||||
[dependencies.webbrowser]
|
||||
version = "0.7"
|
||||
|
|
|
@ -6,13 +6,15 @@ use {
|
|||
crate::commands::import,
|
||||
crate::constants,
|
||||
crate::recipe,
|
||||
anyhow::Result,
|
||||
anyhow::{bail, Result},
|
||||
chrono::naive::{NaiveDate, NaiveDateTime, NaiveTime},
|
||||
chrono::{DateTime, Local, TimeZone},
|
||||
futures::future::try_join_all,
|
||||
ics::properties as calprop,
|
||||
ics::Event,
|
||||
reqwest::StatusCode,
|
||||
std::collections::{HashMap, HashSet},
|
||||
std::fmt::Write,
|
||||
std::iter::Iterator,
|
||||
std::path::Path,
|
||||
};
|
||||
|
@ -53,11 +55,11 @@ pub async fn with(api_client: &ApiClient, calendar: &str, csv_file: &Path) -> Re
|
|||
})
|
||||
.flatten();
|
||||
|
||||
publish_events(&api_client, calendar, events)?;
|
||||
publish_events(&api_client, calendar, events).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_event(date: NaiveDate, meal: Meal, recipe: &recipe::Recipe) -> Event {
|
||||
fn to_event(date: NaiveDate, meal: Meal, recipe: &recipe::Recipe) -> (String, Event) {
|
||||
// TODO: this is momentarily hardcoded, should be an option
|
||||
let meal_time = match meal {
|
||||
Meal::Lunch => NaiveTime::from_hms(12, 00, 00),
|
||||
|
@ -74,7 +76,7 @@ fn to_event(date: NaiveDate, meal: Meal, recipe: &recipe::Recipe) -> Event {
|
|||
let end_time = NaiveDateTime::new(date, meal_time);
|
||||
let start_time = end_time - recipe.total_time();
|
||||
|
||||
let mut event = Event::new(uid, dt_fmt(&Local::now()));
|
||||
let mut event = Event::new(uid.clone(), dt_fmt(&Local::now()));
|
||||
event.push(calprop::Summary::new(&recipe.name));
|
||||
event.push(calprop::Description::new(format!("cookbook@{}", recipe.id)));
|
||||
event.push(calprop::Location::new(&recipe.url));
|
||||
|
@ -91,7 +93,7 @@ fn to_event(date: NaiveDate, meal: Meal, recipe: &recipe::Recipe) -> Event {
|
|||
);
|
||||
event.add_alarm(alarm);
|
||||
|
||||
event
|
||||
(uid, event)
|
||||
}
|
||||
|
||||
fn urls_from_csv<'a, RecordsIter>(records: RecordsIter) -> Result<HashSet<String>>
|
||||
|
@ -112,7 +114,7 @@ where
|
|||
}
|
||||
|
||||
fn dt_fmt(datetime: &DateTime<Local>) -> String {
|
||||
datetime.format("%Y%m%dT%H%M%SZ").to_string()
|
||||
datetime.format("%Y%m%dT%H%M%S").to_string()
|
||||
}
|
||||
|
||||
async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, recipe::Recipe>> {
|
||||
|
@ -148,21 +150,15 @@ async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, recip
|
|||
))
|
||||
}
|
||||
|
||||
fn publish_events<'a, EventsIter>(
|
||||
async fn publish_events<'a, EventsIter>(
|
||||
api_client: &ApiClient,
|
||||
calendar: &str,
|
||||
events: EventsIter,
|
||||
) -> Result<()>
|
||||
where
|
||||
EventsIter: Iterator<Item = Event<'a>>,
|
||||
EventsIter: Iterator<Item = (String, Event<'a>)>,
|
||||
{
|
||||
let calendar_url = api_client.base_url.join(&format!(
|
||||
"remote.php/dav/calendars/{}/{}/",
|
||||
&api_client.username,
|
||||
calendar.to_lowercase().as_str().replace(" ", "-")
|
||||
));
|
||||
|
||||
let cal = ics::ICalendar::new(
|
||||
let calendar_prototype: ics::ICalendar = ics::ICalendar::new(
|
||||
"2.0",
|
||||
format!(
|
||||
"-//{}//NONSGML {}//EN",
|
||||
|
@ -170,12 +166,48 @@ where
|
|||
env!("CARGO_PKG_NAME")
|
||||
),
|
||||
);
|
||||
let cal = events.fold(cal, |mut cal, e| {
|
||||
cal.add_event(e);
|
||||
cal
|
||||
|
||||
let dav_base = api_client
|
||||
.rest
|
||||
.head(api_client.base_url.join("/.well-known/caldav")?)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let calendar_url = dav_base.url().join(&format!(
|
||||
"calendars/{}/{}/",
|
||||
&api_client.username,
|
||||
calendar.to_lowercase().as_str().replace(" ", "-")
|
||||
))?;
|
||||
|
||||
let calendar_prototype = &calendar_prototype;
|
||||
let calendar_url = &calendar_url;
|
||||
let update_requests = events.map(|(event_id, event)| async move {
|
||||
let mut cal = calendar_prototype.clone();
|
||||
cal.add_event(event);
|
||||
|
||||
let url = calendar_url.join(&format!("{}.ics", event_id)).unwrap();
|
||||
api_client
|
||||
.rest
|
||||
.put(url)
|
||||
.header("Content-Type", "text/calendar; charset=utf-8")
|
||||
.body(cal.to_string())
|
||||
.send()
|
||||
.await
|
||||
});
|
||||
|
||||
println!("CALENDAR: \n {:?}", cal);
|
||||
let responses = try_join_all(update_requests).await?;
|
||||
let failed_responses = responses.into_iter().filter(|response| {
|
||||
![StatusCode::NO_CONTENT, StatusCode::CREATED].contains(&response.status())
|
||||
});
|
||||
|
||||
let mut errors = String::new();
|
||||
for r in failed_responses {
|
||||
write!(errors, "\n{}", r.text().await.unwrap())?;
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
bail!("Error while updating calendar events: {}", errors);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue