mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 20:32:48 +00:00
Refactoring
This commit is contained in:
@@ -9,12 +9,8 @@ use actix_web::{
|
|||||||
HttpRequest,
|
HttpRequest,
|
||||||
};
|
};
|
||||||
use rustical_dav::{
|
use rustical_dav::{
|
||||||
methods::propfind::{PropElement, PropfindType},
|
|
||||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||||
xml::{
|
xml::{multistatus::ResponseElement, MultistatusElement, PropElement, PropfindType},
|
||||||
multistatus::{PropstatWrapper, ResponseElement},
|
|
||||||
MultistatusElement,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -69,13 +65,8 @@ pub async fn handle_calendar_multiget<C: CalendarStore + ?Sized>(
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
cal_store: &C,
|
cal_store: &C,
|
||||||
) -> Result<
|
) -> Result<MultistatusElement<EitherProp<CalendarObjectProp, CommonPropertiesProp>, String>, Error>
|
||||||
MultistatusElement<
|
{
|
||||||
PropstatWrapper<EitherProp<CalendarObjectProp, CommonPropertiesProp>>,
|
|
||||||
String,
|
|
||||||
>,
|
|
||||||
Error,
|
|
||||||
> {
|
|
||||||
let principal_url = PrincipalResource::get_url(req.resource_map(), vec![principal]).unwrap();
|
let principal_url = PrincipalResource::get_url(req.resource_map(), vec![principal]).unwrap();
|
||||||
let (objects, not_found) =
|
let (objects, not_found) =
|
||||||
get_objects_calendar_multiget(&cal_multiget, &principal_url, principal, cal_id, cal_store)
|
get_objects_calendar_multiget(&cal_multiget, &principal_url, principal, cal_id, cal_store)
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use actix_web::HttpRequest;
|
use actix_web::HttpRequest;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use rustical_dav::{
|
use rustical_dav::{
|
||||||
methods::propfind::{PropElement, PropfindType},
|
|
||||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||||
xml::{multistatus::PropstatWrapper, MultistatusElement},
|
xml::{MultistatusElement, PropElement, PropfindType},
|
||||||
};
|
};
|
||||||
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -210,13 +209,8 @@ pub async fn handle_calendar_query<C: CalendarStore + ?Sized>(
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
cal_store: &C,
|
cal_store: &C,
|
||||||
) -> Result<
|
) -> Result<MultistatusElement<EitherProp<CalendarObjectProp, CommonPropertiesProp>, String>, Error>
|
||||||
MultistatusElement<
|
{
|
||||||
PropstatWrapper<EitherProp<CalendarObjectProp, CommonPropertiesProp>>,
|
|
||||||
String,
|
|
||||||
>,
|
|
||||||
Error,
|
|
||||||
> {
|
|
||||||
let objects = get_objects_calendar_query(&cal_query, principal, cal_id, cal_store).await?;
|
let objects = get_objects_calendar_query(&cal_query, principal, cal_id, cal_store).await?;
|
||||||
|
|
||||||
let props = match cal_query.prop {
|
let props = match cal_query.prop {
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
use actix_web::{http::StatusCode, HttpRequest};
|
use actix_web::{http::StatusCode, HttpRequest};
|
||||||
use rustical_dav::{
|
use rustical_dav::{
|
||||||
methods::propfind::{PropElement, PropfindType},
|
|
||||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||||
xml::{
|
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||||
multistatus::{PropstatWrapper, ResponseElement},
|
xml::{PropElement, PropfindType},
|
||||||
MultistatusElement,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use rustical_store::{
|
use rustical_store::{
|
||||||
auth::User,
|
auth::User,
|
||||||
@@ -49,13 +46,8 @@ pub async fn handle_sync_collection<C: CalendarStore + ?Sized>(
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
cal_store: &C,
|
cal_store: &C,
|
||||||
) -> Result<
|
) -> Result<MultistatusElement<EitherProp<CalendarObjectProp, CommonPropertiesProp>, String>, Error>
|
||||||
MultistatusElement<
|
{
|
||||||
PropstatWrapper<EitherProp<CalendarObjectProp, CommonPropertiesProp>>,
|
|
||||||
String,
|
|
||||||
>,
|
|
||||||
Error,
|
|
||||||
> {
|
|
||||||
let props = match sync_collection.prop {
|
let props = match sync_collection.prop {
|
||||||
PropfindType::Allprop => {
|
PropfindType::Allprop => {
|
||||||
vec!["allprop".to_owned()]
|
vec!["allprop".to_owned()]
|
||||||
|
|||||||
@@ -9,12 +9,9 @@ use actix_web::{
|
|||||||
HttpRequest,
|
HttpRequest,
|
||||||
};
|
};
|
||||||
use rustical_dav::{
|
use rustical_dav::{
|
||||||
methods::propfind::{PropElement, PropfindType},
|
|
||||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||||
xml::{
|
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||||
multistatus::{PropstatWrapper, ResponseElement},
|
xml::{PropElement, PropfindType},
|
||||||
MultistatusElement,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use rustical_store::{auth::User, AddressObject, AddressbookStore};
|
use rustical_store::{auth::User, AddressObject, AddressbookStore};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -68,13 +65,8 @@ pub async fn handle_addressbook_multiget<AS: AddressbookStore + ?Sized>(
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
addr_store: &AS,
|
addr_store: &AS,
|
||||||
) -> Result<
|
) -> Result<MultistatusElement<EitherProp<AddressObjectProp, CommonPropertiesProp>, String>, Error>
|
||||||
MultistatusElement<
|
{
|
||||||
PropstatWrapper<EitherProp<AddressObjectProp, CommonPropertiesProp>>,
|
|
||||||
String,
|
|
||||||
>,
|
|
||||||
Error,
|
|
||||||
> {
|
|
||||||
let principal_url = PrincipalResource::get_url(req.resource_map(), vec![principal]).unwrap();
|
let principal_url = PrincipalResource::get_url(req.resource_map(), vec![principal]).unwrap();
|
||||||
let (objects, not_found) = get_objects_addressbook_multiget(
|
let (objects, not_found) = get_objects_addressbook_multiget(
|
||||||
&addr_multiget,
|
&addr_multiget,
|
||||||
|
|||||||
@@ -4,12 +4,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use actix_web::{http::StatusCode, HttpRequest};
|
use actix_web::{http::StatusCode, HttpRequest};
|
||||||
use rustical_dav::{
|
use rustical_dav::{
|
||||||
methods::propfind::{PropElement, PropfindType},
|
|
||||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||||
xml::{
|
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||||
multistatus::{PropstatWrapper, ResponseElement},
|
xml::{PropElement, PropfindType},
|
||||||
MultistatusElement,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use rustical_store::{
|
use rustical_store::{
|
||||||
auth::User,
|
auth::User,
|
||||||
@@ -47,13 +44,8 @@ pub async fn handle_sync_collection<AS: AddressbookStore + ?Sized>(
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
addressbook_id: &str,
|
addressbook_id: &str,
|
||||||
addr_store: &AS,
|
addr_store: &AS,
|
||||||
) -> Result<
|
) -> Result<MultistatusElement<EitherProp<AddressObjectProp, CommonPropertiesProp>, String>, Error>
|
||||||
MultistatusElement<
|
{
|
||||||
PropstatWrapper<EitherProp<AddressObjectProp, CommonPropertiesProp>>,
|
|
||||||
String,
|
|
||||||
>,
|
|
||||||
Error,
|
|
||||||
> {
|
|
||||||
let props = match sync_collection.prop {
|
let props = match sync_collection.prop {
|
||||||
PropfindType::Allprop => {
|
PropfindType::Allprop => {
|
||||||
vec!["allprop".to_owned()]
|
vec!["allprop".to_owned()]
|
||||||
|
|||||||
11
crates/carddav/tests/integration_test.rs
Normal file
11
crates/carddav/tests/integration_test.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use actix_web::{web, App};
|
||||||
|
use rustical_carddav::configure_dav;
|
||||||
|
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn test_asd() {
|
||||||
|
let app = App::new().service(web::scope("/carddav").configure(
|
||||||
|
|config| configure_dav(config, auth_provider, store)
|
||||||
|
));
|
||||||
|
let app = actix_web::test::init_service()
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
pub mod depth_header;
|
pub mod depth_header;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod methods;
|
|
||||||
pub mod namespace;
|
pub mod namespace;
|
||||||
pub mod privileges;
|
pub mod privileges;
|
||||||
pub mod resource;
|
pub mod resource;
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
pub mod delete;
|
|
||||||
pub mod propfind;
|
|
||||||
pub mod proppatch;
|
|
||||||
|
|
||||||
pub use delete::route_delete;
|
|
||||||
pub use propfind::route_propfind;
|
|
||||||
pub use proppatch::route_proppatch;
|
|
||||||
7
crates/dav/src/resource/methods/mod.rs
Normal file
7
crates/dav/src/resource/methods/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mod delete;
|
||||||
|
mod propfind;
|
||||||
|
mod proppatch;
|
||||||
|
|
||||||
|
pub(crate) use delete::route_delete;
|
||||||
|
pub(crate) use propfind::route_propfind;
|
||||||
|
pub(crate) use proppatch::route_proppatch;
|
||||||
@@ -4,9 +4,9 @@ use crate::resource::CommonPropertiesProp;
|
|||||||
use crate::resource::EitherProp;
|
use crate::resource::EitherProp;
|
||||||
use crate::resource::Resource;
|
use crate::resource::Resource;
|
||||||
use crate::resource::ResourceService;
|
use crate::resource::ResourceService;
|
||||||
use crate::xml::multistatus::PropstatWrapper;
|
|
||||||
use crate::xml::MultistatusElement;
|
use crate::xml::MultistatusElement;
|
||||||
use crate::xml::TagList;
|
use crate::xml::PropElement;
|
||||||
|
use crate::xml::PropfindType;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use actix_web::web::Path;
|
use actix_web::web::Path;
|
||||||
use actix_web::HttpRequest;
|
use actix_web::HttpRequest;
|
||||||
@@ -17,21 +17,7 @@ use tracing_actix_web::RootSpan;
|
|||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct PropElement {
|
#[serde(deny_unknown_fields)]
|
||||||
#[serde(flatten)]
|
|
||||||
pub prop: TagList,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
pub enum PropfindType {
|
|
||||||
Propname,
|
|
||||||
Allprop,
|
|
||||||
Prop(PropElement),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
struct PropfindElement {
|
struct PropfindElement {
|
||||||
#[serde(rename = "$value")]
|
#[serde(rename = "$value")]
|
||||||
prop: PropfindType,
|
prop: PropfindType,
|
||||||
@@ -39,7 +25,7 @@ struct PropfindElement {
|
|||||||
|
|
||||||
#[instrument(parent = root_span.id(), skip(path_components, req, root_span))]
|
#[instrument(parent = root_span.id(), skip(path_components, req, root_span))]
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub async fn route_propfind<R: ResourceService>(
|
pub(crate) async fn route_propfind<R: ResourceService>(
|
||||||
path_components: Path<R::PathComponents>,
|
path_components: Path<R::PathComponents>,
|
||||||
body: String,
|
body: String,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
@@ -48,8 +34,8 @@ pub async fn route_propfind<R: ResourceService>(
|
|||||||
root_span: RootSpan,
|
root_span: RootSpan,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
MultistatusElement<
|
MultistatusElement<
|
||||||
PropstatWrapper<EitherProp<<R::Resource as Resource>::Prop, CommonPropertiesProp>>,
|
EitherProp<<R::Resource as Resource>::Prop, CommonPropertiesProp>,
|
||||||
PropstatWrapper<EitherProp<<R::MemberType as Resource>::Prop, CommonPropertiesProp>>,
|
EitherProp<<R::MemberType as Resource>::Prop, CommonPropertiesProp>,
|
||||||
>,
|
>,
|
||||||
R::Error,
|
R::Error,
|
||||||
> {
|
> {
|
||||||
@@ -71,12 +57,8 @@ pub async fn route_propfind<R: ResourceService>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let props = match propfind.prop {
|
let props = match propfind.prop {
|
||||||
PropfindType::Allprop => {
|
PropfindType::Allprop => vec!["allprop".to_owned()],
|
||||||
vec!["allprop".to_owned()]
|
PropfindType::Propname => vec!["propname".to_owned()],
|
||||||
}
|
|
||||||
PropfindType::Propname => {
|
|
||||||
vec!["propname".to_owned()]
|
|
||||||
}
|
|
||||||
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags.into_inner(),
|
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags.into_inner(),
|
||||||
};
|
};
|
||||||
let props: Vec<&str> = props.iter().map(String::as_str).collect();
|
let props: Vec<&str> = props.iter().map(String::as_str).collect();
|
||||||
@@ -37,8 +37,8 @@ struct RemovePropertyElement {
|
|||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
enum Operation<T> {
|
enum Operation<PropType> {
|
||||||
Set(SetPropertyElement<T>),
|
Set(SetPropertyElement<PropType>),
|
||||||
Remove(RemovePropertyElement),
|
Remove(RemovePropertyElement),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,17 +50,18 @@ struct PropertyupdateElement<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(parent = root_span.id(), skip(path, req, root_span))]
|
#[instrument(parent = root_span.id(), skip(path, req, root_span))]
|
||||||
pub async fn route_proppatch<R: ResourceService>(
|
pub(crate) async fn route_proppatch<R: ResourceService>(
|
||||||
path: Path<R::PathComponents>,
|
path: Path<R::PathComponents>,
|
||||||
body: String,
|
body: String,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
user: User,
|
user: User,
|
||||||
root_span: RootSpan,
|
root_span: RootSpan,
|
||||||
) -> Result<MultistatusElement<PropstatWrapper<String>, PropstatWrapper<String>>, R::Error> {
|
) -> Result<MultistatusElement<String, String>, R::Error> {
|
||||||
let path_components = path.into_inner();
|
let path_components = path.into_inner();
|
||||||
let href = req.path().to_owned();
|
let href = req.path().to_owned();
|
||||||
let resource_service = R::new(&req, path_components.clone()).await?;
|
let resource_service = R::new(&req, path_components.clone()).await?;
|
||||||
|
|
||||||
|
// Extract operations
|
||||||
let PropertyupdateElement::<<R::Resource as Resource>::Prop> { operations } =
|
let PropertyupdateElement::<<R::Resource as Resource>::Prop> { operations } =
|
||||||
quick_xml::de::from_str(&body).map_err(Error::XmlDeserializationError)?;
|
quick_xml::de::from_str(&body).map_err(Error::XmlDeserializationError)?;
|
||||||
|
|
||||||
@@ -104,34 +105,20 @@ pub async fn route_proppatch<R: ResourceService>(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match resource.set_prop(prop) {
|
match resource.set_prop(prop) {
|
||||||
Ok(()) => {
|
Ok(()) => props_ok.push(propname),
|
||||||
props_ok.push(propname);
|
Err(Error::PropReadOnly) => props_conflict.push(propname),
|
||||||
}
|
Err(err) => return Err(err.into()),
|
||||||
Err(Error::PropReadOnly) => {
|
};
|
||||||
props_conflict.push(propname);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Operation::Remove(_remove_el) => {
|
Operation::Remove(_remove_el) => {
|
||||||
match <<R::Resource as Resource>::PropName as FromStr>::from_str(&propname) {
|
match <<R::Resource as Resource>::PropName as FromStr>::from_str(&propname) {
|
||||||
Ok(prop) => match resource.remove_prop(&prop) {
|
Ok(prop) => match resource.remove_prop(&prop) {
|
||||||
Ok(()) => {
|
Ok(()) => props_ok.push(propname),
|
||||||
props_ok.push(propname);
|
Err(Error::PropReadOnly) => props_conflict.push(propname),
|
||||||
}
|
Err(err) => return Err(err.into()),
|
||||||
Err(Error::PropReadOnly) => {
|
|
||||||
props_conflict.push(propname);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Err(_) => {
|
// I guess removing a nonexisting property should be successful :)
|
||||||
// I guess removing a nonexisting property should be successful :)
|
Err(_) => props_ok.push(propname),
|
||||||
props_ok.push(propname);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@ use std::str::FromStr;
|
|||||||
use strum::{EnumString, VariantNames};
|
use strum::{EnumString, VariantNames};
|
||||||
|
|
||||||
mod invalid_property;
|
mod invalid_property;
|
||||||
|
mod methods;
|
||||||
mod resource_service;
|
mod resource_service;
|
||||||
|
|
||||||
pub trait ResourceProp: InvalidProperty + Serialize + for<'de> Deserialize<'de> {}
|
pub trait ResourceProp: InvalidProperty + Serialize + for<'de> Deserialize<'de> {}
|
||||||
@@ -149,10 +150,7 @@ pub trait Resource: Clone + 'static {
|
|||||||
mut props: Vec<&str>,
|
mut props: Vec<&str>,
|
||||||
user: &User,
|
user: &User,
|
||||||
rmap: &ResourceMap,
|
rmap: &ResourceMap,
|
||||||
) -> Result<
|
) -> Result<ResponseElement<EitherProp<Self::Prop, CommonPropertiesProp>>, Self::Error> {
|
||||||
ResponseElement<PropstatWrapper<EitherProp<Self::Prop, CommonPropertiesProp>>>,
|
|
||||||
Self::Error,
|
|
||||||
> {
|
|
||||||
if props.contains(&"propname") {
|
if props.contains(&"propname") {
|
||||||
if props.len() != 1 {
|
if props.len() != 1 {
|
||||||
// propname MUST be the only queried prop per spec
|
// propname MUST be the only queried prop per spec
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use actix_web::{dev::ResourceMap, http::Method, web, HttpRequest, ResponseError}
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::methods::{route_delete, route_propfind, route_proppatch};
|
use super::methods::{route_delete, route_propfind, route_proppatch};
|
||||||
|
|
||||||
use super::Resource;
|
use super::Resource;
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
pub mod multistatus;
|
pub mod multistatus;
|
||||||
|
mod propfind;
|
||||||
mod resourcetype;
|
mod resourcetype;
|
||||||
pub mod tag_list;
|
pub mod tag_list;
|
||||||
pub mod tag_name;
|
pub mod tag_name;
|
||||||
|
|
||||||
|
pub use propfind::{PropElement, PropfindType};
|
||||||
|
|
||||||
use derive_more::derive::From;
|
use derive_more::derive::From;
|
||||||
pub use multistatus::MultistatusElement;
|
pub use multistatus::MultistatusElement;
|
||||||
pub use tag_list::TagList;
|
pub use tag_list::TagList;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub struct ResponseElement<PropstatType: Serialize> {
|
|||||||
pub href: String,
|
pub href: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub status: Option<String>,
|
pub status: Option<String>,
|
||||||
pub propstat: Vec<PropstatType>,
|
pub propstat: Vec<PropstatWrapper<PropstatType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<PT: Serialize> Default for ResponseElement<PT> {
|
impl<PT: Serialize> Default for ResponseElement<PT> {
|
||||||
@@ -55,11 +55,11 @@ impl<PT: Serialize> Default for ResponseElement<PT> {
|
|||||||
// Extended by sync-token as specified in RFC 6578
|
// Extended by sync-token as specified in RFC 6578
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename = "multistatus", rename_all = "kebab-case")]
|
#[serde(rename = "multistatus", rename_all = "kebab-case")]
|
||||||
pub struct MultistatusElement<T1: Serialize, T2: Serialize> {
|
pub struct MultistatusElement<PropType: Serialize, MemberPropType: Serialize> {
|
||||||
#[serde(rename = "response")]
|
#[serde(rename = "response")]
|
||||||
pub responses: Vec<ResponseElement<T1>>,
|
pub responses: Vec<ResponseElement<PropType>>,
|
||||||
#[serde(rename = "response")]
|
#[serde(rename = "response")]
|
||||||
pub member_responses: Vec<ResponseElement<T2>>,
|
pub member_responses: Vec<ResponseElement<MemberPropType>>,
|
||||||
#[serde(rename = "@xmlns")]
|
#[serde(rename = "@xmlns")]
|
||||||
pub ns_dav: &'static str,
|
pub ns_dav: &'static str,
|
||||||
#[serde(rename = "@xmlns:C")]
|
#[serde(rename = "@xmlns:C")]
|
||||||
|
|||||||
17
crates/dav/src/xml/propfind.rs
Normal file
17
crates/dav/src/xml/propfind.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
use super::TagList;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub struct PropElement {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub prop: TagList,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub enum PropfindType {
|
||||||
|
Propname,
|
||||||
|
Allprop,
|
||||||
|
Prop(PropElement),
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user