~whynothugo/vdirsyncer-rs

002ab566a38223c6b4cb4ea087f297361b8d51ce — Hugo Osvaldo Barrera 8 months ago 2cc72c1 as_webdav
wip: do not merge
M libdav/src/caldav.rs => libdav/src/caldav.rs +18 -20
@@ 2,8 2,6 @@
//
// SPDX-License-Identifier: EUPL-1.2

use std::ops::Deref;

use hyper::client::connect::Connect;
use hyper::Uri;



@@ 64,17 62,6 @@ where
    calendar_home_set: Option<Uri>,
}

impl<C> Deref for CalDavClient<C>
where
    C: Connect + Clone + Sync + Send,
{
    type Target = WebDavClient<C>;

    fn deref(&self) -> &Self::Target {
        &self.dav_client
    }
}

impl<C> Rfc6764Protocol for CalDavClient<C>
where
    C: Connect + Clone + Sync + Send,


@@ 116,6 103,11 @@ where
        ClientBuilder::new()
    }

    /// Returns a reference to the internal webdav client instance.
    pub fn as_webdav(&self) -> &WebDavClient<C> {
        &self.dav_client
    }

    /// The home set found during discovery (if any) or explicitly provided during client creation.
    ///
    /// This function does not perform any network operations; it merely returns the already-known URL.


@@ 141,14 133,14 @@ where
    ) -> Result<Vec<FoundCollection>, DavError> {
        let url = url
            .or(self.calendar_home_set.as_ref())
            .unwrap_or(&self.base_url);
            .unwrap_or(&self.dav_client.base_url);

        let props = [
            &names::RESOURCETYPE,
            &names::GETETAG,
            &names::SUPPORTED_REPORT_SET,
        ];
        let (head, body) = self.propfind(url, &props, 1).await?;
        let (head, body) = self.dav_client.propfind(url, &props, 1).await?;
        check_status(head.status)?;

        parse_find_multiple_collections(body, &names::CALENDAR)


@@ 169,9 161,12 @@ where
    ///
    /// If the network request fails, or if the response cannot be parsed.
    pub async fn get_calendar_colour(&self, href: &str) -> Result<Option<String>, DavError> {
        let url = self.relative_uri(href)?;
        let url = self.dav_client.relative_uri(href)?;

        let (head, body) = self.propfind(&url, &[&names::CALENDAR_COLOUR], 0).await?;
        let (head, body) = self
            .dav_client
            .propfind(&url, &[&names::CALENDAR_COLOUR], 0)
            .await?;
        check_status(head.status)?;

        let body = std::str::from_utf8(body.as_ref())?;


@@ 212,8 207,10 @@ where
        href: &str,
        colour: Option<&str>,
    ) -> Result<(), DavError> {
        let url = self.relative_uri(href)?;
        self.propupdate(&url, &names::CALENDAR_COLOUR, colour).await
        let url = self.dav_client.relative_uri(href)?;
        self.dav_client
            .propupdate(&url, &names::CALENDAR_COLOUR, colour)
            .await
    }

    // TODO: get_calendar_description ("calendar-description", "urn:ietf:params:xml:ns:caldav")


@@ 253,7 250,8 @@ where
        }
        body.push_str("</C:calendar-multiget>");

        self.multi_get(calendar_href.as_ref(), body, &names::CALENDAR_DATA)
        self.dav_client
            .multi_get(calendar_href.as_ref(), body, &names::CALENDAR_DATA)
            .await
    }


M libdav/src/carddav.rs => libdav/src/carddav.rs +9 -16
@@ 2,8 2,6 @@
//
// SPDX-License-Identifier: EUPL-1.2

use std::ops::Deref;

use hyper::client::connect::Connect;
use hyper::Uri;



@@ 64,17 62,6 @@ where
    addressbook_home_set: Option<Uri>,
}

impl<C> Deref for CardDavClient<C>
where
    C: Connect + Clone + Sync + Send,
{
    type Target = WebDavClient<C>;

    fn deref(&self) -> &Self::Target {
        &self.dav_client
    }
}

impl<C> Rfc6764Protocol for CardDavClient<C>
where
    C: Connect + Clone + Sync + Send,


@@ 116,6 103,11 @@ where
        ClientBuilder::new()
    }

    /// Returns a reference to the internal webdav client instance.
    pub fn as_webdav(&self) -> &WebDavClient<C> {
        &self.dav_client
    }

    /// The home set found during discovery (if any) or explicitly provided during client creation.
    ///
    /// This function does not perform any network operations; it merely returns the already-known URL.


@@ 141,14 133,14 @@ where
    ) -> Result<Vec<FoundCollection>, DavError> {
        let url = url
            .or(self.addressbook_home_set.as_ref())
            .unwrap_or(&self.base_url);
            .unwrap_or(&self.dav_client.base_url);

        let props = [
            &names::RESOURCETYPE,
            &names::GETETAG,
            &names::SUPPORTED_REPORT_SET,
        ];
        let (head, body) = self.propfind(url, &props, 1).await?;
        let (head, body) = self.dav_client.propfind(url, &props, 1).await?;
        check_status(head.status)?;

        parse_find_multiple_collections(body, &names::ADDRESSBOOK)


@@ 184,7 176,8 @@ where
        }
        body.push_str("</C:addressbook-multiget>");

        self.multi_get(addressbook_href.as_ref(), body, &names::ADDRESS_DATA)
        self.dav_client
            .multi_get(addressbook_href.as_ref(), body, &names::ADDRESS_DATA)
            .await
    }


M libdav/src/lib.rs => libdav/src/lib.rs +5 -2
@@ 7,8 7,11 @@
//!
//! See [`CalDavClient`] and [`CardDavClient`] as a useful entry points.
//!
//! Both clients implement `Deref<Target = DavClient>`, so all the associated
//! functions for [`dav::WebDavClient`] are usable directly.
//! Both clients internally use a [`WebDavClient`], which can be accessed with their respective
//! [`as_webdav`] associated functions.
//!
//! [`WebDavClient`]: dav::WebDavClient
//! [`as_webdav`]: CalDavClient::as_webdav
//!
//! # Hrefs
//!

M live_tests/src/carddav.rs => live_tests/src/carddav.rs +7 -2
@@ 45,7 45,11 @@ pub(crate) async fn test_create_and_delete_addressbook(test_data: &TestData) -> 
    };

    // Delete the addressbook
    test_data.carddav.delete(new_collection, etag).await?;
    test_data
        .carddav
        .as_webdav()
        .delete(new_collection, etag)
        .await?;

    ensure!(orig_addressbook_count == test_data.addressbook_count().await?);



@@ 83,10 87,11 @@ pub(crate) async fn test_create_and_delete_resource(test_data: &TestData) -> any

    test_data
        .carddav
        .as_webdav()
        .create_resource(&resource, content.clone(), mime_types::ADDRESSBOOK)
        .await?;

    let items = test_data.carddav.list_resources(&collection).await?;
    let items = test_data.carddav.as_webdav().list_resources(&collection).await?;
    ensure!(items.len() == 1);

    let updated_entry = String::from_utf8(content)?

M vstorage/src/caldav.rs => vstorage/src/caldav.rs +12 -3
@@ 72,7 72,7 @@ where
        let uri = &self
            .client
            .calendar_home_set()
            .unwrap_or(self.client.base_url());
            .unwrap_or(self.client.as_webdav().base_url());
        self.client
            .check_support(uri)
            .await


@@ 179,6 179,7 @@ where
        }

        self.client
            .as_webdav()
            .delete(href, etag)
            .await
            .map_err(|e| Error::new(ErrorKind::Uncategorised, e))?;


@@ 186,7 187,11 @@ where
    }

    async fn list_items(&self, collection_href: &str) -> Result<Vec<ItemRef>> {
        let response = self.client.list_resources(collection_href).await?;
        let response = self
            .client
            .as_webdav()
            .list_resources(collection_href)
            .await?;
        let mut items = Vec::with_capacity(response.len());
        for r in response {
            items.push(ItemRef {


@@ 266,6 271,7 @@ where

        let response = self
            .client
            .as_webdav()
            .create_resource(
                &href,
                item.as_str().as_bytes().to_vec(),


@@ 286,6 292,7 @@ where
    async fn update_item(&self, href: &str, etag: &Etag, item: &IcsItem) -> Result<Etag> {
        // TODO: check that href is a sub-path of collection.href?
        self.client
            .as_webdav()
            .update_resource(
                href,
                item.as_str().as_bytes().to_vec(),


@@ 310,6 317,7 @@ where
        match meta {
            CalendarProperty::DisplayName => self
                .client
                .as_webdav()
                .set_collection_displayname(collection_href, Some(value))
                .await
                .map_err(Error::from),


@@ 340,6 348,7 @@ where
        match meta {
            CalendarProperty::DisplayName => self
                .client
                .as_webdav()
                .get_collection_displayname(collection_href)
                .await
                .map_err(Error::from),


@@ 354,7 363,7 @@ where

    async fn delete_item(&self, href: &str, etag: &Etag) -> Result<()> {
        // TODO: check that href is a sub-path of this storage?
        self.client.delete(href, etag).await?;
        self.client.as_webdav().delete(href, etag).await?;

        Ok(())
    }

M vstorage/src/carddav.rs => vstorage/src/carddav.rs +12 -3
@@ 57,7 57,7 @@ where
        let uri = &self
            .client
            .addressbook_home_set()
            .unwrap_or(self.client.base_url());
            .unwrap_or(self.client.as_webdav().base_url());
        self.client
            .check_support(uri)
            .await


@@ 165,6 165,7 @@ where
        }

        self.client
            .as_webdav()
            .delete(href, etag)
            .await
            .map_err(|e| Error::new(ErrorKind::Uncategorised, e))?;


@@ 172,7 173,11 @@ where
    }

    async fn list_items(&self, collection_href: &str) -> Result<Vec<ItemRef>> {
        let response = self.client.list_resources(collection_href).await?;
        let response = self
            .client
            .as_webdav()
            .list_resources(collection_href)
            .await?;
        let mut items = Vec::with_capacity(response.len());
        for r in response {
            items.push(ItemRef {


@@ 252,6 257,7 @@ where

        let response = self
            .client
            .as_webdav()
            // FIXME: should not copy data here?
            .create_resource(
                &href,


@@ 273,6 279,7 @@ where
    async fn update_item(&self, href: &str, etag: &Etag, item: &VcardItem) -> Result<Etag> {
        // TODO: check that href is a sub-path of collection_href
        self.client
            .as_webdav()
            .update_resource(
                href,
                item.as_str().as_bytes().to_vec(),


@@ 298,6 305,7 @@ where
        match meta {
            AddressBookProperty::DisplayName => self
                .client
                .as_webdav()
                .set_collection_displayname(collection_href, Some(value))
                .await
                .map_err(Error::from),


@@ 323,6 331,7 @@ where
        match meta {
            AddressBookProperty::DisplayName => self
                .client
                .as_webdav()
                .get_collection_displayname(collection_href)
                .await
                .map_err(Error::from),


@@ 332,7 341,7 @@ where

    async fn delete_item(&self, href: &str, etag: &Etag) -> Result<()> {
        // TODO: check that href is a sub-path of this storage?
        self.client.delete(href, etag).await?;
        self.client.as_webdav().delete(href, etag).await?;

        Ok(())
    }