Add group-membership to both caldav and carddav and fix addressbook-home-set for shared principals

This commit is contained in:
Lennart
2025-06-12 20:55:22 +02:00
parent 1757bbee13
commit 32bc8c707d
7 changed files with 42 additions and 20 deletions

View File

@@ -2,7 +2,9 @@ use crate::Error;
use rustical_dav::extensions::CommonPropertiesExtension; use rustical_dav::extensions::CommonPropertiesExtension;
use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::privileges::UserPrivilegeSet;
use rustical_dav::resource::{PrincipalUri, Resource, ResourceName}; use rustical_dav::resource::{PrincipalUri, Resource, ResourceName};
use rustical_dav::xml::{Resourcetype, ResourcetypeInner, SupportedReportSet}; use rustical_dav::xml::{
GroupMemberSet, GroupMembership, Resourcetype, ResourcetypeInner, SupportedReportSet,
};
use rustical_store::auth::User; use rustical_store::auth::User;
mod service; mod service;
@@ -82,9 +84,9 @@ impl Resource for PrincipalResource {
)) ))
} }
PrincipalPropName::AlternateUriSet => PrincipalProp::AlternateUriSet, PrincipalPropName::AlternateUriSet => PrincipalProp::AlternateUriSet,
PrincipalPropName::PrincipalCollectionSet => { // PrincipalPropName::PrincipalCollectionSet => {
PrincipalProp::PrincipalCollectionSet(puri.principal_collection().into()) // PrincipalProp::PrincipalCollectionSet(puri.principal_collection().into())
} // }
PrincipalPropName::SupportedReportSet => { PrincipalPropName::SupportedReportSet => {
PrincipalProp::SupportedReportSet(SupportedReportSet::all()) PrincipalProp::SupportedReportSet(SupportedReportSet::all())
} }

View File

@@ -1,6 +1,6 @@
use rustical_dav::{ use rustical_dav::{
extensions::CommonPropertiesProp, extensions::CommonPropertiesProp,
xml::{HrefElement, SupportedReportSet}, xml::{GroupMemberSet, GroupMembership, HrefElement, SupportedReportSet},
}; };
use rustical_store::auth::user::PrincipalType; use rustical_store::auth::user::PrincipalType;
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
@@ -24,8 +24,8 @@ pub enum PrincipalProp {
GroupMemberSet(GroupMemberSet), GroupMemberSet(GroupMemberSet),
#[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"alternate-URI-set")] #[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"alternate-URI-set")]
AlternateUriSet, AlternateUriSet,
#[xml(ns = "rustical_dav::namespace::NS_DAV")] // #[xml(ns = "rustical_dav::namespace::NS_DAV")]
PrincipalCollectionSet(HrefElement), // PrincipalCollectionSet(HrefElement),
#[xml(ns = "rustical_dav::namespace::NS_DAV", skip_deserializing)] #[xml(ns = "rustical_dav::namespace::NS_DAV", skip_deserializing)]
SupportedReportSet(SupportedReportSet<ReportMethod>), SupportedReportSet(SupportedReportSet<ReportMethod>),
@@ -41,12 +41,6 @@ pub enum PrincipalPropWrapper {
Common(CommonPropertiesProp), Common(CommonPropertiesProp),
} }
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub(super) Vec<HrefElement>);
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct GroupMemberSet(#[xml(ty = "untagged", flatten)] pub(super) Vec<HrefElement>);
#[derive(XmlSerialize, PartialEq, Clone, VariantArray)] #[derive(XmlSerialize, PartialEq, Clone, VariantArray)]
pub enum ReportMethod { pub enum ReportMethod {
// We don't actually support principal-match // We don't actually support principal-match

View File

@@ -2,7 +2,9 @@ use crate::Error;
use rustical_dav::extensions::CommonPropertiesExtension; use rustical_dav::extensions::CommonPropertiesExtension;
use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::privileges::UserPrivilegeSet;
use rustical_dav::resource::{PrincipalUri, Resource, ResourceName}; use rustical_dav::resource::{PrincipalUri, Resource, ResourceName};
use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner}; use rustical_dav::xml::{
GroupMemberSet, GroupMembership, HrefElement, Resourcetype, ResourcetypeInner,
};
use rustical_store::auth::User; use rustical_store::auth::User;
mod service; mod service;
@@ -13,6 +15,7 @@ pub use prop::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PrincipalResource { pub struct PrincipalResource {
principal: User, principal: User,
members: Vec<String>,
} }
impl ResourceName for PrincipalResource { impl ResourceName for PrincipalResource {
@@ -41,7 +44,7 @@ impl Resource for PrincipalResource {
user: &User, user: &User,
prop: &PrincipalPropWrapperName, prop: &PrincipalPropWrapperName,
) -> Result<Self::Prop, Self::Error> { ) -> Result<Self::Prop, Self::Error> {
let principal_href = HrefElement::new(puri.principal_uri(&user.id)); let principal_href = HrefElement::new(puri.principal_uri(&self.principal.id));
Ok(match prop { Ok(match prop {
PrincipalPropWrapperName::Principal(prop) => { PrincipalPropWrapperName::Principal(prop) => {
@@ -60,6 +63,14 @@ impl Resource for PrincipalResource {
.collect(), .collect(),
)) ))
} }
PrincipalPropName::GroupMemberSet => {
PrincipalProp::GroupMemberSet(GroupMemberSet(
self.members
.iter()
.map(|principal| puri.principal_uri(principal).into())
.collect(),
))
}
PrincipalPropName::AlternateUriSet => PrincipalProp::AlternateUriSet, PrincipalPropName::AlternateUriSet => PrincipalProp::AlternateUriSet,
PrincipalPropName::PrincipalCollectionSet => { PrincipalPropName::PrincipalCollectionSet => {
PrincipalProp::PrincipalCollectionSet(puri.principal_collection().into()) PrincipalProp::PrincipalCollectionSet(puri.principal_collection().into())

View File

@@ -1,4 +1,7 @@
use rustical_dav::{extensions::CommonPropertiesProp, xml::HrefElement}; use rustical_dav::{
extensions::CommonPropertiesProp,
xml::{GroupMemberSet, GroupMembership, HrefElement},
};
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
@@ -10,6 +13,8 @@ pub enum PrincipalProp {
PrincipalUrl(HrefElement), PrincipalUrl(HrefElement),
#[xml(ns = "rustical_dav::namespace::NS_DAV")] #[xml(ns = "rustical_dav::namespace::NS_DAV")]
GroupMembership(GroupMembership), GroupMembership(GroupMembership),
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
GroupMemberSet(GroupMemberSet),
#[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"alternate-URI-set")] #[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"alternate-URI-set")]
AlternateUriSet, AlternateUriSet,
#[xml(ns = "rustical_dav::namespace::NS_DAV")] #[xml(ns = "rustical_dav::namespace::NS_DAV")]
@@ -28,6 +33,3 @@ pub enum PrincipalPropWrapper {
Principal(PrincipalProp), Principal(PrincipalProp),
Common(CommonPropertiesProp), Common(CommonPropertiesProp),
} }
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub(super) Vec<HrefElement>);

View File

@@ -65,7 +65,10 @@ impl<A: AddressbookStore, AP: AuthenticationProvider, S: SubscriptionStore> Reso
.get_principal(principal) .get_principal(principal)
.await? .await?
.ok_or(crate::Error::NotFound)?; .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( async fn get_members(

View File

@@ -0,0 +1,8 @@
use crate::xml::HrefElement;
use rustical_xml::{XmlDeserialize, XmlSerialize};
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct GroupMemberSet(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);

View File

@@ -13,3 +13,5 @@ pub mod sync_collection;
pub use error::ErrorElement; pub use error::ErrorElement;
mod report_set; mod report_set;
pub use report_set::SupportedReportSet; pub use report_set::SupportedReportSet;
mod group;
pub use group::*;