aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/dav/lib/CalDAV
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre/dav/lib/CalDAV')
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Backend/BackendInterface.php6
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php15
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Backend/PDO.php381
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php225
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php296
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Calendar.php63
-rw-r--r--vendor/sabre/dav/lib/CalDAV/CalendarHome.php64
-rw-r--r--vendor/sabre/dav/lib/CalDAV/CalendarObject.php61
-rw-r--r--vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php22
-rw-r--r--vendor/sabre/dav/lib/CalDAV/IShareableCalendar.php48
-rw-r--r--vendor/sabre/dav/lib/CalDAV/ISharedCalendar.php28
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php76
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Notifications/Node.php76
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Plugin.php113
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php64
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php69
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php107
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php16
-rw-r--r--vendor/sabre/dav/lib/CalDAV/ShareableCalendar.php72
-rw-r--r--vendor/sabre/dav/lib/CalDAV/SharedCalendar.php237
-rw-r--r--vendor/sabre/dav/lib/CalDAV/SharingPlugin.php106
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php67
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php11
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php5
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php209
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php22
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php11
-rw-r--r--vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php63
28 files changed, 1194 insertions, 1339 deletions
diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/BackendInterface.php b/vendor/sabre/dav/lib/CalDAV/Backend/BackendInterface.php
index 7513fb60d..bd8ee7602 100644
--- a/vendor/sabre/dav/lib/CalDAV/Backend/BackendInterface.php
+++ b/vendor/sabre/dav/lib/CalDAV/Backend/BackendInterface.php
@@ -44,10 +44,12 @@ interface BackendInterface {
* If the creation was a success, an id must be returned that can be used to
* reference this calendar in other methods, such as updateCalendar.
*
+ * The id can be any type, including ints, strings, objects or array.
+ *
* @param string $principalUri
* @param string $calendarUri
* @param array $properties
- * @return void
+ * @return mixed
*/
function createCalendar($principalUri, $calendarUri, array $properties);
@@ -63,7 +65,7 @@ interface BackendInterface {
*
* Read the PropPatch documentation for more info and examples.
*
- * @param string $path
+ * @param mixed $calendarId
* @param \Sabre\DAV\PropPatch $propPatch
* @return void
*/
diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php b/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php
index 19b9b22a7..9c00a89ef 100644
--- a/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php
+++ b/vendor/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php
@@ -43,4 +43,19 @@ interface NotificationSupport extends BackendInterface {
*/
function deleteNotification($principalUri, NotificationInterface $notification);
+ /**
+ * This method is called when a user replied to a request to share.
+ *
+ * If the user chose to accept the share, this method should return the
+ * newly created calendar url.
+ *
+ * @param string href The sharee who is replying (often a mailto: address)
+ * @param int status One of the SharingPlugin::STATUS_* constants
+ * @param string $calendarUri The url to the calendar thats being shared
+ * @param string $inReplyTo The unique id this message is a response to
+ * @param string $summary A description of the reply
+ * @return null|string
+ */
+ function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null);
+
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php b/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php
index 76b69dc6e..95f1d49a6 100644
--- a/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php
+++ b/vendor/sabre/dav/lib/CalDAV/Backend/PDO.php
@@ -2,10 +2,11 @@
namespace Sabre\CalDAV\Backend;
-use Sabre\VObject;
use Sabre\CalDAV;
use Sabre\DAV;
use Sabre\DAV\Exception\Forbidden;
+use Sabre\VObject;
+use Sabre\DAV\Xml\Element\Sharee;
/**
* PDO CalDAV backend
@@ -17,7 +18,12 @@ use Sabre\DAV\Exception\Forbidden;
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
-class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, SchedulingSupport {
+class PDO extends AbstractBackend
+ implements
+ SyncSupport,
+ SubscriptionSupport,
+ SchedulingSupport,
+ SharingSupport {
/**
* We need to specify a max date, because we need to stop *somewhere*
@@ -44,6 +50,16 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
public $calendarTableName = 'calendars';
/**
+ * The table name that will be used for calendars instances.
+ *
+ * A single calendar can have multiple instances, if the calendar is
+ * shared.
+ *
+ * @var string
+ */
+ public $calendarInstancesTableName = 'calendarinstances';
+
+ /**
* The table name that will be used for calendar objects
*
* @var string
@@ -140,16 +156,23 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
function getCalendarsForUser($principalUri) {
$fields = array_values($this->propertyMap);
- $fields[] = 'id';
+ $fields[] = 'calendarid';
$fields[] = 'uri';
$fields[] = 'synctoken';
$fields[] = 'components';
$fields[] = 'principaluri';
$fields[] = 'transparent';
+ $fields[] = 'access';
// Making fields a comma-delimited list
$fields = implode(', ', $fields);
- $stmt = $this->pdo->prepare("SELECT " . $fields . " FROM " . $this->calendarTableName . " WHERE principaluri = ? ORDER BY calendarorder ASC");
+ $stmt = $this->pdo->prepare(<<<SQL
+SELECT {$this->calendarInstancesTableName}.id as id, $fields FROM {$this->calendarInstancesTableName}
+ LEFT JOIN {$this->calendarTableName} ON
+ {$this->calendarInstancesTableName}.calendarid = {$this->calendarTableName}.id
+WHERE principaluri = ? ORDER BY calendarorder ASC
+SQL
+ );
$stmt->execute([$principalUri]);
$calendars = [];
@@ -161,15 +184,27 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
}
$calendar = [
- 'id' => $row['id'],
+ 'id' => [(int)$row['calendarid'], (int)$row['id']],
'uri' => $row['uri'],
'principaluri' => $row['principaluri'],
'{' . CalDAV\Plugin::NS_CALENDARSERVER . '}getctag' => 'http://sabre.io/ns/sync/' . ($row['synctoken'] ? $row['synctoken'] : '0'),
'{http://sabredav.org/ns}sync-token' => $row['synctoken'] ? $row['synctoken'] : '0',
'{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet($components),
'{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp($row['transparent'] ? 'transparent' : 'opaque'),
+ 'share-resource-uri' => '/ns/share/' . $row['calendarid'],
];
+ $calendar['share-access'] = (int)$row['access'];
+ // 1 = owner, 2 = readonly, 3 = readwrite
+ if ($row['access'] > 1) {
+ // We need to find more information about the original owner.
+ //$stmt2 = $this->pdo->prepare('SELECT principaluri FROM ' . $this->calendarInstancesTableName . ' WHERE access = 1 AND id = ?');
+ //$stmt2->execute([$row['id']]);
+
+ // read-only is for backwards compatbility. Might go away in
+ // the future.
+ $calendar['read-only'] = (int)$row['access'] === \Sabre\DAV\Sharing\Plugin::ACCESS_READ;
+ }
foreach ($this->propertyMap as $xmlName => $dbName) {
$calendar[$xmlName] = $row[$dbName];
@@ -199,31 +234,38 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
$fieldNames = [
'principaluri',
'uri',
- 'synctoken',
'transparent',
+ 'calendarid',
];
$values = [
':principaluri' => $principalUri,
':uri' => $calendarUri,
- ':synctoken' => 1,
':transparent' => 0,
];
- // Default value
+
$sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
- $fieldNames[] = 'components';
if (!isset($properties[$sccs])) {
- $values[':components'] = 'VEVENT,VTODO';
+ // Default value
+ $components = 'VEVENT,VTODO';
} else {
if (!($properties[$sccs] instanceof CalDAV\Xml\Property\SupportedCalendarComponentSet)) {
throw new DAV\Exception('The ' . $sccs . ' property must be of type: \Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet');
}
- $values[':components'] = implode(',', $properties[$sccs]->getValue());
+ $components = implode(',', $properties[$sccs]->getValue());
}
$transp = '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp';
if (isset($properties[$transp])) {
- $values[':transparent'] = $properties[$transp]->getValue() === 'transparent';
+ $values[':transparent'] = $properties[$transp]->getValue() === 'transparent' ? 1 : 0;
}
+ $stmt = $this->pdo->prepare("INSERT INTO " . $this->calendarTableName . " (synctoken, components) VALUES (1, ?)");
+ $stmt->execute([$components]);
+
+ $calendarId = $this->pdo->lastInsertId(
+ $this->calendarTableName . '_id_seq'
+ );
+
+ $values[':calendarid'] = $calendarId;
foreach ($this->propertyMap as $xmlName => $dbName) {
if (isset($properties[$xmlName])) {
@@ -233,10 +275,14 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
}
}
- $stmt = $this->pdo->prepare("INSERT INTO " . $this->calendarTableName . " (" . implode(', ', $fieldNames) . ") VALUES (" . implode(', ', array_keys($values)) . ")");
+ $stmt = $this->pdo->prepare("INSERT INTO " . $this->calendarInstancesTableName . " (" . implode(', ', $fieldNames) . ") VALUES (" . implode(', ', array_keys($values)) . ")");
+
$stmt->execute($values);
- return $this->pdo->lastInsertId();
+ return [
+ $calendarId,
+ $this->pdo->lastInsertId($this->calendarInstancesTableName . '_id_seq')
+ ];
}
@@ -252,16 +298,21 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
*
* Read the PropPatch documenation for more info and examples.
*
- * @param string $calendarId
+ * @param mixed $calendarId
* @param \Sabre\DAV\PropPatch $propPatch
* @return void
*/
function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$supportedProperties = array_keys($this->propertyMap);
$supportedProperties[] = '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp';
- $propPatch->handle($supportedProperties, function($mutations) use ($calendarId) {
+ $propPatch->handle($supportedProperties, function($mutations) use ($calendarId, $instanceId) {
$newValues = [];
foreach ($mutations as $propertyName => $propertyValue) {
@@ -282,8 +333,8 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
$valuesSql[] = $fieldName . ' = ?';
}
- $stmt = $this->pdo->prepare("UPDATE " . $this->calendarTableName . " SET " . implode(', ', $valuesSql) . " WHERE id = ?");
- $newValues['id'] = $calendarId;
+ $stmt = $this->pdo->prepare("UPDATE " . $this->calendarInstancesTableName . " SET " . implode(', ', $valuesSql) . " WHERE id = ?");
+ $newValues['id'] = $instanceId;
$stmt->execute(array_values($newValues));
$this->addChange($calendarId, "", 2);
@@ -297,19 +348,49 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
/**
* Delete a calendar and all it's objects
*
- * @param string $calendarId
+ * @param mixed $calendarId
* @return void
*/
function deleteCalendar($calendarId) {
- $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ?');
- $stmt->execute([$calendarId]);
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
- $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarTableName . ' WHERE id = ?');
- $stmt->execute([$calendarId]);
+ $stmt = $this->pdo->prepare('SELECT access FROM ' . $this->calendarInstancesTableName . ' where id = ?');
+ $stmt->execute([$instanceId]);
+ $access = (int)$stmt->fetchColumn();
+
+ if ($access === \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER) {
+
+ /**
+ * If the user is the owner of the calendar, we delete all data and all
+ * instances.
+ **/
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ?');
+ $stmt->execute([$calendarId]);
+
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarChangesTableName . ' WHERE calendarid = ?');
+ $stmt->execute([$calendarId]);
+
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarInstancesTableName . ' WHERE calendarid = ?');
+ $stmt->execute([$calendarId]);
+
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarTableName . ' WHERE id = ?');
+ $stmt->execute([$calendarId]);
+
+ } else {
+
+ /**
+ * If it was an instance of a shared calendar, we only delete that
+ * instance.
+ */
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarInstancesTableName . ' WHERE id = ?');
+ $stmt->execute([$instanceId]);
+
+ }
- $stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarChangesTableName . ' WHERE calendarid = ?');
- $stmt->execute([$calendarId]);
}
@@ -341,11 +422,16 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
* used/fetched to determine these numbers. If both are specified the
* amount of times this is needed is reduced by a great degree.
*
- * @param string $calendarId
+ * @param mixed $calendarId
* @return array
*/
function getCalendarObjects($calendarId) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$stmt = $this->pdo->prepare('SELECT id, uri, lastmodified, etag, calendarid, size, componenttype FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ?');
$stmt->execute([$calendarId]);
@@ -354,9 +440,8 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
$result[] = [
'id' => $row['id'],
'uri' => $row['uri'],
- 'lastmodified' => $row['lastmodified'],
+ 'lastmodified' => (int)$row['lastmodified'],
'etag' => '"' . $row['etag'] . '"',
- 'calendarid' => $row['calendarid'],
'size' => (int)$row['size'],
'component' => strtolower($row['componenttype']),
];
@@ -378,12 +463,17 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
*
* This method must return null if the object did not exist.
*
- * @param string $calendarId
+ * @param mixed $calendarId
* @param string $objectUri
* @return array|null
*/
function getCalendarObject($calendarId, $objectUri) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$stmt = $this->pdo->prepare('SELECT id, uri, lastmodified, etag, calendarid, size, calendardata, componenttype FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ? AND uri = ?');
$stmt->execute([$calendarId, $objectUri]);
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
@@ -393,9 +483,8 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
return [
'id' => $row['id'],
'uri' => $row['uri'],
- 'lastmodified' => $row['lastmodified'],
+ 'lastmodified' => (int)$row['lastmodified'],
'etag' => '"' . $row['etag'] . '"',
- 'calendarid' => $row['calendarid'],
'size' => (int)$row['size'],
'calendardata' => $row['calendardata'],
'component' => strtolower($row['componenttype']),
@@ -417,6 +506,11 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
*/
function getMultipleCalendarObjects($calendarId, array $uris) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$query = 'SELECT id, uri, lastmodified, etag, calendarid, size, calendardata, componenttype FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ? AND uri IN (';
// Inserting a whole bunch of question marks
$query .= implode(',', array_fill(0, count($uris), '?'));
@@ -431,9 +525,8 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
$result[] = [
'id' => $row['id'],
'uri' => $row['uri'],
- 'lastmodified' => $row['lastmodified'],
+ 'lastmodified' => (int)$row['lastmodified'],
'etag' => '"' . $row['etag'] . '"',
- 'calendarid' => $row['calendarid'],
'size' => (int)$row['size'],
'calendardata' => $row['calendardata'],
'component' => strtolower($row['componenttype']),
@@ -465,6 +558,11 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
*/
function createCalendarObject($calendarId, $objectUri, $calendarData) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$extraData = $this->getDenormalizedData($calendarData);
$stmt = $this->pdo->prepare('INSERT INTO ' . $this->calendarObjectTableName . ' (calendarid, uri, calendardata, lastmodified, etag, size, componenttype, firstoccurence, lastoccurence, uid) VALUES (?,?,?,?,?,?,?,?,?,?)');
@@ -506,6 +604,11 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
*/
function updateCalendarObject($calendarId, $objectUri, $calendarData) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$extraData = $this->getDenormalizedData($calendarData);
$stmt = $this->pdo->prepare('UPDATE ' . $this->calendarObjectTableName . ' SET calendardata = ?, lastmodified = ?, etag = ?, size = ?, componenttype = ?, firstoccurence = ?, lastoccurence = ?, uid = ? WHERE calendarid = ? AND uri = ?');
@@ -583,6 +686,10 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
}
}
+
+ // Ensure Occurence values are positive
+ if ($firstOccurence < 0) $firstOccurence = 0;
+ if ($lastOccurence < 0) $lastOccurence = 0;
}
// Destroy circular references to PHP will GC the object.
@@ -604,12 +711,17 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
*
* The object uri is only the basename, or filename and not a full path.
*
- * @param string $calendarId
+ * @param mixed $calendarId
* @param string $objectUri
* @return void
*/
function deleteCalendarObject($calendarId, $objectUri) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$stmt = $this->pdo->prepare('DELETE FROM ' . $this->calendarObjectTableName . ' WHERE calendarid = ? AND uri = ?');
$stmt->execute([$calendarId, $objectUri]);
@@ -665,12 +777,17 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
* This specific implementation (for the PDO) backend optimizes filters on
* specific components, and VEVENT time-ranges.
*
- * @param string $calendarId
+ * @param mixed $calendarId
* @param array $filters
* @return array
*/
function calendarQuery($calendarId, array $filters) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
$componentType = null;
$requirePostFilter = true;
$timeRange = null;
@@ -766,14 +883,14 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport, S
$query = <<<SQL
SELECT
- calendars.uri AS calendaruri, calendarobjects.uri as objecturi
+ calendar_instances.uri AS calendaruri, calendarobjects.uri as objecturi
FROM
$this->calendarObjectTableName AS calendarobjects
LEFT JOIN
- $this->calendarTableName AS calendars
- ON calendarobjects.calendarid = calendars.id
+ $this->calendarInstancesTableName AS calendar_instances
+ ON calendarobjects.calendarid = calendar_instances.calendarid
WHERE
- calendars.principaluri = ?
+ calendar_instances.principaluri = ?
AND
calendarobjects.uid = ?
SQL;
@@ -837,7 +954,7 @@ SQL;
*
* The limit is 'suggestive'. You are free to ignore it.
*
- * @param string $calendarId
+ * @param mixed $calendarId
* @param string $syncToken
* @param int $syncLevel
* @param int $limit
@@ -845,6 +962,11 @@ SQL;
*/
function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null) {
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
// Current synctoken
$stmt = $this->pdo->prepare('SELECT synctoken FROM ' . $this->calendarTableName . ' WHERE id = ?');
$stmt->execute([ $calendarId ]);
@@ -1043,7 +1165,9 @@ SQL;
$stmt = $this->pdo->prepare("INSERT INTO " . $this->calendarSubscriptionsTableName . " (" . implode(', ', $fieldNames) . ") VALUES (" . implode(', ', array_keys($values)) . ")");
$stmt->execute($values);
- return $this->pdo->lastInsertId();
+ return $this->pdo->lastInsertId(
+ $this->calendarSubscriptionsTableName . '_id_seq'
+ );
}
@@ -1207,4 +1331,179 @@ SQL;
}
+ /**
+ * Updates the list of shares.
+ *
+ * @param mixed $calendarId
+ * @param \Sabre\DAV\Xml\Element\Sharee[] $sharees
+ * @return void
+ */
+ function updateInvites($calendarId, array $sharees) {
+
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to $calendarId is expected to be an array with a calendarId and an instanceId');
+ }
+ $currentInvites = $this->getInvites($calendarId);
+ list($calendarId, $instanceId) = $calendarId;
+
+ $removeStmt = $this->pdo->prepare("DELETE FROM " . $this->calendarInstancesTableName . " WHERE calendarid = ? AND share_href = ? AND access IN (2,3)");
+ $updateStmt = $this->pdo->prepare("UPDATE " . $this->calendarInstancesTableName . " SET access = ?, share_displayname = ?, share_invitestatus = ? WHERE calendarid = ? AND share_href = ?");
+
+ $insertStmt = $this->pdo->prepare('
+INSERT INTO ' . $this->calendarInstancesTableName . '
+ (
+ calendarid,
+ principaluri,
+ access,
+ displayname,
+ uri,
+ description,
+ calendarorder,
+ calendarcolor,
+ timezone,
+ transparent,
+ share_href,
+ share_displayname,
+ share_invitestatus
+ )
+ SELECT
+ ?,
+ ?,
+ ?,
+ displayname,
+ ?,
+ description,
+ calendarorder,
+ calendarcolor,
+ timezone,
+ 1,
+ ?,
+ ?,
+ ?
+ FROM ' . $this->calendarInstancesTableName . ' WHERE id = ?');
+
+ foreach ($sharees as $sharee) {
+
+ if ($sharee->access === \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS) {
+ // if access was set no NOACCESS, it means access for an
+ // existing sharee was removed.
+ $removeStmt->execute([$calendarId, $sharee->href]);
+ continue;
+ }
+
+ if (is_null($sharee->principal)) {
+ // If the server could not determine the principal automatically,
+ // we will mark the invite status as invalid.
+ $sharee->inviteStatus = \Sabre\DAV\Sharing\Plugin::INVITE_INVALID;
+ } else {
+ // Because sabre/dav does not yet have an invitation system,
+ // every invite is automatically accepted for now.
+ $sharee->inviteStatus = \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED;
+ }
+
+ foreach ($currentInvites as $oldSharee) {
+
+ if ($oldSharee->href === $sharee->href) {
+ // This is an update
+ $sharee->properties = array_merge(
+ $oldSharee->properties,
+ $sharee->properties
+ );
+ $updateStmt->execute([
+ $sharee->access,
+ isset($sharee->properties['{DAV:}displayname']) ? $sharee->properties['{DAV:}displayname'] : null,
+ $sharee->inviteStatus ?: $oldSharee->inviteStatus,
+ $calendarId,
+ $sharee->href
+ ]);
+ continue 2;
+ }
+
+ }
+ // If we got here, it means it was a new sharee
+ $insertStmt->execute([
+ $calendarId,
+ $sharee->principal,
+ $sharee->access,
+ \Sabre\DAV\UUIDUtil::getUUID(),
+ $sharee->href,
+ isset($sharee->properties['{DAV:}displayname']) ? $sharee->properties['{DAV:}displayname'] : null,
+ $sharee->inviteStatus ?: \Sabre\DAV\Sharing\Plugin::INVITE_NORESPONSE,
+ $instanceId
+ ]);
+
+ }
+
+ }
+
+ /**
+ * Returns the list of people whom a calendar is shared with.
+ *
+ * Every item in the returned list must be a Sharee object with at
+ * least the following properties set:
+ * $href
+ * $shareAccess
+ * $inviteStatus
+ *
+ * and optionally:
+ * $properties
+ *
+ * @param mixed $calendarId
+ * @return \Sabre\DAV\Xml\Element\Sharee[]
+ */
+ function getInvites($calendarId) {
+
+ if (!is_array($calendarId)) {
+ throw new \InvalidArgumentException('The value passed to getInvites() is expected to be an array with a calendarId and an instanceId');
+ }
+ list($calendarId, $instanceId) = $calendarId;
+
+ $query = <<<SQL
+SELECT
+ principaluri,
+ access,
+ share_href,
+ share_displayname,
+ share_invitestatus
+FROM {$this->calendarInstancesTableName}
+WHERE
+ calendarid = ?
+SQL;
+
+ $stmt = $this->pdo->prepare($query);
+ $stmt->execute([$calendarId]);
+
+ $result = [];
+ while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $result[] = new Sharee([
+ 'href' => isset($row['share_href']) ? $row['share_href'] : \Sabre\HTTP\encodePath($row['principaluri']),
+ 'access' => (int)$row['access'],
+ /// Everyone is always immediately accepted, for now.
+ 'inviteStatus' => (int)$row['share_invitestatus'],
+ 'properties' =>
+ !empty($row['share_displayname'])
+ ? [ '{DAV:}displayname' => $row['share_displayname'] ]
+ : [],
+ 'principal' => $row['principaluri'],
+ ]);
+
+ }
+ return $result;
+
+ }
+
+ /**
+ * Publishes a calendar
+ *
+ * @param mixed $calendarId
+ * @param bool $value
+ * @return void
+ */
+ function setPublishStatus($calendarId, $value) {
+
+ throw new \Sabre\DAV\Exception\NotImplemented('Not implemented');
+
+ }
+
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php b/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php
index 6a11b0ab1..8b6e074e0 100644
--- a/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php
+++ b/vendor/sabre/dav/lib/CalDAV/Backend/SharingSupport.php
@@ -5,231 +5,48 @@ namespace Sabre\CalDAV\Backend;
/**
* Adds support for sharing features to a CalDAV server.
*
- * Note: This feature is experimental, and may change in between different
- * SabreDAV versions.
+ * CalDAV backends that implement this interface, must make the following
+ * modifications to getCalendarsForUser:
*
- * Early warning: Currently SabreDAV provides no implementation for this. This
- * is, because in it's current state there is no elegant way to do this.
- * The problem lies in the fact that a real CalDAV server with sharing support
- * would first need email support (with invite notifications), and really also
- * a browser-frontend that allows people to accept or reject these shares.
- *
- * In addition, the CalDAV backends are currently kept as independent as
- * possible, and should not be aware of principals, email addresses or
- * accounts.
- *
- * Adding an implementation for Sharing to standard-sabredav would contradict
- * these goals, so for this reason this is currently not implemented, although
- * it may very well in the future; but probably not before SabreDAV 2.0.
- *
- * The interface works however, so if you implement all this, and do it
- * correctly sharing _will_ work. It's not particularly easy, and I _urge you_
- * to make yourself acquainted with the following document first:
- *
- * https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-sharing.txt
- *
- * An overview
- * ===========
- *
- * Implementing this interface will allow a user to share his or her calendars
- * to other users. Effectively, when a calendar is shared the calendar will
- * show up in both the Sharer's and Sharee's calendar-home root.
- * This interface adds a few methods that ensure that this happens, and there
- * are also a number of new requirements in the base-class you must now follow.
- *
- *
- * How it works
- * ============
- *
- * When a user shares a calendar, the updateShares() method will be called with
- * a list of sharees that are now added, and a list of sharees that have been
- * removed.
- * Removal is instant, but when a sharee is added the sharee first gets a
- * chance to accept or reject the invitation for a share.
- *
- * After a share is accepted, the calendar will be returned from
- * getUserCalendars for both the sharer, and the sharee.
- *
- * If the sharee deletes the calendar, only their share gets deleted. When the
- * owner deletes a calendar, it will be removed for everybody.
- *
- *
- * Notifications
- * =============
- *
- * During all these sharing operations, a lot of notifications are sent back
- * and forward.
- *
- * Whenever the list of sharees for a calendar has been changed (they have been
- * added, removed or modified) all sharees should get a notification for this
- * change.
- * This notification is always represented by:
- *
- * Sabre\CalDAV\Notifications\Notification\Invite
- *
- * In the case of an invite, the sharee may reply with an 'accept' or
- * 'decline'. These are always represented by:
- *
- * Sabre\CalDAV\Notifications\Notification\InviteReply
- *
- *
- * Calendar access by sharees
- * ==========================
- *
- * As mentioned earlier, shared calendars must now also be returned for
- * getCalendarsForUser for sharees. A few things change though.
- *
- * The following properties must be specified:
- *
- * 1. {http://calendarserver.org/ns/}shared-url
- *
- * This property MUST contain the url to the original calendar, that is.. the
- * path to the calendar from the owner.
- *
- * 2. {http://sabredav.org/ns}owner-principal
- *
- * This is a url to to the principal who is sharing the calendar.
- *
- * 3. {http://sabredav.org/ns}read-only
- *
- * This should be either 0 or 1, depending on if the user has read-only or
- * read-write access to the calendar.
- *
- * Only when this is done, the calendar will correctly be marked as a calendar
- * that's shared to him, thus allowing clients to display the correct interface
- * and ACL enforcement.
- *
- * If a sharee deletes their calendar, only their instance of the calendar
- * should be deleted, the original should still exists.
- * Pretty much any 'dead' WebDAV properties on these shared calendars should be
- * specific to a user. This means that if the displayname is changed by a
- * sharee, the original is not affected. This is also true for:
- * * The description
- * * The color
- * * The order
- * * And any other dead properties.
- *
- * Properties like a ctag should not be different for multiple instances of the
- * calendar.
- *
- * Lastly, objects *within* calendars should also have user-specific data. The
- * two things that are user-specific are:
- * * VALARM objects
- * * The TRANSP property
- *
- * This _also_ implies that if a VALARM is deleted by a sharee for some event,
- * this has no effect on the original VALARM.
- *
- * Understandably, the this last requirement is one of the hardest.
- * Realisticly, I can see people ignoring this part of the spec, but that could
- * cause a different set of issues.
- *
- *
- * Publishing
- * ==========
- *
- * When a user publishes a url, the server should generate a 'publish url'.
- * This is a read-only url, anybody can use to consume the calendar feed.
- *
- * Calendars are in one of two states:
- * * published
- * * unpublished
- *
- * If a calendar is published, the following property should be returned
- * for each calendar in getCalendarsForUser.
- *
- * {http://calendarserver.org/ns/}publish-url
- *
- * This element should contain a {DAV:}href element, which points to the
- * public url that does not require authentication. Unlike every other href,
- * this url must be absolute.
- *
- * Ideally, the following property is always returned
- *
- * {http://calendarserver.org/ns/}pre-publish-url
- *
- * This property should contain the url that the calendar _would_ have, if it
- * were to be published. iCal uses this to display the url, before the user
- * will actually publish it.
- *
- *
- * Selectively disabling publish or share feature
- * ==============================================
- *
- * If Sabre\CalDAV\Property\AllowedSharingModes is returned from
- * getCalendarsForUser, this allows the server to specify whether either sharing,
- * or publishing is supported.
- *
- * This allows a client to determine in advance which features are available,
- * and update the interface appropriately. If this property is not returned by
- * the backend, the SharingPlugin automatically injects it and assumes both
- * features are available.
+ * 1. Return shared calendars for users.
+ * 2. For every calendar, return calendar-resource-uri. This strings is a URI or
+ * relative URI reference that must be unique for every calendar, but
+ * identical for every instance of the same shared calenar.
+ * 3. For every calenar, you must return a share-access element. This element
+ * should contain one of the Sabre\DAV\Sharing\Plugin:ACCESS_* contants and
+ * indicates the access level the user has.
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
-interface SharingSupport extends NotificationSupport {
+interface SharingSupport extends BackendInterface {
/**
* Updates the list of shares.
*
- * The first array is a list of people that are to be added to the
- * calendar.
- *
- * Every element in the add array has the following properties:
- * * href - A url. Usually a mailto: address
- * * commonName - Usually a first and last name, or false
- * * summary - A description of the share, can also be false
- * * readOnly - A boolean value
- *
- * Every element in the remove array is just the address string.
- *
- * Note that if the calendar is currently marked as 'not shared' by and
- * this method is called, the calendar should be 'upgraded' to a shared
- * calendar.
- *
* @param mixed $calendarId
- * @param array $add
- * @param array $remove
+ * @param \Sabre\DAV\Xml\Element\Sharee[] $sharees
* @return void
*/
- function updateShares($calendarId, array $add, array $remove);
+ function updateInvites($calendarId, array $sharees);
/**
* Returns the list of people whom this calendar is shared with.
*
- * Every element in this array should have the following properties:
- * * href - Often a mailto: address
- * * commonName - Optional, for example a first + last name
- * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
- * * readOnly - boolean
- * * summary - Optional, a description for the share
+ * Every item in the returned list must be a Sharee object with at
+ * least the following properties set:
+ * $href
+ * $shareAccess
+ * $inviteStatus
*
- * This method may be called by either the original instance of the
- * calendar, as well as the shared instances. In the case of the shared
- * instances, it is perfectly acceptable to return an empty array in case
- * there are privacy concerns.
+ * and optionally:
+ * $properties
*
* @param mixed $calendarId
- * @return array
- */
- function getShares($calendarId);
-
- /**
- * This method is called when a user replied to a request to share.
- *
- * If the user chose to accept the share, this method should return the
- * newly created calendar url.
- *
- * @param string href The sharee who is replying (often a mailto: address)
- * @param int status One of the SharingPlugin::STATUS_* constants
- * @param string $calendarUri The url to the calendar thats being shared
- * @param string $inReplyTo The unique id this message is a response to
- * @param string $summary A description of the reply
- * @return null|string
+ * @return \Sabre\DAV\Xml\Element\Sharee[]
*/
- function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null);
+ function getInvites($calendarId);
/**
* Publishes a calendar
diff --git a/vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php b/vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php
new file mode 100644
index 000000000..f8238ea9a
--- /dev/null
+++ b/vendor/sabre/dav/lib/CalDAV/Backend/SimplePDO.php
@@ -0,0 +1,296 @@
+<?php
+
+namespace Sabre\CalDAV\Backend;
+
+use Sabre\CalDAV;
+use Sabre\DAV;
+
+/**
+ * Simple PDO CalDAV backend.
+ *
+ * This class is basically the most minmum example to get a caldav backend up
+ * and running. This class uses the following schema (MySQL example):
+ *
+ * CREATE TABLE simple_calendars (
+ * id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ * uri VARBINARY(200) NOT NULL,
+ * principaluri VARBINARY(200) NOT NULL
+ * );
+ *
+ * CREATE TABLE simple_calendarobjects (
+ * id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ * calendarid INT UNSIGNED NOT NULL,
+ * uri VARBINARY(200) NOT NULL,
+ * calendardata MEDIUMBLOB
+ * )
+ *
+ * To make this class work, you absolutely need to have the PropertyStorage
+ * plugin enabled.
+ *
+ * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class SimplePDO extends AbstractBackend {
+
+ /**
+ * pdo
+ *
+ * @var \PDO
+ */
+ protected $pdo;
+
+ /**
+ * Creates the backend
+ *
+ * @param \PDO $pdo
+ */
+ function __construct(\PDO $pdo) {
+
+ $this->pdo = $pdo;
+
+ }
+
+ /**
+ * Returns a list of calendars for a principal.
+ *
+ * Every project is an array with the following keys:
+ * * id, a unique id that will be used by other functions to modify the
+ * calendar. This can be the same as the uri or a database key.
+ * * uri. This is just the 'base uri' or 'filename' of the calendar.
+ * * principaluri. The owner of the calendar. Almost always the same as
+ * principalUri passed to this method.
+ *
+ * Furthermore it can contain webdav properties in clark notation. A very
+ * common one is '{DAV:}displayname'.
+ *
+ * Many clients also require:
+ * {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
+ * For this property, you can just return an instance of
+ * Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet.
+ *
+ * If you return {http://sabredav.org/ns}read-only and set the value to 1,
+ * ACL will automatically be put in read-only mode.
+ *
+ * @param string $principalUri
+ * @return array
+ */
+ function getCalendarsForUser($principalUri) {
+
+ // Making fields a comma-delimited list
+ $stmt = $this->pdo->prepare("SELECT id, uri FROM simple_calendars WHERE principaluri = ? ORDER BY id ASC");
+ $stmt->execute([$principalUri]);
+
+ $calendars = [];
+ while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $calendars[] = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $principalUri,
+ ];
+
+ }
+
+ return $calendars;
+
+ }
+
+ /**
+ * Creates a new calendar for a principal.
+ *
+ * If the creation was a success, an id must be returned that can be used
+ * to reference this calendar in other methods, such as updateCalendar.
+ *
+ * @param string $principalUri
+ * @param string $calendarUri
+ * @param array $properties
+ * @return string
+ */
+ function createCalendar($principalUri, $calendarUri, array $properties) {
+
+ $stmt = $this->pdo->prepare("INSERT INTO simple_calendars (principaluri, uri) VALUES (?, ?)");
+ $stmt->execute([$principalUri, $calendarUri]);
+
+ return $this->pdo->lastInsertId();
+
+ }
+
+ /**
+ * Delete a calendar and all it's objects
+ *
+ * @param string $calendarId
+ * @return void
+ */
+ function deleteCalendar($calendarId) {
+
+ $stmt = $this->pdo->prepare('DELETE FROM simple_calendarobjects WHERE calendarid = ?');
+ $stmt->execute([$calendarId]);
+
+ $stmt = $this->pdo->prepare('DELETE FROM simple_calendars WHERE id = ?');
+ $stmt->execute([$calendarId]);
+
+ }
+
+ /**
+ * Returns all calendar objects within a calendar.
+ *
+ * Every item contains an array with the following keys:
+ * * calendardata - The iCalendar-compatible calendar data
+ * * uri - a unique key which will be used to construct the uri. This can
+ * be any arbitrary string, but making sure it ends with '.ics' is a
+ * good idea. This is only the basename, or filename, not the full
+ * path.
+ * * lastmodified - a timestamp of the last modification time
+ * * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
+ * ' "abcdef"')
+ * * size - The size of the calendar objects, in bytes.
+ * * component - optional, a string containing the type of object, such
+ * as 'vevent' or 'vtodo'. If specified, this will be used to populate
+ * the Content-Type header.
+ *
+ * Note that the etag is optional, but it's highly encouraged to return for
+ * speed reasons.
+ *
+ * The calendardata is also optional. If it's not returned
+ * 'getCalendarObject' will be called later, which *is* expected to return
+ * calendardata.
+ *
+ * If neither etag or size are specified, the calendardata will be
+ * used/fetched to determine these numbers. If both are specified the
+ * amount of times this is needed is reduced by a great degree.
+ *
+ * @param string $calendarId
+ * @return array
+ */
+ function getCalendarObjects($calendarId) {
+
+ $stmt = $this->pdo->prepare('SELECT id, uri, calendardata FROM simple_calendarobjects WHERE calendarid = ?');
+ $stmt->execute([$calendarId]);
+
+ $result = [];
+ foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) {
+ $result[] = [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'etag' => '"' . md5($row['calendardata']) . '"',
+ 'calendarid' => $calendarId,
+ 'size' => strlen($row['calendardata']),
+ 'calendardata' => $row['calendardata'],
+ ];
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Returns information from a single calendar object, based on it's object
+ * uri.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * The returned array must have the same keys as getCalendarObjects. The
+ * 'calendardata' object is required here though, while it's not required
+ * for getCalendarObjects.
+ *
+ * This method must return null if the object did not exist.
+ *
+ * @param string $calendarId
+ * @param string $objectUri
+ * @return array|null
+ */
+ function getCalendarObject($calendarId, $objectUri) {
+
+ $stmt = $this->pdo->prepare('SELECT id, uri, calendardata FROM simple_calendarobjects WHERE calendarid = ? AND uri = ?');
+ $stmt->execute([$calendarId, $objectUri]);
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+
+ if (!$row) return null;
+
+ return [
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'etag' => '"' . md5($row['calendardata']) . '"',
+ 'calendarid' => $calendarId,
+ 'size' => strlen($row['calendardata']),
+ 'calendardata' => $row['calendardata'],
+ ];
+
+ }
+
+ /**
+ * Creates a new calendar object.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string|null
+ */
+ function createCalendarObject($calendarId, $objectUri, $calendarData) {
+
+ $stmt = $this->pdo->prepare('INSERT INTO simple_calendarobjects (calendarid, uri, calendardata) VALUES (?,?,?)');
+ $stmt->execute([
+ $calendarId,
+ $objectUri,
+ $calendarData
+ ]);
+
+ return '"' . md5($calendarData) . '"';
+
+ }
+
+ /**
+ * Updates an existing calendarobject, based on it's uri.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string|null
+ */
+ function updateCalendarObject($calendarId, $objectUri, $calendarData) {
+
+ $stmt = $this->pdo->prepare('UPDATE simple_calendarobjects SET calendardata = ? WHERE calendarid = ? AND uri = ?');
+ $stmt->execute([$calendarData, $calendarId, $objectUri]);
+
+ return '"' . md5($calendarData) . '"';
+
+ }
+
+ /**
+ * Deletes an existing calendar object.
+ *
+ * The object uri is only the basename, or filename and not a full path.
+ *
+ * @param string $calendarId
+ * @param string $objectUri
+ * @return void
+ */
+ function deleteCalendarObject($calendarId, $objectUri) {
+
+ $stmt = $this->pdo->prepare('DELETE FROM simple_calendarobjects WHERE calendarid = ? AND uri = ?');
+ $stmt->execute([$calendarId, $objectUri]);
+
+ }
+
+}
diff --git a/vendor/sabre/dav/lib/CalDAV/Calendar.php b/vendor/sabre/dav/lib/CalDAV/Calendar.php
index ff8e19b15..90ace0d21 100644
--- a/vendor/sabre/dav/lib/CalDAV/Calendar.php
+++ b/vendor/sabre/dav/lib/CalDAV/Calendar.php
@@ -18,6 +18,8 @@ use Sabre\DAV\PropPatch;
*/
class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection, DAV\IMultiGet {
+ use DAVACL\ACLTrait;
+
/**
* This is an array with calendar information
*
@@ -86,7 +88,7 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection,
foreach ($this->calendarInfo as $propName => $propValue) {
- if ($propName[0] === '{')
+ if (!is_null($propValue) && $propName[0] === '{')
$response[$propName] = $this->calendarInfo[$propName];
}
@@ -227,7 +229,7 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection,
/**
* Returns the last modification date as a unix timestamp.
*
- * @return void
+ * @return null
*/
function getLastModified() {
@@ -249,19 +251,6 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection,
}
/**
- * Returns a group principal
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
* Returns a list of ACE's for this node.
*
* Each ACE has the following properties:
@@ -360,50 +349,6 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection,
}
- /**
- * Updates the ACL
- *
- * This method will receive a list of new ACE's.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
-
- // We need to inject 'read-free-busy' in the tree, aggregated under
- // {DAV:}read.
- foreach ($default['aggregates'] as &$agg) {
-
- if ($agg['privilege'] !== '{DAV:}read') continue;
-
- $agg['aggregates'][] = [
- 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy',
- ];
-
- }
- return $default;
-
- }
/**
* Performs a calendar-query on the contents of this calendar.
diff --git a/vendor/sabre/dav/lib/CalDAV/CalendarHome.php b/vendor/sabre/dav/lib/CalDAV/CalendarHome.php
index a53f829e2..0a4bfb68f 100644
--- a/vendor/sabre/dav/lib/CalDAV/CalendarHome.php
+++ b/vendor/sabre/dav/lib/CalDAV/CalendarHome.php
@@ -22,6 +22,8 @@ use Sabre\HTTP\URLUtil;
*/
class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL {
+ use DAVACL\ACLTrait;
+
/**
* CalDAV backend
*
@@ -147,11 +149,7 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL {
foreach ($this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']) as $calendar) {
if ($calendar['uri'] === $name) {
if ($this->caldavBackend instanceof Backend\SharingSupport) {
- if (isset($calendar['{http://calendarserver.org/ns/}shared-url'])) {
- return new SharedCalendar($this->caldavBackend, $calendar);
- } else {
- return new ShareableCalendar($this->caldavBackend, $calendar);
- }
+ return new SharedCalendar($this->caldavBackend, $calendar);
} else {
return new Calendar($this->caldavBackend, $calendar);
}
@@ -198,11 +196,7 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL {
$objs = [];
foreach ($calendars as $calendar) {
if ($this->caldavBackend instanceof Backend\SharingSupport) {
- if (isset($calendar['{http://calendarserver.org/ns/}shared-url'])) {
- $objs[] = new SharedCalendar($this->caldavBackend, $calendar);
- } else {
- $objs[] = new ShareableCalendar($this->caldavBackend, $calendar);
- }
+ $objs[] = new SharedCalendar($this->caldavBackend, $calendar);
} else {
$objs[] = new Calendar($this->caldavBackend, $calendar);
}
@@ -278,11 +272,9 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL {
}
/**
- * Returns the owner principal
+ * Returns the owner of the calendar home.
*
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
+ * @return string
*/
function getOwner() {
@@ -291,19 +283,6 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL {
}
/**
- * Returns a group principal
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
* Returns a list of ACE's for this node.
*
* Each ACE has the following properties:
@@ -348,37 +327,6 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL {
}
- /**
- * Updates the ACL
- *
- * This method will receive a list of new ACE's.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- return null;
-
- }
/**
* This method is called when a user replied to a request to share.
diff --git a/vendor/sabre/dav/lib/CalDAV/CalendarObject.php b/vendor/sabre/dav/lib/CalDAV/CalendarObject.php
index 393ca4cbd..001b35112 100644
--- a/vendor/sabre/dav/lib/CalDAV/CalendarObject.php
+++ b/vendor/sabre/dav/lib/CalDAV/CalendarObject.php
@@ -11,6 +11,8 @@ namespace Sabre\CalDAV;
*/
class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\DAVACL\IACL {
+ use \Sabre\DAVACL\ACLTrait;
+
/**
* Sabre\CalDAV\Backend\BackendInterface
*
@@ -192,19 +194,6 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
}
/**
- * Returns a group principal
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
* Returns a list of ACE's for this node.
*
* Each ACE has the following properties:
@@ -226,22 +215,12 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
// The default ACL
return [
[
- 'privilege' => '{DAV:}read',
- 'principal' => $this->calendarInfo['principaluri'],
- 'protected' => true,
- ],
- [
- 'privilege' => '{DAV:}write',
+ 'privilege' => '{DAV:}all',
'principal' => $this->calendarInfo['principaluri'],
'protected' => true,
],
[
- 'privilege' => '{DAV:}read',
- 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
- 'protected' => true,
- ],
- [
- 'privilege' => '{DAV:}write',
+ 'privilege' => '{DAV:}all',
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
'protected' => true,
],
@@ -255,36 +234,4 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
}
- /**
- * Updates the ACL
- *
- * This method will receive a list of new ACE's.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new \Sabre\DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- return null;
-
- }
-
}
diff --git a/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php b/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php
index 8c296d50f..a3a824c71 100644
--- a/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php
+++ b/vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php
@@ -170,13 +170,13 @@ class ICSExportPlugin extends DAV\ServerPlugin {
protected function generateResponse($path, $start, $end, $expand, $componentType, $format, $properties, ResponseInterface $response) {
$calDataProp = '{' . Plugin::NS_CALDAV . '}calendar-data';
+ $calendarNode = $this->server->tree->getNodeForPath($path);
$blobs = [];
if ($start || $end || $componentType) {
// If there was a start or end filter, we need to enlist
// calendarQuery for speed.
- $calendarNode = $this->server->tree->getNodeForPath($path);
$queryResult = $calendarNode->calendarQuery([
'name' => 'VCALENDAR',
'comp-filters' => [
@@ -246,17 +246,29 @@ class ICSExportPlugin extends DAV\ServerPlugin {
$mergedCalendar = $mergedCalendar->expand($start, $end, $calendarTimeZone);
}
- $response->setHeader('Content-Type', $format);
+ $filenameExtension = '.ics';
switch ($format) {
case 'text/calendar' :
$mergedCalendar = $mergedCalendar->serialize();
+ $filenameExtension = '.ics';
break;
case 'application/calendar+json' :
$mergedCalendar = json_encode($mergedCalendar->jsonSerialize());
+ $filenameExtension = '.json';
break;
}
+ $filename = preg_replace(
+ '/[^a-zA-Z0-9-_ ]/um',
+ '',
+ $calendarNode->getName()
+ );
+ $filename .= '-' . date('Y-m-d') . $filenameExtension;
+
+ $response->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
+ $response->setHeader('Content-Type', $format);
+
$response->setStatus(200);
$response->setBody($mergedCalendar);
@@ -272,11 +284,11 @@ class ICSExportPlugin extends DAV\ServerPlugin {
function mergeObjects(array $properties, array $inputObjects) {
$calendar = new VObject\Component\VCalendar();
- $calendar->version = '2.0';
+ $calendar->VERSION = '2.0';
if (DAV\Server::$exposeVersion) {
- $calendar->prodid = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN';
+ $calendar->PRODID = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN';
} else {
- $calendar->prodid = '-//SabreDAV//SabreDAV//EN';
+ $calendar->PRODID = '-//SabreDAV//SabreDAV//EN';
}
if (isset($properties['{DAV:}displayname'])) {
$calendar->{'X-WR-CALNAME'} = $properties['{DAV:}displayname'];
diff --git a/vendor/sabre/dav/lib/CalDAV/IShareableCalendar.php b/vendor/sabre/dav/lib/CalDAV/IShareableCalendar.php
deleted file mode 100644
index cfda91a55..000000000
--- a/vendor/sabre/dav/lib/CalDAV/IShareableCalendar.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-namespace Sabre\CalDAV;
-
-/**
- * This interface represents a Calendar that can be shared with other users.
- *
- * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
- * @author Evert Pot (http://evertpot.com/)
- * @license http://sabre.io/license/ Modified BSD License
- */
-interface IShareableCalendar extends ICalendar {
-
- /**
- * Updates the list of shares.
- *
- * The first array is a list of people that are to be added to the
- * calendar.
- *
- * Every element in the add array has the following properties:
- * * href - A url. Usually a mailto: address
- * * commonName - Usually a first and last name, or false
- * * summary - A description of the share, can also be false
- * * readOnly - A boolean value
- *
- * Every element in the remove array is just the address string.
- *
- * @param array $add
- * @param array $remove
- * @return void
- */
- function updateShares(array $add, array $remove);
-
- /**
- * Returns the list of people whom this calendar is shared with.
- *
- * Every element in this array should have the following properties:
- * * href - Often a mailto: address
- * * commonName - Optional, for example a first + last name
- * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
- * * readOnly - boolean
- * * summary - Optional, a description for the share
- *
- * @return array
- */
- function getShares();
-
-}
diff --git a/vendor/sabre/dav/lib/CalDAV/ISharedCalendar.php b/vendor/sabre/dav/lib/CalDAV/ISharedCalendar.php
index 84442ac21..15f3b5335 100644
--- a/vendor/sabre/dav/lib/CalDAV/ISharedCalendar.php
+++ b/vendor/sabre/dav/lib/CalDAV/ISharedCalendar.php
@@ -2,6 +2,8 @@
namespace Sabre\CalDAV;
+use Sabre\DAV\Sharing\ISharedNode;
+
/**
* This interface represents a Calendar that is shared by a different user.
*
@@ -9,28 +11,16 @@ namespace Sabre\CalDAV;
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
-interface ISharedCalendar extends ICalendar {
-
- /**
- * This method should return the url of the owners' copy of the shared
- * calendar.
- *
- * @return string
- */
- function getSharedUrl();
+interface ISharedCalendar extends ISharedNode {
/**
- * Returns the list of people whom this calendar is shared with.
+ * Marks this calendar as published.
*
- * Every element in this array should have the following properties:
- * * href - Often a mailto: address
- * * commonName - Optional, for example a first + last name
- * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
- * * readOnly - boolean
- * * summary - Optional, a description for the share
+ * Publishing a calendar should automatically create a read-only, public,
+ * subscribable calendar.
*
- * @return array
+ * @param bool $value
+ * @return void
*/
- function getShares();
-
+ function setPublishStatus($value);
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php b/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php
index 1fcc1171c..5fda61dfa 100644
--- a/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php
+++ b/vendor/sabre/dav/lib/CalDAV/Notifications/Collection.php
@@ -22,6 +22,8 @@ use Sabre\DAVACL;
*/
class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
+ use DAVACL\ACLTrait;
+
/**
* The notification backend
*
@@ -96,78 +98,4 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
}
- /**
- * Returns a group principal
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
- * Returns a list of ACE's for this node.
- *
- * Each ACE has the following properties:
- * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
- * currently the only supported privileges
- * * 'principal', a url to the principal who owns the node
- * * 'protected' (optional), indicating that this ACE is not allowed to
- * be updated.
- *
- * @return array
- */
- function getACL() {
-
- return [
- [
- 'principal' => $this->getOwner(),
- 'privilege' => '{DAV:}read',
- 'protected' => true,
- ],
- [
- 'principal' => $this->getOwner(),
- 'privilege' => '{DAV:}write',
- 'protected' => true,
- ]
- ];
-
- }
-
- /**
- * Updates the ACL
- *
- * This method will receive a list of new ACE's as an array argument.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- return null;
-
- }
-
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php b/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php
index 47e78d5de..11df0c94b 100644
--- a/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php
+++ b/vendor/sabre/dav/lib/CalDAV/Notifications/Node.php
@@ -20,6 +20,8 @@ use Sabre\DAVACL;
*/
class Node extends DAV\File implements INode, DAVACL\IACL {
+ use DAVACL\ACLTrait;
+
/**
* The notification backend
*
@@ -116,78 +118,4 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
}
- /**
- * Returns a group principal
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
- * Returns a list of ACE's for this node.
- *
- * Each ACE has the following properties:
- * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
- * currently the only supported privileges
- * * 'principal', a url to the principal who owns the node
- * * 'protected' (optional), indicating that this ACE is not allowed to
- * be updated.
- *
- * @return array
- */
- function getACL() {
-
- return [
- [
- 'principal' => $this->getOwner(),
- 'privilege' => '{DAV:}read',
- 'protected' => true,
- ],
- [
- 'principal' => $this->getOwner(),
- 'privilege' => '{DAV:}write',
- 'protected' => true,
- ]
- ];
-
- }
-
- /**
- * Updates the ACL
- *
- * This method will receive a list of new ACE's as an array argument.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- return null;
-
- }
-
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Plugin.php b/vendor/sabre/dav/lib/CalDAV/Plugin.php
index 663490023..71ba75206 100644
--- a/vendor/sabre/dav/lib/CalDAV/Plugin.php
+++ b/vendor/sabre/dav/lib/CalDAV/Plugin.php
@@ -5,8 +5,9 @@ namespace Sabre\CalDAV;
use DateTimeZone;
use Sabre\DAV;
use Sabre\DAV\Exception\BadRequest;
+use Sabre\DAV\INode;
use Sabre\DAV\MkCol;
-use Sabre\DAV\Xml\Property\Href;
+use Sabre\DAV\Xml\Property\LocalHref;
use Sabre\DAVACL;
use Sabre\VObject;
use Sabre\HTTP;
@@ -186,6 +187,7 @@ class Plugin extends DAV\ServerPlugin {
$server->on('beforeCreateFile', [$this, 'beforeCreateFile']);
$server->on('beforeWriteContent', [$this, 'beforeWriteContent']);
$server->on('afterMethod:GET', [$this, 'httpAfterGET']);
+ $server->on('getSupportedPrivilegeSet', [$this, 'getSupportedPrivilegeSet']);
$server->xml->namespaceMap[self::NS_CALDAV] = 'cal';
$server->xml->namespaceMap[self::NS_CALENDARSERVER] = 'cs';
@@ -233,9 +235,10 @@ class Plugin extends DAV\ServerPlugin {
*
* @param string $reportName
* @param mixed $report
+ * @param mixed $path
* @return bool
*/
- function report($reportName, $report) {
+ function report($reportName, $report, $path) {
switch ($reportName) {
case '{' . self::NS_CALDAV . '}calendar-multiget' :
@@ -341,7 +344,7 @@ class Plugin extends DAV\ServerPlugin {
$calendarHomePath = $this->getCalendarHomeForPrincipal($principalUrl);
if (is_null($calendarHomePath)) return null;
- return new Href($calendarHomePath . '/');
+ return new LocalHref($calendarHomePath . '/');
});
// The calendar-user-address-set property is basically mapped to
@@ -349,7 +352,7 @@ class Plugin extends DAV\ServerPlugin {
$propFind->handle('{' . self::NS_CALDAV . '}calendar-user-address-set', function() use ($node) {
$addresses = $node->getAlternateUriSet();
$addresses[] = $this->server->getBaseUri() . $node->getPrincipalUrl() . '/';
- return new Href($addresses, false);
+ return new LocalHref($addresses);
});
// For some reason somebody thought it was a good idea to add
// another one of these properties. We're supporting it too.
@@ -394,8 +397,8 @@ class Plugin extends DAV\ServerPlugin {
}
- $propFind->set($propRead, new Href($readList));
- $propFind->set($propWrite, new Href($writeList));
+ $propFind->set($propRead, new LocalHref($readList));
+ $propFind->set($propWrite, new LocalHref($writeList));
}
@@ -821,11 +824,7 @@ class Plugin extends DAV\ServerPlugin {
$data = stream_get_contents($data);
}
- $before = md5($data);
- // Converting the data to unicode, if needed.
- $data = DAV\StringUtil::ensureUTF8($data);
-
- if ($before !== md5($data)) $modified = true;
+ $before = $data;
try {
@@ -865,7 +864,7 @@ class Plugin extends DAV\ServerPlugin {
}
$foundType = null;
- $foundUID = null;
+
foreach ($vobj->getComponents() as $component) {
switch ($component->name) {
case 'VTIMEZONE' :
@@ -873,31 +872,59 @@ class Plugin extends DAV\ServerPlugin {
case 'VEVENT' :
case 'VTODO' :
case 'VJOURNAL' :
- if (is_null($foundType)) {
- $foundType = $component->name;
- if (!in_array($foundType, $supportedComponents)) {
- throw new Exception\InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType);
- }
- if (!isset($component->UID)) {
- throw new DAV\Exception\BadRequest('Every ' . $component->name . ' component must have an UID');
- }
- $foundUID = (string)$component->UID;
- } else {
- if ($foundType !== $component->name) {
- throw new DAV\Exception\BadRequest('A calendar object must only contain 1 component. We found a ' . $component->name . ' as well as a ' . $foundType);
- }
- if ($foundUID !== (string)$component->UID) {
- throw new DAV\Exception\BadRequest('Every ' . $component->name . ' in this object must have identical UIDs');
- }
- }
+ $foundType = $component->name;
break;
- default :
- throw new DAV\Exception\BadRequest('You are not allowed to create components of type: ' . $component->name . ' here');
+ }
+
+ }
+
+ if (!$foundType || !in_array($foundType, $supportedComponents)) {
+ throw new Exception\InvalidComponentType('iCalendar objects must at least have a component of type ' . implode(', ', $supportedComponents));
+ }
+
+ $options = VObject\Node::PROFILE_CALDAV;
+ $prefer = $this->server->getHTTPPrefer();
+
+ if ($prefer['handling'] !== 'strict') {
+ $options |= VObject\Node::REPAIR;
+ }
+
+ $messages = $vobj->validate($options);
+ $highestLevel = 0;
+ $warningMessage = null;
+
+ // $messages contains a list of problems with the vcard, along with
+ // their severity.
+ foreach ($messages as $message) {
+
+ if ($message['level'] > $highestLevel) {
+ // Recording the highest reported error level.
+ $highestLevel = $message['level'];
+ $warningMessage = $message['message'];
}
+ switch ($message['level']) {
+
+ case 1 :
+ // Level 1 means that there was a problem, but it was repaired.
+ $modified = true;
+ break;
+ case 2 :
+ // Level 2 means a warning, but not critical
+ break;
+ case 3 :
+ // Level 3 means a critical error
+ throw new DAV\Exception\UnsupportedMediaType('Validation error in iCalendar: ' . $message['message']);
+
+ }
+
+ }
+ if ($warningMessage) {
+ $response->setHeader(
+ 'X-Sabre-Ew-Gross',
+ 'iCalendar validation warning: ' . $warningMessage
+ );
}
- if (!$foundType)
- throw new DAV\Exception\BadRequest('iCalendar object must contain at least 1 of VEVENT, VTODO or VJOURNAL');
// We use an extra variable to allow event handles to tell us wether
// the object was modified or not.
@@ -917,12 +944,12 @@ class Plugin extends DAV\ServerPlugin {
]
);
- if ($subModified) {
+ if ($modified || $subModified) {
// An event handler told us that it modified the object.
$data = $vobj->serialize();
// Using md5 to figure out if there was an *actual* change.
- if (!$modified && $before !== md5($data)) {
+ if (!$modified && strcmp($data, $before) !== 0) {
$modified = true;
}
@@ -933,6 +960,22 @@ class Plugin extends DAV\ServerPlugin {
}
+ /**
+ * This method is triggered whenever a subsystem reqeuests the privileges
+ * that are supported on a particular node.
+ *
+ * @param INode $node
+ * @param array $supportedPrivilegeSet
+ */
+ function getSupportedPrivilegeSet(INode $node, array &$supportedPrivilegeSet) {
+
+ if ($node instanceof ICalendar) {
+ $supportedPrivilegeSet['{DAV:}read']['aggregates']['{' . self::NS_CALDAV . '}read-free-busy'] = [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ];
+ }
+ }
/**
* This method is used to generate HTML output for the
diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php b/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php
index 13212565e..6b374ea3f 100644
--- a/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php
+++ b/vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php
@@ -17,6 +17,8 @@ use Sabre\VObject;
*/
class Inbox extends DAV\Collection implements IInbox {
+ use DAVACL\ACLTrait;
+
/**
* CalDAV backend
*
@@ -119,19 +121,6 @@ class Inbox extends DAV\Collection implements IInbox {
}
/**
- * Returns a group principal
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
* Returns a list of ACE's for this node.
*
* Each ACE has the following properties:
@@ -167,58 +156,11 @@ class Inbox extends DAV\Collection implements IInbox {
'protected' => true,
],
[
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-invite',
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver',
'principal' => '{DAV:}authenticated',
'protected' => true,
],
- [
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-reply',
- 'principal' => '{DAV:}authenticated',
- 'protected' => true,
- ],
- ];
-
- }
-
- /**
- * Updates the ACL
- *
- * This method will receive a list of new ACE's.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- $ns = '{' . CalDAV\Plugin::NS_CALDAV . '}';
-
- $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
- $default['aggregates'][] = [
- 'privilege' => $ns . 'schedule-deliver',
- 'aggregates' => [
- ['privilege' => $ns . 'schedule-deliver-invite'],
- ['privilege' => $ns . 'schedule-deliver-reply'],
- ],
];
- return $default;
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php b/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php
index dabaee2ca..29eefa744 100644
--- a/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php
+++ b/vendor/sabre/dav/lib/CalDAV/Schedule/Outbox.php
@@ -19,6 +19,8 @@ use Sabre\DAVACL;
*/
class Outbox extends DAV\Collection implements IOutbox {
+ use DAVACL\ACLTrait;
+
/**
* The principal Uri
*
@@ -75,19 +77,6 @@ class Outbox extends DAV\Collection implements IOutbox {
}
/**
- * Returns a group principal
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
* Returns a list of ACE's for this node.
*
* Each ACE has the following properties:
@@ -103,12 +92,7 @@ class Outbox extends DAV\Collection implements IOutbox {
return [
[
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
- 'principal' => $this->getOwner(),
- 'protected' => true,
- ],
- [
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-send',
'principal' => $this->getOwner(),
'protected' => true,
],
@@ -118,12 +102,7 @@ class Outbox extends DAV\Collection implements IOutbox {
'protected' => true,
],
[
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
- 'principal' => $this->getOwner() . '/calendar-proxy-write',
- 'protected' => true,
- ],
- [
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-send',
'principal' => $this->getOwner() . '/calendar-proxy-write',
'protected' => true,
],
@@ -141,44 +120,4 @@ class Outbox extends DAV\Collection implements IOutbox {
}
- /**
- * Updates the ACL
- *
- * This method will receive a list of new ACE's.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
- $default['aggregates'][] = [
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
- ];
- $default['aggregates'][] = [
- 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
- ];
-
- return $default;
-
- }
-
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php b/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php
index 827d6209b..47511140f 100644
--- a/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php
+++ b/vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php
@@ -5,10 +5,12 @@ namespace Sabre\CalDAV\Schedule;
use DateTimeZone;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;
+use Sabre\DAV\Sharing;
use Sabre\DAV\PropFind;
use Sabre\DAV\PropPatch;
use Sabre\DAV\INode;
use Sabre\DAV\Xml\Property\Href;
+use Sabre\DAV\Xml\Property\LocalHref;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
use Sabre\VObject;
@@ -100,12 +102,13 @@ class Plugin extends ServerPlugin {
function initialize(Server $server) {
$this->server = $server;
- $server->on('method:POST', [$this, 'httpPost']);
- $server->on('propFind', [$this, 'propFind']);
- $server->on('propPatch', [$this, 'propPatch']);
- $server->on('calendarObjectChange', [$this, 'calendarObjectChange']);
- $server->on('beforeUnbind', [$this, 'beforeUnbind']);
- $server->on('schedule', [$this, 'scheduleLocalDelivery']);
+ $server->on('method:POST', [$this, 'httpPost']);
+ $server->on('propFind', [$this, 'propFind']);
+ $server->on('propPatch', [$this, 'propPatch']);
+ $server->on('calendarObjectChange', [$this, 'calendarObjectChange']);
+ $server->on('beforeUnbind', [$this, 'beforeUnbind']);
+ $server->on('schedule', [$this, 'scheduleLocalDelivery']);
+ $server->on('getSupportedPrivilegeSet', [$this, 'getSupportedPrivilegeSet']);
$ns = '{' . self::NS_CALDAV . '}';
@@ -215,7 +218,7 @@ class Plugin extends ServerPlugin {
}
$outboxPath = $calendarHomePath . '/outbox/';
- return new Href($outboxPath);
+ return new LocalHref($outboxPath);
});
// schedule-inbox-URL property
@@ -227,7 +230,7 @@ class Plugin extends ServerPlugin {
}
$inboxPath = $calendarHomePath . '/inbox/';
- return new Href($inboxPath);
+ return new LocalHref($inboxPath);
});
@@ -245,18 +248,28 @@ class Plugin extends ServerPlugin {
$result = $this->server->getPropertiesForPath($calendarHomePath, [
'{DAV:}resourcetype',
+ '{DAV:}share-access',
$sccs,
], 1);
foreach ($result as $child) {
- if (!isset($child[200]['{DAV:}resourcetype']) || !$child[200]['{DAV:}resourcetype']->is('{' . self::NS_CALDAV . '}calendar') || $child[200]['{DAV:}resourcetype']->is('{http://calendarserver.org/ns/}shared')) {
- // Node is either not a calendar or a shared instance.
+ if (!isset($child[200]['{DAV:}resourcetype']) || !$child[200]['{DAV:}resourcetype']->is('{' . self::NS_CALDAV . '}calendar')) {
+ // Node is either not a calendar
continue;
}
+ if (isset($child[200]['{DAV:}share-access'])) {
+ $shareAccess = $child[200]['{DAV:}share-access']->getValue();
+ if ($shareAccess !== Sharing\Plugin::ACCESS_NOTSHARED && $shareAccess !== Sharing\Plugin::ACCESS_SHAREDOWNER) {
+ // Node is a shared node, not owned by the relevant
+ // user.
+ continue;
+ }
+
+ }
if (!isset($child[200][$sccs]) || in_array('VEVENT', $child[200][$sccs]->getValue())) {
// Either there is no supported-calendar-component-set
// (which is fine) or we found one that supports VEVENT.
- return new Href($child['href']);
+ return new LocalHref($child['href']);
}
}
@@ -492,7 +505,7 @@ class Plugin extends ServerPlugin {
}
if (!$aclPlugin->checkPrivileges($inboxPath, $caldavNS . $privilege, DAVACL\Plugin::R_PARENT, false)) {
- $iTipMessage->scheduleStatus = '3.8;organizer did not have the ' . $privilege . ' privilege on the attendees inbox';
+ $iTipMessage->scheduleStatus = '3.8;insufficient privileges: ' . $privilege . ' is required on the recipient schedule inbox.';
return;
}
@@ -561,6 +574,65 @@ class Plugin extends ServerPlugin {
}
/**
+ * This method is triggered whenever a subsystem requests the privileges
+ * that are supported on a particular node.
+ *
+ * We need to add a number of privileges for scheduling purposes.
+ *
+ * @param INode $node
+ * @param array $supportedPrivilegeSet
+ */
+ function getSupportedPrivilegeSet(INode $node, array &$supportedPrivilegeSet) {
+
+ $ns = '{' . self::NS_CALDAV . '}';
+ if ($node instanceof IOutbox) {
+ $supportedPrivilegeSet[$ns . 'schedule-send'] = [
+ 'abstract' => false,
+ 'aggregates' => [
+ $ns . 'schedule-send-invite' => [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ],
+ $ns . 'schedule-send-reply' => [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ],
+ $ns . 'schedule-send-freebusy' => [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ],
+ // Privilege from an earlier scheduling draft, but still
+ // used by some clients.
+ $ns . 'schedule-post-vevent' => [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ],
+ ]
+ ];
+ }
+ if ($node instanceof IInbox) {
+ $supportedPrivilegeSet[$ns . 'schedule-deliver'] = [
+ 'abstract' => false,
+ 'aggregates' => [
+ $ns . 'schedule-deliver-invite' => [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ],
+ $ns . 'schedule-deliver-reply' => [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ],
+ $ns . 'schedule-query-freebusy' => [
+ 'abstract' => false,
+ 'aggregates' => [],
+ ],
+ ]
+ ];
+ }
+
+ }
+
+ /**
* This method looks at an old iCalendar object, a new iCalendar object and
* starts sending scheduling messages based on the changes.
*
@@ -647,7 +719,7 @@ class Plugin extends ServerPlugin {
/**
* This method handles POST requests to the schedule-outbox.
*
- * Currently, two types of requests are support:
+ * Currently, two types of requests are supported:
* * FREEBUSY requests from RFC 6638
* * Simple iTIP messages from draft-desruisseaux-caldav-sched-04
*
@@ -699,7 +771,7 @@ class Plugin extends ServerPlugin {
if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') {
- $acl && $acl->checkPrivileges($outboxPath, '{' . self::NS_CALDAV . '}schedule-query-freebusy');
+ $acl && $acl->checkPrivileges($outboxPath, '{' . self::NS_CALDAV . '}schedule-send-freebusy');
$this->handleFreeBusyRequest($outboxNode, $vObject, $request, $response);
// Destroy circular references so PHP can GC the object.
@@ -727,7 +799,7 @@ class Plugin extends ServerPlugin {
protected function handleFreeBusyRequest(IOutbox $outbox, VObject\Component $vObject, RequestInterface $request, ResponseInterface $response) {
$vFreeBusy = $vObject->VFREEBUSY;
- $organizer = $vFreeBusy->organizer;
+ $organizer = $vFreeBusy->ORGANIZER;
$organizer = (string)$organizer;
@@ -863,6 +935,9 @@ class Plugin extends ServerPlugin {
$homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref();
$inboxUrl = $result[0][200][$caldavNS . 'schedule-inbox-URL']->getHref();
+ // Do we have permission?
+ $aclPlugin->checkPrivileges($inboxUrl, $caldavNS . 'schedule-query-freebusy');
+
// Grabbing the calendar list
$objects = [];
$calendarTimeZone = new DateTimeZone('UTC');
@@ -882,8 +957,6 @@ class Plugin extends ServerPlugin {
continue;
}
- $aclPlugin->checkPrivileges($homeSet . $node->getName(), $caldavNS . 'read-free-busy');
-
if (isset($props[$ctz])) {
$vtimezoneObj = VObject\Reader::read($props[$ctz]);
$calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
diff --git a/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php b/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php
index a36646e6c..6d9d3d5ec 100644
--- a/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php
+++ b/vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php
@@ -134,22 +134,12 @@ class SchedulingObject extends \Sabre\CalDAV\CalendarObject implements IScheduli
// The default ACL
return [
[
- 'privilege' => '{DAV:}read',
- 'principal' => $this->objectData['principaluri'],
- 'protected' => true,
- ],
- [
- 'privilege' => '{DAV:}write',
- 'principal' => $this->objectData['principaluri'],
- 'protected' => true,
- ],
- [
- 'privilege' => '{DAV:}read',
- 'principal' => $this->objectData['principaluri'] . '/calendar-proxy-write',
+ 'privilege' => '{DAV:}all',
+ 'principal' => '{DAV:}owner',
'protected' => true,
],
[
- 'privilege' => '{DAV:}write',
+ 'privilege' => '{DAV:}all',
'principal' => $this->objectData['principaluri'] . '/calendar-proxy-write',
'protected' => true,
],
diff --git a/vendor/sabre/dav/lib/CalDAV/ShareableCalendar.php b/vendor/sabre/dav/lib/CalDAV/ShareableCalendar.php
deleted file mode 100644
index c11695d5f..000000000
--- a/vendor/sabre/dav/lib/CalDAV/ShareableCalendar.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-namespace Sabre\CalDAV;
-
-/**
- * This object represents a CalDAV calendar that can be shared with other
- * users.
- *
- * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
- * @author Evert Pot (http://evertpot.com/)
- * @license http://sabre.io/license/ Modified BSD License
- */
-class ShareableCalendar extends Calendar implements IShareableCalendar {
-
- /**
- * Updates the list of shares.
- *
- * The first array is a list of people that are to be added to the
- * calendar.
- *
- * Every element in the add array has the following properties:
- * * href - A url. Usually a mailto: address
- * * commonName - Usually a first and last name, or false
- * * summary - A description of the share, can also be false
- * * readOnly - A boolean value
- *
- * Every element in the remove array is just the address string.
- *
- * @param array $add
- * @param array $remove
- * @return void
- */
- function updateShares(array $add, array $remove) {
-
- $this->caldavBackend->updateShares($this->calendarInfo['id'], $add, $remove);
-
- }
-
- /**
- * Returns the list of people whom this calendar is shared with.
- *
- * Every element in this array should have the following properties:
- * * href - Often a mailto: address
- * * commonName - Optional, for example a first + last name
- * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
- * * readOnly - boolean
- * * summary - Optional, a description for the share
- *
- * @return array
- */
- function getShares() {
-
- return $this->caldavBackend->getShares($this->calendarInfo['id']);
-
- }
-
- /**
- * Marks this calendar as published.
- *
- * Publishing a calendar should automatically create a read-only, public,
- * subscribable calendar.
- *
- * @param bool $value
- * @return void
- */
- function setPublishStatus($value) {
-
- $this->caldavBackend->setPublishStatus($this->calendarInfo['id'], $value);
-
- }
-
-}
diff --git a/vendor/sabre/dav/lib/CalDAV/SharedCalendar.php b/vendor/sabre/dav/lib/CalDAV/SharedCalendar.php
index 7973eff9c..7a77616e3 100644
--- a/vendor/sabre/dav/lib/CalDAV/SharedCalendar.php
+++ b/vendor/sabre/dav/lib/CalDAV/SharedCalendar.php
@@ -2,6 +2,8 @@
namespace Sabre\CalDAV;
+use Sabre\DAV\Sharing\Plugin as SPlugin;
+
/**
* This object represents a CalDAV calendar that is shared by a different user.
*
@@ -12,50 +14,84 @@ namespace Sabre\CalDAV;
class SharedCalendar extends Calendar implements ISharedCalendar {
/**
- * Constructor
+ * Returns the 'access level' for the instance of this shared resource.
+ *
+ * The value should be one of the Sabre\DAV\Sharing\Plugin::ACCESS_
+ * constants.
*
- * @param Backend\BackendInterface $caldavBackend
- * @param array $calendarInfo
+ * @return int
*/
- function __construct(Backend\BackendInterface $caldavBackend, $calendarInfo) {
-
- $required = [
- '{http://calendarserver.org/ns/}shared-url',
- '{http://sabredav.org/ns}owner-principal',
- '{http://sabredav.org/ns}read-only',
- ];
- foreach ($required as $r) {
- if (!isset($calendarInfo[$r])) {
- throw new \InvalidArgumentException('The ' . $r . ' property must be specified for SharedCalendar(s)');
- }
- }
+ function getShareAccess() {
- parent::__construct($caldavBackend, $calendarInfo);
+ return isset($this->calendarInfo['share-access']) ? $this->calendarInfo['share-access'] : SPlugin::ACCESS_NOTSHARED;
}
/**
- * This method should return the url of the owners' copy of the shared
- * calendar.
+ * This function must return a URI that uniquely identifies the shared
+ * resource. This URI should be identical across instances, and is
+ * also used in several other XML bodies to connect invites to
+ * resources.
+ *
+ * This may simply be a relative reference to the original shared instance,
+ * but it could also be a urn. As long as it's a valid URI and unique.
*
* @return string
*/
- function getSharedUrl() {
+ function getShareResourceUri() {
+
+ return $this->calendarInfo['share-resource-uri'];
+
+ }
+
+ /**
+ * Updates the list of sharees.
+ *
+ * Every item must be a Sharee object.
+ *
+ * @param \Sabre\DAV\Xml\Element\Sharee[] $sharees
+ * @return void
+ */
+ function updateInvites(array $sharees) {
- return $this->calendarInfo['{http://calendarserver.org/ns/}shared-url'];
+ $this->caldavBackend->updateInvites($this->calendarInfo['id'], $sharees);
}
/**
- * Returns the owner principal
+ * Returns the list of people whom this resource is shared with.
+ *
+ * Every item in the returned array must be a Sharee object with
+ * at least the following properties set:
+ *
+ * * $href
+ * * $shareAccess
+ * * $inviteStatus
*
- * This must be a url to a principal, or null if there's no owner
+ * and optionally:
*
- * @return string|null
+ * * $properties
+ *
+ * @return \Sabre\DAV\Xml\Element\Sharee[]
*/
- function getOwner() {
+ function getInvites() {
- return $this->calendarInfo['{http://sabredav.org/ns}owner-principal'];
+ return $this->caldavBackend->getInvites($this->calendarInfo['id']);
+
+ }
+
+ /**
+ * Marks this calendar as published.
+ *
+ * Publishing a calendar should automatically create a read-only, public,
+ * subscribable calendar.
+ *
+ * @param bool $value
+ * @return void
+ */
+ function setPublishStatus($value) {
+
+ $this->caldavBackend->setPublishStatus($this->calendarInfo['id'], $value);
}
@@ -73,32 +109,72 @@ class SharedCalendar extends Calendar implements ISharedCalendar {
*/
function getACL() {
- // The top-level ACL only contains access information for the true
- // owner of the calendar, so we need to add the information for the
- // sharee.
- $acl = parent::getACL();
- $acl[] = [
- 'privilege' => '{DAV:}read',
- 'principal' => $this->calendarInfo['principaluri'],
- 'protected' => true,
- ];
- if ($this->calendarInfo['{http://sabredav.org/ns}read-only']) {
- $acl[] = [
- 'privilege' => '{DAV:}write-properties',
- 'principal' => $this->calendarInfo['principaluri'],
- 'protected' => true,
- ];
- } else {
- $acl[] = [
- 'privilege' => '{DAV:}write',
- 'principal' => $this->calendarInfo['principaluri'],
- 'protected' => true,
- ];
+ $acl = [];
+
+ switch ($this->getShareAccess()) {
+ case SPlugin::ACCESS_NOTSHARED :
+ case SPlugin::ACCESS_SHAREDOWNER :
+ $acl[] = [
+ 'privilege' => '{DAV:}share',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}share',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ];
+ // No break intentional!
+ case SPlugin::ACCESS_READWRITE :
+ $acl[] = [
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ];
+ // No break intentional!
+ case SPlugin::ACCESS_READ :
+ $acl[] = [
+ 'privilege' => '{DAV:}write-properties',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}write-properties',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy',
+ 'principal' => '{DAV:}authenticated',
+ 'protected' => true,
+ ];
+ break;
}
return $acl;
}
+
/**
* This method returns the ACL's for calendar objects in this calendar.
* The result of this method automatically gets passed to the
@@ -108,40 +184,45 @@ class SharedCalendar extends Calendar implements ISharedCalendar {
*/
function getChildACL() {
- $acl = parent::getChildACL();
- $acl[] = [
- 'privilege' => '{DAV:}read',
- 'principal' => $this->calendarInfo['principaluri'],
- 'protected' => true,
- ];
-
- if (!$this->calendarInfo['{http://sabredav.org/ns}read-only']) {
- $acl[] = [
- 'privilege' => '{DAV:}write',
- 'principal' => $this->calendarInfo['principaluri'],
- 'protected' => true,
- ];
+ $acl = [];
+
+ switch ($this->getShareAccess()) {
+ case SPlugin::ACCESS_NOTSHARED :
+ // No break intentional
+ case SPlugin::ACCESS_SHAREDOWNER :
+ // No break intentional
+ case SPlugin::ACCESS_READWRITE:
+ $acl[] = [
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ];
+ // No break intentional
+ case SPlugin::ACCESS_READ:
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ];
+ $acl[] = [
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
+ 'protected' => true,
+ ];
+ break;
}
- return $acl;
-
- }
-
- /**
- * Returns the list of people whom this calendar is shared with.
- *
- * Every element in this array should have the following properties:
- * * href - Often a mailto: address
- * * commonName - Optional, for example a first + last name
- * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants.
- * * readOnly - boolean
- * * summary - Optional, a description for the share
- *
- * @return array
- */
- function getShares() {
-
- return $this->caldavBackend->getShares($this->calendarInfo['id']);
+ return $acl;
}
diff --git a/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php b/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php
index 5154fb1de..6f7df02bc 100644
--- a/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php
+++ b/vendor/sabre/dav/lib/CalDAV/SharingPlugin.php
@@ -4,6 +4,7 @@ namespace Sabre\CalDAV;
use Sabre\DAV;
use Sabre\DAV\Xml\Property\Href;
+use Sabre\DAV\Xml\Property\LocalHref;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
@@ -26,15 +27,6 @@ use Sabre\HTTP\ResponseInterface;
class SharingPlugin extends DAV\ServerPlugin {
/**
- * These are the various status constants used by sharing-messages.
- */
- const STATUS_ACCEPTED = 1;
- const STATUS_DECLINED = 2;
- const STATUS_DELETED = 3;
- const STATUS_NORESPONSE = 4;
- const STATUS_INVALID = 5;
-
- /**
* Reference to SabreDAV server object.
*
* @var Sabre\DAV\Server
@@ -83,7 +75,10 @@ class SharingPlugin extends DAV\ServerPlugin {
function initialize(DAV\Server $server) {
$this->server = $server;
- $server->resourceTypeMapping['Sabre\\CalDAV\\ISharedCalendar'] = '{' . Plugin::NS_CALENDARSERVER . '}shared';
+
+ if (is_null($this->server->getPlugin('sharing'))) {
+ throw new \LogicException('The generic "sharing" plugin must be loaded before the caldav sharing plugin. Call $server->addPlugin(new \Sabre\DAV\Sharing\Plugin()); before this one.');
+ }
array_push(
$this->server->protectedProperties,
@@ -114,24 +109,8 @@ class SharingPlugin extends DAV\ServerPlugin {
*/
function propFindEarly(DAV\PropFind $propFind, DAV\INode $node) {
- if ($node instanceof IShareableCalendar) {
-
- $propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}invite', function() use ($node) {
- return new Xml\Property\Invite(
- $node->getShares()
- );
- });
-
- }
-
if ($node instanceof ISharedCalendar) {
- $propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}shared-url', function() use ($node) {
- return new Href(
- $node->getSharedUrl()
- );
- });
-
$propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}invite', function() use ($node) {
// Fetching owner information
@@ -158,7 +137,7 @@ class SharingPlugin extends DAV\ServerPlugin {
}
return new Xml\Property\Invite(
- $node->getShares(),
+ $node->getInvites(),
$ownerInfo
);
@@ -179,10 +158,18 @@ class SharingPlugin extends DAV\ServerPlugin {
*/
function propFindLate(DAV\PropFind $propFind, DAV\INode $node) {
- if ($node instanceof IShareableCalendar) {
+ if ($node instanceof ISharedCalendar) {
+ $shareAccess = $node->getShareAccess();
if ($rt = $propFind->get('{DAV:}resourcetype')) {
- if (count($node->getShares()) > 0) {
- $rt->add('{' . Plugin::NS_CALENDARSERVER . '}shared-owner');
+ switch ($shareAccess) {
+ case \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER :
+ $rt->add('{' . Plugin::NS_CALENDARSERVER . '}shared-owner');
+ break;
+ case \Sabre\DAV\Sharing\Plugin::ACCESS_READ :
+ case \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE :
+ $rt->add('{' . Plugin::NS_CALENDARSERVER . '}shared');
+ break;
+
}
}
$propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes', function() {
@@ -211,21 +198,24 @@ class SharingPlugin extends DAV\ServerPlugin {
function propPatch($path, DAV\PropPatch $propPatch) {
$node = $this->server->tree->getNodeForPath($path);
- if (!$node instanceof IShareableCalendar)
+ if (!$node instanceof ISharedCalendar)
return;
- $propPatch->handle('{DAV:}resourcetype', function($value) use ($node) {
- if ($value->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return false;
- $shares = $node->getShares();
- $remove = [];
- foreach ($shares as $share) {
- $remove[] = $share['href'];
- }
- $node->updateShares([], $remove);
+ if ($node->getShareAccess() === \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER || $node->getShareAccess() === \Sabre\DAV\Sharing\Plugin::ACCESS_NOTSHARED) {
- return true;
+ $propPatch->handle('{DAV:}resourcetype', function($value) use ($node) {
+ if ($value->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return false;
+ $shares = $node->getInvites();
+ foreach ($shares as $share) {
+ $share->access = DAV\Sharing\Plugin::ACCESS_NOACCESS;
+ }
+ $node->updateInvites($shares);
- });
+ return true;
+
+ });
+
+ }
}
@@ -267,26 +257,12 @@ class SharingPlugin extends DAV\ServerPlugin {
switch ($documentType) {
- // Dealing with the 'share' document, which modified invitees on a
- // calendar.
+ // Both the DAV:share-resource and CALENDARSERVER:share requests
+ // behave identically.
case '{' . Plugin::NS_CALENDARSERVER . '}share' :
- // We can only deal with IShareableCalendar objects
- if (!$node instanceof IShareableCalendar) {
- return;
- }
-
- $this->server->transactionType = 'post-calendar-share';
-
- // Getting ACL info
- $acl = $this->server->getPlugin('acl');
-
- // If there's no ACL support, we allow everything
- if ($acl) {
- $acl->checkPrivileges($path, '{DAV:}write');
- }
-
- $node->updateShares($message->set, $message->remove);
+ $sharingPlugin = $this->server->getPlugin('sharing');
+ $sharingPlugin->shareResource($path, $message->sharees);
$response->setStatus(200);
// Adding this because sending a response body may cause issues,
@@ -328,11 +304,11 @@ class SharingPlugin extends DAV\ServerPlugin {
$response->setHeader('X-Sabre-Status', 'everything-went-well');
if ($url) {
- $writer = $this->server->xml->getWriter($this->server->getBaseUri());
+ $writer = $this->server->xml->getWriter();
$writer->openMemory();
$writer->startDocument();
$writer->startElement('{' . Plugin::NS_CALENDARSERVER . '}shared-as');
- $writer->write(new Href($url));
+ $writer->write(new LocalHref($url));
$writer->endElement();
$response->setHeader('Content-Type', 'application/xml');
$response->setBody($writer->outputMemory());
@@ -345,7 +321,7 @@ class SharingPlugin extends DAV\ServerPlugin {
case '{' . Plugin::NS_CALENDARSERVER . '}publish-calendar' :
// We can only deal with IShareableCalendar objects
- if (!$node instanceof IShareableCalendar) {
+ if (!$node instanceof ISharedCalendar) {
return;
}
$this->server->transactionType = 'post-publish-calendar';
@@ -355,7 +331,7 @@ class SharingPlugin extends DAV\ServerPlugin {
// If there's no ACL support, we allow everything
if ($acl) {
- $acl->checkPrivileges($path, '{DAV:}write');
+ $acl->checkPrivileges($path, '{DAV:}share');
}
$node->setPublishStatus(true);
@@ -373,7 +349,7 @@ class SharingPlugin extends DAV\ServerPlugin {
case '{' . Plugin::NS_CALENDARSERVER . '}unpublish-calendar' :
// We can only deal with IShareableCalendar objects
- if (!$node instanceof IShareableCalendar) {
+ if (!$node instanceof ISharedCalendar) {
return;
}
$this->server->transactionType = 'post-unpublish-calendar';
@@ -383,7 +359,7 @@ class SharingPlugin extends DAV\ServerPlugin {
// If there's no ACL support, we allow everything
if ($acl) {
- $acl->checkPrivileges($path, '{DAV:}write');
+ $acl->checkPrivileges($path, '{DAV:}share');
}
$node->setPublishStatus(false);
diff --git a/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php b/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php
index ee53da2c6..3bb3451f3 100644
--- a/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php
+++ b/vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php
@@ -5,8 +5,8 @@ namespace Sabre\CalDAV\Subscriptions;
use Sabre\DAV\Collection;
use Sabre\DAV\Xml\Property\Href;
use Sabre\DAV\PropPatch;
-use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAVACL\IACL;
+use Sabre\DAVACL\ACLTrait;
use Sabre\CalDAV\Backend\SubscriptionSupport;
/**
@@ -20,6 +20,8 @@ use Sabre\CalDAV\Backend\SubscriptionSupport;
*/
class Subscription extends Collection implements ISubscription, IACL {
+ use ACLTrait;
+
/**
* caldavBackend
*
@@ -144,7 +146,7 @@ class Subscription extends Collection implements ISubscription, IACL {
* The Server class will filter out the extra.
*
* @param array $properties
- * @return void
+ * @return array
*/
function getProperties($properties) {
@@ -154,7 +156,7 @@ class Subscription extends Collection implements ISubscription, IACL {
switch ($prop) {
case '{http://calendarserver.org/ns/}source' :
- $r[$prop] = new Href($this->subscriptionInfo['source'], false);
+ $r[$prop] = new Href($this->subscriptionInfo['source']);
break;
default :
if (array_key_exists($prop, $this->subscriptionInfo)) {
@@ -183,19 +185,6 @@ class Subscription extends Collection implements ISubscription, IACL {
}
/**
- * Returns a group principal.
- *
- * This must be a url to a principal, or null if there's no owner
- *
- * @return string|null
- */
- function getGroup() {
-
- return null;
-
- }
-
- /**
* Returns a list of ACE's for this node.
*
* Each ACE has the following properties:
@@ -211,22 +200,12 @@ class Subscription extends Collection implements ISubscription, IACL {
return [
[
- 'privilege' => '{DAV:}read',
- 'principal' => $this->getOwner(),
- 'protected' => true,
- ],
- [
- 'privilege' => '{DAV:}write',
+ 'privilege' => '{DAV:}all',
'principal' => $this->getOwner(),
'protected' => true,
],
[
- 'privilege' => '{DAV:}read',
- 'principal' => $this->getOwner() . '/calendar-proxy-write',
- 'protected' => true,
- ],
- [
- 'privilege' => '{DAV:}write',
+ 'privilege' => '{DAV:}all',
'principal' => $this->getOwner() . '/calendar-proxy-write',
'protected' => true,
],
@@ -239,36 +218,4 @@ class Subscription extends Collection implements ISubscription, IACL {
}
- /**
- * Updates the ACL.
- *
- * This method will receive a list of new ACE's.
- *
- * @param array $acl
- * @return void
- */
- function setACL(array $acl) {
-
- throw new MethodNotAllowed('Changing ACL is not yet supported');
-
- }
-
- /**
- * Returns the list of supported privileges for this node.
- *
- * The returned data structure is a list of nested privileges.
- * See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
- * standard structure.
- *
- * If null is returned from this method, the default privilege set is used,
- * which is fine for most common usecases.
- *
- * @return array|null
- */
- function getSupportedPrivilegeSet() {
-
- return null;
-
- }
-
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php
index 7fb022e33..1ca64f3e8 100644
--- a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php
+++ b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/Invite.php
@@ -5,6 +5,7 @@ namespace Sabre\CalDAV\Xml\Notification;
use Sabre\Xml\Writer;
use Sabre\CalDAV\SharingPlugin as SharingPlugin;
use Sabre\CalDAV;
+use Sabre\DAV;
/**
* This class represents the cs:invite-notification notification element.
@@ -210,16 +211,10 @@ class Invite implements NotificationInterface {
switch ($this->type) {
- case SharingPlugin::STATUS_ACCEPTED :
+ case DAV\Sharing\Plugin::INVITE_ACCEPTED :
$writer->writeElement($cs . 'invite-accepted');
break;
- case SharingPlugin::STATUS_DECLINED :
- $writer->writeElement($cs . 'invite-declined');
- break;
- case SharingPlugin::STATUS_DELETED :
- $writer->writeElement($cs . 'invite-deleted');
- break;
- case SharingPlugin::STATUS_NORESPONSE :
+ case DAV\Sharing\Plugin::INVITE_NORESPONSE :
$writer->writeElement($cs . 'invite-noresponse');
break;
diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php
index 945323fed..51bfc178a 100644
--- a/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php
+++ b/vendor/sabre/dav/lib/CalDAV/Xml/Notification/InviteReply.php
@@ -5,6 +5,7 @@ namespace Sabre\CalDAV\Xml\Notification;
use Sabre\Xml\Writer;
use Sabre\CalDAV;
use Sabre\CalDAV\SharingPlugin;
+use Sabre\DAV;
/**
* This class represents the cs:invite-reply notification element.
@@ -162,10 +163,10 @@ class InviteReply implements NotificationInterface {
switch ($this->type) {
- case SharingPlugin::STATUS_ACCEPTED :
+ case DAV\Sharing\Plugin::INVITE_ACCEPTED :
$writer->writeElement($cs . 'invite-accepted');
break;
- case SharingPlugin::STATUS_DECLINED :
+ case DAV\Sharing\Plugin::INVITE_DECLINED :
$writer->writeElement($cs . 'invite-declined');
break;
diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php
index 3ee053214..40ff6b936 100644
--- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php
+++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/Invite.php
@@ -2,11 +2,10 @@
namespace Sabre\CalDAV\Xml\Property;
-use Sabre\Xml\Element;
-use Sabre\Xml\Reader;
+use Sabre\Xml\XmlSerializable;
use Sabre\Xml\Writer;
use Sabre\CalDAV\Plugin;
-use Sabre\CalDAV\SharingPlugin;
+use Sabre\DAV;
/**
* Invite property
@@ -20,53 +19,23 @@ use Sabre\CalDAV\SharingPlugin;
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
-class Invite implements Element {
+class Invite implements XmlSerializable {
/**
* The list of users a calendar has been shared to.
*
- * @var array
+ * @var Sharee[]
*/
- protected $users;
-
- /**
- * The organizer contains information about the person who shared the
- * object.
- *
- * @var array
- */
- protected $organizer;
+ protected $sharees;
/**
* Creates the property.
*
- * Users is an array. Each element of the array has the following
- * properties:
- *
- * * href - Often a mailto: address
- * * commonName - Optional, for example a first and lastname for a user.
- * * status - One of the SharingPlugin::STATUS_* constants.
- * * readOnly - true or false
- * * summary - Optional, description of the share
- *
- * The organizer key is optional to specify. It's only useful when a
- * 'sharee' requests the sharing information.
- *
- * The organizer may have the following properties:
- * * href - Often a mailto: address.
- * * commonName - Optional human-readable name.
- * * firstName - Optional first name.
- * * lastName - Optional last name.
- *
- * If you wonder why these two structures are so different, I guess a
- * valid answer is that the current spec is still a draft.
- *
- * @param array $users
+ * @param Sharee[] $sharees
*/
- function __construct(array $users, array $organizer = null) {
+ function __construct(array $sharees) {
- $this->users = $users;
- $this->organizer = $organizer;
+ $this->sharees = $sharees;
}
@@ -77,7 +46,7 @@ class Invite implements Element {
*/
function getValue() {
- return $this->users;
+ return $this->sharees;
}
@@ -104,149 +73,55 @@ class Invite implements Element {
$cs = '{' . Plugin::NS_CALENDARSERVER . '}';
- if (!is_null($this->organizer)) {
-
- $writer->startElement($cs . 'organizer');
- $writer->writeElement('{DAV:}href', $this->organizer['href']);
-
- if (isset($this->organizer['commonName']) && $this->organizer['commonName']) {
- $writer->writeElement($cs . 'common-name', $this->organizer['commonName']);
- }
- if (isset($this->organizer['firstName']) && $this->organizer['firstName']) {
- $writer->writeElement($cs . 'first-name', $this->organizer['firstName']);
- }
- if (isset($this->organizer['lastName']) && $this->organizer['lastName']) {
- $writer->writeElement($cs . 'last-name', $this->organizer['lastName']);
- }
- $writer->endElement(); // organizer
+ foreach ($this->sharees as $sharee) {
- }
-
- foreach ($this->users as $user) {
-
- $writer->startElement($cs . 'user');
- $writer->writeElement('{DAV:}href', $user['href']);
- if (isset($user['commonName']) && $user['commonName']) {
- $writer->writeElement($cs . 'common-name', $user['commonName']);
- }
- switch ($user['status']) {
-
- case SharingPlugin::STATUS_ACCEPTED :
- $writer->writeElement($cs . 'invite-accepted');
- break;
- case SharingPlugin::STATUS_DECLINED :
- $writer->writeElement($cs . 'invite-declined');
- break;
- case SharingPlugin::STATUS_NORESPONSE :
- $writer->writeElement($cs . 'invite-noresponse');
- break;
- case SharingPlugin::STATUS_INVALID :
- $writer->writeElement($cs . 'invite-invalid');
- break;
- }
-
- $writer->startElement($cs . 'access');
- if ($user['readOnly']) {
- $writer->writeElement($cs . 'read');
+ if ($sharee->access === \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER) {
+ $writer->startElement($cs . 'organizer');
} else {
- $writer->writeElement($cs . 'read-write');
- }
- $writer->endElement(); // access
-
- if (isset($user['summary']) && $user['summary']) {
- $writer->writeElement($cs . 'summary', $user['summary']);
- }
-
- $writer->endElement(); //user
-
- }
-
- }
-
- /**
- * The deserialize method is called during xml parsing.
- *
- * This method is called statictly, this is because in theory this method
- * may be used as a type of constructor, or factory method.
- *
- * Often you want to return an instance of the current class, but you are
- * free to return other data as well.
- *
- * You are responsible for advancing the reader to the next element. Not
- * doing anything will result in a never-ending loop.
- *
- * If you just want to skip parsing for this element altogether, you can
- * just call $reader->next();
- *
- * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
- * the next element.
- *
- * @param Reader $reader
- * @return mixed
- */
- static function xmlDeserialize(Reader $reader) {
-
- $cs = '{' . Plugin::NS_CALENDARSERVER . '}';
-
- $users = [];
-
- foreach ($reader->parseInnerTree() as $elem) {
+ $writer->startElement($cs . 'user');
- if ($elem['name'] !== $cs . 'user')
- continue;
-
- $user = [
- 'href' => null,
- 'commonName' => null,
- 'readOnly' => null,
- 'summary' => null,
- 'status' => null,
- ];
-
- foreach ($elem['value'] as $userElem) {
-
- switch ($userElem['name']) {
- case $cs . 'invite-accepted' :
- $user['status'] = SharingPlugin::STATUS_ACCEPTED;
- break;
- case $cs . 'invite-declined' :
- $user['status'] = SharingPlugin::STATUS_DECLINED;
+ switch ($sharee->inviteStatus) {
+ case DAV\Sharing\Plugin::INVITE_ACCEPTED :
+ $writer->writeElement($cs . 'invite-accepted');
break;
- case $cs . 'invite-noresponse' :
- $user['status'] = SharingPlugin::STATUS_NORESPONSE;
+ case DAV\Sharing\Plugin::INVITE_DECLINED :
+ $writer->writeElement($cs . 'invite-declined');
break;
- case $cs . 'invite-invalid' :
- $user['status'] = SharingPlugin::STATUS_INVALID;
+ case DAV\Sharing\Plugin::INVITE_NORESPONSE :
+ $writer->writeElement($cs . 'invite-noresponse');
break;
- case '{DAV:}href' :
- $user['href'] = $userElem['value'];
+ case DAV\Sharing\Plugin::INVITE_INVALID :
+ $writer->writeElement($cs . 'invite-invalid');
break;
- case $cs . 'common-name' :
- $user['commonName'] = $userElem['value'];
- break;
- case $cs . 'access' :
- foreach ($userElem['value'] as $accessHref) {
- if ($accessHref['name'] === $cs . 'read') {
- $user['readOnly'] = true;
- }
- }
+ }
+
+ $writer->startElement($cs . 'access');
+ switch ($sharee->access) {
+ case DAV\Sharing\Plugin::ACCESS_READWRITE :
+ $writer->writeElement($cs . 'read-write');
break;
- case $cs . 'summary' :
- $user['summary'] = $userElem['value'];
+ case DAV\Sharing\Plugin::ACCESS_READ :
+ $writer->writeElement($cs . 'read');
break;
}
+ $writer->endElement(); // access
}
- if (!$user['status']) {
- throw new \InvalidArgumentException('Every user must have one of cs:invite-accepted, cs:invite-declined, cs:invite-noresponse or cs:invite-invalid');
- }
- $users[] = $user;
+ $href = new \Sabre\DAV\Xml\Property\Href($sharee->href);
+ $href->xmlSerialize($writer);
- }
+ if (isset($sharee->properties['{DAV:}displayname'])) {
+ $writer->writeElement($cs . 'common-name', $sharee->properties['{DAV:}displayname']);
+ }
+ if ($sharee->comment) {
+ $writer->writeElement($cs . 'summary', $sharee->comment);
+ }
+ $writer->endElement(); // organizer or user
- return new self($users);
+ }
}
+
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php b/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php
index 4a253e008..a82b8eff7 100644
--- a/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php
+++ b/vendor/sabre/dav/lib/CalDAV/Xml/Property/ScheduleCalendarTransp.php
@@ -4,8 +4,8 @@ namespace Sabre\CalDAV\Xml\Property;
use Sabre\Xml\Element;
use Sabre\Xml\Reader;
+use Sabre\Xml\Deserializer;
use Sabre\Xml\Writer;
-use Sabre\Xml\Element\Elements;
use Sabre\CalDAV\Plugin;
/**
@@ -116,23 +116,13 @@ class ScheduleCalendarTransp implements Element {
*/
static function xmlDeserialize(Reader $reader) {
- $elems = Elements::xmlDeserialize($reader);
+ $elems = Deserializer\enum($reader, Plugin::NS_CALDAV);
- $value = null;
-
- foreach ($elems as $elem) {
- switch ($elem) {
- case '{' . Plugin::NS_CALDAV . '}opaque' :
- $value = self::OPAQUE;
- break;
- case '{' . Plugin::NS_CALDAV . '}transparent' :
- $value = self::TRANSPARENT;
- break;
- }
+ if (in_array('transparent', $elems)) {
+ $value = self::TRANSPARENT;
+ } else {
+ $value = self::OPAQUE;
}
- if (is_null($value))
- return null;
-
return new self($value);
}
diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php
index ec627156f..2ecf6c2bb 100644
--- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php
+++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/InviteReply.php
@@ -2,12 +2,13 @@
namespace Sabre\CalDAV\Xml\Request;
+use Sabre\CalDAV\Plugin;
+use Sabre\CalDAV\SharingPlugin;
+use Sabre\DAV;
+use Sabre\DAV\Exception\BadRequest;
use Sabre\Xml\Reader;
use Sabre\Xml\XmlDeserializable;
use Sabre\Xml\Element\KeyValue;
-use Sabre\DAV\Exception\BadRequest;
-use Sabre\CalDAV\Plugin;
-use Sabre\CalDAV\SharingPlugin;
/**
* Invite-reply POST request parser
@@ -121,10 +122,10 @@ class InviteReply implements XmlDeserializable {
}
break;
case '{' . Plugin::NS_CALENDARSERVER . '}invite-accepted' :
- $status = SharingPlugin::STATUS_ACCEPTED;
+ $status = DAV\Sharing\Plugin::INVITE_ACCEPTED;
break;
case '{' . Plugin::NS_CALENDARSERVER . '}invite-declined' :
- $status = SharingPlugin::STATUS_DECLINED;
+ $status = DAV\Sharing\Plugin::INVITE_DECLINED;
break;
case '{' . Plugin::NS_CALENDARSERVER . '}in-reply-to' :
$inReplyTo = $value;
diff --git a/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php b/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php
index dacc5dc94..b5d9a133c 100644
--- a/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php
+++ b/vendor/sabre/dav/lib/CalDAV/Xml/Request/Share.php
@@ -2,9 +2,10 @@
namespace Sabre\CalDAV\Xml\Request;
+use Sabre\CalDAV\Plugin;
+use Sabre\DAV\Xml\Element\Sharee;
use Sabre\Xml\Reader;
use Sabre\Xml\XmlDeserializable;
-use Sabre\CalDAV\Plugin;
/**
* Share POST request parser
@@ -20,37 +21,20 @@ use Sabre\CalDAV\Plugin;
class Share implements XmlDeserializable {
/**
- * The list of new people added or updated.
- *
- * Every element has the following keys:
- * 1. href - An email address
- * 2. commonName - Some name
- * 3. summary - An optional description of the share
- * 4. readOnly - true or false
- *
- * @var array
- */
- public $set = [];
-
- /**
- * List of people removed from the share list.
- *
- * The list is a flat list of email addresses (including mailto:).
+ * The list of new people added or updated or removed from the share.
*
- * @var array
+ * @var Sharee[]
*/
- public $remove = [];
+ public $sharees = [];
/**
* Constructor
*
- * @param array $set
- * @param array $remove
+ * @param Sharee[] $sharees
*/
- function __construct(array $set, array $remove) {
+ function __construct(array $sharees) {
- $this->set = $set;
- $this->remove = $remove;
+ $this->sharees = $sharees;
}
@@ -77,13 +61,12 @@ class Share implements XmlDeserializable {
*/
static function xmlDeserialize(Reader $reader) {
- $elems = $reader->parseInnerTree([
+ $elems = $reader->parseGetElements([
'{' . Plugin::NS_CALENDARSERVER . '}set' => 'Sabre\\Xml\\Element\\KeyValue',
'{' . Plugin::NS_CALENDARSERVER . '}remove' => 'Sabre\\Xml\\Element\\KeyValue',
]);
- $set = [];
- $remove = [];
+ $sharees = [];
foreach ($elems as $elem) {
switch ($elem['name']) {
@@ -94,22 +77,34 @@ class Share implements XmlDeserializable {
$sumElem = '{' . Plugin::NS_CALENDARSERVER . '}summary';
$commonName = '{' . Plugin::NS_CALENDARSERVER . '}common-name';
- $set[] = [
+ $properties = [];
+ if (isset($sharee[$commonName])) {
+ $properties['{DAV:}displayname'] = $sharee[$commonName];
+ }
+
+ $access = array_key_exists('{' . Plugin::NS_CALENDARSERVER . '}read-write', $sharee)
+ ? \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE
+ : \Sabre\DAV\Sharing\Plugin::ACCESS_READ;
+
+ $sharees[] = new Sharee([
'href' => $sharee['{DAV:}href'],
- 'commonName' => isset($sharee[$commonName]) ? $sharee[$commonName] : null,
- 'summary' => isset($sharee[$sumElem]) ? $sharee[$sumElem] : null,
- 'readOnly' => !array_key_exists('{' . Plugin::NS_CALENDARSERVER . '}read-write', $sharee),
- ];
+ 'properties' => $properties,
+ 'access' => $access,
+ 'comment' => isset($sharee[$sumElem]) ? $sharee[$sumElem] : null
+ ]);
break;
case '{' . Plugin::NS_CALENDARSERVER . '}remove' :
- $remove[] = $elem['value']['{DAV:}href'];
+ $sharees[] = new Sharee([
+ 'href' => $elem['value']['{DAV:}href'],
+ 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS
+ ]);
break;
}
}
- return new self($set, $remove);
+ return new self($sharees);
}