From c041dfece4e7818a50836cb5f07ab23045c12212 Mon Sep 17 00:00:00 2001 From: DeepRot Date: Thu, 30 Apr 2026 23:58:56 +0200 Subject: [PATCH] fix(carddav): resolve PROPFIND 404 and MKCOL 500 bugs --- .../pg/address_book_pg_repository.rs | 2 +- .../api/handlers/carddav_handler.rs | 72 +++++++++++++++++-- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/infrastructure/repositories/pg/address_book_pg_repository.rs b/src/infrastructure/repositories/pg/address_book_pg_repository.rs index 5dbe30e7..2d348b37 100644 --- a/src/infrastructure/repositories/pg/address_book_pg_repository.rs +++ b/src/infrastructure/repositories/pg/address_book_pg_repository.rs @@ -26,7 +26,7 @@ impl AddressBookRepository for AddressBookPgRepository { let row = sqlx::query( r#" INSERT INTO carddav.address_books (id, name, owner_id, description, color, is_public, created_at, updated_at) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + VALUES ($1, $2, $3::uuid, $4, $5, $6, $7, $8) RETURNING id, name, owner_id, description, color, is_public, created_at, updated_at "# ) diff --git a/src/interfaces/api/handlers/carddav_handler.rs b/src/interfaces/api/handlers/carddav_handler.rs index a50441e0..d4a29f70 100644 --- a/src/interfaces/api/handlers/carddav_handler.rs +++ b/src/interfaces/api/handlers/carddav_handler.rs @@ -228,8 +228,10 @@ async fn handle_propfind( .map_err(|e| AppError::bad_request(format!("Failed to parse PROPFIND: {}", e)))? }; - if path.is_empty() { - // Root CardDAV path — list user's address books + let effective_path = strip_username_prefix(path); + + if effective_path.is_empty() { + // Root CardDAV path or user home — list user's address books let address_books = addressbook_service .list_user_address_books(user.id) .await @@ -237,13 +239,18 @@ async fn handle_propfind( AppError::internal_error(format!("Failed to list address books: {}", e)) })?; - let base_href = "/carddav/"; + let base_href = if path.is_empty() { + "/carddav/".to_string() + } else { + let user_part = path.split('/').next().unwrap_or(path); + format!("/carddav/{}/", user_part) + }; let mut response_body = Vec::new(); CardDavAdapter::generate_addressbooks_propfind_response( &mut response_body, &address_books, &propfind_request, - base_href, + &base_href, ) .map_err(|e| AppError::internal_error(format!("Failed to generate XML: {}", e)))?; @@ -253,8 +260,7 @@ async fn handle_propfind( .body(Body::from(response_body)) .unwrap()) } else { - let effective_path = strip_username_prefix(path); - let parts: Vec<&str> = effective_path.splitn(2, '/').collect(); + let parts: Vec<&str> = effective_path.splitn(2, '/').collect(); let address_book_id = parts[0]; if parts.len() == 1 { @@ -731,3 +737,57 @@ async fn handle_proppatch( .body(Body::from(response_body)) .unwrap()) } + +#[cfg(test)] +mod tests { + use super::strip_username_prefix; + + #[test] + fn test_strip_username_prefix_uuid_only() { + let uuid = "ae8ae236-709f-4939-b766-37ad589ac7f2"; + assert_eq!(strip_username_prefix(uuid), uuid); + } + + #[test] + fn test_strip_username_prefix_uuid_with_contact() { + let path = "ae8ae236-709f-4939-b766-37ad589ac7f2/contact.vcf"; + assert_eq!(strip_username_prefix(path), path); + } + + #[test] + fn test_strip_username_prefix_username_and_uuid() { + let path = "timm/ae8ae236-709f-4939-b766-37ad589ac7f2"; + assert_eq!( + strip_username_prefix(path), + "ae8ae236-709f-4939-b766-37ad589ac7f2" + ); + } + + #[test] + fn test_strip_username_prefix_username_uuid_and_contact() { + let path = "timm/ae8ae236-709f-4939-b766-37ad589ac7f2/contact.vcf"; + assert_eq!( + strip_username_prefix(path), + "ae8ae236-709f-4939-b766-37ad589ac7f2/contact.vcf" + ); + } + + #[test] + fn test_strip_username_prefix_bare_username() { + assert_eq!(strip_username_prefix("timm"), ""); + } + + #[test] + fn test_strip_username_prefix_empty() { + assert_eq!(strip_username_prefix(""), ""); + } + + #[test] + fn test_strip_username_prefix_email_style_username() { + let path = "user@example.com/ae8ae236-709f-4939-b766-37ad589ac7f2/contact.vcf"; + assert_eq!( + strip_username_prefix(path), + "ae8ae236-709f-4939-b766-37ad589ac7f2/contact.vcf" + ); + } +}