rustical_dav/resource/
resource_service.rs

1use actix_web::dev::{AppService, HttpServiceFactory};
2use actix_web::error::UrlGenerationError;
3use actix_web::test::TestRequest;
4use actix_web::web::Data;
5use actix_web::{ResponseError, dev::ResourceMap, http::Method, web};
6use async_trait::async_trait;
7use serde::Deserialize;
8use std::str::FromStr;
9
10use crate::Principal;
11
12use super::Resource;
13use super::methods::{route_delete, route_propfind, route_proppatch};
14
15#[async_trait(?Send)]
16pub trait ResourceService: Sized + 'static {
17    type MemberType: Resource<Error = Self::Error, Principal = Self::Principal>;
18    type PathComponents: for<'de> Deserialize<'de> + Sized + Clone + 'static; // defines how the resource URI maps to parameters, i.e. /{principal}/{calendar} -> (String, String)
19    type Resource: Resource<Error = Self::Error, Principal = Self::Principal>;
20    type Error: ResponseError + From<crate::Error>;
21    type Principal: Principal;
22
23    async fn get_members(
24        &self,
25        _path_components: &Self::PathComponents,
26    ) -> Result<Vec<(String, Self::MemberType)>, Self::Error> {
27        Ok(vec![])
28    }
29
30    async fn get_resource(
31        &self,
32        _path: &Self::PathComponents,
33    ) -> Result<Self::Resource, Self::Error>;
34    async fn save_resource(
35        &self,
36        _path: &Self::PathComponents,
37        _file: Self::Resource,
38    ) -> Result<(), Self::Error> {
39        Err(crate::Error::Unauthorized.into())
40    }
41    async fn delete_resource(
42        &self,
43        _path: &Self::PathComponents,
44        _use_trashbin: bool,
45    ) -> Result<(), Self::Error> {
46        Err(crate::Error::Unauthorized.into())
47    }
48
49    #[inline]
50    fn actix_resource(self) -> actix_web::Resource {
51        Self::actix_additional_routes(
52            web::resource("")
53                .app_data(Data::new(self))
54                .route(
55                    web::method(Method::from_str("PROPFIND").unwrap()).to(route_propfind::<Self>),
56                )
57                .route(
58                    web::method(Method::from_str("PROPPATCH").unwrap()).to(route_proppatch::<Self>),
59                )
60                .delete(route_delete::<Self>),
61        )
62    }
63
64    /// Hook for other resources to insert their additional methods (i.e. REPORT, MKCALENDAR)
65    #[inline]
66    fn actix_additional_routes(res: actix_web::Resource) -> actix_web::Resource {
67        res
68    }
69}
70
71pub trait NamedRoute {
72    fn route_name() -> &'static str;
73
74    fn get_url<U, I>(rmap: &ResourceMap, elements: U) -> Result<String, UrlGenerationError>
75    where
76        U: IntoIterator<Item = I>,
77        I: AsRef<str>,
78    {
79        Ok(rmap
80            .url_for(
81                &TestRequest::default().to_http_request(),
82                Self::route_name(),
83                elements,
84            )?
85            .path()
86            .to_owned())
87    }
88}
89
90pub struct ResourceServiceRoute<RS: ResourceService>(pub RS);
91
92impl<RS: ResourceService> HttpServiceFactory for ResourceServiceRoute<RS> {
93    fn register(self, config: &mut AppService) {
94        self.0.actix_resource().register(config);
95    }
96}