From 2774d092ac8fb5e12d77a9f59ca9c4a920ee923e Mon Sep 17 00:00:00 2001
From: Lennart <18233294+lennart-k@users.noreply.github.com>
Date: Thu, 10 Jul 2025 15:45:54 +0200
Subject: [PATCH] propfind: Implement
Implements #95
---
.../caldav/src/calendar/methods/report/mod.rs | 2 +-
.../methods/report/sync_collection.rs | 2 +-
.../methods/report/addressbook_multiget.rs | 2 +-
.../methods/report/sync_collection.rs | 2 +-
crates/dav/src/resource/methods/propfind.rs | 11 +++-
crates/dav/src/resource/mod.rs | 63 ++++++++++---------
crates/dav/src/xml/propfind.rs | 3 +-
7 files changed, 50 insertions(+), 35 deletions(-)
diff --git a/crates/caldav/src/calendar/methods/report/mod.rs b/crates/caldav/src/calendar/methods/report/mod.rs
index f6de9b0..9af5cba 100644
--- a/crates/caldav/src/calendar/methods/report/mod.rs
+++ b/crates/caldav/src/calendar/methods/report/mod.rs
@@ -67,7 +67,7 @@ fn objects_response(
object,
principal: principal.to_owned(),
}
- .propfind(&path, prop, puri, user)?,
+ .propfind(&path, prop, None, puri, user)?,
);
}
diff --git a/crates/caldav/src/calendar/methods/report/sync_collection.rs b/crates/caldav/src/calendar/methods/report/sync_collection.rs
index fa0479f..7b70f20 100644
--- a/crates/caldav/src/calendar/methods/report/sync_collection.rs
+++ b/crates/caldav/src/calendar/methods/report/sync_collection.rs
@@ -39,7 +39,7 @@ pub async fn handle_sync_collection(
object,
principal: principal.to_owned(),
}
- .propfind(&path, &sync_collection.prop, puri, user)?,
+ .propfind(&path, &sync_collection.prop, None, puri, user)?,
);
}
diff --git a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs
index d156b4f..a3bf595 100644
--- a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs
+++ b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs
@@ -81,7 +81,7 @@ pub async fn handle_addressbook_multiget(
object,
principal: principal.to_owned(),
}
- .propfind(&path, prop, puri, user)?,
+ .propfind(&path, prop, None, puri, user)?,
);
}
diff --git a/crates/carddav/src/addressbook/methods/report/sync_collection.rs b/crates/carddav/src/addressbook/methods/report/sync_collection.rs
index b4dfd33..f27837b 100644
--- a/crates/carddav/src/addressbook/methods/report/sync_collection.rs
+++ b/crates/carddav/src/addressbook/methods/report/sync_collection.rs
@@ -39,7 +39,7 @@ pub async fn handle_sync_collection(
object,
principal: principal.to_owned(),
}
- .propfind(&path, &sync_collection.prop, puri, user)?,
+ .propfind(&path, &sync_collection.prop, None, puri, user)?,
);
}
diff --git a/crates/dav/src/resource/methods/propfind.rs b/crates/dav/src/resource/methods/propfind.rs
index e8c610f..daed710 100644
--- a/crates/dav/src/resource/methods/propfind.rs
+++ b/crates/dav/src/resource/methods/propfind.rs
@@ -64,6 +64,7 @@ pub(crate) async fn route_propfind(
} else {
PropfindElement {
prop: PropfindType::Allprop,
+ include: None,
}
};
let propfind_member: PropfindElement<<::Prop as PropName>::Names> =
@@ -72,6 +73,7 @@ pub(crate) async fn route_propfind(
} else {
PropfindElement {
prop: PropfindType::Allprop,
+ include: None,
}
};
@@ -82,13 +84,20 @@ pub(crate) async fn route_propfind(
member_responses.push(member.propfind(
&format!("{}/{}", path.trim_end_matches('/'), member.get_name()),
&propfind_member.prop,
+ propfind_member.include.as_ref(),
puri,
principal,
)?);
}
}
- let response = resource.propfind(path, &propfind_self.prop, puri, principal)?;
+ let response = resource.propfind(
+ path,
+ &propfind_self.prop,
+ propfind_self.include.as_ref(),
+ puri,
+ principal,
+ )?;
Ok(MultistatusElement {
responses: vec![response],
diff --git a/crates/dav/src/resource/mod.rs b/crates/dav/src/resource/mod.rs
index c5afa79..79b39c9 100644
--- a/crates/dav/src/resource/mod.rs
+++ b/crates/dav/src/resource/mod.rs
@@ -106,6 +106,7 @@ pub trait Resource: Clone + Send + 'static {
&self,
path: &str,
prop: &PropfindType<::Names>,
+ include: Option<&PropElement<::Names>>,
principal_uri: &impl PrincipalUri,
principal: &Self::Principal,
) -> Result, Self::Error> {
@@ -115,36 +116,40 @@ pub trait Resource: Clone + Send + 'static {
path.push('/');
}
- // TODO: Support include element
- let (props, invalid_props): (HashSet<::Names>, Vec<_>) = match prop
- {
- PropfindType::Propname => {
- let props = Self::list_props()
- .into_iter()
- .map(|(ns, tag)| (ns.map(NamespaceOwned::from), tag.to_string()))
- .collect_vec();
+ let (mut props, mut invalid_props): (HashSet<::Names>, Vec<_>) =
+ match prop {
+ PropfindType::Propname => {
+ let props = Self::list_props()
+ .into_iter()
+ .map(|(ns, tag)| (ns.map(NamespaceOwned::from), tag.to_string()))
+ .collect_vec();
- return Ok(ResponseElement {
- href: path.to_owned(),
- propstat: vec![PropstatWrapper::TagList(PropstatElement {
- prop: TagList::from(props),
- status: StatusCode::OK,
- })],
- ..Default::default()
- });
- }
- PropfindType::Allprop => (
- Self::list_props()
- .iter()
- .map(|(_ns, name)| ::Names::from_str(name).unwrap())
- .collect(),
- vec![],
- ),
- PropfindType::Prop(PropElement(valid_tags, invalid_tags)) => (
- valid_tags.iter().cloned().collect(),
- invalid_tags.to_owned(),
- ),
- };
+ return Ok(ResponseElement {
+ href: path.to_owned(),
+ propstat: vec![PropstatWrapper::TagList(PropstatElement {
+ prop: TagList::from(props),
+ status: StatusCode::OK,
+ })],
+ ..Default::default()
+ });
+ }
+ PropfindType::Allprop => (
+ Self::list_props()
+ .iter()
+ .map(|(_ns, name)| ::Names::from_str(name).unwrap())
+ .collect(),
+ vec![],
+ ),
+ PropfindType::Prop(PropElement(valid_tags, invalid_tags)) => (
+ valid_tags.iter().cloned().collect(),
+ invalid_tags.to_owned(),
+ ),
+ };
+
+ if let Some(PropElement(valid_tags, invalid_tags)) = include {
+ props.extend(valid_tags.clone());
+ invalid_props.extend(invalid_tags.to_owned());
+ }
let prop_responses = props
.into_iter()
diff --git a/crates/dav/src/xml/propfind.rs b/crates/dav/src/xml/propfind.rs
index c8232c9..587bbc3 100644
--- a/crates/dav/src/xml/propfind.rs
+++ b/crates/dav/src/xml/propfind.rs
@@ -11,10 +11,11 @@ use rustical_xml::XmlRootTag;
pub struct PropfindElement {
#[xml(ty = "untagged")]
pub prop: PropfindType,
+ #[xml(ns = "crate::namespace::NS_DAV")]
+ pub include: Option>,
}
#[derive(Debug, Clone, PartialEq)]
-// pub struct PropElement(#[xml(ty = "untagged", flatten)] pub Vec);
pub struct PropElement(
// valid
pub Vec,