debug support of calendar-data pruning
This commit is contained in:
parent
68e08bed4f
commit
418adf92be
6 changed files with 160 additions and 37 deletions
|
@ -4,5 +4,5 @@
|
||||||
/// the goal will be to rewrite it in the end so it better
|
/// the goal will be to rewrite it in the end so it better
|
||||||
/// integrates into Aerogramme
|
/// integrates into Aerogramme
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod query;
|
|
||||||
pub mod prune;
|
pub mod prune;
|
||||||
|
pub mod query;
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
use icalendar::parser::{Component, Property};
|
|
||||||
use aero_dav::caltypes as cal;
|
use aero_dav::caltypes as cal;
|
||||||
|
use icalendar::parser::{Component, Property};
|
||||||
|
|
||||||
pub fn component<'a>(src: &'a Component<'a>, prune: &cal::Comp) -> Option<Component<'a>> {
|
pub fn component<'a>(src: &'a Component<'a>, prune: &cal::Comp) -> Option<Component<'a>> {
|
||||||
if src.name.as_str() != prune.name.as_str() {
|
if src.name.as_str() != prune.name.as_str() {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = src.name.clone();
|
let name = src.name.clone();
|
||||||
|
|
||||||
let properties = match &prune.prop_kind {
|
let properties = match &prune.prop_kind {
|
||||||
None => vec![],
|
Some(cal::PropKind::AllProp) | None => src.properties.clone(),
|
||||||
Some(cal::PropKind::AllProp) => src.properties.clone(),
|
Some(cal::PropKind::Prop(l)) => src
|
||||||
Some(cal::PropKind::Prop(l)) => src.properties.iter().filter_map(|prop| {
|
.properties
|
||||||
let sel_filt = match l.iter().find(|filt| filt.name.0.as_str() == prop.name.as_str()) {
|
.iter()
|
||||||
|
.filter_map(|prop| {
|
||||||
|
let sel_filt = match l
|
||||||
|
.iter()
|
||||||
|
.find(|filt| filt.name.0.as_str() == prop.name.as_str())
|
||||||
|
{
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return None
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
match sel_filt.novalue {
|
match sel_filt.novalue {
|
||||||
|
@ -22,19 +27,29 @@ pub fn component<'a>(src: &'a Component<'a>, prune: &cal::Comp) -> Option<Compon
|
||||||
Some(true) => Some(Property {
|
Some(true) => Some(Property {
|
||||||
name: prop.name.clone(),
|
name: prop.name.clone(),
|
||||||
params: prop.params.clone(),
|
params: prop.params.clone(),
|
||||||
val: "".into()
|
val: "".into(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>(),
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let components = match &prune.comp_kind {
|
let components = match &prune.comp_kind {
|
||||||
None => vec![],
|
Some(cal::CompKind::AllComp) | None => src.components.clone(),
|
||||||
Some(cal::CompKind::AllComp) => src.components.clone(),
|
Some(cal::CompKind::Comp(many_inner_prune)) => src
|
||||||
Some(cal::CompKind::Comp(many_inner_prune)) => src.components.iter().filter_map(|src_component| {
|
.components
|
||||||
many_inner_prune.iter().find_map(|inner_prune| component(src_component, inner_prune))
|
.iter()
|
||||||
}).collect::<Vec<_>>(),
|
.filter_map(|src_component| {
|
||||||
|
many_inner_prune
|
||||||
|
.iter()
|
||||||
|
.find_map(|inner_prune| component(src_component, inner_prune))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Component { name, properties, components })
|
Some(Component {
|
||||||
|
name,
|
||||||
|
properties,
|
||||||
|
components,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -333,7 +333,6 @@ impl<'a> Path<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@FIXME move somewhere else
|
|
||||||
//@FIXME naive implementation, must be refactored later
|
//@FIXME naive implementation, must be refactored later
|
||||||
use futures::stream::Stream;
|
use futures::stream::Stream;
|
||||||
fn apply_filter<'a>(
|
fn apply_filter<'a>(
|
||||||
|
|
|
@ -565,17 +565,49 @@ impl DavNode for EventNode {
|
||||||
dav::Property::GetEtag(etag)
|
dav::Property::GetEtag(etag)
|
||||||
}
|
}
|
||||||
dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
|
dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
|
||||||
cal::PropertyRequest::CalendarData(_req),
|
cal::PropertyRequest::CalendarData(req),
|
||||||
)) => {
|
)) => {
|
||||||
let ics = String::from_utf8(
|
let ics = String::from_utf8(
|
||||||
this.col.get(this.blob_id).await.or(Err(n.clone()))?,
|
this.col.get(this.blob_id).await.or(Err(n.clone()))?,
|
||||||
)
|
)
|
||||||
.or(Err(n.clone()))?;
|
.or(Err(n.clone()))?;
|
||||||
|
|
||||||
|
let new_ics = match &req.comp {
|
||||||
|
None => ics,
|
||||||
|
Some(prune_comp) => {
|
||||||
|
// parse content
|
||||||
|
let ics = match icalendar::parser::read_calendar(&ics) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::warn!(err=?e, "Unable to parse ICS in calendar-query");
|
||||||
|
return Err(n.clone())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// build a fake vcal component for caldav compat
|
||||||
|
let fake_vcal_component = icalendar::parser::Component {
|
||||||
|
name: cal::Component::VCalendar.as_str().into(),
|
||||||
|
properties: ics.properties,
|
||||||
|
components: ics.components,
|
||||||
|
};
|
||||||
|
|
||||||
|
// rebuild component
|
||||||
|
let new_comp = match aero_ical::prune::component(&fake_vcal_component, prune_comp) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Err(n.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// reserialize
|
||||||
|
format!("{}", icalendar::parser::Calendar { properties: new_comp.properties, components: new_comp.components })
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dav::Property::Extension(all::Property::Cal(
|
dav::Property::Extension(all::Property::Cal(
|
||||||
cal::Property::CalendarData(cal::CalendarDataPayload {
|
cal::Property::CalendarData(cal::CalendarDataPayload {
|
||||||
mime: None,
|
mime: None,
|
||||||
payload: ics,
|
payload: new_ics,
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -634,14 +666,15 @@ impl DavNode for EventNode {
|
||||||
// so we load everything in memory
|
// so we load everything in memory
|
||||||
let calendar = self.col.clone();
|
let calendar = self.col.clone();
|
||||||
let blob_id = self.blob_id.clone();
|
let blob_id = self.blob_id.clone();
|
||||||
let r = async move {
|
let calblob = async move {
|
||||||
let content = calendar
|
let raw_ics = calendar
|
||||||
.get(blob_id)
|
.get(blob_id)
|
||||||
.await
|
.await
|
||||||
.or(Err(std::io::Error::from(std::io::ErrorKind::Interrupted)));
|
.or(Err(std::io::Error::from(std::io::ErrorKind::Interrupted)))?;
|
||||||
Ok(hyper::body::Bytes::from(content?))
|
|
||||||
|
Ok(hyper::body::Bytes::from(raw_ics))
|
||||||
};
|
};
|
||||||
futures::stream::once(Box::pin(r)).boxed()
|
futures::stream::once(Box::pin(calblob)).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content_type(&self) -> &str {
|
fn content_type(&self) -> &str {
|
||||||
|
|
|
@ -956,7 +956,55 @@ fn rfc4791_webdav_caldav() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- REPORT calendar-query, with calendar-data tx ---
|
// --- REPORT calendar-query, with calendar-data tx ---
|
||||||
//@FIXME add support for calendar-data...
|
let cal_query = r#"<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||||
|
<D:prop>
|
||||||
|
<D:getetag/>
|
||||||
|
<C:calendar-data>
|
||||||
|
<C:comp name="VCALENDAR">
|
||||||
|
<C:prop name="VERSION"/>
|
||||||
|
<C:comp name="VEVENT">
|
||||||
|
<C:prop name="UID"/>
|
||||||
|
<C:prop name="DTSTART"/>
|
||||||
|
<C:prop name="DTEND"/>
|
||||||
|
<C:prop name="DURATION"/>
|
||||||
|
<C:prop name="RRULE"/>
|
||||||
|
<C:prop name="RDATE"/>
|
||||||
|
<C:prop name="EXRULE"/>
|
||||||
|
<C:prop name="EXDATE"/>
|
||||||
|
<C:prop name="RECURRENCE-ID"/>
|
||||||
|
</C:comp>
|
||||||
|
<C:comp name="VTIMEZONE"/>
|
||||||
|
</C:comp>
|
||||||
|
</C:calendar-data>
|
||||||
|
</D:prop>
|
||||||
|
<C:filter>
|
||||||
|
<C:comp-filter name="VCALENDAR">
|
||||||
|
<C:comp-filter name="VEVENT">
|
||||||
|
<C:time-range start="20060104T000000Z" end="20060105T000000Z"/>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:filter>
|
||||||
|
</C:calendar-query>"#;
|
||||||
|
|
||||||
|
let resp = http
|
||||||
|
.request(
|
||||||
|
reqwest::Method::from_bytes(b"REPORT")?,
|
||||||
|
"http://localhost:8087/alice/calendar/Personal/",
|
||||||
|
)
|
||||||
|
.body(cal_query)
|
||||||
|
.send()?;
|
||||||
|
assert_eq!(resp.status(), 207);
|
||||||
|
let multistatus = dav_deserialize::<dav::Multistatus<All>>(&resp.text()?);
|
||||||
|
assert_eq!(multistatus.responses.len(), 1);
|
||||||
|
check_cal(
|
||||||
|
&multistatus,
|
||||||
|
(
|
||||||
|
"/alice/calendar/Personal/rfc3.ics",
|
||||||
|
Some(obj3_etag.to_str().expect("etag header convertible to str")),
|
||||||
|
Some(ICAL_RFC3_STRIPPED),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|
|
@ -125,6 +125,34 @@ END:VEVENT
|
||||||
END:VCALENDAR
|
END:VCALENDAR
|
||||||
";
|
";
|
||||||
|
|
||||||
|
pub static ICAL_RFC3_STRIPPED: &[u8] = b"BEGIN:VCALENDAR\r
|
||||||
|
VERSION:2.0\r
|
||||||
|
BEGIN:VTIMEZONE\r
|
||||||
|
LAST-MODIFIED:20040110T032845Z\r
|
||||||
|
TZID:US/Eastern\r
|
||||||
|
BEGIN:DAYLIGHT\r
|
||||||
|
DTSTART:20000404T020000\r
|
||||||
|
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4\r
|
||||||
|
TZNAME:EDT\r
|
||||||
|
TZOFFSETFROM:-0500\r
|
||||||
|
TZOFFSETTO:-0400\r
|
||||||
|
END:DAYLIGHT\r
|
||||||
|
BEGIN:STANDARD\r
|
||||||
|
DTSTART:20001026T020000\r
|
||||||
|
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r
|
||||||
|
TZNAME:EST\r
|
||||||
|
TZOFFSETFROM:-0400\r
|
||||||
|
TZOFFSETTO:-0500\r
|
||||||
|
END:STANDARD\r
|
||||||
|
END:VTIMEZONE\r
|
||||||
|
BEGIN:VEVENT\r
|
||||||
|
DTSTART;TZID=US/Eastern:20060104T100000\r
|
||||||
|
DURATION:PT1H\r
|
||||||
|
UID:DC6C50A017428C5216A2F1CD@example.com\r
|
||||||
|
END:VEVENT\r
|
||||||
|
END:VCALENDAR\r
|
||||||
|
";
|
||||||
|
|
||||||
pub static ICAL_RFC4: &[u8] = br#"BEGIN:VCALENDAR
|
pub static ICAL_RFC4: &[u8] = br#"BEGIN:VCALENDAR
|
||||||
VERSION:2.0
|
VERSION:2.0
|
||||||
PRODID:-//Example Corp.//CalDAV Client//EN
|
PRODID:-//Example Corp.//CalDAV Client//EN
|
||||||
|
|
Loading…
Reference in a new issue