Add namespaces to propnames

This commit is contained in:
Lennart
2025-01-18 18:56:37 +01:00
parent 461c67a72b
commit ea9f5a711d
12 changed files with 118 additions and 76 deletions

View File

@@ -8,6 +8,7 @@ use crate::Error;
use actix_web::http::StatusCode;
use actix_web::web::Data;
use actix_web::{web::Path, HttpRequest};
use itertools::Itertools;
use rustical_store::auth::User;
use rustical_xml::Unparsed;
use rustical_xml::XmlDeserialize;
@@ -98,20 +99,27 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
let propname: <R::Resource as Resource>::PropName = prop.clone().into();
let propname: &str = propname.into();
match resource.set_prop(prop) {
Ok(()) => props_ok.push(propname.to_owned()),
Err(Error::PropReadOnly) => props_conflict.push(propname.to_owned()),
Ok(()) => props_ok.push((None, propname.to_owned())),
Err(Error::PropReadOnly) => {
props_conflict.push((None, propname.to_owned()))
}
Err(err) => return Err(err.into()),
};
}
SetPropertyPropWrapper::Invalid(invalid) => {
let propname = invalid.tag_name();
if <R::Resource as Resource>::list_props().contains(&propname.as_str()) {
if <R::Resource as Resource>::list_props()
.into_iter()
.map(|(_ns, tag)| tag)
.collect_vec()
.contains(&propname.as_str())
{
// This happens in following cases:
// - read-only properties with #[serde(skip_deserializing)]
// - internal properties
props_conflict.push(propname)
props_conflict.push((None, propname))
} else {
props_not_found.push(propname);
props_not_found.push((None, propname));
}
}
}
@@ -120,12 +128,12 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
let propname = remove_el.prop.0 .0;
match <<R::Resource as Resource>::PropName as FromStr>::from_str(&propname) {
Ok(prop) => match resource.remove_prop(&prop) {
Ok(()) => props_ok.push(propname),
Err(Error::PropReadOnly) => props_conflict.push(propname),
Ok(()) => props_ok.push((None, propname)),
Err(Error::PropReadOnly) => props_conflict.push((None, propname)),
Err(err) => return Err(err.into()),
},
// I guess removing a nonexisting property should be successful :)
Err(_) => props_ok.push(propname),
Err(_) => props_ok.push((None, propname)),
};
}
}

View File

@@ -6,11 +6,12 @@ use crate::Error;
use actix_web::dev::ResourceMap;
use actix_web::{http::StatusCode, ResponseError};
use itertools::Itertools;
use quick_xml::name::Namespace;
pub use resource_service::ResourceService;
use rustical_store::auth::User;
use rustical_xml::{XmlDeserialize, XmlSerialize};
use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize};
use std::str::FromStr;
use strum::{EnumString, VariantNames};
use strum::EnumString;
mod methods;
mod resource_service;
@@ -20,10 +21,10 @@ pub use resource_service::*;
pub trait ResourceProp: XmlSerialize + XmlDeserialize {}
impl<T: XmlSerialize + XmlDeserialize> ResourceProp for T {}
pub trait ResourcePropName: FromStr + VariantNames {}
impl<T: FromStr + VariantNames> ResourcePropName for T {}
pub trait ResourcePropName: FromStr {}
impl<T: FromStr> ResourcePropName for T {}
#[derive(XmlDeserialize, XmlSerialize, PartialEq)]
#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumVariants)]
pub enum CommonPropertiesProp {
// WebDAV (RFC 2518)
#[xml(skip_deserializing)]
@@ -49,7 +50,7 @@ pub enum EitherProp<Left: ResourceProp, Right: ResourceProp> {
Right(Right),
}
#[derive(EnumString, VariantNames, Clone)]
#[derive(EnumString, Clone)]
#[strum(serialize_all = "kebab-case")]
pub enum CommonPropertiesPropName {
Resourcetype,
@@ -60,14 +61,18 @@ pub enum CommonPropertiesPropName {
pub trait Resource: Clone + 'static {
type PropName: ResourcePropName + From<Self::Prop> + Into<&'static str>;
type Prop: ResourceProp + PartialEq + Clone;
type Prop: ResourceProp + PartialEq + Clone + EnumVariants;
type Error: ResponseError + From<crate::Error>;
type PrincipalResource: Resource + NamedRoute;
fn get_resourcetype(&self) -> Resourcetype;
fn list_props() -> Vec<&'static str> {
[Self::PropName::VARIANTS, CommonPropertiesPropName::VARIANTS].concat()
fn list_props() -> Vec<(Option<Namespace<'static>>, &'static str)> {
[
Self::Prop::variant_names(),
CommonPropertiesProp::variant_names(),
]
.concat()
}
fn get_internal_prop(
@@ -137,9 +142,10 @@ pub trait Resource: Clone + 'static {
Error::BadRequest("propname MUST be the only queried prop".to_owned()).into(),
);
}
let props = Self::list_props()
.into_iter()
.map(str::to_string)
.map(|(ns, tag)| (ns.to_owned(), tag.to_string()))
.collect_vec();
return Ok(ResponseElement {
@@ -159,7 +165,10 @@ pub trait Resource: Clone + 'static {
Error::BadRequest("allprop MUST be the only queried prop".to_owned()).into(),
);
}
props = Self::list_props();
props = Self::list_props()
.into_iter()
.map(|(_ns, tag)| tag)
.collect();
}
let mut valid_props = vec![];
@@ -195,7 +204,11 @@ pub trait Resource: Clone + 'static {
if !invalid_props.is_empty() {
propstats.push(PropstatWrapper::TagList(PropstatElement {
status: StatusCode::NOT_FOUND,
prop: invalid_props.into(),
prop: invalid_props
.into_iter()
.map(|tag| (None, tag))
.collect_vec()
.into(),
}));
}
Ok(ResponseElement {