Skip to main content

rustical_caldav/calendar/
service.rs

1use crate::calendar::methods::get::route_get;
2use crate::calendar::methods::import::route_import;
3use crate::calendar::methods::mkcalendar::route_mkcalendar;
4use crate::calendar::methods::post::route_post;
5use crate::calendar::methods::report::route_report_calendar;
6use crate::calendar::resource::CalendarResource;
7use crate::calendar_object::CalendarObjectResourceService;
8use crate::calendar_object::resource::CalendarObjectResource;
9use crate::{CalDavConfig, CalDavPrincipalUri, Error};
10use async_trait::async_trait;
11use axum::Router;
12use axum::body::Body;
13use axum::extract::Request;
14use axum::handler::Handler;
15use rustical_dav::resource::{AxumMethods, MethodFunction, ResourceService};
16use rustical_dav_push::DavPushStore;
17use rustical_store::CalendarStore;
18use rustical_store::auth::Principal;
19use std::sync::Arc;
20use tower::Service;
21
22pub struct CalendarResourceService<C: CalendarStore, DP: DavPushStore> {
23    pub(crate) cal_store: Arc<C>,
24    pub(crate) dav_push_store: Arc<DP>,
25    pub(crate) config: Arc<CalDavConfig>,
26}
27
28impl<C: CalendarStore, DP: DavPushStore> Clone for CalendarResourceService<C, DP> {
29    fn clone(&self) -> Self {
30        Self {
31            cal_store: self.cal_store.clone(),
32            dav_push_store: self.dav_push_store.clone(),
33            config: self.config.clone(),
34        }
35    }
36}
37
38impl<C: CalendarStore, DP: DavPushStore> CalendarResourceService<C, DP> {
39    pub const fn new(
40        cal_store: Arc<C>,
41        dav_push_store: Arc<DP>,
42        config: Arc<CalDavConfig>,
43    ) -> Self {
44        Self {
45            cal_store,
46            dav_push_store,
47            config,
48        }
49    }
50}
51
52#[async_trait]
53impl<C: CalendarStore, DP: DavPushStore> ResourceService for CalendarResourceService<C, DP> {
54    type MemberType = CalendarObjectResource;
55    type PathComponents = (String, String); // principal, calendar_id
56    type Resource = CalendarResource;
57    type Error = Error;
58    type Principal = Principal;
59    type PrincipalUri = CalDavPrincipalUri;
60
61    const DAV_HEADER: &str = "1, 3, access-control, calendar-access, webdav-push";
62
63    async fn get_resource(
64        &self,
65        (principal, cal_id): &Self::PathComponents,
66        show_deleted: bool,
67    ) -> Result<Self::Resource, Error> {
68        let calendar = self
69            .cal_store
70            .get_calendar(principal, cal_id, show_deleted)
71            .await?;
72        Ok(CalendarResource {
73            cal: calendar,
74            read_only: self.cal_store.is_read_only(cal_id),
75        })
76    }
77
78    async fn get_members(
79        &self,
80        (principal, cal_id): &Self::PathComponents,
81    ) -> Result<Vec<Self::MemberType>, Self::Error> {
82        Ok(self
83            .cal_store
84            .get_objects(principal, cal_id)
85            .await?
86            .into_iter()
87            .map(|(object_id, object)| CalendarObjectResource {
88                object,
89                object_id,
90                principal: principal.to_owned(),
91            })
92            .collect())
93    }
94
95    async fn save_resource(
96        &self,
97        (principal, cal_id): &Self::PathComponents,
98        file: Self::Resource,
99    ) -> Result<(), Self::Error> {
100        self.cal_store
101            .update_calendar(principal, cal_id, file.into())
102            .await?;
103        Ok(())
104    }
105
106    async fn delete_resource(
107        &self,
108        (principal, cal_id): &Self::PathComponents,
109        use_trashbin: bool,
110    ) -> Result<(), Self::Error> {
111        self.cal_store
112            .delete_calendar(principal, cal_id, use_trashbin)
113            .await?;
114        Ok(())
115    }
116
117    fn axum_router<State: Send + Sync + Clone + 'static>(self) -> axum::Router<State> {
118        Router::new()
119            .nest(
120                "/{object_id}",
121                CalendarObjectResourceService::new(self.cal_store.clone(), self.config.clone())
122                    .axum_router(),
123            )
124            .route_service("/", self.axum_service())
125    }
126}
127
128impl<C: CalendarStore, DP: DavPushStore> AxumMethods for CalendarResourceService<C, DP> {
129    fn report() -> Option<MethodFunction<Self>> {
130        Some(|state, req| {
131            let mut service = Handler::with_state(route_report_calendar::<C, DP>, state);
132            Box::pin(Service::call(&mut service, req))
133        })
134    }
135
136    fn get() -> Option<MethodFunction<Self>> {
137        Some(|state, req| {
138            let mut service = Handler::with_state(route_get::<C, DP>, state);
139            Box::pin(Service::call(&mut service, req))
140        })
141    }
142
143    fn post() -> Option<MethodFunction<Self>> {
144        Some(|state, req| {
145            let mut service = Handler::with_state(route_post::<C, DP>, state);
146            Box::pin(Service::call(&mut service, req))
147        })
148    }
149
150    fn import() -> Option<MethodFunction<Self>> {
151        Some(|state, req| {
152            let mut service = Handler::with_state(route_import::<C, DP>, state);
153            Box::pin(Service::call(&mut service, req))
154        })
155    }
156
157    fn mkcalendar() -> Option<MethodFunction<Self>> {
158        Some(|state, req| {
159            let mut service = Handler::with_state(route_mkcalendar::<C, DP>, state);
160            Box::pin(Service::<Request<Body>>::call(&mut service, req))
161        })
162    }
163
164    fn mkcol() -> Option<MethodFunction<Self>> {
165        Some(|state, req| {
166            let mut service = Handler::with_state(route_mkcalendar::<C, DP>, state);
167            Box::pin(Service::<Request<Body>>::call(&mut service, req))
168        })
169    }
170}