mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 22:52:22 +00:00
Migrate all deserialization business to rustical_xml
This commit is contained in:
@@ -1,20 +1,20 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct SupportedCalendarComponent {
|
pub struct SupportedCalendarComponent {
|
||||||
#[serde(rename = "@name")]
|
#[serde(rename = "@name")]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct SupportedCalendarComponentSet {
|
pub struct SupportedCalendarComponentSet {
|
||||||
#[serde(rename = "C:comp")]
|
#[serde(rename = "C:comp")]
|
||||||
pub comp: Vec<SupportedCalendarComponent>,
|
pub comp: Vec<SupportedCalendarComponent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct CalendarData {
|
pub struct CalendarData {
|
||||||
#[serde(rename = "@content-type")]
|
#[serde(rename = "@content-type")]
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ use rustical_dav::resource::{Resource, ResourceService};
|
|||||||
use rustical_dav::xml::HrefElement;
|
use rustical_dav::xml::HrefElement;
|
||||||
use rustical_store::auth::User;
|
use rustical_store::auth::User;
|
||||||
use rustical_store::{Calendar, CalendarStore};
|
use rustical_store::{Calendar, CalendarStore};
|
||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -31,7 +32,7 @@ pub struct CalendarResourceService<C: CalendarStore + ?Sized> {
|
|||||||
calendar_id: String,
|
calendar_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)]
|
#[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
|
||||||
#[strum_discriminants(
|
#[strum_discriminants(
|
||||||
name(CalendarPropName),
|
name(CalendarPropName),
|
||||||
derive(EnumString, VariantNames),
|
derive(EnumString, VariantNames),
|
||||||
@@ -48,6 +49,7 @@ pub enum CalendarProp {
|
|||||||
// in DAVx5 yet
|
// in DAVx5 yet
|
||||||
// https://github.com/bitfireAT/webdav-push/commit/461259a2f2174454b2b00033419b11fac52b79e3
|
// https://github.com/bitfireAT/webdav-push/commit/461259a2f2174454b2b00033419b11fac52b79e3
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[xml(skip_deserializing)]
|
||||||
#[serde(rename = "P:push-transports", alias = "push-transports")]
|
#[serde(rename = "P:push-transports", alias = "push-transports")]
|
||||||
Transports(Transports),
|
Transports(Transports),
|
||||||
Topic(String),
|
Topic(String),
|
||||||
@@ -65,15 +67,19 @@ pub enum CalendarProp {
|
|||||||
rename = "C:supported-calendar-component-set",
|
rename = "C:supported-calendar-component-set",
|
||||||
alias = "supported-calendar-component-set"
|
alias = "supported-calendar-component-set"
|
||||||
)]
|
)]
|
||||||
|
// TODO: Re-add
|
||||||
|
#[xml(skip_deserializing)]
|
||||||
SupportedCalendarComponentSet(SupportedCalendarComponentSet),
|
SupportedCalendarComponentSet(SupportedCalendarComponentSet),
|
||||||
#[serde(
|
#[serde(
|
||||||
rename = "C:supported-calendar-data",
|
rename = "C:supported-calendar-data",
|
||||||
alias = "supported-calendar-data"
|
alias = "supported-calendar-data"
|
||||||
)]
|
)]
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[xml(skip_deserializing)]
|
||||||
SupportedCalendarData(SupportedCalendarData),
|
SupportedCalendarData(SupportedCalendarData),
|
||||||
MaxResourceSize(i64),
|
MaxResourceSize(i64),
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[xml(skip_deserializing)]
|
||||||
SupportedReportSet(SupportedReportSet),
|
SupportedReportSet(SupportedReportSet),
|
||||||
|
|
||||||
// Collection Synchronization (RFC 6578)
|
// Collection Synchronization (RFC 6578)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use rustical_dav::{
|
|||||||
resource::{Resource, ResourceService},
|
resource::{Resource, ResourceService},
|
||||||
};
|
};
|
||||||
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
||||||
|
use rustical_xml::XmlDeserialize;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
||||||
@@ -19,7 +20,7 @@ pub struct CalendarObjectResourceService<C: CalendarStore + ?Sized> {
|
|||||||
object_id: String,
|
object_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)]
|
#[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
|
||||||
#[strum_discriminants(
|
#[strum_discriminants(
|
||||||
name(CalendarObjectPropName),
|
name(CalendarObjectPropName),
|
||||||
derive(EnumString, VariantNames),
|
derive(EnumString, VariantNames),
|
||||||
@@ -36,6 +37,7 @@ pub enum CalendarObjectProp {
|
|||||||
CalendarData(String),
|
CalendarData(String),
|
||||||
|
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
|
#[xml(other)]
|
||||||
#[strum_discriminants(strum(disabled))]
|
#[strum_discriminants(strum(disabled))]
|
||||||
#[default]
|
#[default]
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ use rustical_dav::resource::{Resource, ResourceService};
|
|||||||
use rustical_dav::xml::HrefElement;
|
use rustical_dav::xml::HrefElement;
|
||||||
use rustical_store::auth::User;
|
use rustical_store::auth::User;
|
||||||
use rustical_store::CalendarStore;
|
use rustical_store::CalendarStore;
|
||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ pub struct PrincipalResource {
|
|||||||
principal: String,
|
principal: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)]
|
#[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
|
||||||
#[strum_discriminants(
|
#[strum_discriminants(
|
||||||
name(PrincipalPropName),
|
name(PrincipalPropName),
|
||||||
derive(EnumString, VariantNames),
|
derive(EnumString, VariantNames),
|
||||||
@@ -43,6 +44,7 @@ pub enum PrincipalProp {
|
|||||||
CalendarUserAddressSet(HrefElement),
|
CalendarUserAddressSet(HrefElement),
|
||||||
|
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
|
#[xml(other)]
|
||||||
#[strum_discriminants(strum(disabled))]
|
#[strum_discriminants(strum(disabled))]
|
||||||
#[default]
|
#[default]
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use rustical_dav::{
|
|||||||
resource::{Resource, ResourceService},
|
resource::{Resource, ResourceService},
|
||||||
};
|
};
|
||||||
use rustical_store::{auth::User, AddressObject, AddressbookStore};
|
use rustical_store::{auth::User, AddressObject, AddressbookStore};
|
||||||
|
use rustical_xml::XmlDeserialize;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
||||||
@@ -20,7 +21,7 @@ pub struct AddressObjectResourceService<AS: AddressbookStore + ?Sized> {
|
|||||||
object_id: String,
|
object_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)]
|
#[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
|
||||||
#[strum_discriminants(
|
#[strum_discriminants(
|
||||||
name(AddressObjectPropName),
|
name(AddressObjectPropName),
|
||||||
derive(EnumString, VariantNames),
|
derive(EnumString, VariantNames),
|
||||||
@@ -37,6 +38,7 @@ pub enum AddressObjectProp {
|
|||||||
AddressData(String),
|
AddressData(String),
|
||||||
|
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
|
#[xml(other)]
|
||||||
#[strum_discriminants(strum(disabled))]
|
#[strum_discriminants(strum(disabled))]
|
||||||
#[default]
|
#[default]
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ use rustical_dav::privileges::UserPrivilegeSet;
|
|||||||
use rustical_dav::resource::{Resource, ResourceService};
|
use rustical_dav::resource::{Resource, ResourceService};
|
||||||
use rustical_store::auth::User;
|
use rustical_store::auth::User;
|
||||||
use rustical_store::{Addressbook, AddressbookStore};
|
use rustical_store::{Addressbook, AddressbookStore};
|
||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
||||||
@@ -25,7 +26,7 @@ pub struct AddressbookResourceService<AS: AddressbookStore + ?Sized> {
|
|||||||
addressbook_id: String,
|
addressbook_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)]
|
#[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
#[strum_discriminants(
|
#[strum_discriminants(
|
||||||
name(AddressbookPropName),
|
name(AddressbookPropName),
|
||||||
@@ -48,8 +49,10 @@ pub enum AddressbookProp {
|
|||||||
alias = "supported-address-data"
|
alias = "supported-address-data"
|
||||||
)]
|
)]
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[xml(skip_deserializing)]
|
||||||
SupportedAddressData(SupportedAddressData),
|
SupportedAddressData(SupportedAddressData),
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[xml(skip_deserializing)]
|
||||||
SupportedReportSet(SupportedReportSet),
|
SupportedReportSet(SupportedReportSet),
|
||||||
MaxResourceSize(i64),
|
MaxResourceSize(i64),
|
||||||
|
|
||||||
@@ -60,6 +63,7 @@ pub enum AddressbookProp {
|
|||||||
Getctag(String),
|
Getctag(String),
|
||||||
|
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
|
#[xml(other)]
|
||||||
#[strum_discriminants(strum(disabled))]
|
#[strum_discriminants(strum(disabled))]
|
||||||
#[default]
|
#[default]
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ use rustical_dav::resource::{Resource, ResourceService};
|
|||||||
use rustical_dav::xml::HrefElement;
|
use rustical_dav::xml::HrefElement;
|
||||||
use rustical_store::auth::User;
|
use rustical_store::auth::User;
|
||||||
use rustical_store::AddressbookStore;
|
use rustical_store::AddressbookStore;
|
||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
use strum::{EnumDiscriminants, EnumString, VariantNames};
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ pub struct PrincipalResource {
|
|||||||
principal: String,
|
principal: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)]
|
#[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
|
||||||
#[strum_discriminants(
|
#[strum_discriminants(
|
||||||
name(PrincipalPropName),
|
name(PrincipalPropName),
|
||||||
derive(EnumString, VariantNames),
|
derive(EnumString, VariantNames),
|
||||||
@@ -43,6 +44,7 @@ pub enum PrincipalProp {
|
|||||||
PrincipalAddress(Option<HrefElement>),
|
PrincipalAddress(Option<HrefElement>),
|
||||||
|
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
|
#[xml(other)]
|
||||||
#[strum_discriminants(strum(disabled))]
|
#[strum_discriminants(strum(disabled))]
|
||||||
#[default]
|
#[default]
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ pub enum Error {
|
|||||||
PropReadOnly,
|
PropReadOnly,
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NewXmlDeserializationError(#[from] rustical_xml::XmlDeError),
|
XmlDeserializationError(#[from] rustical_xml::XmlDeError),
|
||||||
|
|
||||||
#[error(transparent)]
|
|
||||||
XmlDeserializationError(#[from] quick_xml::DeError),
|
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
XmlSerializationError(#[from] quick_xml::SeError),
|
XmlSerializationError(#[from] quick_xml::SeError),
|
||||||
@@ -36,7 +33,6 @@ impl actix_web::error::ResponseError for Error {
|
|||||||
Self::NotFound => StatusCode::NOT_FOUND,
|
Self::NotFound => StatusCode::NOT_FOUND,
|
||||||
Self::BadRequest(_) => StatusCode::BAD_REQUEST,
|
Self::BadRequest(_) => StatusCode::BAD_REQUEST,
|
||||||
Self::Unauthorized => StatusCode::UNAUTHORIZED,
|
Self::Unauthorized => StatusCode::UNAUTHORIZED,
|
||||||
Self::NewXmlDeserializationError(_) => StatusCode::BAD_REQUEST,
|
|
||||||
Self::XmlDeserializationError(_) => StatusCode::BAD_REQUEST,
|
Self::XmlDeserializationError(_) => StatusCode::BAD_REQUEST,
|
||||||
Self::XmlSerializationError(_) => StatusCode::BAD_REQUEST,
|
Self::XmlSerializationError(_) => StatusCode::BAD_REQUEST,
|
||||||
Error::PropReadOnly => StatusCode::CONFLICT,
|
Error::PropReadOnly => StatusCode::CONFLICT,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, Hash, PartialEq)]
|
#[derive(Debug, Clone, Serialize, XmlDeserialize, Eq, Hash, PartialEq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
pub enum UserPrivilege {
|
pub enum UserPrivilege {
|
||||||
Read,
|
Read,
|
||||||
Write,
|
Write,
|
||||||
@@ -42,10 +42,9 @@ impl Serialize for UserPrivilegeSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement Deserialize once we need it
|
#[derive(Debug, Clone, XmlDeserialize, Default, PartialEq)]
|
||||||
#[derive(Debug, Clone, Deserialize, Default, PartialEq)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
pub struct UserPrivilegeSet {
|
pub struct UserPrivilegeSet {
|
||||||
|
#[xml(flatten)]
|
||||||
privileges: HashSet<UserPrivilege>,
|
privileges: HashSet<UserPrivilege>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ pub(crate) async fn route_propfind<R: ResourceService>(
|
|||||||
|
|
||||||
// A request body is optional. If empty we MUST return all props
|
// A request body is optional. If empty we MUST return all props
|
||||||
let propfind: PropfindElement = if !body.is_empty() {
|
let propfind: PropfindElement = if !body.is_empty() {
|
||||||
PropfindElement::parse_str(&body).map_err(Error::NewXmlDeserializationError)?
|
PropfindElement::parse_str(&body).map_err(Error::XmlDeserializationError)?
|
||||||
} else {
|
} else {
|
||||||
PropfindElement {
|
PropfindElement {
|
||||||
prop: PropfindType::Allprop,
|
prop: PropfindType::Allprop,
|
||||||
|
|||||||
@@ -5,47 +5,53 @@ use crate::resource::ResourceService;
|
|||||||
use crate::xml::multistatus::{PropstatElement, PropstatWrapper, ResponseElement};
|
use crate::xml::multistatus::{PropstatElement, PropstatWrapper, ResponseElement};
|
||||||
use crate::xml::MultistatusElement;
|
use crate::xml::MultistatusElement;
|
||||||
use crate::xml::TagList;
|
use crate::xml::TagList;
|
||||||
use crate::xml::TagName;
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
use actix_web::{web::Path, HttpRequest};
|
use actix_web::{web::Path, HttpRequest};
|
||||||
use rustical_store::auth::User;
|
use rustical_store::auth::User;
|
||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use rustical_xml::XmlDocument;
|
||||||
|
use rustical_xml::XmlRootTag;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use tracing_actix_web::RootSpan;
|
use tracing_actix_web::RootSpan;
|
||||||
|
|
||||||
// https://docs.rs/quick-xml/latest/quick_xml/de/index.html#normal-enum-variant
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
struct SetPropertyElement<T: XmlDeserialize> {
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
struct PropertyElement<T> {
|
|
||||||
#[serde(rename = "$value")]
|
|
||||||
prop: T,
|
prop: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
struct TagName {
|
||||||
struct SetPropertyElement<T> {
|
#[xml(ty = "tag_name")]
|
||||||
prop: PropertyElement<T>,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
struct PropertyElement {
|
||||||
|
#[xml(ty = "untagged")]
|
||||||
|
property: TagName,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
struct RemovePropertyElement {
|
struct RemovePropertyElement {
|
||||||
prop: PropertyElement<TagName>,
|
prop: PropertyElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
enum Operation<T: XmlDeserialize> {
|
||||||
enum Operation<PropType> {
|
Set(SetPropertyElement<T>),
|
||||||
Set(SetPropertyElement<PropType>),
|
|
||||||
Remove(RemovePropertyElement),
|
Remove(RemovePropertyElement),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(XmlDeserialize, XmlRootTag, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[xml(root = b"propertyupdate")]
|
||||||
struct PropertyupdateElement<T> {
|
struct PropertyupdateElement<T: XmlDeserialize> {
|
||||||
#[serde(rename = "$value", default = "Vec::new")]
|
// #[xml(flatten)]
|
||||||
|
// set: Vec<T>,
|
||||||
|
// #[xml(flatten)]
|
||||||
|
// remove: Vec<TagName>,
|
||||||
|
#[xml(ty = "untagged", flatten)]
|
||||||
operations: Vec<Operation<T>>,
|
operations: Vec<Operation<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,18 +69,18 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
|
|||||||
|
|
||||||
// Extract operations
|
// 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)?;
|
XmlDocument::parse_str(&body).map_err(Error::XmlDeserializationError)?;
|
||||||
|
|
||||||
// Extract all set property names without verification
|
// Extract all set property names without verification
|
||||||
// Weird workaround because quick_xml doesn't allow untagged enums
|
// Weird workaround because quick_xml doesn't allow untagged enums
|
||||||
let propnames: Vec<String> = quick_xml::de::from_str::<PropertyupdateElement<TagName>>(&body)
|
let propnames: Vec<String> = PropertyupdateElement::<TagName>::parse_str(&body)
|
||||||
.map_err(Error::XmlDeserializationError)?
|
.map_err(Error::XmlDeserializationError)?
|
||||||
.operations
|
.operations
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|op_el| match op_el {
|
.map(|op_el| match op_el {
|
||||||
Operation::Set(set_el) => set_el.prop.prop.into(),
|
Operation::Set(set_el) => set_el.prop.name,
|
||||||
// If we can't remove a nonexisting property then that's no big deal
|
// If we can't remove a nonexisting property then that's no big deal
|
||||||
Operation::Remove(remove_el) => remove_el.prop.prop.into(),
|
Operation::Remove(remove_el) => remove_el.prop.property.name,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -90,9 +96,7 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
|
|||||||
|
|
||||||
for (operation, propname) in operations.into_iter().zip(propnames) {
|
for (operation, propname) in operations.into_iter().zip(propnames) {
|
||||||
match operation {
|
match operation {
|
||||||
Operation::Set(SetPropertyElement {
|
Operation::Set(SetPropertyElement { prop }) => {
|
||||||
prop: PropertyElement { prop },
|
|
||||||
}) => {
|
|
||||||
if prop.invalid_property() {
|
if prop.invalid_property() {
|
||||||
if <R::Resource as Resource>::list_props().contains(&propname.as_str()) {
|
if <R::Resource as Resource>::list_props().contains(&propname.as_str()) {
|
||||||
// This happens in following cases:
|
// This happens in following cases:
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ pub use invalid_property::InvalidProperty;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
pub use resource_service::ResourceService;
|
pub use resource_service::ResourceService;
|
||||||
use rustical_store::auth::User;
|
use rustical_store::auth::User;
|
||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use strum::{EnumString, VariantNames};
|
use strum::{EnumString, VariantNames};
|
||||||
|
|
||||||
@@ -19,20 +20,21 @@ mod invalid_property;
|
|||||||
mod methods;
|
mod methods;
|
||||||
mod resource_service;
|
mod resource_service;
|
||||||
|
|
||||||
pub trait ResourceProp: InvalidProperty + Serialize + for<'de> Deserialize<'de> {}
|
pub trait ResourceProp: InvalidProperty + Serialize + XmlDeserialize {}
|
||||||
impl<T: InvalidProperty + Serialize + for<'de> Deserialize<'de>> ResourceProp for T {}
|
impl<T: InvalidProperty + Serialize + XmlDeserialize> ResourceProp for T {}
|
||||||
|
|
||||||
pub trait ResourcePropName: FromStr + VariantNames {}
|
pub trait ResourcePropName: FromStr + VariantNames {}
|
||||||
impl<T: FromStr + VariantNames> ResourcePropName for T {}
|
impl<T: FromStr + VariantNames> ResourcePropName for T {}
|
||||||
|
|
||||||
pub trait ResourceType: Serialize + for<'de> Deserialize<'de> {}
|
pub trait ResourceType: Serialize + XmlDeserialize {}
|
||||||
impl<T: Serialize + for<'de> Deserialize<'de>> ResourceType for T {}
|
impl<T: Serialize + XmlDeserialize> ResourceType for T {}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, PartialEq, Default)]
|
#[derive(XmlDeserialize, Serialize, PartialEq, Default)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum CommonPropertiesProp {
|
pub enum CommonPropertiesProp {
|
||||||
// WebDAV (RFC 2518)
|
// WebDAV (RFC 2518)
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
#[xml(skip_deserializing)]
|
||||||
Resourcetype(Resourcetype),
|
Resourcetype(Resourcetype),
|
||||||
|
|
||||||
// WebDAV Current Principal Extension (RFC 5397)
|
// WebDAV Current Principal Extension (RFC 5397)
|
||||||
@@ -40,7 +42,7 @@ pub enum CommonPropertiesProp {
|
|||||||
|
|
||||||
// WebDAV Access Control Protocol (RFC 3477)
|
// WebDAV Access Control Protocol (RFC 3477)
|
||||||
CurrentUserPrivilegeSet(UserPrivilegeSet),
|
CurrentUserPrivilegeSet(UserPrivilegeSet),
|
||||||
Owner(Option<HrefElement>),
|
Owner(HrefElement),
|
||||||
|
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
#[default]
|
#[default]
|
||||||
@@ -97,11 +99,18 @@ pub trait Resource: Clone + 'static {
|
|||||||
CommonPropertiesProp::CurrentUserPrivilegeSet(self.get_user_privileges(user)?)
|
CommonPropertiesProp::CurrentUserPrivilegeSet(self.get_user_privileges(user)?)
|
||||||
}
|
}
|
||||||
CommonPropertiesPropName::Owner => {
|
CommonPropertiesPropName::Owner => {
|
||||||
CommonPropertiesProp::Owner(self.get_owner().map(|owner| {
|
// TODO: Reintroduce optional owner field
|
||||||
|
let owner = self.get_owner().unwrap_or(&user.id);
|
||||||
|
CommonPropertiesProp::Owner(
|
||||||
Self::PrincipalResource::get_url(rmap, [owner])
|
Self::PrincipalResource::get_url(rmap, [owner])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into()
|
.into(),
|
||||||
}))
|
)
|
||||||
|
// CommonPropertiesProp::Owner(self.get_owner().map(|owner| {
|
||||||
|
// Self::PrincipalResource::get_url(rmap, [owner])
|
||||||
|
// .unwrap()
|
||||||
|
// .into()
|
||||||
|
// }))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ use actix_web::dev::ResourceMap;
|
|||||||
use actix_web::HttpRequest;
|
use actix_web::HttpRequest;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use rustical_store::auth::User;
|
use rustical_store::auth::User;
|
||||||
use serde::{Deserialize, Serialize};
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use strum::{EnumString, VariantNames};
|
use strum::{EnumString, VariantNames};
|
||||||
@@ -22,7 +23,7 @@ impl<PR: Resource> Default for RootResource<PR> {
|
|||||||
#[strum(serialize_all = "kebab-case")]
|
#[strum(serialize_all = "kebab-case")]
|
||||||
pub enum RootResourcePropName {}
|
pub enum RootResourcePropName {}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Default, Clone, PartialEq)]
|
#[derive(XmlDeserialize, Serialize, Default, Clone, PartialEq)]
|
||||||
pub enum RootResourceProp {
|
pub enum RootResourceProp {
|
||||||
#[serde(other)]
|
#[serde(other)]
|
||||||
#[default]
|
#[default]
|
||||||
|
|||||||
@@ -2,20 +2,15 @@ pub mod multistatus;
|
|||||||
mod propfind;
|
mod propfind;
|
||||||
mod resourcetype;
|
mod resourcetype;
|
||||||
pub mod tag_list;
|
pub mod tag_list;
|
||||||
pub mod tag_name;
|
|
||||||
|
|
||||||
pub use propfind::{PropElement, PropfindElement, PropfindType, Propname};
|
|
||||||
|
|
||||||
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 propfind::{PropElement, PropfindElement, PropfindType, Propname};
|
||||||
pub use tag_name::TagName;
|
|
||||||
|
|
||||||
pub use resourcetype::Resourcetype;
|
pub use resourcetype::Resourcetype;
|
||||||
|
use rustical_xml::XmlDeserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
pub use tag_list::TagList;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
#[derive(XmlDeserialize, Debug, Clone, Serialize, From, PartialEq)]
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, From, PartialEq)]
|
|
||||||
pub struct HrefElement {
|
pub struct HrefElement {
|
||||||
pub href: String,
|
pub href: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
use serde::{
|
|
||||||
de::{VariantAccess, Visitor},
|
|
||||||
Deserialize,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct TagName(pub String);
|
|
||||||
|
|
||||||
impl From<TagName> for String {
|
|
||||||
fn from(value: TagName) -> Self {
|
|
||||||
value.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for TagName {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for TagName {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct __Visitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for __Visitor {
|
|
||||||
type Value = TagName;
|
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
formatter.write_str("tagname")
|
|
||||||
}
|
|
||||||
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
|
||||||
where
|
|
||||||
A: serde::de::EnumAccess<'de>,
|
|
||||||
{
|
|
||||||
let (name, variant): (String, _) = data.variant()?;
|
|
||||||
VariantAccess::unit_variant(variant)?;
|
|
||||||
Ok(TagName(name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deserializer.deserialize_enum("doesn't matter", &[], __Visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user