From c19e4745f9cb185f4368d869aa52c9d72f65ac84 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 4 Jan 2025 14:24:01 +0100 Subject: [PATCH] Refactor how ResourceService works --- crates/caldav/src/calendar/methods/mod.rs | 1 - crates/caldav/src/calendar/methods/post.rs | 15 ---- crates/caldav/src/calendar/resource.rs | 70 ++++++++----------- crates/caldav/src/calendar_object/resource.rs | 54 +++++++------- crates/caldav/src/lib.rs | 12 ++-- crates/caldav/src/principal/mod.rs | 37 ++++------ crates/carddav/src/address_object/methods.rs | 10 +-- crates/carddav/src/address_object/resource.rs | 62 ++++++++-------- crates/carddav/src/addressbook/resource.rs | 60 +++++++--------- crates/carddav/src/lib.rs | 12 ++-- crates/carddav/src/principal/mod.rs | 38 ++++------ crates/dav/src/resource/methods/delete.rs | 11 ++- crates/dav/src/resource/methods/propfind.rs | 15 ++-- crates/dav/src/resource/methods/proppatch.rs | 10 +-- crates/dav/src/resource/resource_service.rs | 29 +++++--- crates/dav/src/resources/root.rs | 17 ++--- 16 files changed, 203 insertions(+), 250 deletions(-) delete mode 100644 crates/caldav/src/calendar/methods/post.rs diff --git a/crates/caldav/src/calendar/methods/mod.rs b/crates/caldav/src/calendar/methods/mod.rs index bd97f27..436ff41 100644 --- a/crates/caldav/src/calendar/methods/mod.rs +++ b/crates/caldav/src/calendar/methods/mod.rs @@ -1,3 +1,2 @@ pub mod mkcalendar; -pub mod post; pub mod report; diff --git a/crates/caldav/src/calendar/methods/post.rs b/crates/caldav/src/calendar/methods/post.rs deleted file mode 100644 index 6ec18ee..0000000 --- a/crates/caldav/src/calendar/methods/post.rs +++ /dev/null @@ -1,15 +0,0 @@ -use actix_web::{web::Data, web::Path, Responder}; -use rustical_store::{auth::User, CalendarStore}; -use tracing::instrument; -use tracing_actix_web::RootSpan; - -#[instrument(parent = root_span.id(), skip(store, root_span))] -pub async fn route_post( - path: Path<(String, String)>, - body: String, - user: User, - store: Data, - root_span: RootSpan, -) -> impl Responder { - "asd" -} diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index 249f8e2..468097c 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -1,9 +1,7 @@ use super::methods::mkcalendar::route_mkcalendar; -use super::methods::post::route_post; use super::methods::report::route_report_calendar; use super::prop::{ - SupportedCalendarComponent, SupportedCalendarComponentSet, SupportedCalendarData, - SupportedReportSet, Transports, + SupportedCalendarComponentSet, SupportedCalendarData, SupportedReportSet, Transports, }; use crate::calendar_object::resource::CalendarObjectResource; use crate::principal::PrincipalResource; @@ -11,7 +9,6 @@ use crate::Error; use actix_web::dev::ResourceMap; use actix_web::http::Method; use actix_web::web; -use actix_web::{web::Data, HttpRequest}; use async_trait::async_trait; use derive_more::derive::{From, Into}; use rustical_dav::privileges::UserPrivilegeSet; @@ -27,8 +24,12 @@ use strum::{EnumDiscriminants, EnumString, IntoStaticStr, VariantNames}; pub struct CalendarResourceService { cal_store: Arc, - principal: String, - calendar_id: String, +} + +impl CalendarResourceService { + pub fn new(cal_store: Arc) -> Self { + Self { cal_store } + } } #[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone)] @@ -243,10 +244,13 @@ impl ResourceService for CalendarResourceService { type Resource = CalendarResource; type Error = Error; - async fn get_resource(&self) -> Result { + async fn get_resource( + &self, + (principal, cal_id): &Self::PathComponents, + ) -> Result { let calendar = self .cal_store - .get_calendar(&self.principal, &self.calendar_id) + .get_calendar(principal, cal_id) .await .map_err(|_e| Error::NotFound)?; Ok(calendar.into()) @@ -254,60 +258,45 @@ impl ResourceService for CalendarResourceService { async fn get_members( &self, + (principal, cal_id): &Self::PathComponents, rmap: &ResourceMap, ) -> Result, Self::Error> { Ok(self .cal_store - .get_objects(&self.principal, &self.calendar_id) + .get_objects(principal, cal_id) .await? .into_iter() .map(|object| { ( - CalendarObjectResource::get_url( - rmap, - vec![&self.principal, &self.calendar_id, object.get_id()], - ) - .unwrap(), + CalendarObjectResource::get_url(rmap, vec![principal, cal_id, object.get_id()]) + .unwrap(), CalendarObjectResource { object, - principal: self.principal.to_owned(), + principal: principal.to_owned(), }, ) }) .collect()) } - async fn new( - req: &HttpRequest, - path_components: Self::PathComponents, - ) -> Result { - let cal_store = req - .app_data::>() - .expect("no calendar store in app_data!") - .clone() - .into_inner(); - - Ok(Self { - principal: path_components.0, - calendar_id: path_components.1, - cal_store, - }) - } - - async fn save_resource(&self, file: Self::Resource) -> Result<(), Self::Error> { + async fn save_resource( + &self, + (principal, cal_id): &Self::PathComponents, + file: Self::Resource, + ) -> Result<(), Self::Error> { self.cal_store - .update_calendar( - self.principal.to_owned(), - self.calendar_id.to_owned(), - file.into(), - ) + .update_calendar(principal.to_owned(), cal_id.to_owned(), file.into()) .await?; Ok(()) } - async fn delete_resource(&self, use_trashbin: bool) -> Result<(), Self::Error> { + async fn delete_resource( + &self, + (principal, cal_id): &Self::PathComponents, + use_trashbin: bool, + ) -> Result<(), Self::Error> { self.cal_store - .delete_calendar(&self.principal, &self.calendar_id, use_trashbin) + .delete_calendar(principal, cal_id, use_trashbin) .await?; Ok(()) } @@ -319,6 +308,5 @@ impl ResourceService for CalendarResourceService { res.route(report_method.to(route_report_calendar::)) .route(mkcalendar_method.to(route_mkcalendar::)) - .post(route_post::) } } diff --git a/crates/caldav/src/calendar_object/resource.rs b/crates/caldav/src/calendar_object/resource.rs index c6d1611..e70b2be 100644 --- a/crates/caldav/src/calendar_object/resource.rs +++ b/crates/caldav/src/calendar_object/resource.rs @@ -1,6 +1,6 @@ use super::methods::{get_event, put_event}; use crate::{principal::PrincipalResource, Error}; -use actix_web::{dev::ResourceMap, web::Data, HttpRequest}; +use actix_web::dev::ResourceMap; use async_trait::async_trait; use derive_more::derive::{From, Into}; use rustical_dav::{ @@ -15,9 +15,12 @@ use strum::{EnumDiscriminants, EnumString, IntoStaticStr, VariantNames}; pub struct CalendarObjectResourceService { cal_store: Arc, - principal: String, - cal_id: String, - object_id: String, +} + +impl CalendarObjectResourceService { + pub fn new(cal_store: Arc) -> Self { + Self { cal_store } + } } #[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone)] @@ -117,44 +120,35 @@ impl ResourceService for CalendarObjectResourceServic type MemberType = CalendarObjectResource; type Error = Error; - async fn new( - req: &HttpRequest, - path_components: Self::PathComponents, - ) -> Result { - let CalendarObjectPathComponents { + async fn get_resource( + &self, + CalendarObjectPathComponents { principal, cal_id, object_id, - } = path_components; - - let cal_store = req - .app_data::>() - .expect("no calendar store in app_data!") - .clone() - .into_inner(); - - Ok(Self { - cal_store, - principal, - cal_id, - object_id, - }) - } - - async fn get_resource(&self) -> Result { + }: &Self::PathComponents, + ) -> Result { let object = self .cal_store - .get_object(&self.principal, &self.cal_id, &self.object_id) + .get_object(principal, cal_id, object_id) .await?; Ok(CalendarObjectResource { object, - principal: self.principal.to_owned(), + principal: principal.to_owned(), }) } - async fn delete_resource(&self, use_trashbin: bool) -> Result<(), Self::Error> { + async fn delete_resource( + &self, + CalendarObjectPathComponents { + principal, + cal_id, + object_id, + }: &Self::PathComponents, + use_trashbin: bool, + ) -> Result<(), Self::Error> { self.cal_store - .delete_object(&self.principal, &self.cal_id, &self.object_id, use_trashbin) + .delete_object(principal, cal_id, object_id, use_trashbin) .await?; Ok(()) } diff --git a/crates/caldav/src/lib.rs b/crates/caldav/src/lib.rs index c09b801..dd5664c 100644 --- a/crates/caldav/src/lib.rs +++ b/crates/caldav/src/lib.rs @@ -52,17 +52,21 @@ pub fn configure_dav( }), ) .app_data(Data::from(store.clone())) - .service(RootResourceService::::actix_resource()) + .service(RootResourceService::::default().actix_resource()) .service( web::scope("/user").service( web::scope("/{principal}") - .service(PrincipalResourceService::::actix_resource()) + .service(PrincipalResourceService::::new(store.clone()).actix_resource()) .service( web::scope("/{calendar}") - .service(CalendarResourceService::::actix_resource()) + .service( + CalendarResourceService::::new(store.clone()) + .actix_resource(), + ) .service( web::scope("/{object}").service( - CalendarObjectResourceService::::actix_resource(), + CalendarObjectResourceService::::new(store.clone()) + .actix_resource(), ), ), ), diff --git a/crates/caldav/src/principal/mod.rs b/crates/caldav/src/principal/mod.rs index 5ced502..03e8088 100644 --- a/crates/caldav/src/principal/mod.rs +++ b/crates/caldav/src/principal/mod.rs @@ -1,8 +1,6 @@ use crate::calendar::resource::CalendarResource; use crate::Error; use actix_web::dev::ResourceMap; -use actix_web::web::Data; -use actix_web::HttpRequest; use async_trait::async_trait; use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::resource::{Resource, ResourceService}; @@ -14,10 +12,15 @@ use std::sync::Arc; use strum::{EnumDiscriminants, EnumString, IntoStaticStr, VariantNames}; pub struct PrincipalResourceService { - principal: String, cal_store: Arc, } +impl PrincipalResourceService { + pub fn new(cal_store: Arc) -> Self { + Self { cal_store } + } +} + #[derive(Clone)] pub struct PrincipalResource { principal: String, @@ -96,38 +99,26 @@ impl ResourceService for PrincipalResourceService type Resource = PrincipalResource; type Error = Error; - async fn new( - req: &HttpRequest, - (principal,): Self::PathComponents, - ) -> Result { - let cal_store = req - .app_data::>() - .expect("no calendar store in app_data!") - .clone() - .into_inner(); - - Ok(Self { - cal_store, - principal, - }) - } - - async fn get_resource(&self) -> Result { + async fn get_resource( + &self, + (principal,): &Self::PathComponents, + ) -> Result { Ok(PrincipalResource { - principal: self.principal.to_owned(), + principal: principal.to_owned(), }) } async fn get_members( &self, + (principal,): &Self::PathComponents, rmap: &ResourceMap, ) -> Result, Self::Error> { - let calendars = self.cal_store.get_calendars(&self.principal).await?; + let calendars = self.cal_store.get_calendars(principal).await?; Ok(calendars .into_iter() .map(|cal| { ( - CalendarResource::get_url(rmap, vec![&self.principal, &cal.id]).unwrap(), + CalendarResource::get_url(rmap, vec![principal, &cal.id]).unwrap(), cal.into(), ) }) diff --git a/crates/carddav/src/address_object/methods.rs b/crates/carddav/src/address_object/methods.rs index bdb53c8..4b6fd2c 100644 --- a/crates/carddav/src/address_object/methods.rs +++ b/crates/carddav/src/address_object/methods.rs @@ -19,7 +19,7 @@ pub async fn get_object( ) -> Result { let AddressObjectPathComponents { principal, - cal_id, + addressbook_id, object_id, } = path.into_inner(); @@ -27,12 +27,14 @@ pub async fn get_object( return Ok(HttpResponse::Unauthorized().body("")); } - let addressbook = store.get_addressbook(&principal, &cal_id).await?; + let addressbook = store.get_addressbook(&principal, &addressbook_id).await?; if user.id != addressbook.principal { return Ok(HttpResponse::Unauthorized().body("")); } - let object = store.get_object(&principal, &cal_id, &object_id).await?; + let object = store + .get_object(&principal, &addressbook_id, &object_id) + .await?; Ok(HttpResponse::Ok() .insert_header(("ETag", object.get_etag())) @@ -51,7 +53,7 @@ pub async fn put_object( ) -> Result { let AddressObjectPathComponents { principal, - cal_id: addressbook_id, + addressbook_id, object_id, } = path.into_inner(); diff --git a/crates/carddav/src/address_object/resource.rs b/crates/carddav/src/address_object/resource.rs index 0257e7b..40f8191 100644 --- a/crates/carddav/src/address_object/resource.rs +++ b/crates/carddav/src/address_object/resource.rs @@ -1,5 +1,5 @@ use crate::{principal::PrincipalResource, Error}; -use actix_web::{dev::ResourceMap, web::Data, HttpRequest}; +use actix_web::dev::ResourceMap; use async_trait::async_trait; use derive_more::derive::{From, Into}; use rustical_dav::{ @@ -16,9 +16,12 @@ use super::methods::{get_object, put_object}; pub struct AddressObjectResourceService { addr_store: Arc, - principal: String, - cal_id: String, - object_id: String, +} + +impl AddressObjectResourceService { + pub fn new(addr_store: Arc) -> Self { + Self { addr_store } + } } #[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone)] @@ -89,7 +92,7 @@ impl Resource for AddressObjectResource { #[derive(Debug, Clone)] pub struct AddressObjectPathComponents { pub principal: String, - pub cal_id: String, + pub addressbook_id: String, pub object_id: String, } @@ -99,13 +102,13 @@ impl<'de> Deserialize<'de> for AddressObjectPathComponents { D: serde::Deserializer<'de>, { type Inner = (String, String, String); - let (principal, calendar, mut object) = Inner::deserialize(deserializer)?; + let (principal, addressbook_id, mut object) = Inner::deserialize(deserializer)?; if object.ends_with(".vcf") { object.truncate(object.len() - 4); } Ok(Self { principal, - cal_id: calendar, + addressbook_id, object_id: object, }) } @@ -118,44 +121,35 @@ impl ResourceService for AddressObjectResourceSer type MemberType = AddressObjectResource; type Error = Error; - async fn new( - req: &HttpRequest, - path_components: Self::PathComponents, - ) -> Result { - let AddressObjectPathComponents { + async fn get_resource( + &self, + AddressObjectPathComponents { principal, - cal_id, + addressbook_id, object_id, - } = path_components; - - let addr_store = req - .app_data::>() - .expect("no addressbook store in app_data!") - .clone() - .into_inner(); - - Ok(Self { - addr_store, - principal, - cal_id, - object_id, - }) - } - - async fn get_resource(&self) -> Result { + }: &Self::PathComponents, + ) -> Result { let object = self .addr_store - .get_object(&self.principal, &self.cal_id, &self.object_id) + .get_object(principal, addressbook_id, object_id) .await?; Ok(AddressObjectResource { object, - principal: self.principal.to_owned(), + principal: principal.to_owned(), }) } - async fn delete_resource(&self, use_trashbin: bool) -> Result<(), Self::Error> { + async fn delete_resource( + &self, + AddressObjectPathComponents { + principal, + addressbook_id, + object_id, + }: &Self::PathComponents, + use_trashbin: bool, + ) -> Result<(), Self::Error> { self.addr_store - .delete_object(&self.principal, &self.cal_id, &self.object_id, use_trashbin) + .delete_object(principal, addressbook_id, object_id, use_trashbin) .await?; Ok(()) } diff --git a/crates/carddav/src/addressbook/resource.rs b/crates/carddav/src/addressbook/resource.rs index b93cad3..fb67aed 100644 --- a/crates/carddav/src/addressbook/resource.rs +++ b/crates/carddav/src/addressbook/resource.rs @@ -7,7 +7,6 @@ use crate::Error; use actix_web::dev::ResourceMap; use actix_web::http::Method; use actix_web::web; -use actix_web::{web::Data, HttpRequest}; use async_trait::async_trait; use derive_more::derive::{From, Into}; use rustical_dav::privileges::UserPrivilegeSet; @@ -21,8 +20,12 @@ use strum::{EnumDiscriminants, EnumString, IntoStaticStr, VariantNames}; pub struct AddressbookResourceService { addr_store: Arc, - principal: String, - addressbook_id: String, +} + +impl AddressbookResourceService { + pub fn new(addr_store: Arc) -> Self { + Self { addr_store } + } } #[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone)] @@ -157,10 +160,13 @@ impl ResourceService for AddressbookResourceServi type Resource = AddressbookResource; type Error = Error; - async fn get_resource(&self) -> Result { + async fn get_resource( + &self, + (principal, addressbook_id): &Self::PathComponents, + ) -> Result { let addressbook = self .addr_store - .get_addressbook(&self.principal, &self.addressbook_id) + .get_addressbook(principal, addressbook_id) .await .map_err(|_e| Error::NotFound)?; Ok(addressbook.into()) @@ -168,60 +174,48 @@ impl ResourceService for AddressbookResourceServi async fn get_members( &self, + (principal, addressbook_id): &Self::PathComponents, rmap: &ResourceMap, ) -> Result, Self::Error> { Ok(self .addr_store - .get_objects(&self.principal, &self.addressbook_id) + .get_objects(principal, addressbook_id) .await? .into_iter() .map(|object| { ( AddressObjectResource::get_url( rmap, - vec![&self.principal, &self.addressbook_id, object.get_id()], + vec![principal, addressbook_id, object.get_id()], ) .unwrap(), AddressObjectResource { object, - principal: self.principal.to_owned(), + principal: principal.to_owned(), }, ) }) .collect()) } - async fn new( - req: &HttpRequest, - path_components: Self::PathComponents, - ) -> Result { - let addr_store = req - .app_data::>() - .expect("no addressbook store in app_data!") - .clone() - .into_inner(); - - Ok(Self { - principal: path_components.0, - addressbook_id: path_components.1, - addr_store, - }) - } - - async fn save_resource(&self, file: Self::Resource) -> Result<(), Self::Error> { + async fn save_resource( + &self, + (principal, addressbook_id): &Self::PathComponents, + file: Self::Resource, + ) -> Result<(), Self::Error> { self.addr_store - .update_addressbook( - self.principal.to_owned(), - self.addressbook_id.to_owned(), - file.into(), - ) + .update_addressbook(principal.to_owned(), addressbook_id.to_owned(), file.into()) .await?; Ok(()) } - async fn delete_resource(&self, use_trashbin: bool) -> Result<(), Self::Error> { + async fn delete_resource( + &self, + (principal, addressbook_id): &Self::PathComponents, + use_trashbin: bool, + ) -> Result<(), Self::Error> { self.addr_store - .delete_addressbook(&self.principal, &self.addressbook_id, use_trashbin) + .delete_addressbook(principal, addressbook_id, use_trashbin) .await?; Ok(()) } diff --git a/crates/carddav/src/lib.rs b/crates/carddav/src/lib.rs index 14d6547..6126eaf 100644 --- a/crates/carddav/src/lib.rs +++ b/crates/carddav/src/lib.rs @@ -57,17 +57,21 @@ pub fn configure_dav( }), ) .app_data(Data::from(store.clone())) - .service(RootResourceService::::actix_resource()) + .service(RootResourceService::::default().actix_resource()) .service( web::scope("/user").service( web::scope("/{principal}") - .service(PrincipalResourceService::::actix_resource()) + .service(PrincipalResourceService::::new(store.clone()).actix_resource()) .service( web::scope("/{addressbook}") - .service(AddressbookResourceService::::actix_resource()) + .service( + AddressbookResourceService::::new(store.clone()) + .actix_resource(), + ) .service( web::scope("/{object}").service( - AddressObjectResourceService::::actix_resource(), + AddressObjectResourceService::::new(store.clone()) + .actix_resource(), ), ), ), diff --git a/crates/carddav/src/principal/mod.rs b/crates/carddav/src/principal/mod.rs index 7e97a4d..1275188 100644 --- a/crates/carddav/src/principal/mod.rs +++ b/crates/carddav/src/principal/mod.rs @@ -1,8 +1,6 @@ use crate::addressbook::resource::AddressbookResource; use crate::Error; use actix_web::dev::ResourceMap; -use actix_web::web::Data; -use actix_web::HttpRequest; use async_trait::async_trait; use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::resource::{Resource, ResourceService}; @@ -14,10 +12,15 @@ use std::sync::Arc; use strum::{EnumDiscriminants, EnumString, IntoStaticStr, VariantNames}; pub struct PrincipalResourceService { - principal: String, addr_store: Arc, } +impl PrincipalResourceService { + pub fn new(addr_store: Arc) -> Self { + Self { addr_store } + } +} + #[derive(Debug, Clone)] pub struct PrincipalResource { principal: String, @@ -97,39 +100,26 @@ impl ResourceService for PrincipalResourceService< type Resource = PrincipalResource; type Error = Error; - async fn new( - req: &HttpRequest, - (principal,): Self::PathComponents, - ) -> Result { - let addr_store = req - .app_data::>() - .expect("no addressbook store in app_data!") - .clone() - .into_inner(); - - Ok(Self { - addr_store, - principal, - }) - } - - async fn get_resource(&self) -> Result { + async fn get_resource( + &self, + (principal,): &Self::PathComponents, + ) -> Result { Ok(PrincipalResource { - principal: self.principal.to_owned(), + principal: principal.to_owned(), }) } async fn get_members( &self, + (principal,): &Self::PathComponents, rmap: &ResourceMap, ) -> Result, Self::Error> { - let addressbooks = self.addr_store.get_addressbooks(&self.principal).await?; + let addressbooks = self.addr_store.get_addressbooks(principal).await?; Ok(addressbooks .into_iter() .map(|addressbook| { ( - AddressbookResource::get_url(rmap, vec![&self.principal, &addressbook.id]) - .unwrap(), + AddressbookResource::get_url(rmap, vec![principal, &addressbook.id]).unwrap(), addressbook.into(), ) }) diff --git a/crates/dav/src/resource/methods/delete.rs b/crates/dav/src/resource/methods/delete.rs index c77df51..59e5c5c 100644 --- a/crates/dav/src/resource/methods/delete.rs +++ b/crates/dav/src/resource/methods/delete.rs @@ -2,6 +2,7 @@ use crate::privileges::UserPrivilege; use crate::resource::Resource; use crate::resource::ResourceService; use crate::Error; +use actix_web::web::Data; use actix_web::web::Path; use actix_web::HttpRequest; use actix_web::HttpResponse; @@ -9,27 +10,25 @@ use actix_web::Responder; use rustical_store::auth::User; pub async fn route_delete( - path_components: Path, + path: Path, req: HttpRequest, user: User, + resource_service: Data, ) -> Result { - let path_components = path_components.into_inner(); - let no_trash = req .headers() .get("X-No-Trashbin") .map(|val| matches!(val.to_str(), Ok("1"))) .unwrap_or(false); - let resource_service = R::new(&req, path_components.clone()).await?; - let resource = resource_service.get_resource().await?; + let resource = resource_service.get_resource(&path).await?; let privileges = resource.get_user_privileges(&user)?; if !privileges.has(&UserPrivilege::Write) { // TODO: Actually the spec wants us to look whether we have unbind access in the parent // collection return Err(Error::Unauthorized.into()); } - resource_service.delete_resource(!no_trash).await?; + resource_service.delete_resource(&path, !no_trash).await?; Ok(HttpResponse::Ok().body("")) } diff --git a/crates/dav/src/resource/methods/propfind.rs b/crates/dav/src/resource/methods/propfind.rs index 78ce906..95be3ef 100644 --- a/crates/dav/src/resource/methods/propfind.rs +++ b/crates/dav/src/resource/methods/propfind.rs @@ -9,6 +9,7 @@ use crate::xml::PropElement; use crate::xml::PropfindElement; use crate::xml::PropfindType; use crate::Error; +use actix_web::web::Data; use actix_web::web::Path; use actix_web::HttpRequest; use rustical_store::auth::User; @@ -16,15 +17,16 @@ use rustical_xml::de::XmlDocument; use tracing::instrument; use tracing_actix_web::RootSpan; -#[instrument(parent = root_span.id(), skip(path_components, req, root_span))] +#[instrument(parent = root_span.id(), skip(path, req, root_span, resource_service))] #[allow(clippy::type_complexity)] pub(crate) async fn route_propfind( - path_components: Path, + path: Path, body: String, req: HttpRequest, user: User, depth: Depth, root_span: RootSpan, + resource_service: Data, ) -> Result< MultistatusElement< EitherProp<::Prop, CommonPropertiesProp>, @@ -32,9 +34,7 @@ pub(crate) async fn route_propfind( >, R::Error, > { - let resource_service = R::new(&req, path_components.into_inner()).await?; - - let resource = resource_service.get_resource().await?; + let resource = resource_service.get_resource(&path).await?; let privileges = resource.get_user_privileges(&user)?; if !privileges.has(&UserPrivilege::Read) { return Err(Error::Unauthorized.into()); @@ -61,7 +61,10 @@ pub(crate) async fn route_propfind( let mut member_responses = Vec::new(); if depth != Depth::Zero { - for (path, member) in resource_service.get_members(req.resource_map()).await? { + for (path, member) in resource_service + .get_members(&path, req.resource_map()) + .await? + { member_responses.push(member.propfind(&path, &props, &user, req.resource_map())?); } } diff --git a/crates/dav/src/resource/methods/proppatch.rs b/crates/dav/src/resource/methods/proppatch.rs index 77cf9b4..aef147b 100644 --- a/crates/dav/src/resource/methods/proppatch.rs +++ b/crates/dav/src/resource/methods/proppatch.rs @@ -6,6 +6,7 @@ use crate::xml::MultistatusElement; use crate::xml::TagList; use crate::Error; use actix_web::http::StatusCode; +use actix_web::web::Data; use actix_web::{web::Path, HttpRequest}; use rustical_store::auth::User; use rustical_xml::Unparsed; @@ -71,24 +72,23 @@ struct PropertyupdateElement { operations: Vec>, } -#[instrument(parent = root_span.id(), skip(path, req, root_span))] +#[instrument(parent = root_span.id(), skip(path, req, root_span, resource_service))] pub(crate) async fn route_proppatch( path: Path, body: String, req: HttpRequest, user: User, root_span: RootSpan, + resource_service: Data, ) -> Result, R::Error> { - let path_components = path.into_inner(); let href = req.path().to_owned(); - let resource_service = R::new(&req, path_components.clone()).await?; // Extract operations let PropertyupdateElement::::Prop>> { operations, } = XmlDocument::parse_str(&body).map_err(Error::XmlDeserializationError)?; - let mut resource = resource_service.get_resource().await?; + let mut resource = resource_service.get_resource(&path).await?; let privileges = resource.get_user_privileges(&user)?; if !privileges.has(&UserPrivilege::Write) { return Err(Error::Unauthorized.into()); @@ -141,7 +141,7 @@ pub(crate) async fn route_proppatch( if props_not_found.is_empty() && props_conflict.is_empty() { // Only save if no errors occured - resource_service.save_resource(resource).await?; + resource_service.save_resource(&path, resource).await?; } Ok(MultistatusElement { diff --git a/crates/dav/src/resource/resource_service.rs b/crates/dav/src/resource/resource_service.rs index 643b126..1c12915 100644 --- a/crates/dav/src/resource/resource_service.rs +++ b/crates/dav/src/resource/resource_service.rs @@ -1,6 +1,7 @@ use std::str::FromStr; -use actix_web::{dev::ResourceMap, http::Method, web, HttpRequest, ResponseError}; +use actix_web::web::Data; +use actix_web::{dev::ResourceMap, http::Method, web, ResponseError}; use async_trait::async_trait; use serde::Deserialize; @@ -14,23 +15,30 @@ pub trait ResourceService: Sized + 'static { type Resource: Resource; type Error: ResponseError + From; - async fn new( - req: &HttpRequest, - path_components: Self::PathComponents, - ) -> Result; - async fn get_members( &self, + path: &Self::PathComponents, _rmap: &ResourceMap, ) -> Result, Self::Error> { Ok(vec![]) } - async fn get_resource(&self) -> Result; - async fn save_resource(&self, _file: Self::Resource) -> Result<(), Self::Error> { + async fn get_resource( + &self, + path: &Self::PathComponents, + ) -> Result; + async fn save_resource( + &self, + path: &Self::PathComponents, + file: Self::Resource, + ) -> Result<(), Self::Error> { Err(crate::Error::Unauthorized.into()) } - async fn delete_resource(&self, _use_trashbin: bool) -> Result<(), Self::Error> { + async fn delete_resource( + &self, + path: &Self::PathComponents, + _use_trashbin: bool, + ) -> Result<(), Self::Error> { Err(crate::Error::Unauthorized.into()) } @@ -40,9 +48,10 @@ pub trait ResourceService: Sized + 'static { } #[inline] - fn actix_resource() -> actix_web::Resource { + fn actix_resource(self) -> actix_web::Resource { Self::actix_additional_routes( web::resource("") + .app_data(Data::new(self)) .name(Self::resource_name()) .route( web::method(Method::from_str("PROPFIND").unwrap()).to(route_propfind::), diff --git a/crates/dav/src/resources/root.rs b/crates/dav/src/resources/root.rs index cc221e5..b6a3147 100644 --- a/crates/dav/src/resources/root.rs +++ b/crates/dav/src/resources/root.rs @@ -1,7 +1,6 @@ use crate::privileges::UserPrivilegeSet; use crate::resource::{Resource, ResourceService}; use actix_web::dev::ResourceMap; -use actix_web::HttpRequest; use async_trait::async_trait; use rustical_store::auth::User; use rustical_xml::{XmlDeserialize, XmlSerialize}; @@ -61,9 +60,14 @@ impl Resource for RootResource { } } -#[derive(Default)] pub struct RootResourceService(PhantomData); +impl Default for RootResourceService { + fn default() -> Self { + Self(PhantomData) + } +} + #[async_trait(?Send)] impl ResourceService for RootResourceService { type PathComponents = (); @@ -71,14 +75,7 @@ impl ResourceService for RootResourceService { type Resource = RootResource; type Error = PR::Error; - async fn new( - _req: &HttpRequest, - _path_components: Self::PathComponents, - ) -> Result { - Ok(Self(Default::default())) - } - - async fn get_resource(&self) -> Result { + async fn get_resource(&self, _: &()) -> Result { Ok(RootResource::::default()) } }