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        let vapid_pubkey = self.dav_push_store.get_vapid_pubkey_b64().await?.clone();
73        Ok(CalendarResource {
74            cal: calendar,
75            read_only: self.cal_store.is_read_only(cal_id),
76            vapid_pubkey,
77        })
78    }
79
80    async fn get_members(
81        &self,
82        (principal, cal_id): &Self::PathComponents,
83    ) -> Result<Vec<Self::MemberType>, Self::Error> {
84        Ok(self
85            .cal_store
86            .get_objects(principal, cal_id)
87            .await?
88            .into_iter()
89            .map(|(object_id, object)| CalendarObjectResource {
90                object,
91                object_id,
92                principal: principal.to_owned(),
93            })
94            .collect())
95    }
96
97    async fn save_resource(
98        &self,
99        (principal, cal_id): &Self::PathComponents,
100        file: Self::Resource,
101    ) -> Result<(), Self::Error> {
102        self.cal_store
103            .update_calendar(principal, cal_id, file.into())
104            .await?;
105        Ok(())
106    }
107
108    async fn delete_resource(
109        &self,
110        (principal, cal_id): &Self::PathComponents,
111        use_trashbin: bool,
112    ) -> Result<(), Self::Error> {
113        self.cal_store
114            .delete_calendar(principal, cal_id, use_trashbin)
115            .await?;
116        Ok(())
117    }
118
119    fn axum_router<State: Send + Sync + Clone + 'static>(self) -> axum::Router<State> {
120        Router::new()
121            .nest(
122                "/{object_id}",
123                CalendarObjectResourceService::new(self.cal_store.clone(), self.config.clone())
124                    .axum_router(),
125            )
126            .route_service("/", self.axum_service())
127    }
128}
129
130impl<C: CalendarStore, DP: DavPushStore> AxumMethods for CalendarResourceService<C, DP> {
131    fn report() -> Option<MethodFunction<Self>> {
132        Some(|state, req| {
133            let mut service = Handler::with_state(route_report_calendar::<C, DP>, state);
134            Box::pin(Service::call(&mut service, req))
135        })
136    }
137
138    fn get() -> Option<MethodFunction<Self>> {
139        Some(|state, req| {
140            let mut service = Handler::with_state(route_get::<C, DP>, state);
141            Box::pin(Service::call(&mut service, req))
142        })
143    }
144
145    fn post() -> Option<MethodFunction<Self>> {
146        Some(|state, req| {
147            let mut service = Handler::with_state(route_post::<C, DP>, state);
148            Box::pin(Service::call(&mut service, req))
149        })
150    }
151
152    fn import() -> Option<MethodFunction<Self>> {
153        Some(|state, req| {
154            let mut service = Handler::with_state(route_import::<C, DP>, state);
155            Box::pin(Service::call(&mut service, req))
156        })
157    }
158
159    fn mkcalendar() -> Option<MethodFunction<Self>> {
160        Some(|state, req| {
161            let mut service = Handler::with_state(route_mkcalendar::<C, DP>, state);
162            Box::pin(Service::<Request<Body>>::call(&mut service, req))
163        })
164    }
165
166    fn mkcol() -> Option<MethodFunction<Self>> {
167        Some(|state, req| {
168            let mut service = Handler::with_state(route_mkcalendar::<C, DP>, state);
169            Box::pin(Service::<Request<Body>>::call(&mut service, req))
170        })
171    }
172}