Refactoring

This commit is contained in:
Lennart
2024-11-06 15:57:10 +01:00
parent ae4d5f0fc6
commit c21993ab15
17 changed files with 85 additions and 128 deletions

View File

@@ -1,6 +1,5 @@
pub mod depth_header;
pub mod error;
pub mod methods;
pub mod namespace;
pub mod privileges;
pub mod resource;

View File

@@ -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;

View 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;

View File

@@ -4,9 +4,9 @@ use crate::resource::CommonPropertiesProp;
use crate::resource::EitherProp;
use crate::resource::Resource;
use crate::resource::ResourceService;
use crate::xml::multistatus::PropstatWrapper;
use crate::xml::MultistatusElement;
use crate::xml::TagList;
use crate::xml::PropElement;
use crate::xml::PropfindType;
use crate::Error;
use actix_web::web::Path;
use actix_web::HttpRequest;
@@ -17,21 +17,7 @@ use tracing_actix_web::RootSpan;
#[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),
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
struct PropfindElement {
#[serde(rename = "$value")]
prop: PropfindType,
@@ -39,7 +25,7 @@ struct PropfindElement {
#[instrument(parent = root_span.id(), skip(path_components, req, root_span))]
#[allow(clippy::type_complexity)]
pub async fn route_propfind<R: ResourceService>(
pub(crate) async fn route_propfind<R: ResourceService>(
path_components: Path<R::PathComponents>,
body: String,
req: HttpRequest,
@@ -48,8 +34,8 @@ pub async fn route_propfind<R: ResourceService>(
root_span: RootSpan,
) -> Result<
MultistatusElement<
PropstatWrapper<EitherProp<<R::Resource as Resource>::Prop, CommonPropertiesProp>>,
PropstatWrapper<EitherProp<<R::MemberType as Resource>::Prop, CommonPropertiesProp>>,
EitherProp<<R::Resource as Resource>::Prop, CommonPropertiesProp>,
EitherProp<<R::MemberType as Resource>::Prop, CommonPropertiesProp>,
>,
R::Error,
> {
@@ -71,12 +57,8 @@ pub async fn route_propfind<R: ResourceService>(
};
let props = match propfind.prop {
PropfindType::Allprop => {
vec!["allprop".to_owned()]
}
PropfindType::Propname => {
vec!["propname".to_owned()]
}
PropfindType::Allprop => vec!["allprop".to_owned()],
PropfindType::Propname => vec!["propname".to_owned()],
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags.into_inner(),
};
let props: Vec<&str> = props.iter().map(String::as_str).collect();

View File

@@ -37,8 +37,8 @@ struct RemovePropertyElement {
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
enum Operation<T> {
Set(SetPropertyElement<T>),
enum Operation<PropType> {
Set(SetPropertyElement<PropType>),
Remove(RemovePropertyElement),
}
@@ -50,17 +50,18 @@ struct PropertyupdateElement<T> {
}
#[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>,
body: String,
req: HttpRequest,
user: User,
root_span: RootSpan,
) -> Result<MultistatusElement<PropstatWrapper<String>, PropstatWrapper<String>>, R::Error> {
) -> Result<MultistatusElement<String, String>, R::Error> {
let path_components = path.into_inner();
let href = req.path().to_owned();
let resource_service = R::new(&req, path_components.clone()).await?;
// Extract operations
let PropertyupdateElement::<<R::Resource as Resource>::Prop> { operations } =
quick_xml::de::from_str(&body).map_err(Error::XmlDeserializationError)?;
@@ -104,34 +105,20 @@ pub async fn route_proppatch<R: ResourceService>(
continue;
}
match resource.set_prop(prop) {
Ok(()) => {
props_ok.push(propname);
}
Err(Error::PropReadOnly) => {
props_conflict.push(propname);
}
Err(err) => {
return Err(err.into());
}
}
Ok(()) => props_ok.push(propname),
Err(Error::PropReadOnly) => props_conflict.push(propname),
Err(err) => return Err(err.into()),
};
}
Operation::Remove(_remove_el) => {
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);
}
Err(err) => {
return Err(err.into());
}
Ok(()) => props_ok.push(propname),
Err(Error::PropReadOnly) => props_conflict.push(propname),
Err(err) => return Err(err.into()),
},
Err(_) => {
// I guess removing a nonexisting property should be successful :)
props_ok.push(propname);
}
// I guess removing a nonexisting property should be successful :)
Err(_) => props_ok.push(propname),
};
}
}

View File

@@ -16,6 +16,7 @@ use std::str::FromStr;
use strum::{EnumString, VariantNames};
mod invalid_property;
mod methods;
mod resource_service;
pub trait ResourceProp: InvalidProperty + Serialize + for<'de> Deserialize<'de> {}
@@ -149,10 +150,7 @@ pub trait Resource: Clone + 'static {
mut props: Vec<&str>,
user: &User,
rmap: &ResourceMap,
) -> Result<
ResponseElement<PropstatWrapper<EitherProp<Self::Prop, CommonPropertiesProp>>>,
Self::Error,
> {
) -> Result<ResponseElement<EitherProp<Self::Prop, CommonPropertiesProp>>, Self::Error> {
if props.contains(&"propname") {
if props.len() != 1 {
// propname MUST be the only queried prop per spec

View File

@@ -4,8 +4,7 @@ use actix_web::{dev::ResourceMap, http::Method, web, HttpRequest, ResponseError}
use async_trait::async_trait;
use serde::Deserialize;
use crate::methods::{route_delete, route_propfind, route_proppatch};
use super::methods::{route_delete, route_propfind, route_proppatch};
use super::Resource;
#[async_trait(?Send)]

View File

@@ -1,8 +1,11 @@
pub mod multistatus;
mod propfind;
mod resourcetype;
pub mod tag_list;
pub mod tag_name;
pub use propfind::{PropElement, PropfindType};
use derive_more::derive::From;
pub use multistatus::MultistatusElement;
pub use tag_list::TagList;

View File

@@ -37,7 +37,7 @@ pub struct ResponseElement<PropstatType: Serialize> {
pub href: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
pub propstat: Vec<PropstatType>,
pub propstat: Vec<PropstatWrapper<PropstatType>>,
}
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
#[derive(Serialize)]
#[serde(rename = "multistatus", rename_all = "kebab-case")]
pub struct MultistatusElement<T1: Serialize, T2: Serialize> {
pub struct MultistatusElement<PropType: Serialize, MemberPropType: Serialize> {
#[serde(rename = "response")]
pub responses: Vec<ResponseElement<T1>>,
pub responses: Vec<ResponseElement<PropType>>,
#[serde(rename = "response")]
pub member_responses: Vec<ResponseElement<T2>>,
pub member_responses: Vec<ResponseElement<MemberPropType>>,
#[serde(rename = "@xmlns")]
pub ns_dav: &'static str,
#[serde(rename = "@xmlns:C")]

View 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),
}