mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 22:52:22 +00:00
resourcetype: Proper namespace handling
This commit is contained in:
@@ -13,7 +13,7 @@ use async_trait::async_trait;
|
||||
use derive_more::derive::{From, Into};
|
||||
use rustical_dav::privileges::UserPrivilegeSet;
|
||||
use rustical_dav::resource::{Resource, ResourceService};
|
||||
use rustical_dav::xml::HrefElement;
|
||||
use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner};
|
||||
use rustical_store::auth::User;
|
||||
use rustical_store::{Calendar, CalendarStore};
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
@@ -93,11 +93,33 @@ impl Resource for CalendarResource {
|
||||
type Error = Error;
|
||||
type PrincipalResource = PrincipalResource;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str] {
|
||||
fn get_resourcetype(&self) -> Resourcetype {
|
||||
if self.0.subscription_url.is_none() {
|
||||
&["collection", "C:calendar"]
|
||||
Resourcetype {
|
||||
inner: &[
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_DAV,
|
||||
name: "collection",
|
||||
},
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_CALDAV,
|
||||
name: "calendar",
|
||||
},
|
||||
],
|
||||
}
|
||||
} else {
|
||||
&["collection", "CS:subscribed"]
|
||||
Resourcetype {
|
||||
inner: &[
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_DAV,
|
||||
name: "collection",
|
||||
},
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_CALENDARSERVER,
|
||||
name: "subscribed",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use derive_more::derive::{From, Into};
|
||||
use rustical_dav::{
|
||||
privileges::UserPrivilegeSet,
|
||||
resource::{Resource, ResourceService},
|
||||
xml::Resourcetype,
|
||||
};
|
||||
use rustical_store::{auth::User, CalendarObject, CalendarStore};
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
@@ -53,8 +54,8 @@ impl Resource for CalendarObjectResource {
|
||||
type Error = Error;
|
||||
type PrincipalResource = PrincipalResource;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str] {
|
||||
&[]
|
||||
fn get_resourcetype(&self) -> Resourcetype {
|
||||
Resourcetype { inner: &[] }
|
||||
}
|
||||
|
||||
fn get_prop(
|
||||
|
||||
@@ -4,7 +4,7 @@ use actix_web::dev::ResourceMap;
|
||||
use async_trait::async_trait;
|
||||
use rustical_dav::privileges::UserPrivilegeSet;
|
||||
use rustical_dav::resource::{Resource, ResourceService};
|
||||
use rustical_dav::xml::HrefElement;
|
||||
use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner};
|
||||
use rustical_store::auth::User;
|
||||
use rustical_store::CalendarStore;
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
@@ -57,8 +57,19 @@ impl Resource for PrincipalResource {
|
||||
type Error = Error;
|
||||
type PrincipalResource = PrincipalResource;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str] {
|
||||
&["collection", "principal"]
|
||||
fn get_resourcetype(&self) -> Resourcetype {
|
||||
Resourcetype {
|
||||
inner: &[
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_DAV,
|
||||
name: "collection",
|
||||
},
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_DAV,
|
||||
name: "principal",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn get_prop(
|
||||
|
||||
@@ -5,6 +5,7 @@ use derive_more::derive::{From, Into};
|
||||
use rustical_dav::{
|
||||
privileges::UserPrivilegeSet,
|
||||
resource::{Resource, ResourceService},
|
||||
xml::Resourcetype,
|
||||
};
|
||||
use rustical_store::{auth::User, AddressObject, AddressbookStore};
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
@@ -54,8 +55,8 @@ impl Resource for AddressObjectResource {
|
||||
type Error = Error;
|
||||
type PrincipalResource = PrincipalResource;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str] {
|
||||
&[]
|
||||
fn get_resourcetype(&self) -> Resourcetype {
|
||||
Resourcetype { inner: &[] }
|
||||
}
|
||||
|
||||
fn get_prop(
|
||||
|
||||
@@ -11,6 +11,7 @@ use async_trait::async_trait;
|
||||
use derive_more::derive::{From, Into};
|
||||
use rustical_dav::privileges::UserPrivilegeSet;
|
||||
use rustical_dav::resource::{Resource, ResourceService};
|
||||
use rustical_dav::xml::{Resourcetype, ResourcetypeInner};
|
||||
use rustical_store::auth::User;
|
||||
use rustical_store::{Addressbook, AddressbookStore};
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
@@ -68,9 +69,19 @@ impl Resource for AddressbookResource {
|
||||
type Error = Error;
|
||||
type PrincipalResource = PrincipalResource;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str] {
|
||||
// TODO: namespace
|
||||
&["collection", "CARD:addressbook"]
|
||||
fn get_resourcetype(&self) -> Resourcetype {
|
||||
Resourcetype {
|
||||
inner: &[
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_DAV,
|
||||
name: "collection",
|
||||
},
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_CARDDAV,
|
||||
name: "addressbook",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn get_prop(
|
||||
|
||||
@@ -4,7 +4,7 @@ use actix_web::dev::ResourceMap;
|
||||
use async_trait::async_trait;
|
||||
use rustical_dav::privileges::UserPrivilegeSet;
|
||||
use rustical_dav::resource::{Resource, ResourceService};
|
||||
use rustical_dav::xml::HrefElement;
|
||||
use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner};
|
||||
use rustical_store::auth::User;
|
||||
use rustical_store::AddressbookStore;
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
@@ -58,8 +58,19 @@ impl Resource for PrincipalResource {
|
||||
type Error = Error;
|
||||
type PrincipalResource = PrincipalResource;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str] {
|
||||
&["collection", "principal"]
|
||||
fn get_resourcetype(&self) -> Resourcetype {
|
||||
Resourcetype {
|
||||
inner: &[
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_DAV,
|
||||
name: "collection",
|
||||
},
|
||||
ResourcetypeInner {
|
||||
ns: rustical_dav::namespace::NS_DAV,
|
||||
name: "principal",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn get_prop(
|
||||
|
||||
@@ -64,7 +64,7 @@ pub trait Resource: Clone + 'static {
|
||||
type Error: ResponseError + From<crate::Error>;
|
||||
type PrincipalResource: Resource;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str];
|
||||
fn get_resourcetype(&self) -> Resourcetype;
|
||||
|
||||
fn list_props() -> Vec<&'static str> {
|
||||
[Self::PropName::VARIANTS, CommonPropertiesPropName::VARIANTS].concat()
|
||||
@@ -78,7 +78,7 @@ pub trait Resource: Clone + 'static {
|
||||
) -> Result<CommonPropertiesProp, Self::Error> {
|
||||
Ok(match prop {
|
||||
CommonPropertiesPropName::Resourcetype => {
|
||||
CommonPropertiesProp::Resourcetype(Resourcetype(self.get_resourcetype()))
|
||||
CommonPropertiesProp::Resourcetype(self.get_resourcetype())
|
||||
}
|
||||
CommonPropertiesPropName::CurrentUserPrincipal => {
|
||||
CommonPropertiesProp::CurrentUserPrincipal(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::privileges::UserPrivilegeSet;
|
||||
use crate::resource::{Resource, ResourceService};
|
||||
use crate::xml::{Resourcetype, ResourcetypeInner};
|
||||
use actix_web::dev::ResourceMap;
|
||||
use async_trait::async_trait;
|
||||
use rustical_store::auth::User;
|
||||
@@ -37,8 +38,13 @@ impl<PR: Resource> Resource for RootResource<PR> {
|
||||
type Error = PR::Error;
|
||||
type PrincipalResource = PR;
|
||||
|
||||
fn get_resourcetype(&self) -> &'static [&'static str] {
|
||||
&["collection"]
|
||||
fn get_resourcetype(&self) -> Resourcetype {
|
||||
Resourcetype {
|
||||
inner: &[ResourcetypeInner {
|
||||
ns: crate::namespace::NS_DAV,
|
||||
name: "collection",
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
fn get_prop(
|
||||
|
||||
@@ -5,7 +5,7 @@ pub mod tag_list;
|
||||
use derive_more::derive::From;
|
||||
pub use multistatus::MultistatusElement;
|
||||
pub use propfind::{PropElement, PropfindElement, PropfindType, Propname};
|
||||
pub use resourcetype::Resourcetype;
|
||||
pub use resourcetype::{Resourcetype, ResourcetypeInner};
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
pub use tag_list::TagList;
|
||||
|
||||
|
||||
@@ -1,47 +1,25 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use quick_xml::events::attributes::Attribute;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, Event};
|
||||
use quick_xml::name::Namespace;
|
||||
use rustical_xml::XmlSerialize;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Resourcetype(pub &'static [&'static str]);
|
||||
|
||||
impl XmlSerialize for Resourcetype {
|
||||
fn serialize<W: std::io::Write>(
|
||||
&self,
|
||||
ns: Option<Namespace>,
|
||||
tag: Option<&[u8]>,
|
||||
namespaces: &HashMap<Namespace, &[u8]>,
|
||||
writer: &mut quick_xml::Writer<W>,
|
||||
) -> std::io::Result<()> {
|
||||
let tag_str = tag.map(String::from_utf8_lossy);
|
||||
if let Some(tag) = &tag_str {
|
||||
writer.write_event(Event::Start(BytesStart::new(tag.clone())))?;
|
||||
#[derive(Debug, Clone, PartialEq, XmlSerialize)]
|
||||
pub struct Resourcetype {
|
||||
#[xml(flatten, ty = "untagged")]
|
||||
pub inner: &'static [ResourcetypeInner],
|
||||
}
|
||||
|
||||
for &ty in self.0 {
|
||||
writer.write_event(Event::Empty(BytesStart::new(ty)))?;
|
||||
}
|
||||
|
||||
if let Some(tag) = &tag_str {
|
||||
writer.write_event(Event::End(BytesEnd::new(tag.clone())))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(refining_impl_trait)]
|
||||
fn attributes<'a>(&self) -> Option<Vec<Attribute<'a>>> {
|
||||
None
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, XmlSerialize)]
|
||||
pub struct ResourcetypeInner {
|
||||
#[xml(ty = "namespace")]
|
||||
pub ns: quick_xml::name::Namespace<'static>,
|
||||
#[xml(ty = "tag_name")]
|
||||
pub name: &'static str,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Resourcetype;
|
||||
use rustical_xml::{XmlRootTag, XmlSerialize, XmlSerializeRoot};
|
||||
|
||||
use super::{Resourcetype, ResourcetypeInner};
|
||||
|
||||
#[derive(XmlSerialize, XmlRootTag)]
|
||||
#[xml(root = b"document")]
|
||||
struct Document {
|
||||
@@ -53,14 +31,25 @@ mod tests {
|
||||
let mut buf = Vec::new();
|
||||
let mut writer = quick_xml::Writer::new(&mut buf);
|
||||
Document {
|
||||
resourcetype: Resourcetype(&["collection", "hello"]),
|
||||
resourcetype: Resourcetype {
|
||||
inner: &[
|
||||
ResourcetypeInner {
|
||||
ns: crate::namespace::NS_DAV,
|
||||
name: "displayname",
|
||||
},
|
||||
ResourcetypeInner {
|
||||
ns: crate::namespace::NS_CALENDARSERVER,
|
||||
name: "calendar-color",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
.serialize_root(&mut writer)
|
||||
.unwrap();
|
||||
let out = String::from_utf8(buf).unwrap();
|
||||
assert_eq!(
|
||||
out,
|
||||
"<document><resourcetype><collection/><hello/></resourcetype></document>"
|
||||
"<document><resourcetype><displayname xmlns=\"DAV:\"/><calendar-color xmlns=\"http://calendarserver.org/ns/\"/></resourcetype></document>"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::attrs::{FieldType, StructAttrs};
|
||||
use crate::{field, Field};
|
||||
use crate::Field;
|
||||
use core::panic;
|
||||
use darling::FromDeriveInput;
|
||||
use quote::quote;
|
||||
@@ -197,7 +197,7 @@ impl NamedStruct {
|
||||
pub fn impl_se(&self) -> proc_macro2::TokenStream {
|
||||
let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl();
|
||||
let ident = &self.ident;
|
||||
let tag_writers = self.fields.iter().map(Field::tag_writer);
|
||||
let tag_writers: Vec<_> = self.fields.iter().filter_map(Field::tag_writer).collect();
|
||||
|
||||
let untagged_attributes = self
|
||||
.fields
|
||||
@@ -240,7 +240,18 @@ impl NamedStruct {
|
||||
}
|
||||
});
|
||||
|
||||
let is_empty = tag_writers.len() == 0;
|
||||
let namespace_field = self
|
||||
.fields
|
||||
.iter()
|
||||
.find(|field| field.attrs.xml_ty == FieldType::Namespace)
|
||||
.map(|field| {
|
||||
let field_ident = field.field_ident();
|
||||
quote! {
|
||||
let ns = Some(self.#field_ident);
|
||||
}
|
||||
});
|
||||
|
||||
let is_empty = tag_writers.is_empty();
|
||||
|
||||
// If we are the root element write the xmlns attributes
|
||||
let prefix_attributes = if self.attrs.root.is_some() {
|
||||
@@ -276,6 +287,7 @@ impl NamedStruct {
|
||||
use ::quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
|
||||
|
||||
#tag_name_field;
|
||||
#namespace_field;
|
||||
|
||||
let prefix = ns
|
||||
.map(|ns| namespaces.get(&ns))
|
||||
|
||||
Reference in New Issue
Block a user