use super::methods::mkcol::route_mkcol; use super::methods::report::route_report_addressbook; use crate::address_object::AddressObjectResourceService; use crate::address_object::resource::AddressObjectResource; use crate::addressbook::methods::get::route_get; use crate::addressbook::methods::put::route_put; use crate::addressbook::resource::AddressbookResource; use crate::{CardDavPrincipalUri, Error}; use async_trait::async_trait; use axum::Router; use axum::extract::Request; use axum::handler::Handler; use axum::response::Response; use futures_util::future::BoxFuture; use rustical_dav::resource::{AxumMethods, ResourceService}; use rustical_store::auth::User; use rustical_store::{AddressbookStore, SubscriptionStore}; use std::convert::Infallible; use std::sync::Arc; use tower::Service; pub struct AddressbookResourceService { pub(crate) addr_store: Arc, pub(crate) sub_store: Arc, } impl AddressbookResourceService { pub fn new(addr_store: Arc, sub_store: Arc) -> Self { Self { addr_store, sub_store, } } } impl Clone for AddressbookResourceService { fn clone(&self) -> Self { Self { addr_store: self.addr_store.clone(), sub_store: self.sub_store.clone(), } } } #[async_trait] impl ResourceService for AddressbookResourceService { type MemberType = AddressObjectResource; type PathComponents = (String, String); // principal, addressbook_id type Resource = AddressbookResource; type Error = Error; type Principal = User; type PrincipalUri = CardDavPrincipalUri; const DAV_HEADER: &str = "1, 3, access-control, addressbook"; async fn get_resource( &self, (principal, addressbook_id): &Self::PathComponents, ) -> Result { let addressbook = self .addr_store .get_addressbook(principal, addressbook_id, false) .await .map_err(|_e| Error::NotFound)?; Ok(addressbook.into()) } async fn get_members( &self, (principal, addressbook_id): &Self::PathComponents, ) -> Result, Self::Error> { Ok(self .addr_store .get_objects(principal, addressbook_id) .await? .into_iter() .map(|object| AddressObjectResource { object, principal: principal.to_owned(), }) .collect()) } async fn save_resource( &self, (principal, addressbook_id): &Self::PathComponents, file: Self::Resource, ) -> Result<(), Self::Error> { self.addr_store .update_addressbook(principal.to_owned(), addressbook_id.to_owned(), file.into()) .await?; Ok(()) } async fn delete_resource( &self, (principal, addressbook_id): &Self::PathComponents, use_trashbin: bool, ) -> Result<(), Self::Error> { self.addr_store .delete_addressbook(principal, addressbook_id, use_trashbin) .await?; Ok(()) } fn axum_router(self) -> Router { Router::new() .nest( "/{object_id}", AddressObjectResourceService::new(self.addr_store.clone()).axum_router(), ) .route_service("/", self.axum_service()) } } impl AxumMethods for AddressbookResourceService { fn report() -> Option BoxFuture<'static, Result>> { Some(|state, req| { let mut service = Handler::with_state(route_report_addressbook::, state); Box::pin(Service::call(&mut service, req)) }) } fn get() -> Option BoxFuture<'static, Result>> { Some(|state, req| { let mut service = Handler::with_state(route_get::, state); Box::pin(Service::call(&mut service, req)) }) } fn put() -> Option BoxFuture<'static, Result>> { Some(|state, req| { let mut service = Handler::with_state(route_put::, state); Box::pin(Service::call(&mut service, req)) }) } fn mkcol() -> Option BoxFuture<'static, Result>> { Some(|state, req| { let mut service = Handler::with_state(route_mkcol::, state); Box::pin(Service::call(&mut service, req)) }) } }