diff options
author | Thomas Citharel <tcit@tcit.fr> | 2023-02-13 09:27:25 +0100 |
---|---|---|
committer | Thomas Citharel <tcit@tcit.fr> | 2023-02-13 09:27:29 +0100 |
commit | 79adeb8b088c239d20b7d8c4983190d41d26a262 (patch) | |
tree | 46647150af35504f7c49c87e3d07206fb2bf6ad5 | |
parent | 8f0849a3177315547625c4d30a79da648165a830 (diff) | |
download | nextcloud-server-direct-access-shared-calendar.tar.gz nextcloud-server-direct-access-shared-calendar.zip |
feat(dav): Directly access shared calendars by URIdirect-access-shared-calendar
Each time we access a shared calendar details (with getChild), this loads every user's calendars and iterates until the correct one is found.
Now we lookup from the shared calendars which ones has the correct URI, just iterating on the possible shares (for instance a calendar can be shared directly through user-to-user share or through user-to-group share).
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 81 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarHome.php | 5 |
2 files changed, 83 insertions, 3 deletions
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index b60d731b215..f89565f0be5 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -389,7 +389,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription ->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri'))) ->andWhere($query->expr()->eq('s.type', $query->createParameter('type'))) ->setParameter('type', 'calendar') - ->setParameter('principaluri', $principals, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY); + ->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY); $result = $query->executeQuery(); @@ -657,6 +657,85 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription return $calendar; } + public function getSharedCalendarByUri(string $principalUri, string $calendarSharedUri): ?array { + // query for shared calendars + [$calendarUri, ] = explode('_shared_by_', $calendarSharedUri, 2); + + $principals = $this->principalBackend->getGroupMembership($principalUri, true); + $principals = array_merge($principals, $this->principalBackend->getCircleMembership($principalUri)); + + $principals[] = $principalUri; + + $fields = array_column($this->propertyMap, 0); + $fields[] = 'a.id'; + $fields[] = 'a.uri'; + $fields[] = 'a.synctoken'; + $fields[] = 'a.components'; + $fields[] = 'a.principaluri'; + $fields[] = 'a.transparent'; + $fields[] = 's.access'; + $query = $this->db->getQueryBuilder(); + $query->select($fields) + ->from('dav_shares', 's') + ->join('s', 'calendars', 'a', $query->expr()->eq('s.resourceid', 'a.id')) + ->where($query->expr()->eq('a.uri', $query->createParameter('uri'))) + ->andWhere($query->expr()->in('s.principaluri', $query->createParameter('principaluri'))) + ->andWhere($query->expr()->eq('s.type', $query->createParameter('type'))) + ->setParameter('uri', $calendarUri) + ->setParameter('type', 'calendar') + ->setParameter('principaluri', $principals, IQueryBuilder::PARAM_STR_ARRAY); + + $result = $query->executeQuery(); + + $readOnlyPropertyName = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}read-only'; + + $calendar = null; + + while ($row = $result->fetch()) { + $row['principaluri'] = (string)$row['principaluri']; + if ($row['principaluri'] === $principalUri) { + continue; + } + + $readOnly = (int)$row['access'] === Backend::ACCESS_READ; + if (isset($calendars[$row['id']])) { + if ($readOnly) { + // New share can not have more permissions then the old one. + continue; + } + if (isset($calendars[$row['id']][$readOnlyPropertyName]) && + $calendars[$row['id']][$readOnlyPropertyName] === 0) { + // Old share is already read-write, no more permissions can be gained + continue; + } + } + + // Fixes for shared calendars + [, $name] = Uri\split($row['principaluri']); + $row['displayname'] = $row['displayname'] . ' (' . ($this->userManager->getDisplayName($name) ?? ($name ?? '')) . ')'; + + $components = []; + if ($row['components']) { + $components = explode(',', $row['components']); + } + + $calendar = [ + 'id' => $row['id'], + 'uri' => $row['uri'] . '_shared_by_' . $name, + 'principaluri' => $this->convertPrincipal($principalUri, !$this->legacyEndpoint), + '{' . Plugin::NS_CALENDARSERVER . '}getctag' => 'http://sabre.io/ns/sync/' . ($row['synctoken'] ?: '0'), + '{http://sabredav.org/ns}sync-token' => $row['synctoken'] ?: '0', + '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components), + '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent'] ? 'transparent' : 'opaque'), + '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $this->convertPrincipal($row['principaluri'], !$this->legacyEndpoint), + $readOnlyPropertyName => $readOnly, + ]; + } + $calendar = $this->rowToCalendar($row, $calendar); + $calendar = $this->addOwnerPrincipalToCalendar($calendar); + return $this->addResourceTypeToCalendar($row, $calendar); + } + /** * @return array{id: int, uri: string, '{http://calendarserver.org/ns/}getctag': string, '{http://sabredav.org/ns}sync-token': int, '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set': SupportedCalendarComponentSet, '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp': ScheduleCalendarTransp, '{urn:ietf:params:xml:ns:caldav}calendar-timezone': ?string }|null */ diff --git a/apps/dav/lib/CalDAV/CalendarHome.php b/apps/dav/lib/CalDAV/CalendarHome.php index a59e76d121f..ab9669f3a45 100644 --- a/apps/dav/lib/CalDAV/CalendarHome.php +++ b/apps/dav/lib/CalDAV/CalendarHome.php @@ -169,8 +169,9 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { } // Fallback to cover shared calendars - foreach ($this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']) as $calendar) { - if ($calendar['uri'] === $name) { + if ($this->caldavBackend instanceof CalDavBackend) { + $calendar = $this->caldavBackend->getSharedCalendarByUri($this->principalInfo['uri'], $name); + if(!empty($calendar)) { return new Calendar($this->caldavBackend, $calendar, $this->l10n, $this->config, $this->logger); } } |