Properly handle moved appointments instead of just defining an exclusion date and a new date (this fixes edge cases where an appointment has been moved to the same date)
This commit is contained in:
@@ -8,6 +8,51 @@ use log::warn;
|
|||||||
use reqwest::IntoUrl;
|
use reqwest::IntoUrl;
|
||||||
use rrule::{RRule, RRuleSet, RRuleSetIter, Tz, Unvalidated};
|
use rrule::{RRule, RRuleSet, RRuleSetIter, Tz, Unvalidated};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct RRuleWithReplacements {
|
||||||
|
rrule_set: RRuleSet,
|
||||||
|
replacements: HashMap<DateTime<Tz>, DateTime<Tz>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RRuleWithReplacementsIter<'a> {
|
||||||
|
inner: RRuleSetIter<'a>,
|
||||||
|
rrule_set: &'a RRuleWithReplacements,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for RRuleWithReplacementsIter<'a> {
|
||||||
|
type Item = <RRuleSetIter<'a> as IntoIterator>::Item;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.inner.next().map(|mut next_appointment| {
|
||||||
|
if let Some(replacement) = self.rrule_set.replacements.get(&next_appointment) {
|
||||||
|
next_appointment = *replacement;
|
||||||
|
}
|
||||||
|
next_appointment
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a RRuleWithReplacements {
|
||||||
|
type Item = <RRuleSetIter<'a> as IntoIterator>::Item;
|
||||||
|
type IntoIter = RRuleWithReplacementsIter<'a>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
Self::IntoIter {
|
||||||
|
inner: self.rrule_set.into_iter(),
|
||||||
|
rrule_set: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RRuleWithReplacements {
|
||||||
|
fn new(rrule_set: RRuleSet) -> Self {
|
||||||
|
Self {
|
||||||
|
rrule_set,
|
||||||
|
replacements: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn fetch_next_appointment<U: IntoUrl>(url: U) -> Result<Option<Appointment<Tz>>> {
|
pub async fn fetch_next_appointment<U: IntoUrl>(url: U) -> Result<Option<Appointment<Tz>>> {
|
||||||
let response = reqwest::get(url).await?.bytes().await?;
|
let response = reqwest::get(url).await?.bytes().await?;
|
||||||
|
|
||||||
@@ -25,6 +70,7 @@ pub async fn fetch_next_appointment<U: IntoUrl>(url: U) -> Result<Option<Appoint
|
|||||||
let mut series = HashMap::new();
|
let mut series = HashMap::new();
|
||||||
let mut ends = HashMap::new();
|
let mut ends = HashMap::new();
|
||||||
for event in events {
|
for event in events {
|
||||||
|
println!("{}", event.start);
|
||||||
ends.insert(event.uid.clone(), event.end);
|
ends.insert(event.uid.clone(), event.end);
|
||||||
if let Some(rrule) = event.rrule {
|
if let Some(rrule) = event.rrule {
|
||||||
// TODO This is a workaround for https://github.com/fmeringdal/rust-rrule/issues/87
|
// TODO This is a workaround for https://github.com/fmeringdal/rust-rrule/issues/87
|
||||||
@@ -35,14 +81,19 @@ pub async fn fetch_next_appointment<U: IntoUrl>(url: U) -> Result<Option<Appoint
|
|||||||
for exdate in event.exdates {
|
for exdate in event.exdates {
|
||||||
rrule_set = rrule_set.exdate(exdate);
|
rrule_set = rrule_set.exdate(exdate);
|
||||||
}
|
}
|
||||||
series.insert(event.uid, rrule_set);
|
series.insert(event.uid, RRuleWithReplacements::new(rrule_set));
|
||||||
} else if let Some(recurrence_id) = event.recurrence_id {
|
} else if let Some(recurrence_id) = event.recurrence_id {
|
||||||
let uid = event.uid;
|
let uid = event.uid;
|
||||||
let (uid, rrule_set) = series.remove_entry(&uid).unwrap();
|
series
|
||||||
let rrule_set = rrule_set.exdate(recurrence_id).rdate(event.start);
|
.get_mut(&uid)
|
||||||
series.insert(uid, rrule_set);
|
.unwrap()
|
||||||
|
.replacements
|
||||||
|
.insert(recurrence_id, event.start);
|
||||||
} else {
|
} else {
|
||||||
series.insert(event.uid, RRuleSet::new(now).rdate(event.start));
|
series.insert(
|
||||||
|
event.uid,
|
||||||
|
RRuleWithReplacements::new(RRuleSet::new(now).rdate(event.start)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +117,7 @@ pub async fn fetch_next_appointment<U: IntoUrl>(url: U) -> Result<Option<Appoint
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AppointmentsIterator<'a> {
|
struct AppointmentsIterator<'a> {
|
||||||
inner: Vec<(&'a String, DateTime<Tz>, RRuleSetIter<'a>)>,
|
inner: Vec<(&'a String, DateTime<Tz>, RRuleWithReplacementsIter<'a>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for AppointmentsIterator<'a> {
|
impl<'a> Iterator for AppointmentsIterator<'a> {
|
||||||
@@ -92,7 +143,7 @@ trait IterAppointments {
|
|||||||
fn iter_appointments(&self) -> AppointmentsIterator<'_>;
|
fn iter_appointments(&self) -> AppointmentsIterator<'_>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IterAppointments for HashMap<String, RRuleSet> {
|
impl IterAppointments for HashMap<String, RRuleWithReplacements> {
|
||||||
fn iter_appointments(&self) -> AppointmentsIterator {
|
fn iter_appointments(&self) -> AppointmentsIterator {
|
||||||
let mut inner = vec![];
|
let mut inner = vec![];
|
||||||
for (uid, rrule_set) in self {
|
for (uid, rrule_set) in self {
|
||||||
|
|||||||
Reference in New Issue
Block a user