rustical_caldav/calendar_object/
service.rs1use crate::{
2 CalDavConfig, CalDavPrincipalUri, Error,
3 calendar_object::{
4 methods::{get_event, put_event},
5 resource::CalendarObjectResource,
6 },
7};
8use async_trait::async_trait;
9use axum::{extract::Request, handler::Handler, response::Response};
10use futures_util::future::BoxFuture;
11use rustical_dav::resource::{AxumMethods, ResourceService};
12use rustical_store::{CalendarStore, auth::Principal};
13use serde::{Deserialize, Deserializer};
14use std::{convert::Infallible, sync::Arc};
15use tower::Service;
16
17#[derive(Debug, Clone, Deserialize)]
18pub struct CalendarObjectPathComponents {
19 pub principal: String,
20 pub calendar_id: String,
21 #[serde(deserialize_with = "deserialize_ics_name")]
22 pub object_id: String,
23}
24
25pub struct CalendarObjectResourceService<C: CalendarStore> {
26 pub(crate) cal_store: Arc<C>,
27 pub(crate) config: Arc<CalDavConfig>,
28}
29
30impl<C: CalendarStore> Clone for CalendarObjectResourceService<C> {
31 fn clone(&self) -> Self {
32 Self {
33 cal_store: self.cal_store.clone(),
34 config: self.config.clone(),
35 }
36 }
37}
38
39impl<C: CalendarStore> CalendarObjectResourceService<C> {
40 pub const fn new(cal_store: Arc<C>, config: Arc<CalDavConfig>) -> Self {
41 Self { cal_store, config }
42 }
43}
44
45#[async_trait]
46impl<C: CalendarStore> ResourceService for CalendarObjectResourceService<C> {
47 type PathComponents = CalendarObjectPathComponents;
48 type Resource = CalendarObjectResource;
49 type MemberType = CalendarObjectResource;
50 type Error = Error;
51 type Principal = Principal;
52 type PrincipalUri = CalDavPrincipalUri;
53
54 const DAV_HEADER: &str = "1, 3, access-control, calendar-access";
55
56 async fn get_resource(
57 &self,
58 CalendarObjectPathComponents {
59 principal,
60 calendar_id,
61 object_id,
62 }: &Self::PathComponents,
63 show_deleted: bool,
64 ) -> Result<Self::Resource, Self::Error> {
65 let object = self
66 .cal_store
67 .get_object(principal, calendar_id, object_id, show_deleted)
68 .await?;
69 Ok(CalendarObjectResource {
70 object,
71 object_id: object_id.to_owned(),
72 principal: principal.to_owned(),
73 })
74 }
75
76 async fn delete_resource(
77 &self,
78 CalendarObjectPathComponents {
79 principal,
80 calendar_id,
81 object_id,
82 }: &Self::PathComponents,
83 use_trashbin: bool,
84 ) -> Result<(), Self::Error> {
85 self.cal_store
86 .delete_object(principal, calendar_id, object_id, use_trashbin)
87 .await?;
88 Ok(())
89 }
90}
91
92impl<C: CalendarStore> AxumMethods for CalendarObjectResourceService<C> {
93 fn get() -> Option<fn(Self, Request) -> BoxFuture<'static, Result<Response, Infallible>>> {
94 Some(|state, req| {
95 let mut service = Handler::with_state(get_event::<C>, state);
96 Box::pin(Service::call(&mut service, req))
97 })
98 }
99 fn put() -> Option<fn(Self, Request) -> BoxFuture<'static, Result<Response, Infallible>>> {
100 Some(|state, req| {
101 let mut service = Handler::with_state(put_event::<C>, state);
102 Box::pin(Service::call(&mut service, req))
103 })
104 }
105}
106
107fn deserialize_ics_name<'de, D>(deserializer: D) -> Result<String, D::Error>
108where
109 D: Deserializer<'de>,
110{
111 let name: String = Deserialize::deserialize(deserializer)?;
112 name.strip_suffix(".ics").map_or_else(
113 || Err(serde::de::Error::custom("Missing .ics extension")),
114 |object_id| Ok(object_id.to_owned()),
115 )
116}