aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/CalDAV
diff options
context:
space:
mode:
authorDaniel Kesselberg <mail@danielkesselberg.de>2024-03-26 21:39:22 +0100
committerDaniel Kesselberg <mail@danielkesselberg.de>2024-05-08 10:49:21 +0200
commit9faddcd5d82f40b0107b42885b473b7d7ac5b4da (patch)
tree95490e631fba8969803179565fa7c6cf5b327328 /apps/dav/lib/CalDAV
parentd30f0de40d43ed090b02868a7c52fe5ffaf121cf (diff)
downloadnextcloud-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.php2
-rw-r--r--apps/dav/lib/CalDAV/CachedSubscription.php6
-rw-r--r--apps/dav/lib/CalDAV/CachedSubscriptionImpl.php117
-rw-r--r--apps/dav/lib/CalDAV/CachedSubscriptionProvider.php57
-rw-r--r--apps/dav/lib/CalDAV/CalDavBackend.php8
-rw-r--r--apps/dav/lib/CalDAV/CalendarHome.php14
-rw-r--r--apps/dav/lib/CalDAV/CalendarRoot.php13
-rw-r--r--apps/dav/lib/CalDAV/WebcalCaching/Plugin.php20
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;
}