aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Citharel <tcit@tcit.fr>2023-02-13 09:27:25 +0100
committerThomas Citharel <tcit@tcit.fr>2023-02-13 09:27:29 +0100
commit79adeb8b088c239d20b7d8c4983190d41d26a262 (patch)
tree46647150af35504f7c49c87e3d07206fb2bf6ad5
parent8f0849a3177315547625c4d30a79da648165a830 (diff)
downloadnextcloud-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.php81
-rw-r--r--apps/dav/lib/CalDAV/CalendarHome.php5
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);
}
}