diff --git a/crates/caldav/src/calendar/service.rs b/crates/caldav/src/calendar/service.rs index a82c96a..aed3cb8 100644 --- a/crates/caldav/src/calendar/service.rs +++ b/crates/caldav/src/calendar/service.rs @@ -50,7 +50,7 @@ impl ResourceService for CalendarResourc type Principal = User; type PrincipalUri = CalDavPrincipalUri; - const DAV_HEADER: &str = "1, 3, access-control, calendar-access"; + const DAV_HEADER: &str = "1, 3, access-control, calendar-access, calendar-proxy"; async fn get_resource( &self, diff --git a/crates/caldav/src/principal/mod.rs b/crates/caldav/src/principal/mod.rs index 5077a4d..ce9b35e 100644 --- a/crates/caldav/src/principal/mod.rs +++ b/crates/caldav/src/principal/mod.rs @@ -2,7 +2,7 @@ use crate::Error; use rustical_dav::extensions::CommonPropertiesExtension; use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::resource::{PrincipalUri, Resource, ResourceName}; -use rustical_dav::xml::{Resourcetype, ResourcetypeInner}; +use rustical_dav::xml::{Resourcetype, ResourcetypeInner, SupportedReportSet}; use rustical_store::auth::User; mod service; @@ -13,6 +13,7 @@ pub use prop::*; #[derive(Clone)] pub struct PrincipalResource { principal: User, + members: Vec, } impl ResourceName for PrincipalResource { @@ -32,6 +33,11 @@ impl Resource for PrincipalResource { Resourcetype(&[ ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "collection"), ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "principal"), + // https://github.com/apple/ccs-calendarserver/blob/13c706b985fb728b9aab42dc0fef85aae21921c3/doc/Extensions/caldav-proxy.txt + ResourcetypeInner( + Some(rustical_dav::namespace::NS_CALENDARSERVER), + "calendar-proxy-write", + ), ]) } @@ -64,6 +70,14 @@ impl Resource for PrincipalResource { PrincipalPropName::CalendarUserAddressSet => { PrincipalProp::CalendarUserAddressSet(principal_url.into()) } + PrincipalPropName::GroupMemberSet => { + PrincipalProp::GroupMemberSet(GroupMemberSet( + self.members + .iter() + .map(|principal| puri.principal_uri(principal).into()) + .collect(), + )) + } PrincipalPropName::GroupMembership => { PrincipalProp::GroupMembership(GroupMembership( self.principal @@ -79,6 +93,9 @@ impl Resource for PrincipalResource { puri.principal_collection().into(), )) } + PrincipalPropName::SupportedReportSet => { + PrincipalProp::SupportedReportSet(SupportedReportSet::all()) + } }) } PrincipalPropWrapperName::Common(prop) => PrincipalPropWrapper::Common( diff --git a/crates/caldav/src/principal/prop.rs b/crates/caldav/src/principal/prop.rs index f62eb29..b46a3cb 100644 --- a/crates/caldav/src/principal/prop.rs +++ b/crates/caldav/src/principal/prop.rs @@ -1,6 +1,10 @@ -use rustical_dav::{extensions::CommonPropertiesProp, xml::HrefElement}; +use rustical_dav::{ + extensions::CommonPropertiesProp, + xml::{HrefElement, SupportedReportSet}, +}; use rustical_store::auth::user::PrincipalType; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; +use strum_macros::VariantArray; #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "PrincipalPropName")] @@ -16,10 +20,14 @@ pub enum PrincipalProp { PrincipalUrl(HrefElement), #[xml(ns = "rustical_dav::namespace::NS_DAV")] GroupMembership(GroupMembership), + #[xml(ns = "rustical_dav::namespace::NS_DAV")] + GroupMemberSet(GroupMemberSet), #[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"alternate-URI-set")] AlternateUriSet, #[xml(ns = "rustical_dav::namespace::NS_DAV")] PrincipalCollectionSet(PrincipalCollectionSet), + #[xml(ns = "rustical_dav::namespace::NS_DAV", skip_deserializing)] + SupportedReportSet(SupportedReportSet), // CalDAV (RFC 4791) #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] @@ -39,5 +47,15 @@ pub struct CalendarHomeSet(#[xml(ty = "untagged", flatten)] pub(super) Vec); +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] +pub struct GroupMemberSet(#[xml(ty = "untagged", flatten)] pub(super) Vec); + #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] pub struct PrincipalCollectionSet(#[xml(ty = "untagged")] pub(super) HrefElement); + +#[derive(XmlSerialize, PartialEq, Clone, VariantArray)] +pub enum ReportMethod { + // We don't actually support principal-match + #[xml(ns = "rustical_dav::namespace::NS_DAV")] + PrincipalMatch, +} diff --git a/crates/caldav/src/principal/service.rs b/crates/caldav/src/principal/service.rs index b24cbcf..e8b72ef 100644 --- a/crates/caldav/src/principal/service.rs +++ b/crates/caldav/src/principal/service.rs @@ -43,7 +43,7 @@ impl Resour type Principal = User; type PrincipalUri = CalDavPrincipalUri; - const DAV_HEADER: &str = "1, 3, access-control, calendar-access"; + const DAV_HEADER: &str = "1, 3, access-control, calendar-access, calendar-proxy"; async fn get_resource( &self, @@ -54,7 +54,10 @@ impl Resour .get_principal(principal) .await? .ok_or(crate::Error::NotFound)?; - Ok(PrincipalResource { principal: user }) + Ok(PrincipalResource { + members: self.auth_provider.list_members(&user.id).await?, + principal: user, + }) } async fn get_members(