diff --git a/crates/caldav/src/calendar/methods/report/mod.rs b/crates/caldav/src/calendar/methods/report/mod.rs index 9e1ec56..739bd7f 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_typed(&path, prop, puri, user)?, + .propfind(&path, prop, 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 7686c75..33c762d 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_typed(&path, &sync_collection.prop, puri, user)?, + .propfind(&path, &sync_collection.prop, puri, user)?, ); } diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index 89f883d..706d85c 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -100,6 +100,8 @@ impl Resource for CalendarResource { type Error = Error; type Principal = User; + const IS_COLLECTION: bool = true; + fn get_resourcetype(&self) -> Resourcetype { if self.cal.subscription_url.is_none() { Resourcetype(&[ diff --git a/crates/caldav/src/calendar/service.rs b/crates/caldav/src/calendar/service.rs index 9a41e10..62244e6 100644 --- a/crates/caldav/src/calendar/service.rs +++ b/crates/caldav/src/calendar/service.rs @@ -50,7 +50,6 @@ impl ResourceService for CalendarResourc type PrincipalUri = CalDavPrincipalUri; const DAV_HEADER: &str = "1, 3, access-control, calendar-access"; - const IS_COLLECTION: bool = true; async fn get_resource( &self, diff --git a/crates/caldav/src/calendar_object/resource.rs b/crates/caldav/src/calendar_object/resource.rs index 489d4de..16f5d0e 100644 --- a/crates/caldav/src/calendar_object/resource.rs +++ b/crates/caldav/src/calendar_object/resource.rs @@ -27,6 +27,8 @@ impl Resource for CalendarObjectResource { type Error = Error; type Principal = User; + const IS_COLLECTION: bool = false; + fn get_resourcetype(&self) -> Resourcetype { Resourcetype(&[]) } diff --git a/crates/caldav/src/calendar_object/service.rs b/crates/caldav/src/calendar_object/service.rs index bf15dd0..bd8106b 100644 --- a/crates/caldav/src/calendar_object/service.rs +++ b/crates/caldav/src/calendar_object/service.rs @@ -50,7 +50,6 @@ impl ResourceService for CalendarObjectResourceService { type PrincipalUri = CalDavPrincipalUri; const DAV_HEADER: &str = "1, 3, access-control, calendar-access"; - const IS_COLLECTION: bool = false; async fn get_resource( &self, diff --git a/crates/caldav/src/calendar_set/mod.rs b/crates/caldav/src/calendar_set/mod.rs index 5b702d7..20cfb59 100644 --- a/crates/caldav/src/calendar_set/mod.rs +++ b/crates/caldav/src/calendar_set/mod.rs @@ -28,6 +28,8 @@ impl Resource for CalendarSetResource { type Error = Error; type Principal = User; + const IS_COLLECTION: bool = true; + fn get_resourcetype(&self) -> Resourcetype { Resourcetype(&[ResourcetypeInner( Some(rustical_dav::namespace::NS_DAV), diff --git a/crates/caldav/src/calendar_set/service.rs b/crates/caldav/src/calendar_set/service.rs index bdd644d..68d15da 100644 --- a/crates/caldav/src/calendar_set/service.rs +++ b/crates/caldav/src/calendar_set/service.rs @@ -45,7 +45,6 @@ impl ResourceService for CalendarSetReso type PrincipalUri = CalDavPrincipalUri; const DAV_HEADER: &str = "1, 3, access-control, extended-mkcol, calendar-access"; - const IS_COLLECTION: bool = true; async fn get_resource( &self, diff --git a/crates/caldav/src/principal/mod.rs b/crates/caldav/src/principal/mod.rs index 3723cf4..f6d8ff0 100644 --- a/crates/caldav/src/principal/mod.rs +++ b/crates/caldav/src/principal/mod.rs @@ -27,6 +27,8 @@ impl Resource for PrincipalResource { type Error = Error; type Principal = User; + const IS_COLLECTION: bool = true; + fn get_resourcetype(&self) -> Resourcetype { Resourcetype(&[ ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "collection"), diff --git a/crates/caldav/src/principal/service.rs b/crates/caldav/src/principal/service.rs index cf2e90f..ee6099a 100644 --- a/crates/caldav/src/principal/service.rs +++ b/crates/caldav/src/principal/service.rs @@ -46,7 +46,6 @@ impl Resourcetype { Resourcetype(&[]) } diff --git a/crates/carddav/src/address_object/service.rs b/crates/carddav/src/address_object/service.rs index 6bca921..f81754f 100644 --- a/crates/carddav/src/address_object/service.rs +++ b/crates/carddav/src/address_object/service.rs @@ -41,7 +41,6 @@ impl ResourceService for AddressObjectResourceService type PrincipalUri = CardDavPrincipalUri; const DAV_HEADER: &str = "1, 3, access-control, addressbook"; - const IS_COLLECTION: bool = false; async fn get_resource( &self, diff --git a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs index c7c0760..4c0da9e 100644 --- a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs +++ b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs @@ -80,7 +80,7 @@ pub async fn handle_addressbook_multiget( object, principal: principal.to_owned(), } - .propfind_typed(&path, prop, puri, user)?, + .propfind(&path, prop, 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 61bfc37..25a15dc 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_typed(&path, &sync_collection.prop, puri, user)?, + .propfind(&path, &sync_collection.prop, puri, user)?, ); } diff --git a/crates/carddav/src/addressbook/resource.rs b/crates/carddav/src/addressbook/resource.rs index 80d2ad7..6a6cc68 100644 --- a/crates/carddav/src/addressbook/resource.rs +++ b/crates/carddav/src/addressbook/resource.rs @@ -38,6 +38,8 @@ impl Resource for AddressbookResource { type Error = Error; type Principal = User; + const IS_COLLECTION: bool = true; + fn get_resourcetype(&self) -> Resourcetype { Resourcetype(&[ ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "collection"), diff --git a/crates/carddav/src/addressbook/service.rs b/crates/carddav/src/addressbook/service.rs index 4383dee..71daaec 100644 --- a/crates/carddav/src/addressbook/service.rs +++ b/crates/carddav/src/addressbook/service.rs @@ -52,7 +52,6 @@ impl ResourceService type PrincipalUri = CardDavPrincipalUri; const DAV_HEADER: &str = "1, 3, access-control, addressbook"; - const IS_COLLECTION: bool = true; async fn get_resource( &self, diff --git a/crates/carddav/src/principal/mod.rs b/crates/carddav/src/principal/mod.rs index 7ffcd18..252a992 100644 --- a/crates/carddav/src/principal/mod.rs +++ b/crates/carddav/src/principal/mod.rs @@ -26,6 +26,8 @@ impl Resource for PrincipalResource { type Error = Error; type Principal = User; + const IS_COLLECTION: bool = true; + fn get_resourcetype(&self) -> Resourcetype { Resourcetype(&[ ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "collection"), diff --git a/crates/carddav/src/principal/service.rs b/crates/carddav/src/principal/service.rs index 4925c3a..5edd65f 100644 --- a/crates/carddav/src/principal/service.rs +++ b/crates/carddav/src/principal/service.rs @@ -55,7 +55,6 @@ impl Reso type PrincipalUri = CardDavPrincipalUri; const DAV_HEADER: &str = "1, 3, access-control, addressbook"; - const IS_COLLECTION: bool = true; async fn get_resource( &self, diff --git a/crates/dav/src/resource/methods/propfind.rs b/crates/dav/src/resource/methods/propfind.rs index e2b176e..4f10719 100644 --- a/crates/dav/src/resource/methods/propfind.rs +++ b/crates/dav/src/resource/methods/propfind.rs @@ -76,13 +76,8 @@ pub(crate) async fn route_propfind( let mut member_responses = Vec::new(); if depth != &Depth::Zero { for member in resource_service.get_members(path_components).await? { - // Collections should have a trailing slash - let mut name = member.get_name(); - if R::IS_COLLECTION { - name.push('/') - } - member_responses.push(member.propfind_typed( - &format!("{}/{}", path.trim_end_matches('/'), name), + member_responses.push(member.propfind( + &format!("{}/{}", path.trim_end_matches('/'), member.get_name()), &propfind_member.prop, puri, principal, @@ -90,7 +85,7 @@ pub(crate) async fn route_propfind( } } - let response = resource.propfind_typed(path, &propfind_self.prop, puri, principal)?; + let response = resource.propfind(path, &propfind_self.prop, puri, principal)?; Ok(MultistatusElement { responses: vec![response], diff --git a/crates/dav/src/resource/mod.rs b/crates/dav/src/resource/mod.rs index f73e1a9..c063ce0 100644 --- a/crates/dav/src/resource/mod.rs +++ b/crates/dav/src/resource/mod.rs @@ -37,6 +37,8 @@ pub trait Resource: Clone + Send + 'static { type Error: From; type Principal: Principal; + const IS_COLLECTION: bool; + fn get_resourcetype(&self) -> Resourcetype; fn list_props() -> Vec<(Option>, &'static str)> { @@ -95,13 +97,19 @@ pub trait Resource: Clone + Send + 'static { principal: &Self::Principal, ) -> Result; - fn propfind_typed( + fn propfind( &self, path: &str, prop: &PropfindType<::Names>, principal_uri: &impl PrincipalUri, principal: &Self::Principal, ) -> Result, Self::Error> { + // Collections have a trailing slash + let mut path = path.to_string(); + if Self::IS_COLLECTION && !path.ends_with('/') { + path.push('/'); + } + // TODO: Support include element let (props, invalid_props): (HashSet<::Names>, Vec<_>) = match prop { diff --git a/crates/dav/src/resource/resource_service.rs b/crates/dav/src/resource/resource_service.rs index 49fcf0d..83c8ccb 100644 --- a/crates/dav/src/resource/resource_service.rs +++ b/crates/dav/src/resource/resource_service.rs @@ -18,7 +18,6 @@ pub trait ResourceService: Clone + Sized + Send + Sync + AxumMethods + 'static { type PrincipalUri: PrincipalUri; const DAV_HEADER: &'static str; - const IS_COLLECTION: bool; async fn get_members( &self, diff --git a/crates/dav/src/resources/root.rs b/crates/dav/src/resources/root.rs index 4f5ecb3..bb79496 100644 --- a/crates/dav/src/resources/root.rs +++ b/crates/dav/src/resources/root.rs @@ -24,6 +24,8 @@ impl Resource for RootResource { type Error = PR::Error; type Principal = P; + const IS_COLLECTION: bool = true; + fn get_resourcetype(&self) -> Resourcetype { Resourcetype(&[ResourcetypeInner( Some(crate::namespace::NS_DAV), @@ -77,7 +79,6 @@ where type PrincipalUri = PURI; const DAV_HEADER: &str = "1, 3, access-control"; - const IS_COLLECTION: bool = true; async fn get_resource(&self, _: &()) -> Result { Ok(RootResource::::default())