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:
2024-05-09 16:13:35 +02:00
parent 0381cf37d8
commit 196cfae94f

View File

@@ -8,6 +8,51 @@ use log::warn;
use reqwest::IntoUrl;
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>>> {
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 ends = HashMap::new();
for event in events {
println!("{}", event.start);
ends.insert(event.uid.clone(), event.end);
if let Some(rrule) = event.rrule {
// 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 {
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 {
let uid = event.uid;
let (uid, rrule_set) = series.remove_entry(&uid).unwrap();
let rrule_set = rrule_set.exdate(recurrence_id).rdate(event.start);
series.insert(uid, rrule_set);
series
.get_mut(&uid)
.unwrap()
.replacements
.insert(recurrence_id, event.start);
} 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> {
inner: Vec<(&'a String, DateTime<Tz>, RRuleSetIter<'a>)>,
inner: Vec<(&'a String, DateTime<Tz>, RRuleWithReplacementsIter<'a>)>,
}
impl<'a> Iterator for AppointmentsIterator<'a> {
@@ -92,7 +143,7 @@ trait IterAppointments {
fn iter_appointments(&self) -> AppointmentsIterator<'_>;
}
impl IterAppointments for HashMap<String, RRuleSet> {
impl IterAppointments for HashMap<String, RRuleWithReplacements> {
fn iter_appointments(&self) -> AppointmentsIterator {
let mut inner = vec![];
for (uid, rrule_set) in self {