mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 21:42:34 +00:00
dav: Fix proppatch supporting multiple properties in <set> and <remove> elements
This commit is contained in:
@@ -26,21 +26,21 @@ enum SetPropertyPropWrapper<T: XmlDeserialize> {
|
|||||||
// We are <prop>
|
// We are <prop>
|
||||||
#[derive(XmlDeserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
struct SetPropertyPropWrapperWrapper<T: XmlDeserialize>(
|
struct SetPropertyPropWrapperWrapper<T: XmlDeserialize>(
|
||||||
#[xml(ty = "untagged")] SetPropertyPropWrapper<T>,
|
#[xml(ty = "untagged", flatten)] Vec<SetPropertyPropWrapper<T>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
// We are <set>
|
// We are <set>
|
||||||
#[derive(XmlDeserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
struct SetPropertyElement<T: XmlDeserialize> {
|
struct SetPropertyElement<T: XmlDeserialize> {
|
||||||
#[xml(ns = "crate::namespace::NS_DAV")]
|
#[xml(ns = "crate::namespace::NS_DAV")]
|
||||||
prop: T,
|
prop: SetPropertyPropWrapperWrapper<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(XmlDeserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
struct TagName(#[xml(ty = "tag_name")] String);
|
struct TagName(#[xml(ty = "tag_name")] String);
|
||||||
|
|
||||||
#[derive(XmlDeserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
struct PropertyElement(#[xml(ty = "untagged")] TagName);
|
struct PropertyElement(#[xml(ty = "untagged", flatten)] Vec<TagName>);
|
||||||
|
|
||||||
#[derive(XmlDeserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
struct RemovePropertyElement {
|
struct RemovePropertyElement {
|
||||||
@@ -81,9 +81,8 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
|
|||||||
let href = path.to_owned();
|
let href = path.to_owned();
|
||||||
|
|
||||||
// Extract operations
|
// Extract operations
|
||||||
let PropertyupdateElement::<SetPropertyPropWrapperWrapper<<R::Resource as Resource>::Prop>>(
|
let PropertyupdateElement::<<R::Resource as Resource>::Prop>(operations) =
|
||||||
operations,
|
XmlDocument::parse_str(body).map_err(Error::XmlError)?;
|
||||||
) = XmlDocument::parse_str(body).map_err(Error::XmlError)?;
|
|
||||||
|
|
||||||
let mut resource = resource_service
|
let mut resource = resource_service
|
||||||
.get_resource(path_components, false)
|
.get_resource(path_components, false)
|
||||||
@@ -100,17 +99,17 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
|
|||||||
for operation in operations.into_iter() {
|
for operation in operations.into_iter() {
|
||||||
match operation {
|
match operation {
|
||||||
Operation::Set(SetPropertyElement {
|
Operation::Set(SetPropertyElement {
|
||||||
prop: SetPropertyPropWrapperWrapper(property),
|
prop: SetPropertyPropWrapperWrapper(properties),
|
||||||
}) => {
|
}) => {
|
||||||
|
for property in properties {
|
||||||
match property {
|
match property {
|
||||||
SetPropertyPropWrapper::Valid(prop) => {
|
SetPropertyPropWrapper::Valid(prop) => {
|
||||||
let propname: <<R::Resource as Resource>::Prop as PropName>::Names =
|
let propname: <<R::Resource as Resource>::Prop as PropName>::Names =
|
||||||
prop.clone().into();
|
prop.clone().into();
|
||||||
let (ns, propname): (Option<Namespace>, &str) = propname.into();
|
let (ns, propname): (Option<Namespace>, &str) = propname.into();
|
||||||
match resource.set_prop(prop) {
|
match resource.set_prop(prop) {
|
||||||
Ok(()) => {
|
Ok(()) => props_ok
|
||||||
props_ok.push((ns.map(NamespaceOwned::from), propname.to_owned()))
|
.push((ns.map(NamespaceOwned::from), propname.to_owned())),
|
||||||
}
|
|
||||||
Err(Error::PropReadOnly) => props_conflict
|
Err(Error::PropReadOnly) => props_conflict
|
||||||
.push((ns.map(NamespaceOwned::from), propname.to_owned())),
|
.push((ns.map(NamespaceOwned::from), propname.to_owned())),
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
@@ -139,9 +138,12 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Operation::Remove(remove_el) => {
|
Operation::Remove(remove_el) => {
|
||||||
let propname = remove_el.prop.0.0;
|
for tagname in remove_el.prop.0 {
|
||||||
match <<R::Resource as Resource>::Prop as PropName>::Names::from_str(&propname) {
|
let propname = tagname.0;
|
||||||
|
match <<R::Resource as Resource>::Prop as PropName>::Names::from_str(&propname)
|
||||||
|
{
|
||||||
Ok(prop) => match resource.remove_prop(&prop) {
|
Ok(prop) => match resource.remove_prop(&prop) {
|
||||||
Ok(()) => props_ok.push((None, propname)),
|
Ok(()) => props_ok.push((None, propname)),
|
||||||
Err(Error::PropReadOnly) => props_conflict.push({
|
Err(Error::PropReadOnly) => props_conflict.push({
|
||||||
@@ -156,6 +158,7 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if props_not_found.is_empty() && props_conflict.is_empty() {
|
if props_not_found.is_empty() && props_conflict.is_empty() {
|
||||||
// Only save if no errors occured
|
// Only save if no errors occured
|
||||||
|
|||||||
Reference in New Issue
Block a user