mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-14 05:52:19 +00:00
WIP: Complete work of propfind parsing
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
use super::ReportPropName;
|
||||
use crate::Error;
|
||||
use crate::{Error, calendar_object::resource::CalendarObjectPropWrapperName};
|
||||
use actix_web::dev::{Path, ResourceDef};
|
||||
use rustical_dav::xml::PropfindType;
|
||||
use rustical_ical::CalendarObject;
|
||||
@@ -11,7 +10,7 @@ use rustical_xml::XmlDeserialize;
|
||||
// <!ELEMENT calendar-query ((DAV:allprop | DAV:propname | DAV:prop)?, href+)>
|
||||
pub(crate) struct CalendarMultigetRequest {
|
||||
#[xml(ty = "untagged")]
|
||||
pub(crate) prop: PropfindType<ReportPropName>,
|
||||
pub(crate) prop: PropfindType<CalendarObjectPropWrapperName>,
|
||||
#[xml(flatten)]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
pub(crate) href: Vec<String>,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use super::ReportPropName;
|
||||
use crate::Error;
|
||||
use crate::{Error, calendar_object::resource::CalendarObjectPropWrapperName};
|
||||
use rustical_dav::xml::PropfindType;
|
||||
use rustical_ical::{CalendarObject, UtcDateTime};
|
||||
use rustical_store::{CalendarStore, calendar_store::CalendarQuery};
|
||||
@@ -171,7 +170,7 @@ impl From<&FilterElement> for CalendarQuery {
|
||||
// <!ELEMENT calendar-query ((DAV:allprop | DAV:propname | DAV:prop)?, filter, timezone?)>
|
||||
pub struct CalendarQueryRequest {
|
||||
#[xml(ty = "untagged")]
|
||||
pub prop: PropfindType<ReportPropName>,
|
||||
pub prop: PropfindType<CalendarObjectPropWrapperName>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) filter: Option<FilterElement>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::{
|
||||
CalDavPrincipalUri, Error,
|
||||
calendar_object::resource::{CalendarObjectPropWrapper, CalendarObjectResource},
|
||||
calendar_object::resource::{
|
||||
CalendarObjectPropWrapper, CalendarObjectPropWrapperName, CalendarObjectResource,
|
||||
},
|
||||
};
|
||||
use actix_web::{
|
||||
HttpRequest, Responder,
|
||||
@@ -12,11 +14,11 @@ use calendar_query::{CalendarQueryRequest, get_objects_calendar_query};
|
||||
use rustical_dav::{
|
||||
resource::{PrincipalUri, Resource},
|
||||
xml::{
|
||||
MultistatusElement, PropElement, PropfindType, Propname, multistatus::ResponseElement,
|
||||
MultistatusElement, PropfindType, multistatus::ResponseElement,
|
||||
sync_collection::SyncCollectionRequest,
|
||||
},
|
||||
};
|
||||
use rustical_ical::{CalendarObject, UtcDateTime};
|
||||
use rustical_ical::CalendarObject;
|
||||
use rustical_store::{CalendarStore, auth::User};
|
||||
use rustical_xml::{XmlDeserialize, XmlDocument};
|
||||
use sync_collection::handle_sync_collection;
|
||||
@@ -26,34 +28,6 @@ mod calendar_multiget;
|
||||
mod calendar_query;
|
||||
mod sync_collection;
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
pub(crate) struct ExpandElement {
|
||||
#[xml(ty = "attr")]
|
||||
start: UtcDateTime,
|
||||
#[xml(ty = "attr")]
|
||||
end: UtcDateTime,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct CalendarData {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
comp: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
expand: Option<ExpandElement>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
limit_recurrence_set: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
limit_freebusy_set: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
pub enum ReportPropName {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
CalendarData(CalendarData),
|
||||
#[xml(other)]
|
||||
Propname(Propname),
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum ReportRequest {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
@@ -61,31 +35,15 @@ pub(crate) enum ReportRequest {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
CalendarQuery(CalendarQueryRequest),
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
SyncCollection(SyncCollectionRequest<ReportPropName>),
|
||||
SyncCollection(SyncCollectionRequest<CalendarObjectPropWrapperName>),
|
||||
}
|
||||
|
||||
impl ReportRequest {
|
||||
fn props(&self) -> Vec<&str> {
|
||||
let prop_element = match self {
|
||||
fn props(&self) -> &PropfindType<CalendarObjectPropWrapperName> {
|
||||
match &self {
|
||||
ReportRequest::CalendarMultiget(CalendarMultigetRequest { prop, .. }) => prop,
|
||||
ReportRequest::CalendarQuery(CalendarQueryRequest { prop, .. }) => prop,
|
||||
ReportRequest::SyncCollection(SyncCollectionRequest { prop, .. }) => prop,
|
||||
};
|
||||
|
||||
match prop_element {
|
||||
PropfindType::Allprop => {
|
||||
vec!["allprop"]
|
||||
}
|
||||
PropfindType::Propname => {
|
||||
vec!["propname"]
|
||||
}
|
||||
PropfindType::Prop(PropElement(prop_tags)) => prop_tags
|
||||
.iter()
|
||||
.map(|propname| match propname {
|
||||
ReportPropName::Propname(propname) => propname.name.as_str(),
|
||||
ReportPropName::CalendarData(_) => "calendar-data",
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +55,7 @@ fn objects_response(
|
||||
principal: &str,
|
||||
puri: &impl PrincipalUri,
|
||||
user: &User,
|
||||
props: &[&str],
|
||||
prop: &PropfindType<CalendarObjectPropWrapperName>,
|
||||
) -> Result<MultistatusElement<CalendarObjectPropWrapper, String>, Error> {
|
||||
let mut responses = Vec::new();
|
||||
for object in objects {
|
||||
@@ -107,7 +65,7 @@ fn objects_response(
|
||||
object,
|
||||
principal: principal.to_owned(),
|
||||
}
|
||||
.propfind(&path, props, puri, user)?,
|
||||
.propfind_typed(&path, prop, puri, user)?,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -156,7 +114,7 @@ pub async fn route_report_calendar<C: CalendarStore>(
|
||||
&principal,
|
||||
puri.as_ref(),
|
||||
&user,
|
||||
&props,
|
||||
props,
|
||||
)?
|
||||
}
|
||||
ReportRequest::CalendarMultiget(cal_multiget) => {
|
||||
@@ -175,13 +133,12 @@ pub async fn route_report_calendar<C: CalendarStore>(
|
||||
&principal,
|
||||
puri.as_ref(),
|
||||
&user,
|
||||
&props,
|
||||
props,
|
||||
)?
|
||||
}
|
||||
ReportRequest::SyncCollection(sync_collection) => {
|
||||
handle_sync_collection(
|
||||
sync_collection,
|
||||
&props,
|
||||
req.path(),
|
||||
puri.as_ref(),
|
||||
&user,
|
||||
@@ -197,10 +154,11 @@ pub async fn route_report_calendar<C: CalendarStore>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::calendar_object::resource::{CalendarData, CalendarObjectPropName, ExpandElement};
|
||||
use calendar_query::{CompFilterElement, FilterElement, TimeRangeElement};
|
||||
use rustical_dav::xml::{PropElement, PropfindType, Propname};
|
||||
use rustical_dav::xml::PropElement;
|
||||
use rustical_ical::UtcDateTime;
|
||||
use rustical_xml::ValueDeserialize;
|
||||
use rustical_xml::{NamespaceOwned, ValueDeserialize};
|
||||
|
||||
#[test]
|
||||
fn test_xml_calendar_data() {
|
||||
@@ -222,13 +180,14 @@ mod tests {
|
||||
report_request,
|
||||
ReportRequest::CalendarMultiget(CalendarMultigetRequest {
|
||||
prop: rustical_dav::xml::PropfindType::Prop(PropElement(vec![
|
||||
ReportPropName::Propname(Propname{name: "getetag".to_owned(), ns: Some("DAV:".into())}),
|
||||
ReportPropName::Propname(Propname{name: "displayname".to_owned(), ns: Some("DAV:".into())}),
|
||||
ReportPropName::CalendarData(CalendarData { comp: None, expand: Some(ExpandElement {
|
||||
CalendarObjectPropWrapperName::CalendarObject(CalendarObjectPropName::Getetag),
|
||||
CalendarObjectPropWrapperName::CalendarObject(CalendarObjectPropName::CalendarData(
|
||||
CalendarData { comp: None, expand: Some(ExpandElement {
|
||||
start: <UtcDateTime as ValueDeserialize>::deserialize("20250426T220000Z").unwrap(),
|
||||
end: <UtcDateTime as ValueDeserialize>::deserialize("20250503T220000Z").unwrap(),
|
||||
}), limit_recurrence_set: None, limit_freebusy_set: None })
|
||||
])),
|
||||
}), limit_recurrence_set: None, limit_freebusy_set: None }
|
||||
)),
|
||||
], vec![(Some(NamespaceOwned(Vec::from("DAV:"))), "displayname".to_string())])),
|
||||
href: vec![
|
||||
"/caldav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned()
|
||||
]
|
||||
@@ -258,10 +217,12 @@ mod tests {
|
||||
assert_eq!(
|
||||
report_request,
|
||||
ReportRequest::CalendarQuery(CalendarQueryRequest {
|
||||
prop: PropfindType::Prop(PropElement(vec![ReportPropName::Propname(Propname {
|
||||
name: "getetag".to_owned(),
|
||||
ns: Some("DAV:".into())
|
||||
})])),
|
||||
prop: rustical_dav::xml::PropfindType::Prop(PropElement(
|
||||
vec![CalendarObjectPropWrapperName::CalendarObject(
|
||||
CalendarObjectPropName::Getetag
|
||||
),],
|
||||
vec![]
|
||||
)),
|
||||
filter: Some(FilterElement {
|
||||
comp_filter: CompFilterElement {
|
||||
is_not_defined: None,
|
||||
@@ -308,9 +269,8 @@ mod tests {
|
||||
report_request,
|
||||
ReportRequest::CalendarMultiget(CalendarMultigetRequest {
|
||||
prop: rustical_dav::xml::PropfindType::Prop(PropElement(vec![
|
||||
ReportPropName::Propname(Propname{name: "getetag".to_owned(), ns: Some("DAV:".into())}),
|
||||
ReportPropName::Propname(Propname{name: "displayname".to_owned(), ns: Some("DAV:".into())})
|
||||
])),
|
||||
CalendarObjectPropWrapperName::CalendarObject(CalendarObjectPropName::Getetag),
|
||||
], vec![(Some(NamespaceOwned(Vec::from("DAV:"))), "displayname".to_string())])),
|
||||
href: vec![
|
||||
"/caldav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned()
|
||||
]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::ReportPropName;
|
||||
use crate::{
|
||||
Error,
|
||||
calendar_object::resource::{CalendarObjectPropWrapper, CalendarObjectResource},
|
||||
calendar_object::resource::{
|
||||
CalendarObjectPropWrapper, CalendarObjectPropWrapperName, CalendarObjectResource,
|
||||
},
|
||||
};
|
||||
use actix_web::http::StatusCode;
|
||||
use rustical_dav::{
|
||||
@@ -17,8 +18,7 @@ use rustical_store::{
|
||||
};
|
||||
|
||||
pub async fn handle_sync_collection<C: CalendarStore>(
|
||||
sync_collection: &SyncCollectionRequest<ReportPropName>,
|
||||
props: &[&str],
|
||||
sync_collection: &SyncCollectionRequest<CalendarObjectPropWrapperName>,
|
||||
path: &str,
|
||||
puri: &impl PrincipalUri,
|
||||
user: &User,
|
||||
@@ -39,7 +39,7 @@ pub async fn handle_sync_collection<C: CalendarStore>(
|
||||
object,
|
||||
principal: principal.to_owned(),
|
||||
}
|
||||
.propfind(&path, props, puri, user)?,
|
||||
.propfind_typed(&path, &sync_collection.prop, puri, user)?,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ use rustical_dav_push::{DavPushExtension, DavPushExtensionProp};
|
||||
use rustical_ical::CalDateTime;
|
||||
use rustical_store::auth::User;
|
||||
use rustical_store::{Calendar, CalendarStore, SubscriptionStore};
|
||||
use rustical_xml::{EnumUnitVariants, EnumVariants};
|
||||
use rustical_xml::{EnumVariants, PropName};
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)]
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
|
||||
#[xml(unit_variants_ident = "CalendarPropName")]
|
||||
pub enum CalendarProp {
|
||||
// WebDAV (RFC 2518)
|
||||
@@ -64,7 +64,7 @@ pub enum CalendarProp {
|
||||
MaxDateTime(String),
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)]
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
|
||||
#[xml(unit_variants_ident = "CalendarPropWrapperName", untagged)]
|
||||
pub enum CalendarPropWrapper {
|
||||
Calendar(CalendarProp),
|
||||
|
||||
@@ -9,9 +9,9 @@ use rustical_dav::{
|
||||
resource::{PrincipalUri, Resource, ResourceService},
|
||||
xml::Resourcetype,
|
||||
};
|
||||
use rustical_ical::CalendarObject;
|
||||
use rustical_ical::{CalendarObject, UtcDateTime};
|
||||
use rustical_store::{CalendarStore, auth::User};
|
||||
use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize};
|
||||
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -25,7 +25,27 @@ impl<C: CalendarStore> CalendarObjectResourceService<C> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)]
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct ExpandElement {
|
||||
#[xml(ty = "attr")]
|
||||
pub(crate) start: UtcDateTime,
|
||||
#[xml(ty = "attr")]
|
||||
pub(crate) end: UtcDateTime,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq, Default, Eq, Hash)]
|
||||
pub struct CalendarData {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) comp: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) expand: Option<ExpandElement>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) limit_recurrence_set: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) limit_freebusy_set: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
|
||||
#[xml(unit_variants_ident = "CalendarObjectPropName")]
|
||||
pub enum CalendarObjectProp {
|
||||
// WebDAV (RFC 2518)
|
||||
@@ -36,10 +56,11 @@ pub enum CalendarObjectProp {
|
||||
|
||||
// CalDAV (RFC 4791)
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
#[xml(prop = "CalendarData")]
|
||||
CalendarData(String),
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)]
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
|
||||
#[xml(unit_variants_ident = "CalendarObjectPropWrapperName", untagged)]
|
||||
pub enum CalendarObjectPropWrapper {
|
||||
CalendarObject(CalendarObjectProp),
|
||||
@@ -73,8 +94,15 @@ impl Resource for CalendarObjectResource {
|
||||
CalendarObjectPropName::Getetag => {
|
||||
CalendarObjectProp::Getetag(self.object.get_etag())
|
||||
}
|
||||
CalendarObjectPropName::CalendarData => {
|
||||
CalendarObjectProp::CalendarData(self.object.get_ics().to_owned())
|
||||
CalendarObjectPropName::CalendarData(CalendarData { expand, .. }) => {
|
||||
CalendarObjectProp::CalendarData(if let Some(expand) = expand.as_ref() {
|
||||
self.object.expand_recurrence(
|
||||
Some(expand.start.to_utc()),
|
||||
Some(expand.end.to_utc()),
|
||||
)?
|
||||
} else {
|
||||
self.object.get_ics().to_owned()
|
||||
})
|
||||
}
|
||||
CalendarObjectPropName::Getcontenttype => {
|
||||
CalendarObjectProp::Getcontenttype("text/calendar;charset=utf-8")
|
||||
|
||||
@@ -8,7 +8,7 @@ use rustical_dav::resource::{PrincipalUri, Resource, ResourceService};
|
||||
use rustical_dav::xml::{Resourcetype, ResourcetypeInner};
|
||||
use rustical_store::auth::User;
|
||||
use rustical_store::{CalendarStore, SubscriptionStore};
|
||||
use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize};
|
||||
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -17,7 +17,7 @@ pub struct CalendarSetResource {
|
||||
pub(crate) read_only: bool,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)]
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
|
||||
#[xml(unit_variants_ident = "PrincipalPropWrapperName", untagged)]
|
||||
pub enum PrincipalPropWrapper {
|
||||
Common(CommonPropertiesProp),
|
||||
|
||||
@@ -9,7 +9,7 @@ use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner};
|
||||
use rustical_store::auth::user::PrincipalType;
|
||||
use rustical_store::auth::{AuthenticationProvider, User};
|
||||
use rustical_store::{CalendarStore, SubscriptionStore};
|
||||
use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize};
|
||||
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -21,7 +21,7 @@ pub struct PrincipalResource {
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
|
||||
pub struct CalendarHomeSet(#[xml(ty = "untagged", flatten)] Vec<HrefElement>);
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)]
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
|
||||
#[xml(unit_variants_ident = "PrincipalPropName")]
|
||||
pub enum PrincipalProp {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
@@ -42,7 +42,7 @@ pub enum PrincipalProp {
|
||||
CalendarHomeSet(CalendarHomeSet),
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)]
|
||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
|
||||
#[xml(unit_variants_ident = "PrincipalPropWrapperName", untagged)]
|
||||
pub enum PrincipalPropWrapper {
|
||||
Principal(PrincipalProp),
|
||||
|
||||
Reference in New Issue
Block a user