diff options
author | Georg Ehrke <developer@georgehrke.com> | 2020-01-27 13:21:57 +0100 |
---|---|---|
committer | Georg Ehrke <developer@georgehrke.com> | 2020-02-18 14:35:14 +0100 |
commit | b46e5cb270b1730a6e6d4a98e52ca672eafebd39 (patch) | |
tree | a67f62762d13273c5b0037078443dc081f61744d /apps/dav/lib/CalDAV | |
parent | a1fc233fcb30d9181415ad24a4141f0285b6899a (diff) | |
download | nextcloud-server-b46e5cb270b1730a6e6d4a98e52ca672eafebd39.tar.gz nextcloud-server-b46e5cb270b1730a6e6d4a98e52ca672eafebd39.zip |
Allow apps to provide Calendars in user's calendarHome
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
Diffstat (limited to 'apps/dav/lib/CalDAV')
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarHome.php | 36 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/Integration/ExternalCalendar.php | 132 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/Integration/ICalendarProvider.php | 73 |
3 files changed, 239 insertions, 2 deletions
diff --git a/apps/dav/lib/CalDAV/CalendarHome.php b/apps/dav/lib/CalDAV/CalendarHome.php index b491c2304d2..ce29ed12db6 100644 --- a/apps/dav/lib/CalDAV/CalendarHome.php +++ b/apps/dav/lib/CalDAV/CalendarHome.php @@ -26,6 +26,9 @@ namespace OCA\DAV\CalDAV; +use OCA\DAV\AppInfo\PluginManager; +use OCA\DAV\CalDAV\Integration\ExternalCalendar; +use OCA\DAV\CalDAV\Integration\ICalendarProvider; use Sabre\CalDAV\Backend\BackendInterface; use Sabre\CalDAV\Backend\NotificationSupport; use Sabre\CalDAV\Backend\SchedulingSupport; @@ -44,6 +47,9 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { /** @var \OCP\IConfig */ private $config; + /** @var PluginManager */ + private $pluginManager; + /** @var bool */ private $returnCachedSubscriptions=false; @@ -51,6 +57,10 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { parent::__construct($caldavBackend, $principalInfo); $this->l10n = \OC::$server->getL10N('dav'); $this->config = \OC::$server->getConfig(); + $this->pluginManager = new PluginManager( + \OC::$server, + \OC::$server->getAppManager() + ); } /** @@ -66,7 +76,7 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { function createExtendedCollection($name, MkCol $mkCol) { $reservedNames = [BirthdayService::BIRTHDAY_CALENDAR_URI]; - if (in_array($name, $reservedNames)) { + if (\in_array($name, $reservedNames, true) || ExternalCalendar::doesViolateReservedName($name)) { throw new MethodNotAllowed('The resource you tried to create has a reserved name'); } @@ -104,6 +114,14 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { } } + foreach ($this->pluginManager->getCalendarPlugins() as $calendarPlugin) { + /** @var ICalendarProvider $calendarPlugin */ + $calendars = $calendarPlugin->fetchAllForCalendarHome($this->principalInfo['uri']); + foreach ($calendars as $calendar) { + $objects[] = $calendar; + } + } + return $objects; } @@ -139,7 +157,21 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { return new Subscription($this->caldavBackend, $subscription); } } + } + + if (ExternalCalendar::isAppGeneratedCalendar($name)) { + [$appId, $calendarUri] = ExternalCalendar::splitAppGeneratedCalendarUri($name); + foreach ($this->pluginManager->getCalendarPlugins() as $calendarPlugin) { + /** @var ICalendarProvider $calendarPlugin */ + if ($calendarPlugin->getAppId() !== $appId) { + continue; + } + + if ($calendarPlugin->hasCalendarInCalendarHome($this->principalInfo['uri'], $calendarUri)) { + return $calendarPlugin->getCalendarInCalendarHome($this->principalInfo['uri'], $calendarUri); + } + } } throw new NotFound('Node with name \'' . $name . '\' could not be found'); @@ -155,7 +187,7 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { return $this->caldavBackend->calendarSearch($principalUri, $filters, $limit, $offset); } - + public function enableCachedSubscriptionsForThisRequest() { $this->returnCachedSubscriptions = true; } diff --git a/apps/dav/lib/CalDAV/Integration/ExternalCalendar.php b/apps/dav/lib/CalDAV/Integration/ExternalCalendar.php new file mode 100644 index 00000000000..88d43f0bb55 --- /dev/null +++ b/apps/dav/lib/CalDAV/Integration/ExternalCalendar.php @@ -0,0 +1,132 @@ +<?php +/** + * @copyright 2020, Georg Ehrke <oc.list@georgehrke.com> + * + * @author Georg Ehrke <oc.list@georgehrke.com> + * + * @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\Integration; + +use Sabre\CalDAV; +use Sabre\DAV; + +/** + * Class ExternalCalendar + * + * @package OCA\DAV\CalDAV\Integration + * @since 19.0.0 + */ +abstract class ExternalCalendar implements CalDAV\ICalendar, DAV\IProperties { + + /** @var string */ + private const PREFIX = 'app-generated'; + + /** + * @var string + * + * Double dash is a valid delimiter, + * because it will always split the calendarURIs correctly: + * - our prefix contains only one dash and won't be split + * - appIds are not allowed to contain dashes as per spec: + * > must contain only lowercase ASCII characters and underscore + * - explode has a limit of three, so even if the app-generated + * calendar uri has double dashes, it won't be split + */ + private const DELIMITER = '--'; + + /** @var string */ + private $appId; + + /** @var string */ + private $calendarUri; + + /** + * ExternalCalendar constructor. + * + * @param string $appId + * @param string $calendarUri + */ + public function __construct(string $appId, string $calendarUri) { + $this->appId = $appId; + $this->calendarUri = $calendarUri; + } + + /** + * @inheritDoc + */ + final public function getName() { + return implode(self::DELIMITER, [ + self::PREFIX, + $this->appId, + $this->calendarUri, + ]); + } + + /** + * @inheritDoc + */ + final public function setName($name) { + throw new DAV\Exception\MethodNotAllowed('Renaming calendars is not yet supported'); + } + + /** + * @inheritDoc + */ + final public function createDirectory($name) { + throw new DAV\Exception\MethodNotAllowed('Creating collections in calendar objects is not allowed'); + + } + + /** + * Checks whether the calendar uri is app-generated + * + * @param string $calendarUri + * @return bool + */ + public static function isAppGeneratedCalendar(string $calendarUri):bool { + return strpos($calendarUri, self::PREFIX) === 0 && substr_count($calendarUri, self::DELIMITER) >= 2; + } + + /** + * Splits an app-generated calendar-uri into appId and calendarUri + * + * @param string $calendarUri + * @return array + */ + public static function splitAppGeneratedCalendarUri(string $calendarUri):array { + $array = array_slice(explode(self::DELIMITER, $calendarUri, 3), 1); + // Check the array has expected amount of elements + // and none of them is an empty string + if (\count($array) !== 2 || \in_array('', $array, true)) { + throw new \InvalidArgumentException('Provided calendar uri was not app-generated'); + } + + return $array; + } + + /** + * Checks whether a calendar-name, the user wants to create, violates + * the reserved name for calendar uris + * + * @param string $calendarUri + * @return bool + */ + public static function doesViolateReservedName(string $calendarUri):bool { + return strpos($calendarUri, self::PREFIX) === 0; + } +} diff --git a/apps/dav/lib/CalDAV/Integration/ICalendarProvider.php b/apps/dav/lib/CalDAV/Integration/ICalendarProvider.php new file mode 100644 index 00000000000..29f5f113ef5 --- /dev/null +++ b/apps/dav/lib/CalDAV/Integration/ICalendarProvider.php @@ -0,0 +1,73 @@ +<?php +/** + * @copyright 2020, Georg Ehrke <oc.list@georgehrke.com> + * + * @author Georg Ehrke <oc.list@georgehrke.com> + * + * @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\Integration; + +use Sabre\CalDAV\ICalendar; + +/** + * Interface ICalendarProvider + * + * @package OCA\DAV\CalDAV\Integration + * @since 19.0.0 + */ +interface ICalendarProvider { + + /** + * Provides the appId of the plugin + * + * @since 19.0.0 + * @return string AppId + */ + public function getAppId(): string; + + /** + * Fetches all calendars for a given principal uri + * + * @since 19.0.0 + * @param string $principalUri E.g. principals/users/user1 + * @return ExternalCalendar[] Array of all calendars + */ + public function fetchAllForCalendarHome(string $principalUri): array; + + /** + * Checks whether plugin has a calendar for a given principalUri and calendarUri + * + * @since 19.0.0 + * @param string $principalUri E.g. principals/users/user1 + * @param string $calendarUri E.g. personal + * @return bool True if calendar for principalUri and calendarUri exists, false otherwise + */ + public function hasCalendarInCalendarHome(string $principalUri, string $calendarUri): bool; + + /** + * Fetches a calendar for a given principalUri and calendarUri + * Returns null if calendar does not exist + * + * @since 19.0.0 + * @param string $principalUri E.g. principals/users/user1 + * @param string $calendarUri E.g. personal + * @return ExternalCalendar|null Calendar if it exists, null otherwise + */ + public function getCalendarInCalendarHome(string $principalUri, string $calendarUri): ?ExternalCalendar; + +} |