mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 21:42:34 +00:00
Implement almost all previous features
This commit is contained in:
@@ -28,3 +28,4 @@ uuid.workspace = true
|
||||
rustical_dav_push.workspace = true
|
||||
rustical_ical.workspace = true
|
||||
http.workspace = true
|
||||
tower-http.workspace = true
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user