adding card dav and cald dav

This commit is contained in:
DioCrafts
2025-04-13 01:04:04 +02:00
parent f2ecbc1a39
commit 52d8250d51
52 changed files with 8056 additions and 536 deletions
@@ -0,0 +1,23 @@
use axum::{
Router,
routing::get,
http::StatusCode,
response::IntoResponse,
Json,
};
use std::sync::Arc;
use serde_json::json;
use crate::common::di::AppState;
// Temporary placeholder implementation
pub fn caldav_routes() -> Router<AppState> {
Router::new()
.route("/placeholder", get(placeholder_handler))
}
async fn placeholder_handler() -> impl IntoResponse {
(StatusCode::OK, Json(json!({
"message": "CalDAV functionality is not yet implemented"
})))
}
@@ -0,0 +1,362 @@
use axum::{
Router,
routing::{get, put, delete, any},
extract::{Path, State, Request},
http::{StatusCode, HeaderMap},
response::{IntoResponse, Response},
body::Body,
Json,
};
use tracing::error;
use std::sync::Arc;
use serde_json::json;
use crate::common::di::AppState;
use crate::application::dtos::calendar_dto::{
CalendarDto, CreateCalendarDto, UpdateCalendarDto,
CalendarEventDto, CreateEventDto as CreateCalendarEventDto,
UpdateEventDto as UpdateCalendarEventDto
};
// CalDAV handler implementation
pub fn caldav_routes() -> Router<AppState> {
Router::new()
// Calendar operations
.route("/calendars", get(list_calendars))
.route("/calendars/:calendar_id",
get(get_calendar)
.put(update_calendar)
.delete(delete_calendar)
)
.route("/calendars/:calendar_id/events",
get(list_events)
.post(create_event)
)
.route("/calendars/:calendar_id/events/:event_id",
get(get_event)
.put(update_event)
.delete(delete_event)
)
}
async fn list_calendars(
State(state): State<AppState>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.calendar_service {
Some(calendar_service) => {
let params = json!({
"user_id": user_id
});
match calendar_service.handle_request("list_user_calendars", params).await {
Ok(result) => {
let calendars: Vec<CalendarDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(calendars))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to list calendars: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn get_calendar(
State(state): State<AppState>,
Path(calendar_id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.calendar_service {
Some(calendar_service) => {
let params = json!({
"calendar_id": calendar_id,
"user_id": user_id
});
match calendar_service.handle_request("get_calendar", params).await {
Ok(result) => {
let calendar: CalendarDto = serde_json::from_value(result)
.unwrap_or_else(|_| CalendarDto::default());
(StatusCode::OK, Json(calendar))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to get calendar: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn update_calendar(
State(state): State<AppState>,
Path(calendar_id): Path<String>,
Json(update): Json<UpdateCalendarDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
// Set the user ID in the update
let mut update_with_user = update;
update_with_user.user_id = user_id.to_string();
match &state.calendar_service {
Some(calendar_service) => {
match calendar_service.handle_request("update_calendar", json!({
"calendar_id": calendar_id,
"name": update_with_user.name,
"description": update_with_user.description,
"color": update_with_user.color,
"is_public": update_with_user.is_public,
"user_id": update_with_user.user_id
})).await {
Ok(result) => {
let calendar: CalendarDto = serde_json::from_value(result)
.unwrap_or_else(|_| CalendarDto::default());
(StatusCode::OK, Json(calendar))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to update calendar: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn delete_calendar(
State(state): State<AppState>,
Path(calendar_id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.calendar_service {
Some(calendar_service) => {
let params = json!({
"calendar_id": calendar_id,
"user_id": user_id
});
match calendar_service.handle_request("delete_calendar", params).await {
Ok(_) => {
(StatusCode::NO_CONTENT, Json(json!({})))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to delete calendar: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn list_events(
State(state): State<AppState>,
Path(calendar_id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.calendar_service {
Some(calendar_service) => {
let params = json!({
"calendar_id": calendar_id,
"user_id": user_id
});
match calendar_service.handle_request("list_events", params).await {
Ok(result) => {
let events: Vec<CalendarEventDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(events))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to list events: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn create_event(
State(state): State<AppState>,
Path(calendar_id): Path<String>,
Json(mut event): Json<CreateCalendarEventDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
// Set the calendar ID and user ID in the event
event.calendar_id = calendar_id;
event.user_id = user_id.to_string();
match &state.calendar_service {
Some(calendar_service) => {
match calendar_service.handle_request("create_event", serde_json::to_value(event).unwrap()).await {
Ok(result) => {
let event: CalendarEventDto = serde_json::from_value(result)
.unwrap_or_else(|_| CalendarEventDto::default());
(StatusCode::CREATED, Json(event))
},
Err(e) => {
let error_dto = CalendarEventDto::default();
error!(
"Failed to create event: {}",
e
);
(StatusCode::INTERNAL_SERVER_ERROR, Json(error_dto))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn get_event(
State(state): State<AppState>,
Path((calendar_id, event_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.calendar_service {
Some(calendar_service) => {
let params = json!({
"event_id": event_id,
"user_id": user_id
});
match calendar_service.handle_request("get_event", params).await {
Ok(result) => {
let event: CalendarEventDto = serde_json::from_value(result)
.unwrap_or_else(|_| CalendarEventDto::default());
(StatusCode::OK, Json(event))
},
Err(e) => {
let error_dto = CalendarEventDto::default();
error!(
"Failed to get event: {}",
e
);
(StatusCode::INTERNAL_SERVER_ERROR, Json(error_dto))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn update_event(
State(state): State<AppState>,
Path((calendar_id, event_id)): Path<(String, String)>,
Json(mut update): Json<UpdateCalendarEventDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
// Set the user ID in the update
update.user_id = user_id.to_string();
match &state.calendar_service {
Some(calendar_service) => {
let mut params = serde_json::to_value(update).unwrap();
// Add event_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("event_id".to_string(), serde_json::Value::String(event_id));
}
match calendar_service.handle_request("update_event", params).await {
Ok(result) => {
let event: CalendarEventDto = serde_json::from_value(result)
.unwrap_or_else(|_| CalendarEventDto::default());
(StatusCode::OK, Json(event))
},
Err(e) => {
let error_dto = CalendarEventDto::default();
error!(
"Failed to update event: {}",
e
);
(StatusCode::INTERNAL_SERVER_ERROR, Json(error_dto))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
async fn delete_event(
State(state): State<AppState>,
Path((calendar_id, event_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.calendar_service {
Some(calendar_service) => {
let params = json!({
"event_id": event_id,
"user_id": user_id
});
match calendar_service.handle_request("delete_event", params).await {
Ok(_) => {
(StatusCode::NO_CONTENT, Json(json!({})))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to delete event: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Calendar service not available"
})))
}
}
}
@@ -0,0 +1,41 @@
--- caldav_handler.rs
+++ caldav_handler.rs
@@ -242,9 +242,9 @@
}
},
None => {
- (StatusCode::NOT_IMPLEMENTED, Json(json\!({
- "error": "Calendar service not available"
- })))
+ let error_dto = CalendarEventDto::default();
+ error\!("Calendar service not available");
+ (StatusCode::NOT_IMPLEMENTED, Json(error_dto))
}
}
}
@@ -277,9 +277,9 @@
}
},
None => {
- (StatusCode::NOT_IMPLEMENTED, Json(json\!({
- "error": "Calendar service not available"
- })))
+ let error_dto = CalendarEventDto::default();
+ error\!("Calendar service not available");
+ (StatusCode::NOT_IMPLEMENTED, Json(error_dto))
}
}
}
@@ -320,9 +320,9 @@
}
},
None => {
- (StatusCode::NOT_IMPLEMENTED, Json(json\!({
- "error": "Calendar service not available"
- })))
+ let error_dto = CalendarEventDto::default();
+ error\!("Calendar service not available");
+ (StatusCode::NOT_IMPLEMENTED, Json(error_dto))
}
}
}
@@ -0,0 +1,954 @@
use axum::{
Router,
routing::{get, put, delete, post},
extract::{Path, State, Json},
http::StatusCode,
response::IntoResponse,
};
use std::sync::Arc;
use serde_json::json;
use crate::common::di::AppState;
use crate::application::dtos::address_book_dto::{
AddressBookDto, CreateAddressBookDto, UpdateAddressBookDto,
ShareAddressBookDto, UnshareAddressBookDto
};
use crate::application::dtos::contact_dto::{
ContactDto, CreateContactDto, UpdateContactDto, CreateContactVCardDto,
ContactGroupDto, CreateContactGroupDto, UpdateContactGroupDto, GroupMembershipDto
};
// CardDAV handler implementation
pub fn carddav_routes() -> Router<AppState> {
Router::new()
// Address book operations
.route("/address-books", get(list_address_books).post(create_address_book))
.route("/address-books/:id",
get(get_address_book)
.put(update_address_book)
.delete(delete_address_book)
)
.route("/address-books/:id/shares",
get(get_address_book_shares)
)
.route("/address-books/:id/share",
post(share_address_book)
)
.route("/address-books/:id/unshare/:user_id",
delete(unshare_address_book)
)
// Contact operations
.route("/address-books/:id/contacts",
get(list_contacts)
.post(create_contact)
)
.route("/address-books/:id/contacts/search",
get(search_contacts)
)
.route("/address-books/:id/contacts/vcard",
post(create_contact_from_vcard)
)
.route("/address-books/:address_book_id/contacts/:contact_id",
get(get_contact)
.put(update_contact)
.delete(delete_contact)
)
.route("/address-books/:address_book_id/contacts/:contact_id/vcard",
get(get_contact_vcard)
)
// Group operations
.route("/address-books/:id/groups",
get(list_groups)
.post(create_group)
)
.route("/address-books/:address_book_id/groups/:group_id",
get(get_group)
.put(update_group)
.delete(delete_group)
)
.route("/address-books/:address_book_id/groups/:group_id/contacts",
get(list_contacts_in_group)
)
.route("/groups/:group_id/contacts/:contact_id",
post(add_contact_to_group)
.delete(remove_contact_from_group)
)
.route("/contacts/:contact_id/groups",
get(list_groups_for_contact)
)
}
// Address Book handlers
async fn list_address_books(
State(state): State<AppState>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"user_id": user_id
});
match contact_service.handle_request("list_user_address_books", params).await {
Ok(result) => {
let address_books: Vec<AddressBookDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(address_books))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to list address books: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn create_address_book(
State(state): State<AppState>,
Json(dto): Json<CreateAddressBookDto>,
) -> impl IntoResponse {
match &state.contact_service {
Some(contact_service) => {
match contact_service.handle_request("create_address_book", serde_json::to_value(dto).unwrap()).await {
Ok(result) => {
let address_book: AddressBookDto = serde_json::from_value(result)
.unwrap_or_else(|_| AddressBookDto::default());
(StatusCode::CREATED, Json(address_book))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to create address book: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn get_address_book(
State(state): State<AppState>,
Path(id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"address_book_id": id,
"user_id": user_id
});
match contact_service.handle_request("get_address_book", params).await {
Ok(result) => {
let address_book: AddressBookDto = serde_json::from_value(result)
.unwrap_or_else(|_| AddressBookDto::default());
(StatusCode::OK, Json(address_book))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to get address book: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn update_address_book(
State(state): State<AppState>,
Path(id): Path<String>,
Json(mut update): Json<UpdateAddressBookDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
update.user_id = user_id.to_string();
match &state.contact_service {
Some(contact_service) => {
let mut params = serde_json::to_value(update).unwrap();
// Add address_book_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("address_book_id".to_string(), serde_json::Value::String(id));
}
match contact_service.handle_request("update_address_book", params).await {
Ok(result) => {
let address_book: AddressBookDto = serde_json::from_value(result)
.unwrap_or_else(|_| AddressBookDto::default());
(StatusCode::OK, Json(address_book))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to update address book: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn delete_address_book(
State(state): State<AppState>,
Path(id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"address_book_id": id,
"user_id": user_id
});
match contact_service.handle_request("delete_address_book", params).await {
Ok(_) => {
StatusCode::NO_CONTENT
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to delete address book: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn get_address_book_shares(
State(state): State<AppState>,
Path(id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"address_book_id": id,
"user_id": user_id
});
match contact_service.handle_request("get_address_book_shares", params).await {
Ok(result) => {
(StatusCode::OK, Json(result))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to get address book shares: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn share_address_book(
State(state): State<AppState>,
Path(address_book_id): Path<String>,
Json(mut dto): Json<ShareAddressBookDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
dto.address_book_id = address_book_id;
match &state.contact_service {
Some(contact_service) => {
let mut params = serde_json::to_value(dto).unwrap();
// Add user_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("user_id".to_string(), serde_json::Value::String(user_id.to_string()));
}
match contact_service.handle_request("share_address_book", params).await {
Ok(_) => {
StatusCode::NO_CONTENT
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to share address book: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn unshare_address_book(
State(state): State<AppState>,
Path((address_book_id, shared_with)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let dto = UnshareAddressBookDto {
address_book_id,
user_id: shared_with,
};
let mut params = serde_json::to_value(dto).unwrap();
// Add user_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("user_id".to_string(), serde_json::Value::String(user_id.to_string()));
}
match contact_service.handle_request("unshare_address_book", params).await {
Ok(_) => {
StatusCode::NO_CONTENT
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to unshare address book: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
// Contact handlers
async fn list_contacts(
State(state): State<AppState>,
Path(address_book_id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"address_book_id": address_book_id,
"user_id": user_id
});
match contact_service.handle_request("list_contacts", params).await {
Ok(result) => {
let contacts: Vec<ContactDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(contacts))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to list contacts: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn search_contacts(
State(state): State<AppState>,
Path(address_book_id): Path<String>,
axum::extract::Query(params): axum::extract::Query<std::collections::HashMap<String, String>>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
let query = params.get("q").unwrap_or(&String::new()).to_string();
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"address_book_id": address_book_id,
"query": query,
"user_id": user_id
});
match contact_service.handle_request("search_contacts", params).await {
Ok(result) => {
let contacts: Vec<ContactDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(contacts))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to search contacts: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn create_contact(
State(state): State<AppState>,
Path(address_book_id): Path<String>,
Json(mut dto): Json<CreateContactDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
dto.address_book_id = address_book_id;
dto.user_id = user_id.to_string();
match &state.contact_service {
Some(contact_service) => {
match contact_service.handle_request("create_contact", serde_json::to_value(dto).unwrap()).await {
Ok(result) => {
let contact: ContactDto = serde_json::from_value(result)
.unwrap_or_else(|_| ContactDto::default());
(StatusCode::CREATED, Json(contact))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to create contact: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn create_contact_from_vcard(
State(state): State<AppState>,
Path(address_book_id): Path<String>,
Json(mut dto): Json<CreateContactVCardDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
dto.address_book_id = address_book_id;
dto.user_id = user_id.to_string();
match &state.contact_service {
Some(contact_service) => {
match contact_service.handle_request("create_contact_from_vcard", serde_json::to_value(dto).unwrap()).await {
Ok(result) => {
let contact: ContactDto = serde_json::from_value(result)
.unwrap_or_else(|_| ContactDto::default());
(StatusCode::CREATED, Json(contact))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to create contact from vCard: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn get_contact(
State(state): State<AppState>,
Path((_, contact_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"contact_id": contact_id,
"user_id": user_id
});
match contact_service.handle_request("get_contact", params).await {
Ok(result) => {
let contact: ContactDto = serde_json::from_value(result)
.unwrap_or_else(|_| ContactDto::default());
(StatusCode::OK, Json(contact))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to get contact: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn update_contact(
State(state): State<AppState>,
Path((_, contact_id)): Path<(String, String)>,
Json(mut update): Json<UpdateContactDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
update.user_id = user_id.to_string();
match &state.contact_service {
Some(contact_service) => {
let mut params = serde_json::to_value(update).unwrap();
// Add contact_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("contact_id".to_string(), serde_json::Value::String(contact_id));
}
match contact_service.handle_request("update_contact", params).await {
Ok(result) => {
let contact: ContactDto = serde_json::from_value(result)
.unwrap_or_else(|_| ContactDto::default());
(StatusCode::OK, Json(contact))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to update contact: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn delete_contact(
State(state): State<AppState>,
Path((_, contact_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"contact_id": contact_id,
"user_id": user_id
});
match contact_service.handle_request("delete_contact", params).await {
Ok(_) => {
StatusCode::NO_CONTENT
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to delete contact: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn get_contact_vcard(
State(state): State<AppState>,
Path((_, contact_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"contact_id": contact_id,
"user_id": user_id
});
match contact_service.handle_request("get_contact_vcard", params).await {
Ok(result) => {
let vcard = match result {
serde_json::Value::String(s) => s,
_ => "BEGIN:VCARD\nVERSION:3.0\nEND:VCARD".to_string(),
};
// Return vCard with proper content type
(
StatusCode::OK,
[
("Content-Type", "text/vcard; charset=utf-8"),
("Content-Disposition", "attachment; filename=\"contact.vcf\""),
],
vcard
)
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to get contact vCard: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
// Group handlers
async fn list_groups(
State(state): State<AppState>,
Path(address_book_id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"address_book_id": address_book_id,
"user_id": user_id
});
match contact_service.handle_request("list_groups", params).await {
Ok(result) => {
let groups: Vec<ContactGroupDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(groups))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to list groups: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn create_group(
State(state): State<AppState>,
Path(address_book_id): Path<String>,
Json(mut dto): Json<CreateContactGroupDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
dto.address_book_id = address_book_id;
dto.user_id = user_id.to_string();
match &state.contact_service {
Some(contact_service) => {
match contact_service.handle_request("create_group", serde_json::to_value(dto).unwrap()).await {
Ok(result) => {
let group: ContactGroupDto = serde_json::from_value(result)
.unwrap_or_else(|_| ContactGroupDto::default());
(StatusCode::CREATED, Json(group))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to create group: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn get_group(
State(state): State<AppState>,
Path((_, group_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"group_id": group_id,
"user_id": user_id
});
match contact_service.handle_request("get_group", params).await {
Ok(result) => {
let group: ContactGroupDto = serde_json::from_value(result)
.unwrap_or_else(|_| ContactGroupDto::default());
(StatusCode::OK, Json(group))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to get group: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn update_group(
State(state): State<AppState>,
Path((_, group_id)): Path<(String, String)>,
Json(mut update): Json<UpdateContactGroupDto>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
update.user_id = user_id.to_string();
match &state.contact_service {
Some(contact_service) => {
let mut params = serde_json::to_value(update).unwrap();
// Add group_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("group_id".to_string(), serde_json::Value::String(group_id));
}
match contact_service.handle_request("update_group", params).await {
Ok(result) => {
let group: ContactGroupDto = serde_json::from_value(result)
.unwrap_or_else(|_| ContactGroupDto::default());
(StatusCode::OK, Json(group))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to update group: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn delete_group(
State(state): State<AppState>,
Path((_, group_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"group_id": group_id,
"user_id": user_id
});
match contact_service.handle_request("delete_group", params).await {
Ok(_) => {
StatusCode::NO_CONTENT
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to delete group: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn list_contacts_in_group(
State(state): State<AppState>,
Path((_, group_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"group_id": group_id,
"user_id": user_id
});
match contact_service.handle_request("list_contacts_in_group", params).await {
Ok(result) => {
let contacts: Vec<ContactDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(contacts))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to list contacts in group: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn add_contact_to_group(
State(state): State<AppState>,
Path((group_id, contact_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let dto = GroupMembershipDto {
group_id,
contact_id,
};
let mut params = serde_json::to_value(dto).unwrap();
// Add user_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("user_id".to_string(), serde_json::Value::String(user_id.to_string()));
}
match contact_service.handle_request("add_contact_to_group", params).await {
Ok(_) => {
StatusCode::NO_CONTENT
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to add contact to group: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn remove_contact_from_group(
State(state): State<AppState>,
Path((group_id, contact_id)): Path<(String, String)>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let dto = GroupMembershipDto {
group_id,
contact_id,
};
let mut params = serde_json::to_value(dto).unwrap();
// Add user_id to the params
if let serde_json::Value::Object(ref mut map) = params {
map.insert("user_id".to_string(), serde_json::Value::String(user_id.to_string()));
}
match contact_service.handle_request("remove_contact_from_group", params).await {
Ok(_) => {
StatusCode::NO_CONTENT
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to remove contact from group: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
async fn list_groups_for_contact(
State(state): State<AppState>,
Path(contact_id): Path<String>,
) -> impl IntoResponse {
let user_id = "default_user"; // In production, get this from auth middleware
match &state.contact_service {
Some(contact_service) => {
let params = json!({
"contact_id": contact_id,
"user_id": user_id
});
match contact_service.handle_request("list_groups_for_contact", params).await {
Ok(result) => {
let groups: Vec<ContactGroupDto> = serde_json::from_value(result)
.unwrap_or_else(|_| Vec::new());
(StatusCode::OK, Json(groups))
},
Err(e) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(json!({
"error": format!("Failed to list groups for contact: {}", e)
})))
}
}
},
None => {
(StatusCode::NOT_IMPLEMENTED, Json(json!({
"error": "Contact service not available"
})))
}
}
}
+1
View File
@@ -9,6 +9,7 @@ pub mod share_handler;
pub mod favorites_handler;
pub mod recent_handler;
pub mod webdav_handler;
pub mod caldav_handler;
/// Tipo de resultado para controladores de API
pub type ApiResult<T> = Result<T, (axum::http::StatusCode, String)>;
+21 -1
View File
@@ -119,7 +119,9 @@ pub fn create_api_routes(
trash_service: trash_service.clone(), // This is the important part - include the trash service
share_service: share_service.clone(), // Include the share service for routes
favorites_service: favorites_service.clone(), // Include the favorites service for routes
recent_service: recent_service.clone() // Include the recent service for routes
recent_service: recent_service.clone(), // Include the recent service for routes
calendar_service: None, // Adding missing field
contact_service: None // Adding missing field
};
// Inicializar el servicio de operaciones por lotes
let batch_service = Arc::new(BatchOperationService::default(
@@ -640,6 +642,24 @@ pub fn create_api_routes(
} else {
router
};
// Add CalDAV routes if needed
let caldav_enabled = true; // In production, you'd read this from a config
let router = if caldav_enabled {
use crate::interfaces::api::handlers::caldav_handler;
router.nest("/caldav", caldav_handler::caldav_routes())
} else {
router
};
// Add CardDAV routes if needed
let carddav_enabled = true; // In production, you'd read this from a config
let router = if carddav_enabled {
// Note: We'll implement carddav_handler in the next phase
router
} else {
router
};
router
.layer(CompressionLayer::new())