use actix_web::{ HttpResponse, dev::{HttpServiceFactory, ServiceResponse}, http::{ Method, StatusCode, header::{self, HeaderName, HeaderValue}, }, middleware::{ErrorHandlerResponse, ErrorHandlers}, web::{self, Data}, }; use address_object::resource::AddressObjectResourceService; use addressbook::resource::AddressbookResourceService; pub use error::Error; use principal::{PrincipalResource, PrincipalResourceService}; use rustical_dav::resource::{NamedRoute, ResourceService}; use rustical_dav::resources::RootResourceService; use rustical_store::{ AddressbookStore, SubscriptionStore, auth::{AuthenticationMiddleware, AuthenticationProvider, User}, }; use std::sync::Arc; pub mod address_object; pub mod addressbook; pub mod error; pub mod principal; pub fn carddav_service( auth_provider: Arc, store: Arc, subscription_store: Arc, ) -> impl HttpServiceFactory { web::scope("") .wrap(AuthenticationMiddleware::new(auth_provider.clone())) .wrap( ErrorHandlers::new().handler(StatusCode::METHOD_NOT_ALLOWED, |res| { Ok(ErrorHandlerResponse::Response( if res.request().method() == Method::OPTIONS { let mut response = HttpResponse::Ok(); response.insert_header(( HeaderName::from_static("dav"), // https://datatracker.ietf.org/doc/html/rfc4918#section-18 HeaderValue::from_static( "1, 3, access-control, addressbook, extended-mkcol", ), )); if let Some(allow) = res.headers().get(header::ALLOW) { response.insert_header((header::ALLOW, allow.to_owned())); } ServiceResponse::new(res.into_parts().0, response.finish()) .map_into_right_body() } else { res.map_into_left_body() }, )) }), ) .app_data(Data::from(store.clone())) .app_data(Data::from(subscription_store)) .service(RootResourceService::::default().actix_resource()) .service( web::scope("/principal").service( web::scope("/{principal}") .service( PrincipalResourceService::new(store.clone(), auth_provider) .actix_resource() .name(PrincipalResource::route_name()), ) .service( web::scope("/{addressbook_id}") .service( AddressbookResourceService::::new(store.clone()) .actix_resource(), ) .service( web::scope("/{object_id}.vcf").service( AddressObjectResourceService::::new(store.clone()) .actix_resource(), ), ), ), ), ) }