Fix outputting tzid and alarm trigger
This commit is contained in:
parent
096db12c74
commit
77404d1642
|
@ -8,6 +8,15 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.58"
|
||||
|
@ -160,6 +169,7 @@ dependencies = [
|
|||
"csv",
|
||||
"directories",
|
||||
"futures",
|
||||
"iana-time-zone",
|
||||
"ics",
|
||||
"minicaldav",
|
||||
"reqwest",
|
||||
|
@ -170,7 +180,7 @@ dependencies = [
|
|||
"strum_macros",
|
||||
"tokio",
|
||||
"toml",
|
||||
"uuid",
|
||||
"ureq",
|
||||
"webbrowser",
|
||||
]
|
||||
|
||||
|
@ -571,6 +581,19 @@ dependencies = [
|
|||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00c0d80ad9ca8d30ca648bf6cb1e3e3326d75071b76dbe143dd4a9cedcd58975"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ics"
|
||||
version = "0.5.7"
|
||||
|
@ -944,12 +967,6 @@ 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"
|
||||
|
@ -978,36 +995,6 @@ 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"
|
||||
|
@ -1529,16 +1516,6 @@ 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"
|
||||
|
|
|
@ -26,6 +26,9 @@ version = "0.13"
|
|||
version = "0.4"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.iana-time-zone]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.csv]
|
||||
version = "1.1"
|
||||
|
||||
|
@ -69,9 +72,8 @@ version = "0.5"
|
|||
version = "1"
|
||||
features = ["rt-multi-thread", "net", "macros"]
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "1.1"
|
||||
features = ["v4", "fast-rng"]
|
||||
[dependencies.ureq]
|
||||
version = "2.5"
|
||||
|
||||
[dependencies.webbrowser]
|
||||
version = "0.7"
|
||||
|
|
|
@ -2,18 +2,21 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use {
|
||||
crate::config::Config, crate::constants, anyhow::anyhow,
|
||||
crate::config::Config, crate::constants, anyhow::anyhow, anyhow::Result,
|
||||
base64::write::EncoderWriter as Base64Encoder, reqwest::Url, std::io::Write,
|
||||
};
|
||||
|
||||
pub struct ApiClient {
|
||||
pub base_url: Url,
|
||||
pub username: String,
|
||||
pub rest: reqwest::Client,
|
||||
rest: reqwest::Client,
|
||||
agent: ureq::Agent,
|
||||
base_url: Url,
|
||||
caldav_base_url: Url,
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
impl ApiClient {
|
||||
pub fn new(server_name: &str, configuration: &Config) -> anyhow::Result<Self> {
|
||||
pub fn new(server_name: &str, configuration: &Config) -> Result<Self> {
|
||||
let server = configuration
|
||||
.credentials
|
||||
.servers
|
||||
|
@ -43,10 +46,58 @@ impl ApiClient {
|
|||
.default_headers(default_headers)
|
||||
.build()?;
|
||||
|
||||
let base_url = Url::parse(&server.url)?;
|
||||
let caldav_base_url = futures::executor::block_on(
|
||||
rest_client
|
||||
.head(base_url.join("/.well-known/caldav")?)
|
||||
.send(),
|
||||
)?
|
||||
.url()
|
||||
.clone();
|
||||
|
||||
Ok(ApiClient {
|
||||
base_url: Url::parse(&server.url)?,
|
||||
base_url,
|
||||
caldav_base_url,
|
||||
username: server.login_name.clone(),
|
||||
password: server.password.clone(),
|
||||
rest: rest_client,
|
||||
agent: ureq::Agent::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rest(&self) -> &reqwest::Client {
|
||||
&self.rest
|
||||
}
|
||||
|
||||
pub fn base_url(&self) -> &Url {
|
||||
&self.base_url
|
||||
}
|
||||
|
||||
pub fn username(&self) -> &str {
|
||||
&self.username
|
||||
}
|
||||
|
||||
pub fn get_calendars(
|
||||
&self,
|
||||
) -> core::result::Result<Vec<minicaldav::Calendar>, minicaldav::Error> {
|
||||
minicaldav::get_calendars(
|
||||
self.agent.clone(),
|
||||
self.username(),
|
||||
&self.password,
|
||||
&self.caldav_base_url,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_events(
|
||||
&self,
|
||||
calendar: &minicaldav::Calendar,
|
||||
) -> core::result::Result<(Vec<minicaldav::Event>, Vec<minicaldav::Error>), minicaldav::Error>
|
||||
{
|
||||
minicaldav::get_events(
|
||||
self.agent.clone(),
|
||||
self.username(),
|
||||
&self.password,
|
||||
calendar,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ where
|
|||
{
|
||||
for url in urls {
|
||||
let response = api_client
|
||||
.rest
|
||||
.post(api_client.base_url.join("apps/cookbook/import")?)
|
||||
.rest()
|
||||
.post(api_client.base_url().join("apps/cookbook/import")?)
|
||||
.json(&serde_json::json!({
|
||||
"url": url.as_ref(),
|
||||
}))
|
||||
|
|
|
@ -5,8 +5,8 @@ use {crate::api_client::ApiClient, crate::recipe, anyhow::Result};
|
|||
|
||||
pub async fn with(api_client: &ApiClient) -> Result<()> {
|
||||
let recipes = api_client
|
||||
.rest
|
||||
.get(api_client.base_url.join("apps/cookbook/api/recipes")?)
|
||||
.rest()
|
||||
.get(api_client.base_url().join("apps/cookbook/api/recipes")?)
|
||||
.send()
|
||||
.await?;
|
||||
println!("{:#?}", recipes.json::<Vec<recipe::Metadata>>().await?);
|
||||
|
|
|
@ -71,8 +71,8 @@ where
|
|||
|
||||
async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, Rc<recipe::Recipe>>> {
|
||||
let metadata = api_client
|
||||
.rest
|
||||
.get(api_client.base_url.join("apps/cookbook/api/recipes")?)
|
||||
.rest()
|
||||
.get(api_client.base_url().join("apps/cookbook/api/recipes")?)
|
||||
.send()
|
||||
.await?
|
||||
.json::<Vec<recipe::Metadata>>()
|
||||
|
@ -80,10 +80,10 @@ async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, Rc<re
|
|||
|
||||
let recipes = metadata.iter().map(|rm| async {
|
||||
let response = api_client
|
||||
.rest
|
||||
.rest()
|
||||
.get(
|
||||
api_client
|
||||
.base_url
|
||||
.base_url()
|
||||
.join(&format!("apps/cookbook/api/recipes/{id}", id = rm.id))
|
||||
.unwrap(),
|
||||
)
|
||||
|
@ -113,21 +113,22 @@ where
|
|||
let calendar_prototype: ics::ICalendar = ics::ICalendar::new(
|
||||
"2.0",
|
||||
format!(
|
||||
"-//{}//NONSGML {}//EN",
|
||||
"-//IDN {}//{} {}//EN",
|
||||
constants::VENDOR,
|
||||
env!("CARGO_PKG_NAME")
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION")
|
||||
),
|
||||
);
|
||||
|
||||
let dav_base = api_client
|
||||
.rest
|
||||
.head(api_client.base_url.join("/.well-known/caldav")?)
|
||||
.rest()
|
||||
.head(api_client.base_url().join("/.well-known/caldav")?)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let calendar_url = dav_base.url().join(&format!(
|
||||
"calendars/{}/{}/",
|
||||
&api_client.username,
|
||||
&api_client.username(),
|
||||
calendar.to_lowercase().as_str().replace(" ", "-")
|
||||
))?;
|
||||
|
||||
|
@ -139,7 +140,7 @@ where
|
|||
cal.add_event(ev.into());
|
||||
|
||||
api_client
|
||||
.rest
|
||||
.rest()
|
||||
.put(url)
|
||||
.header("Content-Type", "text/calendar; charset=utf-8")
|
||||
.body(cal.to_string())
|
||||
|
|
24
src/event.rs
24
src/event.rs
|
@ -48,7 +48,11 @@ impl Event {
|
|||
|
||||
impl<'a> From<Event> for CalEvent<'a> {
|
||||
fn from(ev: Event) -> Self {
|
||||
let start_time = ev.ends_at - ev.recipe.total_time();
|
||||
let start_time = Local
|
||||
.from_local_datetime(&(*&ev.ends_at - ev.recipe.total_time()))
|
||||
.unwrap();
|
||||
let end_time = Local.from_local_datetime(&ev.ends_at).unwrap();
|
||||
let timezone = iana_time_zone::get_timezone().unwrap();
|
||||
|
||||
let mut event = ics::Event::new(ev.uid.clone(), dt_utc_fmt(&Utc::now()));
|
||||
event.push(calprop::Summary::new(escape_text(ev.recipe.name.clone())));
|
||||
|
@ -57,18 +61,22 @@ impl<'a> From<Event> for CalEvent<'a> {
|
|||
ev.recipe.id
|
||||
)));
|
||||
event.push(calprop::Location::new(escape_text(ev.recipe.url.clone())));
|
||||
event.push(calprop::DtStart::new(dt_fmt(
|
||||
&Local.from_local_datetime(&start_time).unwrap(),
|
||||
)));
|
||||
event.push(calprop::DtEnd::new(dt_fmt(
|
||||
&Local.from_local_datetime(&ev.ends_at).unwrap(),
|
||||
)));
|
||||
|
||||
let mut dtstart = calprop::DtStart::new(dt_fmt(&start_time));
|
||||
dtstart.append(ics::parameters!("TZID" => timezone.clone()));
|
||||
event.push(dtstart);
|
||||
|
||||
let mut dtend = calprop::DtEnd::new(dt_fmt(&end_time));
|
||||
dtend.append(ics::parameters!("TZID" => timezone));
|
||||
event.push(dtend);
|
||||
|
||||
// TODO make configurable yearly repetition, for now this suits my personal uses
|
||||
event.push(calprop::RRule::new("FREQ=YEARLY"));
|
||||
|
||||
let mut trigger = calprop::Trigger::new("-PT15M");
|
||||
trigger.append(ics::parameters!("RELATED" => "START"));
|
||||
let alarm = ics::Alarm::display(
|
||||
calprop::Trigger::new("-P15M"),
|
||||
trigger,
|
||||
calprop::Description::new(escape_text(ev.recipe.name.clone())),
|
||||
);
|
||||
event.add_alarm(alarm);
|
||||
|
|
Loading…
Reference in New Issue