DAV: Single-type calendar and tasks folders

Summary:
- Don't store tasks and events in the same folder, set new folder supported-calendar-component-set appropriately
- Make single request on folder creation. Before it was MKCOL + PROPPATCH, now it's MKCOL

Test Plan: Create Tasks folder, check it does not appear in Calendar, and vice-versa

Reviewers: #roundcube_developers, mollekopf

Reviewed By: #roundcube_developers, mollekopf

Subscribers: #roundcube_developers

Differential Revision: https://git.kolab.org/D4656
This commit is contained in:
Aleksander Machniak 2024-08-29 15:41:19 +02:00
parent 102847604d
commit 79756d53df

View file

@ -429,15 +429,18 @@ class kolab_dav_client
*/
public function folderCreate($location, $component, $properties = [])
{
$ns = 'xmlns:d="DAV:"';
$props = '';
[$props, $ns] = $this->folderPropertiesToXml($properties, 'xmlns:d="DAV:"');
if ($component == 'VCARD') {
$ns .= ' xmlns:c="urn:ietf:params:xml:ns:carddav"';
$props = '<d:resourcetype><d:collection/><c:addressbook/></d:resourcetype>';
$props .= '<d:resourcetype><d:collection/><c:addressbook/></d:resourcetype>';
} else {
$ns .= ' xmlns:c="urn:ietf:params:xml:ns:caldav"';
$props = '<d:resourcetype><d:collection/><c:calendar/></d:resourcetype>';
$props .= '<d:resourcetype><d:collection/><c:calendar/></d:resourcetype>'
// Note: Some clients, but also Cyrus by default allows everything in calendar folders,
// i.e. VEVENT, VTODO, VJOURNAL, VFREEBUSY, VAVAILABILITY, but we prefer a single-type folders,
// to keep tasks and event separated
. '<c:supported-calendar-component-set><c:comp name="' . $component . '"/></c:supported-calendar-component-set>';
}
$body = '<?xml version="1.0" encoding="utf-8"?>'
@ -450,12 +453,7 @@ class kolab_dav_client
// Create the collection
$response = $this->request($location, 'MKCOL', $body);
if (empty($response)) {
return false;
}
// Update collection properties
return $this->folderUpdate($location, $component, $properties);
return $response !== false;
}
/**
@ -483,29 +481,35 @@ class kolab_dav_client
*/
public function folderUpdate($location, $component, $properties = [])
{
$ns = 'xmlns:d="DAV:"';
$props = '';
// Note: Changing resourcetype property is forbidden (at least by Cyrus)
if ($component == 'VCARD') {
$ns .= ' xmlns:c="urn:ietf:params:xml:ns:carddav"';
// Resourcetype property is protected
// $props = '<d:resourcetype><d:collection/><c:addressbook/></d:resourcetype>';
} else {
$ns .= ' xmlns:c="urn:ietf:params:xml:ns:caldav"';
// Resourcetype property is protected
// $props = '<d:resourcetype><d:collection/><c:calendar/></d:resourcetype>';
/*
// Note: These are set by Cyrus automatically for calendars
. '<c:supported-calendar-component-set>'
. '<c:comp name="VEVENT"/>'
. '<c:comp name="VTODO"/>'
. '<c:comp name="VJOURNAL"/>'
. '<c:comp name="VFREEBUSY"/>'
. '<c:comp name="VAVAILABILITY"/>'
. '</c:supported-calendar-component-set>';
*/
[$props, $ns] = $this->folderPropertiesToXml($properties, 'xmlns:d="DAV:"');
if (empty($props)) {
return true;
}
$body = '<?xml version="1.0" encoding="utf-8"?>'
. '<d:propertyupdate ' . $ns . '>'
. '<d:set>'
. '<d:prop>' . $props . '</d:prop>'
. '</d:set>'
. '</d:propertyupdate>';
$response = $this->request($location, 'PROPPATCH', $body);
// TODO: Should we make sure "200 OK" status is set for all requested properties?
return $response !== false;
}
/**
* Parse folder properties input into XML string to use in a request
*/
protected function folderPropertiesToXml($properties, $ns = '')
{
$props = '';
foreach ($properties as $name => $value) {
if ($name == 'name') {
$props .= '<d:displayname>' . htmlspecialchars($value, ENT_XML1, 'UTF-8') . '</d:displayname>';
@ -525,22 +529,7 @@ class kolab_dav_client
}
}
if (empty($props)) {
return true;
}
$body = '<?xml version="1.0" encoding="utf-8"?>'
. '<d:propertyupdate ' . $ns . '>'
. '<d:set>'
. '<d:prop>' . $props . '</d:prop>'
. '</d:set>'
. '</d:propertyupdate>';
$response = $this->request($location, 'PROPPATCH', $body);
// TODO: Should we make sure "200 OK" status is set for all requested properties?
return $response !== false;
return [$props, $ns];
}
/**