mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 17:02:32 +00:00
Refactoring
This commit is contained in:
@@ -9,12 +9,8 @@ use actix_web::{
|
||||
HttpRequest,
|
||||
};
|
||||
use rustical_dav::{
|
||||
methods::propfind::{PropElement, PropfindType},
|
||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||
xml::{
|
||||
multistatus::{PropstatWrapper, ResponseElement},
|
||||
MultistatusElement,
|
||||
},
|
||||
xml::{multistatus::ResponseElement, MultistatusElement, PropElement, PropfindType},
|
||||
};
|
||||
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
||||
use serde::Deserialize;
|
||||
@@ -69,13 +65,8 @@ pub async fn handle_calendar_multiget<C: CalendarStore + ?Sized>(
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
cal_store: &C,
|
||||
) -> Result<
|
||||
MultistatusElement<
|
||||
PropstatWrapper<EitherProp<CalendarObjectProp, CommonPropertiesProp>>,
|
||||
String,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
) -> Result<MultistatusElement<EitherProp<CalendarObjectProp, CommonPropertiesProp>, String>, Error>
|
||||
{
|
||||
let principal_url = PrincipalResource::get_url(req.resource_map(), vec![principal]).unwrap();
|
||||
let (objects, not_found) =
|
||||
get_objects_calendar_multiget(&cal_multiget, &principal_url, principal, cal_id, cal_store)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use actix_web::HttpRequest;
|
||||
use chrono::{DateTime, Utc};
|
||||
use rustical_dav::{
|
||||
methods::propfind::{PropElement, PropfindType},
|
||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||
xml::{multistatus::PropstatWrapper, MultistatusElement},
|
||||
xml::{MultistatusElement, PropElement, PropfindType},
|
||||
};
|
||||
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
||||
use serde::Deserialize;
|
||||
@@ -210,13 +209,8 @@ pub async fn handle_calendar_query<C: CalendarStore + ?Sized>(
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
cal_store: &C,
|
||||
) -> Result<
|
||||
MultistatusElement<
|
||||
PropstatWrapper<EitherProp<CalendarObjectProp, CommonPropertiesProp>>,
|
||||
String,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
) -> Result<MultistatusElement<EitherProp<CalendarObjectProp, CommonPropertiesProp>, String>, Error>
|
||||
{
|
||||
let objects = get_objects_calendar_query(&cal_query, principal, cal_id, cal_store).await?;
|
||||
|
||||
let props = match cal_query.prop {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use actix_web::{http::StatusCode, HttpRequest};
|
||||
use rustical_dav::{
|
||||
methods::propfind::{PropElement, PropfindType},
|
||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||
xml::{
|
||||
multistatus::{PropstatWrapper, ResponseElement},
|
||||
MultistatusElement,
|
||||
},
|
||||
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||
xml::{PropElement, PropfindType},
|
||||
};
|
||||
use rustical_store::{
|
||||
auth::User,
|
||||
@@ -49,13 +46,8 @@ pub async fn handle_sync_collection<C: CalendarStore + ?Sized>(
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
cal_store: &C,
|
||||
) -> Result<
|
||||
MultistatusElement<
|
||||
PropstatWrapper<EitherProp<CalendarObjectProp, CommonPropertiesProp>>,
|
||||
String,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
) -> Result<MultistatusElement<EitherProp<CalendarObjectProp, CommonPropertiesProp>, String>, Error>
|
||||
{
|
||||
let props = match sync_collection.prop {
|
||||
PropfindType::Allprop => {
|
||||
vec!["allprop".to_owned()]
|
||||
|
||||
@@ -9,12 +9,9 @@ use actix_web::{
|
||||
HttpRequest,
|
||||
};
|
||||
use rustical_dav::{
|
||||
methods::propfind::{PropElement, PropfindType},
|
||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||
xml::{
|
||||
multistatus::{PropstatWrapper, ResponseElement},
|
||||
MultistatusElement,
|
||||
},
|
||||
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||
xml::{PropElement, PropfindType},
|
||||
};
|
||||
use rustical_store::{auth::User, AddressObject, AddressbookStore};
|
||||
use serde::Deserialize;
|
||||
@@ -68,13 +65,8 @@ pub async fn handle_addressbook_multiget<AS: AddressbookStore + ?Sized>(
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
addr_store: &AS,
|
||||
) -> Result<
|
||||
MultistatusElement<
|
||||
PropstatWrapper<EitherProp<AddressObjectProp, CommonPropertiesProp>>,
|
||||
String,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
) -> Result<MultistatusElement<EitherProp<AddressObjectProp, CommonPropertiesProp>, String>, Error>
|
||||
{
|
||||
let principal_url = PrincipalResource::get_url(req.resource_map(), vec![principal]).unwrap();
|
||||
let (objects, not_found) = get_objects_addressbook_multiget(
|
||||
&addr_multiget,
|
||||
|
||||
@@ -4,12 +4,9 @@ use crate::{
|
||||
};
|
||||
use actix_web::{http::StatusCode, HttpRequest};
|
||||
use rustical_dav::{
|
||||
methods::propfind::{PropElement, PropfindType},
|
||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||
xml::{
|
||||
multistatus::{PropstatWrapper, ResponseElement},
|
||||
MultistatusElement,
|
||||
},
|
||||
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||
xml::{PropElement, PropfindType},
|
||||
};
|
||||
use rustical_store::{
|
||||
auth::User,
|
||||
@@ -47,13 +44,8 @@ pub async fn handle_sync_collection<AS: AddressbookStore + ?Sized>(
|
||||
principal: &str,
|
||||
addressbook_id: &str,
|
||||
addr_store: &AS,
|
||||
) -> Result<
|
||||
MultistatusElement<
|
||||
PropstatWrapper<EitherProp<AddressObjectProp, CommonPropertiesProp>>,
|
||||
String,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
) -> Result<MultistatusElement<EitherProp<AddressObjectProp, CommonPropertiesProp>, String>, Error>
|
||||
{
|
||||
let props = match sync_collection.prop {
|
||||
PropfindType::Allprop => {
|
||||
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 error;
|
||||
pub mod methods;
|
||||
pub mod namespace;
|
||||
pub mod privileges;
|
||||
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::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();
|
||||
@@ -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),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")]
|
||||
|
||||
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