dav: Introduce resource extension for common properties

This commit is contained in:
Lennart
2024-11-03 22:32:21 +01:00
parent 31c7143dd8
commit 0c8d339ced
16 changed files with 492 additions and 262 deletions

View File

@@ -12,7 +12,11 @@ use actix_web::http::Method;
use actix_web::web;
use actix_web::{web::Data, HttpRequest};
use async_trait::async_trait;
use derive_more::derive::{From, Into};
use derive_more::derive::{From, Into, TryInto};
use rustical_dav::extension::BoxedExtension;
use rustical_dav::extensions::{
CommonPropertiesExtension, CommonPropertiesProp, CommonPropertiesPropName,
};
use rustical_dav::privileges::UserPrivilegeSet;
use rustical_dav::resource::{InvalidProperty, Resource, ResourceService};
use rustical_dav::xml::HrefElement;
@@ -30,11 +34,10 @@ pub struct CalendarResourceService<C: CalendarStore + ?Sized> {
pub calendar_id: String,
}
#[derive(EnumString, Debug, VariantNames, Clone)]
#[derive(EnumString, Debug, VariantNames, Clone, From, TryInto)]
#[strum(serialize_all = "kebab-case")]
pub enum CalendarPropName {
Resourcetype,
CurrentUserPrincipal,
Owner,
Displayname,
CalendarColor,
@@ -44,14 +47,17 @@ pub enum CalendarPropName {
SupportedCalendarComponentSet,
SupportedCalendarData,
Getcontenttype,
// CurrentUserPrivilegeSet,
MaxResourceSize,
SupportedReportSet,
SyncToken,
Getctag,
#[from]
#[try_into]
#[strum(disabled)]
ExtCommonProperties(CommonPropertiesPropName),
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize, From, TryInto)]
#[serde(rename_all = "kebab-case")]
pub enum CalendarProp {
// WebDAV (RFC 2518)
@@ -59,12 +65,8 @@ pub enum CalendarProp {
Displayname(Option<String>),
Getcontenttype(String),
// WebDAV Current Principal Extension (RFC 5397)
CurrentUserPrincipal(HrefElement),
// WebDAV Access Control (RFC 3744)
Owner(HrefElement),
// CurrentUserPrivilegeSet(UserPrivilegeSet),
// CalDAV (RFC 4791)
#[serde(rename = "IC:calendar-color", alias = "calendar-color")]
@@ -93,7 +95,13 @@ pub enum CalendarProp {
// Didn't find the spec
Getctag(String),
#[serde(other)]
#[serde(skip_deserializing, untagged)]
#[from]
#[try_into]
ExtCommonProperties(CommonPropertiesProp),
#[serde(untagged)]
Invalid,
}
@@ -111,6 +119,12 @@ impl Resource for CalendarResource {
type Prop = CalendarProp;
type Error = Error;
fn list_extensions() -> Vec<BoxedExtension<Self>> {
vec![BoxedExtension::from_ext(CommonPropertiesExtension::<
PrincipalResource,
>::default())]
}
fn get_prop(
&self,
rmap: &ResourceMap,
@@ -119,11 +133,6 @@ impl Resource for CalendarResource {
) -> Result<Self::Prop, Self::Error> {
Ok(match prop {
CalendarPropName::Resourcetype => CalendarProp::Resourcetype(Resourcetype::default()),
CalendarPropName::CurrentUserPrincipal => {
CalendarProp::CurrentUserPrincipal(HrefElement::new(
PrincipalResource::get_url(rmap, vec![&self.0.principal]).unwrap(),
))
}
CalendarPropName::Owner => CalendarProp::Owner(HrefElement::new(
PrincipalResource::get_url(rmap, vec![&self.0.principal]).unwrap(),
)),
@@ -166,13 +175,13 @@ impl Resource for CalendarResource {
}
CalendarPropName::SyncToken => CalendarProp::SyncToken(self.0.format_synctoken()),
CalendarPropName::Getctag => CalendarProp::Getctag(self.0.format_synctoken()),
_ => panic!("we shouldn't end up here"),
})
}
fn set_prop(&mut self, prop: Self::Prop) -> Result<(), rustical_dav::Error> {
match prop {
CalendarProp::Resourcetype(_) => Err(rustical_dav::Error::PropReadOnly),
CalendarProp::CurrentUserPrincipal(_) => Err(rustical_dav::Error::PropReadOnly),
CalendarProp::Owner(_) => Err(rustical_dav::Error::PropReadOnly),
CalendarProp::Displayname(displayname) => {
self.0.displayname = displayname;
@@ -205,13 +214,13 @@ impl Resource for CalendarResource {
CalendarProp::SyncToken(_) => Err(rustical_dav::Error::PropReadOnly),
CalendarProp::Getctag(_) => Err(rustical_dav::Error::PropReadOnly),
CalendarProp::Invalid => Err(rustical_dav::Error::PropReadOnly),
_ => panic!("we shouldn't end up here"),
}
}
fn remove_prop(&mut self, prop: &Self::PropName) -> Result<(), rustical_dav::Error> {
match prop {
CalendarPropName::Resourcetype => Err(rustical_dav::Error::PropReadOnly),
CalendarPropName::CurrentUserPrincipal => Err(rustical_dav::Error::PropReadOnly),
CalendarPropName::Owner => Err(rustical_dav::Error::PropReadOnly),
CalendarPropName::Displayname => {
self.0.displayname = None;
@@ -243,6 +252,7 @@ impl Resource for CalendarResource {
CalendarPropName::SupportedReportSet => Err(rustical_dav::Error::PropReadOnly),
CalendarPropName::SyncToken => Err(rustical_dav::Error::PropReadOnly),
CalendarPropName::Getctag => Err(rustical_dav::Error::PropReadOnly),
_ => panic!("we shouldn't end up here"),
}
}

View File

@@ -2,8 +2,10 @@ use super::methods::{get_event, put_event};
use crate::{principal::PrincipalResource, Error};
use actix_web::{dev::ResourceMap, web::Data, HttpRequest};
use async_trait::async_trait;
use derive_more::derive::{From, Into};
use derive_more::derive::{From, Into, TryInto};
use rustical_dav::{
extension::BoxedExtension,
extensions::{CommonPropertiesExtension, CommonPropertiesProp, CommonPropertiesPropName},
privileges::UserPrivilegeSet,
resource::{InvalidProperty, Resource, ResourceService},
xml::HrefElement,
@@ -21,18 +23,20 @@ pub struct CalendarObjectResourceService<C: CalendarStore + ?Sized> {
pub object_id: String,
}
#[derive(EnumString, Debug, VariantNames, Clone)]
#[derive(EnumString, Debug, VariantNames, Clone, From, TryInto)]
#[strum(serialize_all = "kebab-case")]
pub enum CalendarObjectPropName {
Getetag,
CalendarData,
Getcontenttype,
CurrentUserPrincipal,
Owner,
CurrentUserPrivilegeSet,
#[from]
#[try_into]
#[strum(disabled)]
ExtCommonProperties(CommonPropertiesPropName),
}
#[derive(Deserialize, Serialize, Debug, Clone)]
#[derive(Deserialize, Serialize, Debug, From, TryInto)]
#[serde(rename_all = "kebab-case")]
pub enum CalendarObjectProp {
// WebDAV (RFC 2518)
@@ -43,13 +47,15 @@ pub enum CalendarObjectProp {
#[serde(rename = "C:calendar-data")]
CalendarData(String),
// WebDAV Current Principal Extension (RFC 5397)
CurrentUserPrincipal(HrefElement),
// WebDAV Access Control (RFC 3744)
Owner(HrefElement),
CurrentUserPrivilegeSet(UserPrivilegeSet),
#[serde(other)]
#[serde(skip_deserializing, untagged)]
#[from]
#[try_into]
ExtCommonProperties(CommonPropertiesProp),
#[serde(untagged)]
Invalid,
}
@@ -70,6 +76,12 @@ impl Resource for CalendarObjectResource {
type Prop = CalendarObjectProp;
type Error = Error;
fn list_extensions() -> Vec<BoxedExtension<Self>> {
vec![BoxedExtension::from_ext(CommonPropertiesExtension::<
PrincipalResource,
>::default())]
}
fn get_prop(
&self,
rmap: &ResourceMap,
@@ -84,17 +96,10 @@ impl Resource for CalendarObjectResource {
CalendarObjectPropName::Getcontenttype => {
CalendarObjectProp::Getcontenttype("text/calendar;charset=utf-8".to_owned())
}
CalendarObjectPropName::CurrentUserPrincipal => {
CalendarObjectProp::CurrentUserPrincipal(HrefElement::new(
PrincipalResource::get_principal_url(rmap, &user.id),
))
}
CalendarObjectPropName::Owner => CalendarObjectProp::Owner(
PrincipalResource::get_principal_url(rmap, &self.principal).into(),
),
CalendarObjectPropName::CurrentUserPrivilegeSet => {
CalendarObjectProp::CurrentUserPrivilegeSet(self.get_user_privileges(&user)?)
}
_ => panic!("we shouldn't end up here"),
})
}

View File

@@ -4,6 +4,11 @@ use actix_web::dev::ResourceMap;
use actix_web::web::Data;
use actix_web::HttpRequest;
use async_trait::async_trait;
use derive_more::derive::{From, TryInto};
use rustical_dav::extension::BoxedExtension;
use rustical_dav::extensions::{
CommonPropertiesExtension, CommonPropertiesProp, CommonPropertiesPropName,
};
use rustical_dav::privileges::UserPrivilegeSet;
use rustical_dav::resource::{InvalidProperty, Resource, ResourceService};
use rustical_dav::xml::HrefElement;
@@ -30,7 +35,7 @@ pub struct Resourcetype {
collection: (),
}
#[derive(Deserialize, Serialize, Debug)]
#[derive(Deserialize, Serialize, Debug, From, TryInto)]
#[serde(rename_all = "kebab-case")]
pub enum PrincipalProp {
// WebDAV (RFC 2518)
@@ -40,12 +45,8 @@ pub enum PrincipalProp {
#[serde(rename = "principal-URL")]
PrincipalUrl(HrefElement),
// WebDAV Current Principal Extension (RFC 5397)
CurrentUserPrincipal(HrefElement),
// WebDAV Access Control (RFC 3744)
Owner(HrefElement),
CurrentUserPrivilegeSet(UserPrivilegeSet),
// CalDAV (RFC 4791)
#[serde(rename = "C:calendar-home-set")]
@@ -53,7 +54,12 @@ pub enum PrincipalProp {
#[serde(rename = "C:calendar-user-address-set")]
CalendarUserAddressSet(HrefElement),
#[serde(other)]
#[serde(skip_deserializing, untagged)]
#[from]
#[try_into]
ExtCommonProperties(CommonPropertiesProp),
#[serde(untagged)]
Invalid,
}
@@ -63,17 +69,19 @@ impl InvalidProperty for PrincipalProp {
}
}
#[derive(EnumString, Debug, VariantNames, Clone)]
#[derive(EnumString, Debug, VariantNames, Clone, From, TryInto)]
#[strum(serialize_all = "kebab-case")]
pub enum PrincipalPropName {
Resourcetype,
CurrentUserPrincipal,
Owner,
CurrentUserPrivilegeSet,
#[strum(serialize = "principal-URL")]
PrincipalUrl,
CalendarHomeSet,
CalendarUserAddressSet,
#[from]
#[try_into]
#[strum(disabled)]
ExtCommonProperties(CommonPropertiesPropName),
}
impl PrincipalResource {
@@ -87,6 +95,12 @@ impl Resource for PrincipalResource {
type Prop = PrincipalProp;
type Error = Error;
fn list_extensions() -> Vec<BoxedExtension<Self>> {
vec![BoxedExtension::from_ext(CommonPropertiesExtension::<
PrincipalResource,
>::default())]
}
fn get_prop(
&self,
rmap: &ResourceMap,
@@ -97,20 +111,15 @@ impl Resource for PrincipalResource {
Ok(match prop {
PrincipalPropName::Resourcetype => PrincipalProp::Resourcetype(Resourcetype::default()),
PrincipalPropName::CurrentUserPrincipal => {
PrincipalProp::CurrentUserPrincipal(principal_href)
}
PrincipalPropName::Owner => PrincipalProp::Owner(HrefElement::new(
PrincipalResource::get_url(rmap, vec![&self.principal]).unwrap(),
)),
PrincipalPropName::CurrentUserPrivilegeSet => {
PrincipalProp::CurrentUserPrivilegeSet(self.get_user_privileges(user)?)
}
PrincipalPropName::PrincipalUrl => PrincipalProp::PrincipalUrl(principal_href),
PrincipalPropName::CalendarHomeSet => PrincipalProp::CalendarHomeSet(principal_href),
PrincipalPropName::CalendarUserAddressSet => {
PrincipalProp::CalendarUserAddressSet(principal_href)
}
_ => panic!("we shouldn't end up here"),
})
}

View File

@@ -3,19 +3,25 @@ use crate::Error;
use actix_web::dev::ResourceMap;
use actix_web::HttpRequest;
use async_trait::async_trait;
use derive_more::derive::{From, TryInto};
use rustical_dav::extension::BoxedExtension;
use rustical_dav::extensions::{
CommonPropertiesExtension, CommonPropertiesProp, CommonPropertiesPropName,
};
use rustical_dav::privileges::UserPrivilegeSet;
use rustical_dav::resource::{InvalidProperty, Resource, ResourceService};
use rustical_dav::xml::HrefElement;
use rustical_store::auth::User;
use serde::{Deserialize, Serialize};
use strum::{EnumString, VariantNames};
#[derive(EnumString, Debug, VariantNames, Clone)]
#[derive(EnumString, Debug, VariantNames, Clone, From, TryInto)]
#[strum(serialize_all = "kebab-case")]
pub enum RootPropName {
Resourcetype,
CurrentUserPrincipal,
CurrentUserPrivilegeSet,
#[from]
#[try_into]
#[strum(disabled)]
ExtCommonProperties(CommonPropertiesPropName),
}
#[derive(Deserialize, Serialize, Default, Debug)]
@@ -24,19 +30,18 @@ pub struct Resourcetype {
collection: (),
}
#[derive(Deserialize, Serialize, Debug)]
#[derive(Deserialize, Serialize, Debug, From, TryInto)]
#[serde(rename_all = "kebab-case")]
pub enum RootProp {
// WebDAV (RFC 2518)
Resourcetype(Resourcetype),
// WebDAV Current Principal Extension (RFC 5397)
CurrentUserPrincipal(HrefElement),
#[serde(skip_deserializing, untagged)]
#[from]
#[try_into]
ExtCommonProperties(CommonPropertiesProp),
// WebDAV Access Control Protocol (RFC 3477)
CurrentUserPrivilegeSet(UserPrivilegeSet),
#[serde(other)]
#[serde(untagged)]
Invalid,
}
@@ -54,6 +59,12 @@ impl Resource for RootResource {
type Prop = RootProp;
type Error = Error;
fn list_extensions() -> Vec<BoxedExtension<Self>> {
vec![BoxedExtension::from_ext(CommonPropertiesExtension::<
PrincipalResource,
>::default())]
}
fn get_prop(
&self,
rmap: &ResourceMap,
@@ -62,12 +73,7 @@ impl Resource for RootResource {
) -> Result<Self::Prop, Self::Error> {
Ok(match prop {
RootPropName::Resourcetype => RootProp::Resourcetype(Resourcetype::default()),
RootPropName::CurrentUserPrincipal => RootProp::CurrentUserPrincipal(HrefElement::new(
PrincipalResource::get_url(rmap, vec![&user.id]).unwrap(),
)),
RootPropName::CurrentUserPrivilegeSet => {
RootProp::CurrentUserPrivilegeSet(self.get_user_privileges(user)?)
}
_ => panic!("we shouldn't end up here"),
})
}