mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2025-12-11 05:46:25 +08:00
CalDAV: support for supported-calendar-component-set (closes #1893)
This commit is contained in:
parent
f6f5d18d68
commit
107561297d
13 changed files with 655 additions and 456 deletions
799
Cargo.lock
generated
799
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -137,6 +137,9 @@ impl Display for CalCondition {
|
|||
}
|
||||
CalCondition::ValidSchedulingMessage => write!(f, "<A:valid-scheduling-message/>"),
|
||||
CalCondition::ValidOrganizer => write!(f, "<A:valid-organizer/>"),
|
||||
CalCondition::SupportedCalendarComponent => {
|
||||
write!(f, "<A:supported-calendar-component/>")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ impl Display for SyncToken {
|
|||
|
||||
impl Display for Comp {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "<A:comp name=\"{}\">", self.0.as_str())
|
||||
write!(f, "<A:comp name=\"{}\"/>", self.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use crate::{
|
|||
Namespace, Namespaces,
|
||||
},
|
||||
};
|
||||
use calcard::icalendar::ICalendarComponentType;
|
||||
use mail_parser::{
|
||||
parsers::fields::date::{DOW, MONTH},
|
||||
DateTime,
|
||||
|
|
@ -119,32 +120,32 @@ impl Display for DavValue {
|
|||
)
|
||||
)
|
||||
}
|
||||
DavValue::SupportedCalendarComponentSet => {
|
||||
write!(
|
||||
f,
|
||||
concat!(
|
||||
"<A:comp name=\"VEVENT\"/>",
|
||||
"<A:comp name=\"VTODO\"/>",
|
||||
"<A:comp name=\"VJOURNAL\"/>",
|
||||
"<A:comp name=\"VFREEBUSY\"/>",
|
||||
"<A:comp name=\"VTIMEZONE\"/>",
|
||||
"<A:comp name=\"VALARM\"/>",
|
||||
"<A:comp name=\"STANDARD\"/>",
|
||||
"<A:comp name=\"DAYLIGHT\"/>",
|
||||
"<A:comp name=\"VAVAILABILITY\"/>",
|
||||
"<A:comp name=\"AVAILABLE\"/>",
|
||||
"<A:comp name=\"PARTICIPANT\"/>",
|
||||
"<A:comp name=\"VLOCATION\"/>",
|
||||
"<A:comp name=\"VRESOURCE\"/>",
|
||||
)
|
||||
)
|
||||
}
|
||||
DavValue::Response(v) => v.fmt(f),
|
||||
DavValue::VCard(_) | DavValue::ICalendar(_) | DavValue::Null => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DavValue {
|
||||
pub fn all_calendar_components() -> Self {
|
||||
DavValue::Components(List(vec![
|
||||
Comp(ICalendarComponentType::VEvent),
|
||||
Comp(ICalendarComponentType::VTodo),
|
||||
Comp(ICalendarComponentType::VJournal),
|
||||
Comp(ICalendarComponentType::VFreebusy),
|
||||
Comp(ICalendarComponentType::VTimezone),
|
||||
Comp(ICalendarComponentType::VAlarm),
|
||||
Comp(ICalendarComponentType::Standard),
|
||||
Comp(ICalendarComponentType::Daylight),
|
||||
Comp(ICalendarComponentType::VAvailability),
|
||||
Comp(ICalendarComponentType::Available),
|
||||
Comp(ICalendarComponentType::Participant),
|
||||
Comp(ICalendarComponentType::VLocation),
|
||||
Comp(ICalendarComponentType::VResource),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
impl DavProperty {
|
||||
fn tag_name(&self) -> (&str, Option<&str>) {
|
||||
(
|
||||
|
|
|
|||
|
|
@ -169,7 +169,6 @@ pub enum DavValue {
|
|||
DeadProperty(DeadProperty),
|
||||
SupportedAddressData,
|
||||
SupportedCalendarData,
|
||||
SupportedCalendarComponentSet,
|
||||
Null,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -244,6 +244,7 @@ pub enum CalCondition {
|
|||
Vec<Filter<Vec<ICalendarComponentType>, ICalendarProperty, ICalendarParameterName>>,
|
||||
),
|
||||
SupportedCollation(String),
|
||||
SupportedCalendarComponent,
|
||||
MinDateTime,
|
||||
MaxDateTime,
|
||||
MaxResourceSize(u32),
|
||||
|
|
@ -366,6 +367,7 @@ impl CalCondition {
|
|||
CalCondition::ValidScheduleDefaultCalendarUrl => "ValidScheduleDefaultCalendarUrl",
|
||||
CalCondition::ValidSchedulingMessage => "ValidSchedulingMessage",
|
||||
CalCondition::ValidOrganizer => "ValidOrganizer",
|
||||
CalCondition::SupportedCalendarComponent => "SupportedCalendarComponent",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use dav_proto::{
|
|||
};
|
||||
use groupware::{
|
||||
cache::GroupwareCache,
|
||||
calendar::{Calendar, CalendarEvent, Timezone},
|
||||
calendar::{Calendar, CalendarEvent, SupportedComponent, Timezone},
|
||||
};
|
||||
use http_proto::HttpResponse;
|
||||
use hyper::StatusCode;
|
||||
|
|
@ -36,6 +36,7 @@ use types::{
|
|||
acl::Acl,
|
||||
collection::{Collection, SyncCollection},
|
||||
};
|
||||
use utils::map::bitmap::Bitmap;
|
||||
|
||||
pub(crate) trait CalendarPropPatchRequestHandler: Sync + Send {
|
||||
fn handle_calendar_proppatch_request(
|
||||
|
|
@ -340,6 +341,39 @@ impl CalendarPropPatchRequestHandler for Server {
|
|||
items.insert_ok(property.property);
|
||||
}
|
||||
}
|
||||
(
|
||||
DavProperty::CalDav(CalDavProperty::SupportedCalendarComponentSet),
|
||||
DavValue::Components(components),
|
||||
) => {
|
||||
if !is_update {
|
||||
calendar.supported_components = Bitmap::<SupportedComponent>::from_iter(
|
||||
components
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|v| SupportedComponent::from(v.0)),
|
||||
)
|
||||
.into_inner();
|
||||
if calendar.supported_components != 0 {
|
||||
items.insert_ok(property.property);
|
||||
} else {
|
||||
items.insert_precondition_failed_with_description(
|
||||
property.property,
|
||||
StatusCode::PRECONDITION_FAILED,
|
||||
CalCondition::SupportedCalendarComponent,
|
||||
"At least one supported component must be specified",
|
||||
);
|
||||
has_errors = true;
|
||||
}
|
||||
} else {
|
||||
items.insert_precondition_failed_with_description(
|
||||
property.property,
|
||||
StatusCode::PRECONDITION_FAILED,
|
||||
CalCondition::SupportedCalendarComponent,
|
||||
"Property cannot be modified",
|
||||
);
|
||||
has_errors = true;
|
||||
}
|
||||
}
|
||||
(DavProperty::DeadProperty(dead), DavValue::DeadProperty(values))
|
||||
if self.core.groupware.dead_property_size.is_some() =>
|
||||
{
|
||||
|
|
@ -362,7 +396,7 @@ impl CalendarPropPatchRequestHandler for Server {
|
|||
has_errors = true;
|
||||
}
|
||||
}
|
||||
(_, DavValue::Null | DavValue::Components(_)) => {
|
||||
(_, DavValue::Null) => {
|
||||
items.insert_ok(property.property);
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use crate::{
|
|||
propfind::{PrincipalPropFind, build_home_set},
|
||||
},
|
||||
};
|
||||
use calcard::common::timezone::Tz;
|
||||
use calcard::{common::timezone::Tz, icalendar::ICalendarComponentType};
|
||||
use common::{DavResourcePath, DavResources, Server, auth::AccessToken};
|
||||
use dav_proto::{
|
||||
Depth, RequestHeaders,
|
||||
|
|
@ -36,9 +36,9 @@ use dav_proto::{
|
|||
schema::{
|
||||
Collation, Namespace,
|
||||
property::{
|
||||
ActiveLock, CalDavProperty, CardDavProperty, DavProperty, DavValue, PrincipalProperty,
|
||||
Privilege, ReportSet, ResourceType, Rfc1123DateTime, SupportedCollation, SupportedLock,
|
||||
WebDavProperty,
|
||||
ActiveLock, CalDavProperty, CardDavProperty, Comp, DavProperty, DavValue,
|
||||
PrincipalProperty, Privilege, ReportSet, ResourceType, Rfc1123DateTime,
|
||||
SupportedCollation, SupportedLock, WebDavProperty,
|
||||
},
|
||||
request::{DavDeadProperty, DavPropertyValue, PropFind},
|
||||
response::{
|
||||
|
|
@ -48,7 +48,7 @@ use dav_proto::{
|
|||
},
|
||||
};
|
||||
use directory::{Permission, Type, backend::internal::manage::ManageDirectory};
|
||||
use groupware::calendar::SCHEDULE_INBOX_ID;
|
||||
use groupware::calendar::{SCHEDULE_INBOX_ID, SupportedComponent};
|
||||
use groupware::{
|
||||
DavCalendarResource, DavResourceName, cache::GroupwareCache, calendar::ArchivedTimezone,
|
||||
};
|
||||
|
|
@ -67,6 +67,7 @@ use types::{
|
|||
collection::{Collection, SyncCollection},
|
||||
dead_property::DeadProperty,
|
||||
};
|
||||
use utils::map::bitmap::Bitmap;
|
||||
|
||||
pub(crate) trait PropFindRequestHandler: Sync + Send {
|
||||
fn handle_propfind_request(
|
||||
|
|
@ -898,11 +899,23 @@ impl PropFindRequestHandler for Server {
|
|||
}
|
||||
(
|
||||
CalDavProperty::SupportedCalendarComponentSet,
|
||||
ArchivedResource::Calendar(_),
|
||||
ArchivedResource::Calendar(calendar),
|
||||
) => {
|
||||
let supported_components =
|
||||
calendar.inner.supported_components.to_native();
|
||||
fields.push(DavPropertyValue::new(
|
||||
property.clone(),
|
||||
DavValue::SupportedCalendarComponentSet,
|
||||
if supported_components != 0 {
|
||||
DavValue::Components(List(
|
||||
Bitmap::<SupportedComponent>::from(supported_components)
|
||||
.into_iter()
|
||||
.map(ICalendarComponentType::from)
|
||||
.map(Comp)
|
||||
.collect(),
|
||||
))
|
||||
} else {
|
||||
DavValue::all_calendar_components()
|
||||
},
|
||||
));
|
||||
}
|
||||
(CalDavProperty::SupportedCalendarData, ArchivedResource::Calendar(_)) => {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ tokio = { version = "1.47", features = ["net"] }
|
|||
tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
|
||||
rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
|
||||
rustls-pki-types = { version = "1" }
|
||||
ldap3 = { version = "0.12", default-features = false, features = ["tls-rustls"] }
|
||||
ldap3 = { version = "0.12", default-features = false, features = ["tls-rustls-ring"] }
|
||||
deadpool = { version = "0.10", features = ["managed", "rt_tokio_1"] }
|
||||
async-trait = "0.1.68"
|
||||
ahash = { version = "0.8" }
|
||||
|
|
|
|||
|
|
@ -11,9 +11,12 @@ pub mod index;
|
|||
pub mod itip;
|
||||
pub mod storage;
|
||||
|
||||
use calcard::icalendar::{ICalendar, ICalendarComponent, ICalendarDuration, ICalendarEntry};
|
||||
use calcard::icalendar::{
|
||||
ICalendar, ICalendarComponent, ICalendarComponentType, ICalendarDuration, ICalendarEntry,
|
||||
};
|
||||
use common::{DavName, auth::AccessToken};
|
||||
use types::{acl::AclGrant, dead_property::DeadProperty};
|
||||
use utils::map::bitmap::BitmapItem;
|
||||
|
||||
#[derive(
|
||||
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
|
||||
|
|
@ -22,11 +25,32 @@ pub struct Calendar {
|
|||
pub name: String,
|
||||
pub preferences: Vec<CalendarPreferences>,
|
||||
pub acls: Vec<AclGrant>,
|
||||
pub supported_components: u64,
|
||||
pub dead_properties: DeadProperty,
|
||||
pub created: i64,
|
||||
pub modified: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SupportedComponent {
|
||||
VCalendar, // [RFC5545, Section 3.4]
|
||||
VEvent, // [RFC5545, Section 3.6.1]
|
||||
VTodo, // [RFC5545, Section 3.6.2]
|
||||
VJournal, // [RFC5545, Section 3.6.3]
|
||||
VFreebusy, // [RFC5545, Section 3.6.4]
|
||||
VTimezone, // [RFC5545, Section 3.6.5]
|
||||
VAlarm, // [RFC5545, Section 3.6.6]
|
||||
Standard, // [RFC5545, Section 3.6.5]
|
||||
Daylight, // [RFC5545, Section 3.6.5]
|
||||
VAvailability, // [RFC7953, Section 3.1]
|
||||
Available, // [RFC7953, Section 3.1]
|
||||
Participant, // [RFC9073, Section 7.1]
|
||||
VLocation, // [RFC9073, Section 7.2] [RFC Errata 7381]
|
||||
VResource, // [RFC9073, Section 7.3]
|
||||
VStatus, // draft-ietf-calext-ical-tasks-14
|
||||
Other,
|
||||
}
|
||||
|
||||
pub const CALENDAR_SUBSCRIBED: u16 = 1;
|
||||
pub const CALENDAR_INVISIBLE: u16 = 1 << 1;
|
||||
pub const CALENDAR_AVAILABILITY_NONE: u16 = 1 << 2;
|
||||
|
|
@ -319,3 +343,105 @@ impl Default for ChangedBy {
|
|||
ChangedBy::CalendarAddress("".into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for SupportedComponent {
|
||||
fn from(value: u64) -> Self {
|
||||
match value {
|
||||
0 => SupportedComponent::VCalendar,
|
||||
1 => SupportedComponent::VEvent,
|
||||
2 => SupportedComponent::VTodo,
|
||||
3 => SupportedComponent::VJournal,
|
||||
4 => SupportedComponent::VFreebusy,
|
||||
5 => SupportedComponent::VTimezone,
|
||||
6 => SupportedComponent::VAlarm,
|
||||
7 => SupportedComponent::Standard,
|
||||
8 => SupportedComponent::Daylight,
|
||||
9 => SupportedComponent::VAvailability,
|
||||
10 => SupportedComponent::Available,
|
||||
11 => SupportedComponent::Participant,
|
||||
12 => SupportedComponent::VLocation,
|
||||
13 => SupportedComponent::VResource,
|
||||
14 => SupportedComponent::VStatus,
|
||||
_ => SupportedComponent::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SupportedComponent> for u64 {
|
||||
fn from(value: SupportedComponent) -> Self {
|
||||
match value {
|
||||
SupportedComponent::VCalendar => 0,
|
||||
SupportedComponent::VEvent => 1,
|
||||
SupportedComponent::VTodo => 2,
|
||||
SupportedComponent::VJournal => 3,
|
||||
SupportedComponent::VFreebusy => 4,
|
||||
SupportedComponent::VTimezone => 5,
|
||||
SupportedComponent::VAlarm => 6,
|
||||
SupportedComponent::Standard => 7,
|
||||
SupportedComponent::Daylight => 8,
|
||||
SupportedComponent::VAvailability => 9,
|
||||
SupportedComponent::Available => 10,
|
||||
SupportedComponent::Participant => 11,
|
||||
SupportedComponent::VLocation => 12,
|
||||
SupportedComponent::VResource => 13,
|
||||
SupportedComponent::VStatus => 14,
|
||||
SupportedComponent::Other => 15,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitmapItem for SupportedComponent {
|
||||
fn max() -> u64 {
|
||||
u64::from(SupportedComponent::Other)
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
!matches!(self, SupportedComponent::Other)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ICalendarComponentType> for SupportedComponent {
|
||||
fn from(value: ICalendarComponentType) -> Self {
|
||||
match value {
|
||||
ICalendarComponentType::VCalendar => SupportedComponent::VCalendar,
|
||||
ICalendarComponentType::VEvent => SupportedComponent::VEvent,
|
||||
ICalendarComponentType::VTodo => SupportedComponent::VTodo,
|
||||
ICalendarComponentType::VJournal => SupportedComponent::VJournal,
|
||||
ICalendarComponentType::VFreebusy => SupportedComponent::VFreebusy,
|
||||
ICalendarComponentType::VTimezone => SupportedComponent::VTimezone,
|
||||
ICalendarComponentType::VAlarm => SupportedComponent::VAlarm,
|
||||
ICalendarComponentType::Standard => SupportedComponent::Standard,
|
||||
ICalendarComponentType::Daylight => SupportedComponent::Daylight,
|
||||
ICalendarComponentType::VAvailability => SupportedComponent::VAvailability,
|
||||
ICalendarComponentType::Available => SupportedComponent::Available,
|
||||
ICalendarComponentType::Participant => SupportedComponent::Participant,
|
||||
ICalendarComponentType::VLocation => SupportedComponent::VLocation,
|
||||
ICalendarComponentType::VResource => SupportedComponent::VResource,
|
||||
ICalendarComponentType::VStatus => SupportedComponent::VStatus,
|
||||
_ => SupportedComponent::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SupportedComponent> for ICalendarComponentType {
|
||||
fn from(value: SupportedComponent) -> Self {
|
||||
match value {
|
||||
SupportedComponent::VCalendar => ICalendarComponentType::VCalendar,
|
||||
SupportedComponent::VEvent => ICalendarComponentType::VEvent,
|
||||
SupportedComponent::VTodo => ICalendarComponentType::VTodo,
|
||||
SupportedComponent::VJournal => ICalendarComponentType::VJournal,
|
||||
SupportedComponent::VFreebusy => ICalendarComponentType::VFreebusy,
|
||||
SupportedComponent::VTimezone => ICalendarComponentType::VTimezone,
|
||||
SupportedComponent::VAlarm => ICalendarComponentType::VAlarm,
|
||||
SupportedComponent::Standard => ICalendarComponentType::Standard,
|
||||
SupportedComponent::Daylight => ICalendarComponentType::Daylight,
|
||||
SupportedComponent::VAvailability => ICalendarComponentType::VAvailability,
|
||||
SupportedComponent::Available => ICalendarComponentType::Available,
|
||||
SupportedComponent::Participant => ICalendarComponentType::Participant,
|
||||
SupportedComponent::VLocation => ICalendarComponentType::VLocation,
|
||||
SupportedComponent::VResource => ICalendarComponentType::VResource,
|
||||
SupportedComponent::VStatus => ICalendarComponentType::VStatus,
|
||||
SupportedComponent::Other => ICalendarComponentType::Other(Default::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,14 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use aes_gcm::{
|
||||
Aes128Gcm, Nonce,
|
||||
aead::{Aead, generic_array::GenericArray},
|
||||
};
|
||||
use aes_gcm::{Aes128Gcm, Nonce, aead::Aead};
|
||||
use hkdf::Hkdf;
|
||||
use p256::{
|
||||
PublicKey,
|
||||
ecdh::EphemeralSecret,
|
||||
elliptic_curve::{rand_core::OsRng, sec1::ToEncodedPoint},
|
||||
};
|
||||
use sha2::Sha256;
|
||||
use sha2::{Sha256, digest::generic_array::GenericArray};
|
||||
use store::rand::Rng;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -141,6 +141,10 @@ impl<T: BitmapItem> Bitmap<T> {
|
|||
_state: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> u64 {
|
||||
self.bitmap
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BitmapItem> From<ArchivedBitmap<T>> for Bitmap<T> {
|
||||
|
|
|
|||
|
|
@ -171,7 +171,6 @@ pub async fn test(test: &WebDavTest) {
|
|||
[
|
||||
("D:displayname", "Named Events 2"),
|
||||
("A:calendar-description", ""),
|
||||
("A:supported-calendar-component-set", ""),
|
||||
],
|
||||
)
|
||||
.await
|
||||
|
|
@ -181,6 +180,61 @@ pub async fn test(test: &WebDavTest) {
|
|||
"A:mkcalendar-response.D:propstat.D:status",
|
||||
["HTTP/1.1 200 OK"],
|
||||
);
|
||||
client
|
||||
.mkcol(
|
||||
"MKCALENDAR",
|
||||
"/dav/cal/john/my-named-events3",
|
||||
[],
|
||||
[
|
||||
("D:displayname", "Named Events 3"),
|
||||
(
|
||||
"A:supported-calendar-component-set",
|
||||
"<A:comp name=\"VEVENT\"/><A:comp name=\"VTODO\"/>",
|
||||
),
|
||||
],
|
||||
)
|
||||
.await
|
||||
.with_status(StatusCode::CREATED)
|
||||
.with_value("A:mkcalendar-response.D:propstat.D:prop.D:displayname", "")
|
||||
.with_values(
|
||||
"A:mkcalendar-response.D:propstat.D:status",
|
||||
["HTTP/1.1 200 OK"],
|
||||
);
|
||||
// Check the properties of the created calendars
|
||||
client
|
||||
.propfind(
|
||||
"/dav/cal/john/my-named-events2/",
|
||||
["A:supported-calendar-component-set"],
|
||||
)
|
||||
.await
|
||||
.properties("/dav/cal/john/my-named-events2/")
|
||||
.get("A:supported-calendar-component-set")
|
||||
.with_status(StatusCode::OK)
|
||||
.with_values([
|
||||
"A:comp.[name]:VJOURNAL",
|
||||
"A:comp.[name]:VTIMEZONE",
|
||||
"A:comp.[name]:VAVAILABILITY",
|
||||
"A:comp.[name]:VALARM",
|
||||
"A:comp.[name]:VRESOURCE",
|
||||
"A:comp.[name]:AVAILABLE",
|
||||
"A:comp.[name]:VTODO",
|
||||
"A:comp.[name]:VFREEBUSY",
|
||||
"A:comp.[name]:VEVENT",
|
||||
"A:comp.[name]:STANDARD",
|
||||
"A:comp.[name]:DAYLIGHT",
|
||||
"A:comp.[name]:VLOCATION",
|
||||
"A:comp.[name]:PARTICIPANT",
|
||||
]);
|
||||
client
|
||||
.propfind(
|
||||
"/dav/cal/john/my-named-events3/",
|
||||
["A:supported-calendar-component-set"],
|
||||
)
|
||||
.await
|
||||
.properties("/dav/cal/john/my-named-events3/")
|
||||
.get("A:supported-calendar-component-set")
|
||||
.with_status(StatusCode::OK)
|
||||
.with_values(["A:comp.[name]:VEVENT", "A:comp.[name]:VTODO"]);
|
||||
|
||||
// Delete everything
|
||||
for path in [
|
||||
|
|
@ -191,6 +245,7 @@ pub async fn test(test: &WebDavTest) {
|
|||
"/dav/card/john/my-named-cards",
|
||||
"/dav/cal/john/my-named-events",
|
||||
"/dav/cal/john/my-named-events2",
|
||||
"/dav/cal/john/my-named-events3",
|
||||
] {
|
||||
client
|
||||
.request("DELETE", path, "")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue