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