aboutsummaryrefslogtreecommitdiff
path: root/aero-proto/src/dav/resource.rs
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-05-16 17:38:34 +0200
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-05-16 17:38:34 +0200
commit32dfd25f570b7a55bf43752684d286be0f6b2dc2 (patch)
treedd77871cda851bb5795743a3f04be61cf4c3ad61 /aero-proto/src/dav/resource.rs
parent6b9542088cd1b66af46e95b787493b601accb495 (diff)
downloadaerogramme-32dfd25f570b7a55bf43752684d286be0f6b2dc2.tar.gz
aerogramme-32dfd25f570b7a55bf43752684d286be0f6b2dc2.zip
format + WIP calendar-query
Diffstat (limited to 'aero-proto/src/dav/resource.rs')
-rw-r--r--aero-proto/src/dav/resource.rs565
1 files changed, 387 insertions, 178 deletions
diff --git a/aero-proto/src/dav/resource.rs b/aero-proto/src/dav/resource.rs
index 944c6c8..d65ce38 100644
--- a/aero-proto/src/dav/resource.rs
+++ b/aero-proto/src/dav/resource.rs
@@ -2,23 +2,32 @@ use std::sync::Arc;
type ArcUser = std::sync::Arc<User>;
use anyhow::{anyhow, Result};
-use futures::stream::{TryStreamExt, StreamExt};
use futures::io::AsyncReadExt;
+use futures::stream::{StreamExt, TryStreamExt};
use futures::{future::BoxFuture, future::FutureExt};
-use aero_collections::{user::User, calendar::Calendar, davdag::{BlobId, Etag}};
-use aero_dav::types as dav;
-use aero_dav::caltypes as cal;
+use aero_collections::{
+ calendar::Calendar,
+ davdag::{BlobId, Etag},
+ user::User,
+};
use aero_dav::acltypes as acl;
-use aero_dav::realization::{All, self as all};
+use aero_dav::caltypes as cal;
+use aero_dav::realization::{self as all, All};
+use aero_dav::types as dav;
-use crate::dav::node::{DavNode, PutPolicy, Content};
use super::node::PropertyStream;
+use crate::dav::node::{Content, DavNode, PutPolicy};
#[derive(Clone)]
pub(crate) struct RootNode {}
impl DavNode for RootNode {
- fn fetch<'a>(&self, user: &'a ArcUser, path: &'a [&str], create: bool) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
+ fn fetch<'a>(
+ &self,
+ user: &'a ArcUser,
+ path: &'a [&str],
+ create: bool,
+ ) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
if path.len() == 0 {
let this = self.clone();
return async { Ok(Box::new(this) as Box<dyn DavNode>) }.boxed();
@@ -34,7 +43,7 @@ impl DavNode for RootNode {
}
fn children<'a>(&self, user: &'a ArcUser) -> BoxFuture<'a, Vec<Box<dyn DavNode>>> {
- async { vec![Box::new(HomeNode { }) as Box<dyn DavNode>] }.boxed()
+ async { vec![Box::new(HomeNode {}) as Box<dyn DavNode>] }.boxed()
}
fn path(&self, user: &ArcUser) -> String {
@@ -46,33 +55,53 @@ impl DavNode for RootNode {
dav::PropertyRequest::DisplayName,
dav::PropertyRequest::ResourceType,
dav::PropertyRequest::GetContentType,
- dav::PropertyRequest::Extension(all::PropertyRequest::Acl(acl::PropertyRequest::CurrentUserPrincipal)),
+ dav::PropertyRequest::Extension(all::PropertyRequest::Acl(
+ acl::PropertyRequest::CurrentUserPrincipal,
+ )),
])
}
fn properties(&self, user: &ArcUser, prop: dav::PropName<All>) -> PropertyStream<'static> {
let user = user.clone();
- futures::stream::iter(prop.0).map(move |n| {
- let prop = match n {
- dav::PropertyRequest::DisplayName => dav::Property::DisplayName("DAV Root".to_string()),
- dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![
- dav::ResourceType::Collection,
- ]),
- dav::PropertyRequest::GetContentType => dav::Property::GetContentType("httpd/unix-directory".into()),
- dav::PropertyRequest::Extension(all::PropertyRequest::Acl(acl::PropertyRequest::CurrentUserPrincipal)) =>
- dav::Property::Extension(all::Property::Acl(acl::Property::CurrentUserPrincipal(acl::User::Authenticated(dav::Href(HomeNode{}.path(&user)))))),
- v => return Err(v),
- };
- Ok(prop)
- }).boxed()
+ futures::stream::iter(prop.0)
+ .map(move |n| {
+ let prop = match n {
+ dav::PropertyRequest::DisplayName => {
+ dav::Property::DisplayName("DAV Root".to_string())
+ }
+ dav::PropertyRequest::ResourceType => {
+ dav::Property::ResourceType(vec![dav::ResourceType::Collection])
+ }
+ dav::PropertyRequest::GetContentType => {
+ dav::Property::GetContentType("httpd/unix-directory".into())
+ }
+ dav::PropertyRequest::Extension(all::PropertyRequest::Acl(
+ acl::PropertyRequest::CurrentUserPrincipal,
+ )) => dav::Property::Extension(all::Property::Acl(
+ acl::Property::CurrentUserPrincipal(acl::User::Authenticated(dav::Href(
+ HomeNode {}.path(&user),
+ ))),
+ )),
+ v => return Err(v),
+ };
+ Ok(prop)
+ })
+ .boxed()
}
- fn put<'a>(&'a self, _policy: PutPolicy, stream: Content<'a>) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
+ fn put<'a>(
+ &'a self,
+ _policy: PutPolicy,
+ stream: Content<'a>,
+ ) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported)).boxed()
}
- fn content(&self) -> Content<'static> {
- futures::stream::once(futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported))).boxed()
+ fn content<'a>(&self) -> Content<'a> {
+ futures::stream::once(futures::future::err(std::io::Error::from(
+ std::io::ErrorKind::Unsupported,
+ )))
+ .boxed()
}
fn content_type(&self) -> &str {
@@ -91,29 +120,37 @@ impl DavNode for RootNode {
#[derive(Clone)]
pub(crate) struct HomeNode {}
impl DavNode for HomeNode {
- fn fetch<'a>(&self, user: &'a ArcUser, path: &'a [&str], create: bool) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
+ fn fetch<'a>(
+ &self,
+ user: &'a ArcUser,
+ path: &'a [&str],
+ create: bool,
+ ) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
if path.len() == 0 {
let node = Box::new(self.clone()) as Box<dyn DavNode>;
- return async { Ok(node) }.boxed()
+ return async { Ok(node) }.boxed();
}
if path[0] == "calendar" {
return async move {
let child = Box::new(CalendarListNode::new(user).await?);
child.fetch(user, &path[1..], create).await
- }.boxed();
+ }
+ .boxed();
}
-
+
//@NOTE: we can't create a node at this level
async { Err(anyhow!("Not found")) }.boxed()
}
fn children<'a>(&self, user: &'a ArcUser) -> BoxFuture<'a, Vec<Box<dyn DavNode>>> {
- async {
- CalendarListNode::new(user).await
+ async {
+ CalendarListNode::new(user)
+ .await
.map(|c| vec![Box::new(c) as Box<dyn DavNode>])
- .unwrap_or(vec![])
- }.boxed()
+ .unwrap_or(vec![])
+ }
+ .boxed()
}
fn path(&self, user: &ArcUser) -> String {
@@ -125,38 +162,58 @@ impl DavNode for HomeNode {
dav::PropertyRequest::DisplayName,
dav::PropertyRequest::ResourceType,
dav::PropertyRequest::GetContentType,
- dav::PropertyRequest::Extension(all::PropertyRequest::Cal(cal::PropertyRequest::CalendarHomeSet)),
+ dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
+ cal::PropertyRequest::CalendarHomeSet,
+ )),
])
}
fn properties(&self, user: &ArcUser, prop: dav::PropName<All>) -> PropertyStream<'static> {
let user = user.clone();
- futures::stream::iter(prop.0).map(move |n| {
- let prop = match n {
- dav::PropertyRequest::DisplayName => dav::Property::DisplayName(format!("{} home", user.username)),
- dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![
- dav::ResourceType::Collection,
- dav::ResourceType::Extension(all::ResourceType::Acl(acl::ResourceType::Principal)),
- ]),
- dav::PropertyRequest::GetContentType => dav::Property::GetContentType("httpd/unix-directory".into()),
- dav::PropertyRequest::Extension(all::PropertyRequest::Cal(cal::PropertyRequest::CalendarHomeSet)) =>
- dav::Property::Extension(all::Property::Cal(cal::Property::CalendarHomeSet(dav::Href(
- //@FIXME we are hardcoding the calendar path, instead we would want to use
- //objects
- format!("/{}/calendar/", user.username)
- )))),
- v => return Err(v),
- };
- Ok(prop)
- }).boxed()
+ futures::stream::iter(prop.0)
+ .map(move |n| {
+ let prop = match n {
+ dav::PropertyRequest::DisplayName => {
+ dav::Property::DisplayName(format!("{} home", user.username))
+ }
+ dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![
+ dav::ResourceType::Collection,
+ dav::ResourceType::Extension(all::ResourceType::Acl(
+ acl::ResourceType::Principal,
+ )),
+ ]),
+ dav::PropertyRequest::GetContentType => {
+ dav::Property::GetContentType("httpd/unix-directory".into())
+ }
+ dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
+ cal::PropertyRequest::CalendarHomeSet,
+ )) => dav::Property::Extension(all::Property::Cal(
+ cal::Property::CalendarHomeSet(dav::Href(
+ //@FIXME we are hardcoding the calendar path, instead we would want to use
+ //objects
+ format!("/{}/calendar/", user.username),
+ )),
+ )),
+ v => return Err(v),
+ };
+ Ok(prop)
+ })
+ .boxed()
}
- fn put<'a>(&'a self, _policy: PutPolicy, stream: Content<'a>) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
+ fn put<'a>(
+ &'a self,
+ _policy: PutPolicy,
+ stream: Content<'a>,
+ ) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported)).boxed()
}
-
- fn content(&self) -> Content<'static> {
- futures::stream::once(futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported))).boxed()
+
+ fn content<'a>(&self) -> Content<'a> {
+ futures::stream::once(futures::future::err(std::io::Error::from(
+ std::io::ErrorKind::Unsupported,
+ )))
+ .boxed()
}
fn content_type(&self) -> &str {
@@ -183,7 +240,12 @@ impl CalendarListNode {
}
}
impl DavNode for CalendarListNode {
- fn fetch<'a>(&self, user: &'a ArcUser, path: &'a [&str], create: bool) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
+ fn fetch<'a>(
+ &self,
+ user: &'a ArcUser,
+ path: &'a [&str],
+ create: bool,
+ ) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
if path.len() == 0 {
let node = Box::new(self.clone()) as Box<dyn DavNode>;
return async { Ok(node) }.boxed();
@@ -191,13 +253,18 @@ impl DavNode for CalendarListNode {
async move {
//@FIXME: we should create a node if the open returns a "not found".
- let cal = user.calendars.open(user, path[0]).await?.ok_or(anyhow!("Not found"))?;
- let child = Box::new(CalendarNode {
+ let cal = user
+ .calendars
+ .open(user, path[0])
+ .await?
+ .ok_or(anyhow!("Not found"))?;
+ let child = Box::new(CalendarNode {
col: cal,
- calname: path[0].to_string()
+ calname: path[0].to_string(),
});
child.fetch(user, &path[1..], create).await
- }.boxed()
+ }
+ .boxed()
}
fn children<'a>(&self, user: &'a ArcUser) -> BoxFuture<'a, Vec<Box<dyn DavNode>>> {
@@ -206,18 +273,23 @@ impl DavNode for CalendarListNode {
//@FIXME maybe we want to be lazy here?!
futures::stream::iter(list.iter())
.filter_map(|name| async move {
- user.calendars.open(user, name).await
+ user.calendars
+ .open(user, name)
+ .await
.ok()
.flatten()
.map(|v| (name, v))
})
- .map(|(name, cal)| Box::new(CalendarNode {
- col: cal,
- calname: name.to_string(),
- }) as Box<dyn DavNode>)
+ .map(|(name, cal)| {
+ Box::new(CalendarNode {
+ col: cal,
+ calname: name.to_string(),
+ }) as Box<dyn DavNode>
+ })
.collect::<Vec<Box<dyn DavNode>>>()
.await
- }.boxed()
+ }
+ .boxed()
}
fn path(&self, user: &ArcUser) -> String {
@@ -234,23 +306,38 @@ impl DavNode for CalendarListNode {
fn properties(&self, user: &ArcUser, prop: dav::PropName<All>) -> PropertyStream<'static> {
let user = user.clone();
- futures::stream::iter(prop.0).map(move |n| {
- let prop = match n {
- dav::PropertyRequest::DisplayName => dav::Property::DisplayName(format!("{} calendars", user.username)),
- dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![dav::ResourceType::Collection]),
- dav::PropertyRequest::GetContentType => dav::Property::GetContentType("httpd/unix-directory".into()),
- v => return Err(v),
- };
- Ok(prop)
- }).boxed()
+ futures::stream::iter(prop.0)
+ .map(move |n| {
+ let prop = match n {
+ dav::PropertyRequest::DisplayName => {
+ dav::Property::DisplayName(format!("{} calendars", user.username))
+ }
+ dav::PropertyRequest::ResourceType => {
+ dav::Property::ResourceType(vec![dav::ResourceType::Collection])
+ }
+ dav::PropertyRequest::GetContentType => {
+ dav::Property::GetContentType("httpd/unix-directory".into())
+ }
+ v => return Err(v),
+ };
+ Ok(prop)
+ })
+ .boxed()
}
- fn put<'a>(&'a self, _policy: PutPolicy, stream: Content<'a>) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
+ fn put<'a>(
+ &'a self,
+ _policy: PutPolicy,
+ stream: Content<'a>,
+ ) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported)).boxed()
}
- fn content(&self) -> Content<'static> {
- futures::stream::once(futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported))).boxed()
+ fn content<'a>(&self) -> Content<'a> {
+ futures::stream::once(futures::future::err(std::io::Error::from(
+ std::io::ErrorKind::Unsupported,
+ )))
+ .boxed()
}
fn content_type(&self) -> &str {
@@ -272,17 +359,22 @@ pub(crate) struct CalendarNode {
calname: String,
}
impl DavNode for CalendarNode {
- fn fetch<'a>(&self, user: &'a ArcUser, path: &'a [&str], create: bool) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
+ fn fetch<'a>(
+ &self,
+ user: &'a ArcUser,
+ path: &'a [&str],
+ create: bool,
+ ) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
if path.len() == 0 {
let node = Box::new(self.clone()) as Box<dyn DavNode>;
- return async { Ok(node) }.boxed()
+ return async { Ok(node) }.boxed();
}
let col = self.col.clone();
let calname = self.calname.clone();
async move {
match (col.dag().await.idx_by_filename.get(path[0]), create) {
- (Some(blob_id), _) => {
+ (Some(blob_id), _) => {
let child = Box::new(EventNode {
col: col.clone(),
calname,
@@ -290,7 +382,7 @@ impl DavNode for CalendarNode {
blob_id: *blob_id,
});
child.fetch(user, &path[1..], create).await
- },
+ }
(None, true) => {
let child = Box::new(CreateEventNode {
col: col.clone(),
@@ -298,11 +390,11 @@ impl DavNode for CalendarNode {
filename: path[0].to_string(),
});
child.fetch(user, &path[1..], create).await
- },
+ }
_ => Err(anyhow!("Not found")),
}
-
- }.boxed()
+ }
+ .boxed()
}
fn children<'a>(&self, user: &'a ArcUser) -> BoxFuture<'a, Vec<Box<dyn DavNode>>> {
@@ -310,15 +402,21 @@ impl DavNode for CalendarNode {
let calname = self.calname.clone();
async move {
- col.dag().await.idx_by_filename.iter().map(|(filename, blob_id)| {
- Box::new(EventNode {
- col: col.clone(),
- calname: calname.clone(),
- filename: filename.to_string(),
- blob_id: *blob_id,
- }) as Box<dyn DavNode>
- }).collect()
- }.boxed()
+ col.dag()
+ .await
+ .idx_by_filename
+ .iter()
+ .map(|(filename, blob_id)| {
+ Box::new(EventNode {
+ col: col.clone(),
+ calname: calname.clone(),
+ filename: filename.to_string(),
+ blob_id: *blob_id,
+ }) as Box<dyn DavNode>
+ })
+ .collect()
+ }
+ .boxed()
}
fn path(&self, user: &ArcUser) -> String {
@@ -330,38 +428,58 @@ impl DavNode for CalendarNode {
dav::PropertyRequest::DisplayName,
dav::PropertyRequest::ResourceType,
dav::PropertyRequest::GetContentType,
- dav::PropertyRequest::Extension(all::PropertyRequest::Cal(cal::PropertyRequest::SupportedCalendarComponentSet)),
+ dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
+ cal::PropertyRequest::SupportedCalendarComponentSet,
+ )),
])
}
fn properties(&self, _user: &ArcUser, prop: dav::PropName<All>) -> PropertyStream<'static> {
let calname = self.calname.to_string();
- futures::stream::iter(prop.0).map(move |n| {
- let prop = match n {
- dav::PropertyRequest::DisplayName => dav::Property::DisplayName(format!("{} calendar", calname)),
- dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![
- dav::ResourceType::Collection,
- dav::ResourceType::Extension(all::ResourceType::Cal(cal::ResourceType::Calendar)),
- ]),
- //dav::PropertyRequest::GetContentType => dav::AnyProperty::Value(dav::Property::GetContentType("httpd/unix-directory".into())),
- //@FIXME seems wrong but seems to be what Thunderbird expects...
- dav::PropertyRequest::GetContentType => dav::Property::GetContentType("text/calendar".into()),
- dav::PropertyRequest::Extension(all::PropertyRequest::Cal(cal::PropertyRequest::SupportedCalendarComponentSet))
- => dav::Property::Extension(all::Property::Cal(cal::Property::SupportedCalendarComponentSet(vec![
- cal::CompSupport(cal::Component::VEvent),
- ]))),
- v => return Err(v),
- };
- Ok(prop)
- }).boxed()
+ futures::stream::iter(prop.0)
+ .map(move |n| {
+ let prop = match n {
+ dav::PropertyRequest::DisplayName => {
+ dav::Property::DisplayName(format!("{} calendar", calname))
+ }
+ dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![
+ dav::ResourceType::Collection,
+ dav::ResourceType::Extension(all::ResourceType::Cal(
+ cal::ResourceType::Calendar,
+ )),
+ ]),
+ //dav::PropertyRequest::GetContentType => dav::AnyProperty::Value(dav::Property::GetContentType("httpd/unix-directory".into())),
+ //@FIXME seems wrong but seems to be what Thunderbird expects...
+ dav::PropertyRequest::GetContentType => {
+ dav::Property::GetContentType("text/calendar".into())
+ }
+ dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
+ cal::PropertyRequest::SupportedCalendarComponentSet,
+ )) => dav::Property::Extension(all::Property::Cal(
+ cal::Property::SupportedCalendarComponentSet(vec![cal::CompSupport(
+ cal::Component::VEvent,
+ )]),
+ )),
+ v => return Err(v),
+ };
+ Ok(prop)
+ })
+ .boxed()
}
- fn put<'a>(&'a self, _policy: PutPolicy, _stream: Content<'a>) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
+ fn put<'a>(
+ &'a self,
+ _policy: PutPolicy,
+ _stream: Content<'a>,
+ ) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported)).boxed()
}
- fn content<'a>(&'a self) -> Content<'static> {
- futures::stream::once(futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported))).boxed()
+ fn content<'a>(&self) -> Content<'a> {
+ futures::stream::once(futures::future::err(std::io::Error::from(
+ std::io::ErrorKind::Unsupported,
+ )))
+ .boxed()
}
fn content_type(&self) -> &str {
@@ -386,13 +504,23 @@ pub(crate) struct EventNode {
}
impl DavNode for EventNode {
- fn fetch<'a>(&self, user: &'a ArcUser, path: &'a [&str], create: bool) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
+ fn fetch<'a>(
+ &self,
+ user: &'a ArcUser,
+ path: &'a [&str],
+ create: bool,
+ ) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
if path.len() == 0 {
let node = Box::new(self.clone()) as Box<dyn DavNode>;
- return async { Ok(node) }.boxed()
+ return async { Ok(node) }.boxed();
}
- async { Err(anyhow!("Not supported: can't create a child on an event node")) }.boxed()
+ async {
+ Err(anyhow!(
+ "Not supported: can't create a child on an event node"
+ ))
+ }
+ .boxed()
}
fn children<'a>(&self, user: &'a ArcUser) -> BoxFuture<'a, Vec<Box<dyn DavNode>>> {
@@ -400,7 +528,10 @@ impl DavNode for EventNode {
}
fn path(&self, user: &ArcUser) -> String {
- format!("/{}/calendar/{}/{}", user.username, self.calname, self.filename)
+ format!(
+ "/{}/calendar/{}/{}",
+ user.username, self.calname, self.filename
+ )
}
fn supported_properties(&self, user: &ArcUser) -> dav::PropName<All> {
@@ -408,66 +539,106 @@ impl DavNode for EventNode {
dav::PropertyRequest::DisplayName,
dav::PropertyRequest::ResourceType,
dav::PropertyRequest::GetEtag,
- dav::PropertyRequest::Extension(all::PropertyRequest::Cal(cal::PropertyRequest::CalendarData(cal::CalendarDataRequest::default()))),
+ dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
+ cal::PropertyRequest::CalendarData(cal::CalendarDataRequest::default()),
+ )),
])
}
fn properties(&self, _user: &ArcUser, prop: dav::PropName<All>) -> PropertyStream<'static> {
let this = self.clone();
- futures::stream::iter(prop.0).then(move |n| {
- let this = this.clone();
-
- async move {
- let prop = match &n {
- dav::PropertyRequest::DisplayName => dav::Property::DisplayName(format!("{} event", this.filename)),
- dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![]),
- dav::PropertyRequest::GetContentType => dav::Property::GetContentType("text/calendar".into()),
- dav::PropertyRequest::GetEtag => {
- let etag = this.etag().await.ok_or(n.clone())?;
- dav::Property::GetEtag(etag)
- },
- dav::PropertyRequest::Extension(all::PropertyRequest::Cal(cal::PropertyRequest::CalendarData(_req))) => {
- let ics = String::from_utf8(this.col.get(this.blob_id).await.or(Err(n.clone()))?).or(Err(n.clone()))?;
-
- dav::Property::Extension(all::Property::Cal(cal::Property::CalendarData(cal::CalendarDataPayload {
- mime: None,
- payload: ics,
- })))
- },
- _ => return Err(n),
- };
- Ok(prop)
- }
- }).boxed()
- }
-
- fn put<'a>(&'a self, policy: PutPolicy, stream: Content<'a>) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
+ futures::stream::iter(prop.0)
+ .then(move |n| {
+ let this = this.clone();
+
+ async move {
+ let prop = match &n {
+ dav::PropertyRequest::DisplayName => {
+ dav::Property::DisplayName(format!("{} event", this.filename))
+ }
+ dav::PropertyRequest::ResourceType => dav::Property::ResourceType(vec![]),
+ dav::PropertyRequest::GetContentType => {
+ dav::Property::GetContentType("text/calendar".into())
+ }
+ dav::PropertyRequest::GetEtag => {
+ let etag = this.etag().await.ok_or(n.clone())?;
+ dav::Property::GetEtag(etag)
+ }
+ dav::PropertyRequest::Extension(all::PropertyRequest::Cal(
+ cal::PropertyRequest::CalendarData(_req),
+ )) => {
+ let ics = String::from_utf8(
+ this.col.get(this.blob_id).await.or(Err(n.clone()))?,
+ )
+ .or(Err(n.clone()))?;
+
+ dav::Property::Extension(all::Property::Cal(
+ cal::Property::CalendarData(cal::CalendarDataPayload {
+ mime: None,
+ payload: ics,
+ }),
+ ))
+ }
+ _ => return Err(n),
+ };
+ Ok(prop)
+ }
+ })
+ .boxed()
+ }
+
+ fn put<'a>(
+ &'a self,
+ policy: PutPolicy,
+ stream: Content<'a>,
+ ) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
async {
- let existing_etag = self.etag().await.ok_or(std::io::Error::new(std::io::ErrorKind::Other, "Etag error"))?;
+ let existing_etag = self
+ .etag()
+ .await
+ .ok_or(std::io::Error::new(std::io::ErrorKind::Other, "Etag error"))?;
match policy {
- PutPolicy::CreateOnly => return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists)),
- PutPolicy::ReplaceEtag(etag) if etag != existing_etag.as_str() => return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists)),
- _ => ()
+ PutPolicy::CreateOnly => {
+ return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists))
+ }
+ PutPolicy::ReplaceEtag(etag) if etag != existing_etag.as_str() => {
+ return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists))
+ }
+ _ => (),
};
//@FIXME for now, our storage interface does not allow streaming,
// so we load everything in memory
let mut evt = Vec::new();
let mut reader = stream.into_async_read();
- reader.read_to_end(&mut evt).await.or(Err(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))?;
- let (_token, entry) = self.col.put(self.filename.as_str(), evt.as_ref()).await.or(Err(std::io::ErrorKind::Interrupted))?;
- self.col.opportunistic_sync().await.or(Err(std::io::ErrorKind::ConnectionReset))?;
+ reader
+ .read_to_end(&mut evt)
+ .await
+ .or(Err(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))?;
+ let (_token, entry) = self
+ .col
+ .put(self.filename.as_str(), evt.as_ref())
+ .await
+ .or(Err(std::io::ErrorKind::Interrupted))?;
+ self.col
+ .opportunistic_sync()
+ .await
+ .or(Err(std::io::ErrorKind::ConnectionReset))?;
Ok(entry.2)
- }.boxed()
+ }
+ .boxed()
}
- fn content<'a>(&'a self) -> Content<'static> {
+ fn content<'a>(&self) -> Content<'a> {
//@FIXME for now, our storage interface does not allow streaming,
// so we load everything in memory
let calendar = self.col.clone();
let blob_id = self.blob_id.clone();
let r = async move {
- let content = calendar.get(blob_id).await.or(Err(std::io::Error::from(std::io::ErrorKind::Interrupted)));
+ let content = calendar
+ .get(blob_id)
+ .await
+ .or(Err(std::io::Error::from(std::io::ErrorKind::Interrupted)));
Ok(hyper::body::Bytes::from(content?))
};
futures::stream::once(Box::pin(r)).boxed()
@@ -481,8 +652,14 @@ impl DavNode for EventNode {
let calendar = self.col.clone();
async move {
- calendar.dag().await.table.get(&self.blob_id).map(|(_, _, etag)| etag.to_string())
- }.boxed()
+ calendar
+ .dag()
+ .await
+ .table
+ .get(&self.blob_id)
+ .map(|(_, _, etag)| etag.to_string())
+ }
+ .boxed()
}
fn delete(&self) -> BoxFuture<std::result::Result<(), std::io::Error>> {
@@ -494,12 +671,16 @@ impl DavNode for EventNode {
Ok(v) => v,
Err(e) => {
tracing::error!(err=?e, "delete event node");
- return Err(std::io::Error::from(std::io::ErrorKind::Interrupted))
- },
+ return Err(std::io::Error::from(std::io::ErrorKind::Interrupted));
+ }
};
- calendar.opportunistic_sync().await.or(Err(std::io::ErrorKind::ConnectionReset))?;
+ calendar
+ .opportunistic_sync()
+ .await
+ .or(Err(std::io::ErrorKind::ConnectionReset))?;
Ok(())
- }.boxed()
+ }
+ .boxed()
}
}
@@ -510,13 +691,23 @@ pub(crate) struct CreateEventNode {
filename: String,
}
impl DavNode for CreateEventNode {
- fn fetch<'a>(&self, user: &'a ArcUser, path: &'a [&str], create: bool) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
+ fn fetch<'a>(
+ &self,
+ user: &'a ArcUser,
+ path: &'a [&str],
+ create: bool,
+ ) -> BoxFuture<'a, Result<Box<dyn DavNode>>> {
if path.len() == 0 {
let node = Box::new(self.clone()) as Box<dyn DavNode>;
- return async { Ok(node) }.boxed()
+ return async { Ok(node) }.boxed();
}
- async { Err(anyhow!("Not supported: can't create a child on an event node")) }.boxed()
+ async {
+ Err(anyhow!(
+ "Not supported: can't create a child on an event node"
+ ))
+ }
+ .boxed()
}
fn children<'a>(&self, user: &'a ArcUser) -> BoxFuture<'a, Vec<Box<dyn DavNode>>> {
@@ -524,33 +715,51 @@ impl DavNode for CreateEventNode {
}
fn path(&self, user: &ArcUser) -> String {
- format!("/{}/calendar/{}/{}", user.username, self.calname, self.filename)
+ format!(
+ "/{}/calendar/{}/{}",
+ user.username, self.calname, self.filename
+ )
}
fn supported_properties(&self, user: &ArcUser) -> dav::PropName<All> {
dav::PropName(vec![])
}
- fn properties(&self, _user: &ArcUser, prop: dav::PropName<All>) -> PropertyStream<'static> {
+ fn properties(&self, _user: &ArcUser, prop: dav::PropName<All>) -> PropertyStream<'static> {
futures::stream::iter(vec![]).boxed()
}
- fn put<'a>(&'a self, _policy: PutPolicy, stream: Content<'a>) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
+ fn put<'a>(
+ &'a self,
+ _policy: PutPolicy,
+ stream: Content<'a>,
+ ) -> BoxFuture<'a, std::result::Result<Etag, std::io::Error>> {
//@NOTE: policy might not be needed here: whatever we put, there is no known entries here
-
+
async {
//@FIXME for now, our storage interface does not allow for streaming
let mut evt = Vec::new();
let mut reader = stream.into_async_read();
reader.read_to_end(&mut evt).await.unwrap();
- let (_token, entry) = self.col.put(self.filename.as_str(), evt.as_ref()).await.or(Err(std::io::ErrorKind::Interrupted))?;
- self.col.opportunistic_sync().await.or(Err(std::io::ErrorKind::ConnectionReset))?;
+ let (_token, entry) = self
+ .col
+ .put(self.filename.as_str(), evt.as_ref())
+ .await
+ .or(Err(std::io::ErrorKind::Interrupted))?;
+ self.col
+ .opportunistic_sync()
+ .await
+ .or(Err(std::io::ErrorKind::ConnectionReset))?;
Ok(entry.2)
- }.boxed()
+ }
+ .boxed()
}
- fn content(&self) -> Content<'static> {
- futures::stream::once(futures::future::err(std::io::Error::from(std::io::ErrorKind::Unsupported))).boxed()
+ fn content<'a>(&self) -> Content<'a> {
+ futures::stream::once(futures::future::err(std::io::Error::from(
+ std::io::ErrorKind::Unsupported,
+ )))
+ .boxed()
}
fn content_type(&self) -> &str {