diff options
author | Daniel Kesselberg <mail@danielkesselberg.de> | 2024-03-26 21:39:22 +0100 |
---|---|---|
committer | Daniel Kesselberg <mail@danielkesselberg.de> | 2024-05-08 10:49:21 +0200 |
commit | 9faddcd5d82f40b0107b42885b473b7d7ac5b4da (patch) | |
tree | 95490e631fba8969803179565fa7c6cf5b327328 /apps/dav/lib/CalDAV | |
parent | d30f0de40d43ed090b02868a7c52fe5ffaf121cf (diff) | |
download | nextcloud-server-9faddcd5d82f40b0107b42885b473b7d7ac5b4da.tar.gz nextcloud-server-9faddcd5d82f40b0107b42885b473b7d7ac5b4da.zip |
feat(caldav): expose calendar subscriptions
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
Diffstat (limited to 'apps/dav/lib/CalDAV')
-rw-r--r-- | apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php | 2 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CachedSubscription.php | 6 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CachedSubscriptionImpl.php | 117 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CachedSubscriptionProvider.php | 57 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 8 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarHome.php | 14 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarRoot.php | 13 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/WebcalCaching/Plugin.php | 20 |
8 files changed, 215 insertions, 22 deletions
diff --git a/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php b/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php index ddf76e27f3a..b6e00baafd6 100644 --- a/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php +++ b/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php @@ -68,7 +68,7 @@ class AppCalendarPlugin implements ICalendarProvider { return array_values( array_filter($this->manager->getCalendarsForPrincipal($principalUri, $calendarUris), function ($c) { // We must not provide a wrapper for DAV calendars - return ! ($c instanceof \OCA\DAV\CalDAV\CalendarImpl); + return ! (($c instanceof \OCA\DAV\CalDAV\CalendarImpl) || ($c instanceof \OCA\DAV\CalDAV\CachedSubscriptionImpl)); }) ); } diff --git a/apps/dav/lib/CalDAV/CachedSubscription.php b/apps/dav/lib/CalDAV/CachedSubscription.php index 4047f8dad0b..79a57bc8c23 100644 --- a/apps/dav/lib/CalDAV/CachedSubscription.php +++ b/apps/dav/lib/CalDAV/CachedSubscription.php @@ -73,6 +73,11 @@ class CachedSubscription extends \Sabre\CalDAV\Calendar { 'principal' => '{DAV:}authenticated', 'protected' => true, ], + [ + 'privilege' => '{DAV:}write-properties', + 'principal' => $this->getOwner(), + 'protected' => true, + ] ]; } @@ -97,7 +102,6 @@ class CachedSubscription extends \Sabre\CalDAV\Calendar { 'principal' => $this->getOwner() . '/calendar-proxy-read', 'protected' => true, ], - ]; } diff --git a/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php b/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php new file mode 100644 index 00000000000..3406707d0d4 --- /dev/null +++ b/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php @@ -0,0 +1,117 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2024 Daniel Kesselberg <mail@danielkesselberg.de> + * + * @author Daniel Kesselberg <mail@danielkesselberg.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\DAV\CalDAV; + +use OCP\Calendar\ICalendar; +use OCP\Constants; + +class CachedSubscriptionImpl implements ICalendar { + private CalDavBackend $backend; + private CachedSubscription $calendar; + /** @var array<string, mixed> */ + private array $calendarInfo; + + public function __construct( + CachedSubscription $calendar, + array $calendarInfo, + CalDavBackend $backend + ) { + $this->calendar = $calendar; + $this->calendarInfo = $calendarInfo; + $this->backend = $backend; + } + + /** + * @return string defining the technical unique key + * @since 13.0.0 + */ + public function getKey(): string { + return (string) $this->calendarInfo['id']; + } + + /** + * {@inheritDoc} + */ + public function getUri(): string { + return $this->calendarInfo['uri']; + } + + /** + * In comparison to getKey() this function returns a human readable (maybe translated) name + * @since 13.0.0 + */ + public function getDisplayName(): ?string { + return $this->calendarInfo['{DAV:}displayname']; + } + + /** + * Calendar color + * @since 13.0.0 + */ + public function getDisplayColor(): ?string { + return $this->calendarInfo['{http://apple.com/ns/ical/}calendar-color']; + } + + /** + * @param string $pattern which should match within the $searchProperties + * @param array $searchProperties defines the properties within the query pattern should match + * @param array $options - optional parameters: + * ['timerange' => ['start' => new DateTime(...), 'end' => new DateTime(...)]] + * @param int|null $limit - limit number of search results + * @param int|null $offset - offset for paging of search results + * @return array an array of events/journals/todos which are arrays of key-value-pairs + * @since 13.0.0 + */ + public function search(string $pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null): array { + return $this->backend->search($this->calendarInfo, $pattern, $searchProperties, $options, $limit, $offset); + } + + /** + * @return int build up using \OCP\Constants + * @since 13.0.0 + */ + public function getPermissions(): int { + $permissions = $this->calendar->getACL(); + $result = 0; + foreach ($permissions as $permission) { + switch ($permission['privilege']) { + case '{DAV:}read': + $result |= Constants::PERMISSION_READ; + break; + } + } + + return $result; + } + + public function isDeleted(): bool { + return false; + } + + public function getSource(): string { + return $this->calendarInfo['source']; + } +} diff --git a/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php b/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php new file mode 100644 index 00000000000..e2508af5592 --- /dev/null +++ b/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2024 Daniel Kesselberg <mail@danielkesselberg.de> + * + * @author Daniel Kesselberg <mail@danielkesselberg.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\DAV\CalDAV; + +use OCP\Calendar\ICalendarProvider; + +class CachedSubscriptionProvider implements ICalendarProvider { + + public function __construct( + private CalDavBackend $calDavBackend + ) { + } + + public function getCalendars(string $principalUri, array $calendarUris = []): array { + $calendarInfos = $this->calDavBackend->getSubscriptionsForUser($principalUri); + + if (count($calendarUris) > 0) { + $calendarInfos = array_filter($calendarInfos, fn (array $subscription) => in_array($subscription['uri'], $calendarUris)); + } + + $calendarInfos = array_values(array_filter($calendarInfos)); + + $iCalendars = []; + foreach ($calendarInfos as $calendarInfo) { + $calendar = new CachedSubscription($this->calDavBackend, $calendarInfo); + $iCalendars[] = new CachedSubscriptionImpl( + $calendar, + $calendarInfo, + $this->calDavBackend, + ); + } + return $iCalendars; + } +} diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 1424ee4f9be..0aa4426c786 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -1882,12 +1882,18 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription $outerQuery = $this->db->getQueryBuilder(); $innerQuery = $this->db->getQueryBuilder(); + if (isset($calendarInfo['source'])) { + $calendarType = self::CALENDAR_TYPE_SUBSCRIPTION; + } else { + $calendarType = self::CALENDAR_TYPE_CALENDAR; + } + $innerQuery->selectDistinct('op.objectid') ->from($this->dbObjectPropertiesTable, 'op') ->andWhere($innerQuery->expr()->eq('op.calendarid', $outerQuery->createNamedParameter($calendarInfo['id']))) ->andWhere($innerQuery->expr()->eq('op.calendartype', - $outerQuery->createNamedParameter(self::CALENDAR_TYPE_CALENDAR))); + $outerQuery->createNamedParameter($calendarType))); $outerQuery->select('c.id', 'c.calendardata', 'c.componenttype', 'c.uid', 'c.uri') ->from('calendarobjects', 'c') diff --git a/apps/dav/lib/CalDAV/CalendarHome.php b/apps/dav/lib/CalDAV/CalendarHome.php index cbf5cebc9e7..31463bcc678 100644 --- a/apps/dav/lib/CalDAV/CalendarHome.php +++ b/apps/dav/lib/CalDAV/CalendarHome.php @@ -53,14 +53,16 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { /** @var PluginManager */ private $pluginManager; - /** @var bool */ - private $returnCachedSubscriptions = false; - /** @var LoggerInterface */ private $logger; private ?array $cachedChildren = null; - public function __construct(BackendInterface $caldavBackend, $principalInfo, LoggerInterface $logger) { + public function __construct( + BackendInterface $caldavBackend, + array $principalInfo, + LoggerInterface $logger, + private bool $returnCachedSubscriptions + ) { parent::__construct($caldavBackend, $principalInfo); $this->l10n = \OC::$server->getL10N('dav'); $this->config = \OC::$server->getConfig(); @@ -219,8 +221,4 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { $principalUri = $this->principalInfo['uri']; return $this->caldavBackend->calendarSearch($principalUri, $filters, $limit, $offset); } - - public function enableCachedSubscriptionsForThisRequest() { - $this->returnCachedSubscriptions = true; - } } diff --git a/apps/dav/lib/CalDAV/CalendarRoot.php b/apps/dav/lib/CalDAV/CalendarRoot.php index 0c701d9cdcf..bece2087e8a 100644 --- a/apps/dav/lib/CalDAV/CalendarRoot.php +++ b/apps/dav/lib/CalDAV/CalendarRoot.php @@ -32,6 +32,8 @@ use Sabre\DAVACL\PrincipalBackend; class CalendarRoot extends \Sabre\CalDAV\CalendarRoot { private LoggerInterface $logger; + private array $returnCachedSubscriptions = []; + public function __construct( PrincipalBackend\BackendInterface $principalBackend, Backend\BackendInterface $caldavBackend, @@ -43,7 +45,12 @@ class CalendarRoot extends \Sabre\CalDAV\CalendarRoot { } public function getChildForPrincipal(array $principal) { - return new CalendarHome($this->caldavBackend, $principal, $this->logger); + return new CalendarHome( + $this->caldavBackend, + $principal, + $this->logger, + array_key_exists($principal['uri'], $this->returnCachedSubscriptions) + ); } public function getName() { @@ -56,4 +63,8 @@ class CalendarRoot extends \Sabre\CalDAV\CalendarRoot { return parent::getName(); } + + public function enableReturnCachedSubscriptions(string $principalUri): void { + $this->returnCachedSubscriptions['principals/users/' . $principalUri] = true; + } } diff --git a/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php b/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php index 3dd8a7c81e5..e7dea134011 100644 --- a/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php +++ b/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php @@ -26,7 +26,7 @@ declare(strict_types=1); */ namespace OCA\DAV\CalDAV\WebcalCaching; -use OCA\DAV\CalDAV\CalendarHome; +use OCA\DAV\CalDAV\CalendarRoot; use OCP\IRequest; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Server; @@ -71,6 +71,11 @@ class Plugin extends ServerPlugin { if ($magicHeader === 'On') { $this->enabled = true; } + + $isExportRequest = $request->getMethod() === 'GET' && array_key_exists('export', $request->getParams()); + if ($isExportRequest) { + $this->enabled = true; + } } /** @@ -85,7 +90,7 @@ class Plugin extends ServerPlugin { */ public function initialize(Server $server) { $this->server = $server; - $server->on('beforeMethod:*', [$this, 'beforeMethod']); + $server->on('beforeMethod:*', [$this, 'beforeMethod'], 15); } /** @@ -103,16 +108,11 @@ class Plugin extends ServerPlugin { return; } - // $calendarHomePath will look like: calendars/username - $calendarHomePath = $pathParts[0] . '/' . $pathParts[1]; try { - $calendarHome = $this->server->tree->getNodeForPath($calendarHomePath); - if (!($calendarHome instanceof CalendarHome)) { - //how did we end up here? - return; + $calendarRoot = $this->server->tree->getNodeForPath($pathParts[0]); + if ($calendarRoot instanceof CalendarRoot) { + $calendarRoot->enableReturnCachedSubscriptions($pathParts[1]); } - - $calendarHome->enableCachedSubscriptionsForThisRequest(); } catch (NotFound $ex) { return; } |