From 25fe2fa23fd5916e2be1afc4297b67f4635fce97 Mon Sep 17 00:00:00 2001 From: Claus-Justus Heine Date: Thu, 16 Feb 2023 19:03:21 +0100 Subject: [PATCH] Revert 'Revert "send invitations for shared calendars"' This is basically the original commit, but with the addition that CalDavBackend::getCalendarObjectByUID() also takes object in writable shared calendars in to account and adjusts their uri s.t. the Sabre library can find the returned object uri in the user's calendar collection. --- apps/dav/lib/CalDAV/CalDavBackend.php | 36 ++++++++++++++++--- apps/dav/lib/CalDAV/Schedule/Plugin.php | 48 ++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index b60d731b21512..e8adbee35c728 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -2146,18 +2146,44 @@ public function searchPrincipalUri(string $principalUri, * @return string|null */ public function getCalendarObjectByUID($principalUri, $uid) { + // query for shared writable calendars + $principals = $this->principalBackend->getGroupMembership($principalUri, true); + $principals = array_merge($principals, $this->principalBackend->getCircleMembership($principalUri)); + $query = $this->db->getQueryBuilder(); - $query->selectAlias('c.uri', 'calendaruri')->selectAlias('co.uri', 'objecturi') + $query + ->selectAlias('c.id', 'calendarid') + ->selectAlias('c.principaluri', 'principaluri') + ->selectAlias('c.uri', 'calendaruri') + ->selectAlias('co.uri', 'objecturi') + ->selectAlias('ds.access', 'access') ->from('calendarobjects', 'co') ->leftJoin('co', 'calendars', 'c', $query->expr()->eq('co.calendarid', 'c.id')) - ->where($query->expr()->eq('c.principaluri', $query->createNamedParameter($principalUri))) - ->andWhere($query->expr()->eq('co.uid', $query->createNamedParameter($uid))) - ->andWhere($query->expr()->isNull('co.deleted_at')); + ->leftJoin('co', 'dav_shares', 'ds', $query->expr()->eq('co.calendarid', 'ds.resourceid')) + ->where($query->expr()->eq('co.uid', $query->createNamedParameter($uid))) + ->andWhere($query->expr()->isNull('co.deleted_at')) + ->andWhere($query->expr()->orX( + $query->expr()->eq('c.principaluri', $query->createNamedParameter($principalUri)), + $query->expr()->andX( + $query->expr()->in('ds.principaluri', $query->createParameter('shareprincipal')), + $query->expr()->eq('ds.type', $query->createParameter('type')), + $query->expr()->eq('ds.access', $query->createParameter('access')), + ) + )) + ->setParameter('access', Backend::ACCESS_READ_WRITE) + ->setParameter('type', 'calendar') + ->setParameter('shareprincipal', $principals, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY); $stmt = $query->executeQuery(); $row = $stmt->fetch(); $stmt->closeCursor(); if ($row) { - return $row['calendaruri'] . '/' . $row['objecturi']; + if ($row['principaluri'] != $principalUri) { + [, $name] = Uri\split($row['principaluri']); + $calendarUri = $row['calendaruri'] . '_shared_by_' . $name; + } else { + $calendarUri = $row['calendaruri']; + } + return $calendarUri . '/' . $row['objecturi']; } return null; diff --git a/apps/dav/lib/CalDAV/Schedule/Plugin.php b/apps/dav/lib/CalDAV/Schedule/Plugin.php index ac8521acfee3a..2080aa2b1c2c1 100644 --- a/apps/dav/lib/CalDAV/Schedule/Plugin.php +++ b/apps/dav/lib/CalDAV/Schedule/Plugin.php @@ -162,7 +162,53 @@ public function calendarObjectChange(RequestInterface $request, ResponseInterfac $this->pathOfCalendarObjectChange = $request->getPath(); } - parent::calendarObjectChange($request, $response, $vCal, $calendarPath, $modified, $isNew); + //parent::calendarObjectChange($request, $response, $vCal, $calendarPath, $modified, $isNew); + + if (!$this->scheduleReply($this->server->httpRequest)) { + return; + } + + $calendarNode = $this->server->tree->getNodeForPath($calendarPath); + + // Original code in parent class: + // + // $addresses = $this->getAddressesForPrincipal( + // $calendarNode->getOwner() + // ); + + // Allow also writable shared calendars: + $addresses = $this->getAddressesForPrincipal( + $calendarNode->getPrincipalURI() + ); + + if (!$isNew) { + $node = $this->server->tree->getNodeForPath($request->getPath()); + $oldObj = Reader::read($node->get()); + } else { + $oldObj = null; + } + + $this->processICalendarChange($oldObj, $vCal, $addresses, [], $modified); + + if ($oldObj) { + // Destroy circular references so PHP will GC the object. + $oldObj->destroy(); + } + } + + /** + * This method checks the 'Schedule-Reply' header + * and returns false if it's 'F', otherwise true. + * + * Copied from Sabre/DAV's Schedule plugin, because it's + * private for whatever reason + * + * @param RequestInterface $request + * @return bool + */ + private function scheduleReply(RequestInterface $request) { + $scheduleReply = $request->getHeader('Schedule-Reply'); + return $scheduleReply !== 'F'; } /**