xml: Strict namespace, some tests and restructuring

This commit is contained in:
Lennart
2025-01-15 19:12:54 +01:00
parent d021e7b8bf
commit 3e0571bb72
15 changed files with 176 additions and 157 deletions

View File

@@ -8,26 +8,34 @@ use tracing_actix_web::RootSpan;
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
pub struct Resourcetype {
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
addressbook: Option<()>,
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
collection: Option<()>,
}
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
pub struct MkcolAddressbookProp {
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
resourcetype: Option<Resourcetype>,
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
displayname: Option<String>,
#[xml(rename = b"addressbook-description")]
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
description: Option<String>,
}
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
pub struct PropElement<T: XmlDeserialize> {
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
prop: T,
}
#[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)]
#[xml(root = b"mkcol")]
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
struct MkcolRequest {
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
set: PropElement<MkcolAddressbookProp>,
}

View File

@@ -16,11 +16,12 @@ use rustical_xml::XmlDeserialize;
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
#[allow(dead_code)]
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
pub struct AddressbookMultigetRequest {
#[xml(ty = "untagged")]
prop: PropfindType,
#[xml(flatten)]
href: Vec<String>,
#[xml(ns = "rustical_dav::namespace::NS_DAV", ty = "untagged")]
pub(crate) prop: PropfindType,
#[xml(ns = "rustical_dav::namespace::NS_DAV", flatten)]
pub(crate) href: Vec<String>,
}
pub async fn get_objects_addressbook_multiget<AS: AddressbookStore>(

View File

@@ -4,9 +4,10 @@ use actix_web::{
HttpRequest, Responder,
};
use addressbook_multiget::{handle_addressbook_multiget, AddressbookMultigetRequest};
use rustical_dav::xml::sync_collection::SyncCollectionRequest;
use rustical_store::{auth::User, AddressbookStore};
use rustical_xml::{XmlDeserialize, XmlDocument};
use sync_collection::{handle_sync_collection, SyncCollectionRequest};
use sync_collection::handle_sync_collection;
use tracing::instrument;
mod addressbook_multiget;
@@ -14,7 +15,9 @@ mod sync_collection;
#[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)]
pub(crate) enum ReportRequest {
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
AddressbookMultiget(AddressbookMultigetRequest),
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
SyncCollection(SyncCollectionRequest),
}
@@ -61,8 +64,7 @@ pub async fn route_report_addressbook<AS: AddressbookStore>(
#[cfg(test)]
mod tests {
use rustical_dav::xml::{PropElement, Propname};
use sync_collection::SyncLevel;
use rustical_dav::xml::{sync_collection::SyncLevel, PropElement, Propname};
use super::*;
@@ -92,4 +94,31 @@ mod tests {
})
)
}
#[test]
fn test_xml_addressbook_multiget() {
let report_request = ReportRequest::parse_str(r#"
<?xml version="1.0" encoding="UTF-8"?>
<addressbook-multiget xmlns="urn:ietf:params:xml:ns:carddav" xmlns:D="DAV:">
<D:prop>
<D:getetag/>
<address-data/>
</D:prop>
<D:href>/carddav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b</D:href>
</addressbook-multiget>
"#).unwrap();
assert_eq!(
report_request,
ReportRequest::AddressbookMultiget(AddressbookMultigetRequest {
prop: rustical_dav::xml::PropfindType::Prop(PropElement(vec![
Propname("getetag".to_owned()),
Propname("address-data".to_owned())
])),
href: vec![
"/carddav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned()
]
})
)
}
}

View File

@@ -5,56 +5,16 @@ use crate::{
use actix_web::{http::StatusCode, HttpRequest};
use rustical_dav::{
resource::{CommonPropertiesProp, EitherProp, Resource},
xml::{multistatus::ResponseElement, MultistatusElement},
xml::{PropElement, PropfindType},
xml::{
multistatus::ResponseElement, sync_collection::SyncCollectionRequest, MultistatusElement,
PropElement, PropfindType,
},
};
use rustical_store::{
auth::User,
synctoken::{format_synctoken, parse_synctoken},
AddressbookStore,
};
use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize};
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum SyncLevel {
One,
Infinity,
}
impl ValueDeserialize for SyncLevel {
fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlError> {
Ok(match val {
"1" => Self::One,
"Infinity" => Self::Infinity,
_ => {
return Err(rustical_xml::XmlError::Other(
"Invalid sync-level".to_owned(),
))
}
})
}
}
impl ValueSerialize for SyncLevel {
fn serialize(&self) -> String {
match self {
SyncLevel::One => "1",
SyncLevel::Infinity => "Infinity",
}
.to_owned()
}
}
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
// <!ELEMENT sync-collection (sync-token, sync-level, limit?, prop)>
// <!-- DAV:limit defined in RFC 5323, Section 5.17 -->
// <!-- DAV:prop defined in RFC 4918, Section 14.18 -->
pub(crate) struct SyncCollectionRequest {
pub(crate) sync_token: String,
pub(crate) sync_level: SyncLevel,
#[xml(ty = "untagged")]
pub prop: PropfindType,
pub(crate) limit: Option<u64>,
}
pub async fn handle_sync_collection<AS: AddressbookStore>(
sync_collection: SyncCollectionRequest,