rustical_caldav/calendar/methods/report/calendar_query/
mod.rs1use crate::Error;
2use rustical_ical::CalendarObject;
3use rustical_store::CalendarStore;
4
5mod comp_filter;
6mod elements;
7mod prop_filter;
8#[cfg(test)]
9mod tests;
10#[allow(unused_imports)]
11pub use comp_filter::{CompFilterElement, CompFilterable};
12pub use elements::*;
13#[allow(unused_imports)]
14pub use prop_filter::PropFilterElement;
15
16pub async fn get_objects_calendar_query<C: CalendarStore>(
17 cal_query: &CalendarQueryRequest,
18 principal: &str,
19 cal_id: &str,
20 store: &C,
21) -> Result<Vec<(String, CalendarObject)>, Error> {
22 let mut objects = store
23 .calendar_query(principal, cal_id, cal_query.into())
24 .await?;
25 if let Some(filter) = &cal_query.filter {
26 objects.retain(|(_id, object)| filter.matches(object.get_inner()));
27 }
28 Ok(objects)
29}
30
31#[cfg(test)]
32mod xml_tests {
33 use super::{
34 CalendarQueryRequest, FilterElement, ParamFilterElement, comp_filter::CompFilterElement,
35 prop_filter::PropFilterElement,
36 };
37 use crate::{
38 calendar::methods::report::ReportRequest,
39 calendar_object::{CalendarData, CalendarObjectPropName, CalendarObjectPropWrapperName},
40 };
41 use rustical_dav::xml::{
42 MatchType, NegateCondition, PropElement, TextCollation, TextMatchElement,
43 };
44 use rustical_xml::XmlDocument;
45
46 #[test]
47 fn calendar_query_7_8_7() {
48 const INPUT: &str = r#"
49 <?xml version="1.0" encoding="utf-8" ?>
50 <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
51 <D:prop xmlns:D="DAV:">
52 <D:getetag/>
53 <C:calendar-data/>
54 </D:prop>
55 <C:filter>
56 <C:comp-filter name="VCALENDAR">
57 <C:comp-filter name="VEVENT">
58 <C:prop-filter name="ATTENDEE">
59 <C:text-match collation="i;ascii-casemap">mailto:lisa@example.com</C:text-match>
60 <C:param-filter name="PARTSTAT">
61 <C:text-match collation="i;ascii-casemap">NEEDS-ACTION</C:text-match>
62 </C:param-filter>
63 </C:prop-filter>
64 </C:comp-filter>
65 </C:comp-filter>
66 </C:filter>
67 </C:calendar-query>
68 "#;
69
70 let report = ReportRequest::parse_str(INPUT).unwrap();
71 let calendar_query: CalendarQueryRequest =
72 if let ReportRequest::CalendarQuery(query) = report {
73 query
74 } else {
75 panic!()
76 };
77 assert_eq!(
78 calendar_query,
79 CalendarQueryRequest {
80 prop: rustical_dav::xml::PropfindType::Prop(PropElement(
81 vec![
82 CalendarObjectPropWrapperName::CalendarObject(
83 CalendarObjectPropName::Getetag,
84 ),
85 CalendarObjectPropWrapperName::CalendarObject(
86 CalendarObjectPropName::CalendarData(CalendarData::default())
87 ),
88 ],
89 vec![]
90 )),
91 filter: Some(FilterElement {
92 comp_filter: CompFilterElement {
93 is_not_defined: None,
94 time_range: None,
95 prop_filter: vec![],
96 comp_filter: vec![CompFilterElement {
97 prop_filter: vec![PropFilterElement {
98 name: "ATTENDEE".to_owned(),
99 text_match: Some(TextMatchElement {
100 match_type: MatchType::Contains,
101 collation: TextCollation::AsciiCasemap,
102 negate_condition: NegateCondition(false),
103 needle: "mailto:lisa@example.com".to_string()
104 }),
105 is_not_defined: None,
106 param_filter: vec![ParamFilterElement {
107 is_not_defined: None,
108 name: "PARTSTAT".to_owned(),
109 text_match: Some(TextMatchElement {
110 match_type: MatchType::Contains,
111 collation: TextCollation::AsciiCasemap,
112 negate_condition: NegateCondition(false),
113 needle: "NEEDS-ACTION".to_string()
114 }),
115 }],
116 time_range: None
117 }],
118 comp_filter: vec![],
119 is_not_defined: None,
120 name: "VEVENT".to_owned(),
121 time_range: None
122 }],
123 name: "VCALENDAR".to_owned()
124 }
125 }),
126 timezone: None,
127 timezone_id: None
128 }
129 );
130 }
131}