Implement almost all previous features

This commit is contained in:
Lennart
2025-06-08 19:38:33 +02:00
parent 95889e3df1
commit 00eb43f048
41 changed files with 906 additions and 916 deletions

View File

@@ -28,3 +28,4 @@ uuid.workspace = true
rustical_dav_push.workspace = true
rustical_ical.workspace = true
http.workspace = true
tower-http.workspace = true

View File

@@ -9,7 +9,7 @@ use axum::extract::{Path, State};
use axum::response::{IntoResponse, Response};
use axum_extra::TypedHeader;
use axum_extra::headers::{ContentType, ETag, HeaderMapExt, IfNoneMatch};
use http::StatusCode;
use http::{HeaderMap, StatusCode};
use rustical_dav::privileges::UserPrivilege;
use rustical_dav::resource::Resource;
use rustical_ical::AddressObject;
@@ -62,13 +62,19 @@ pub async fn put_object<AS: AddressbookStore>(
}): Path<AddressObjectPathComponents>,
State(AddressObjectResourceService { addr_store }): State<AddressObjectResourceService<AS>>,
user: User,
if_none_match: Option<TypedHeader<IfNoneMatch>>,
mut if_none_match: Option<TypedHeader<IfNoneMatch>>,
header_map: HeaderMap,
body: String,
) -> Result<Response, Error> {
if !user.is_principal(&principal) {
return Err(Error::Unauthorized);
}
// https://github.com/hyperium/headers/issues/204
if !header_map.contains_key("If-None-Match") {
if_none_match = None;
}
let overwrite = if let Some(TypedHeader(if_none_match)) = if_none_match {
if_none_match == IfNoneMatch::any()
} else {

View File

@@ -12,7 +12,7 @@ use rustical_dav::{
use rustical_ical::AddressObject;
use rustical_store::{AddressbookStore, auth::User};
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
use serde::Deserialize;
use serde::{Deserialize, Deserializer};
use std::{convert::Infallible, sync::Arc};
use tower::Service;
@@ -108,10 +108,23 @@ impl Resource for AddressObjectResource {
}
}
fn deserialize_vcf_name<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let name: String = Deserialize::deserialize(deserializer)?;
if let Some(object_id) = name.strip_suffix(".vcf") {
Ok(object_id.to_owned())
} else {
Err(serde::de::Error::custom("Missing .vcf extension"))
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct AddressObjectPathComponents {
pub principal: String,
pub addressbook_id: String,
#[serde(deserialize_with = "deserialize_vcf_name")]
pub object_id: String,
}

View File

@@ -35,6 +35,7 @@ pub async fn get_objects_addressbook_multiget<AS: AddressbookStore>(
for href in &addressbook_multiget.href {
if let Some(filename) = href.strip_prefix(path) {
let filename = filename.trim_start_matches("/");
if let Some(object_id) = filename.strip_suffix(".vcf") {
match store
.get_object(principal, addressbook_id, object_id, false)

View File

@@ -23,7 +23,7 @@ pub struct CardDavPrincipalUri(&'static str);
impl PrincipalUri for CardDavPrincipalUri {
fn principal_uri(&self, principal: &str) -> String {
format!("{}/{}", self.0, principal)
format!("{}/principal/{}", self.0, principal)
}
}