diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php index 83aa8370f8971..d3627ee1e2677 100644 --- a/apps/dav/composer/composer/autoload_classmap.php +++ b/apps/dav/composer/composer/autoload_classmap.php @@ -45,7 +45,9 @@ 'OCA\\DAV\\CalDAV\\BirthdayCalendar\\EnablePlugin' => $baseDir . '/../lib/CalDAV/BirthdayCalendar/EnablePlugin.php', 'OCA\\DAV\\CalDAV\\BirthdayService' => $baseDir . '/../lib/CalDAV/BirthdayService.php', 'OCA\\DAV\\CalDAV\\CachedSubscription' => $baseDir . '/../lib/CalDAV/CachedSubscription.php', + 'OCA\\DAV\\CalDAV\\CachedSubscriptionImpl' => $baseDir . '/../lib/CalDAV/CachedSubscriptionImpl.php', 'OCA\\DAV\\CalDAV\\CachedSubscriptionObject' => $baseDir . '/../lib/CalDAV/CachedSubscriptionObject.php', + 'OCA\\DAV\\CalDAV\\CachedSubscriptionProvider' => $baseDir . '/../lib/CalDAV/CachedSubscriptionProvider.php', 'OCA\\DAV\\CalDAV\\CalDavBackend' => $baseDir . '/../lib/CalDAV/CalDavBackend.php', 'OCA\\DAV\\CalDAV\\Calendar' => $baseDir . '/../lib/CalDAV/Calendar.php', 'OCA\\DAV\\CalDAV\\CalendarHome' => $baseDir . '/../lib/CalDAV/CalendarHome.php', diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php index cbf2abe3a4e9d..6a424ba975ae4 100644 --- a/apps/dav/composer/composer/autoload_static.php +++ b/apps/dav/composer/composer/autoload_static.php @@ -60,7 +60,9 @@ class ComposerStaticInitDAV 'OCA\\DAV\\CalDAV\\BirthdayCalendar\\EnablePlugin' => __DIR__ . '/..' . '/../lib/CalDAV/BirthdayCalendar/EnablePlugin.php', 'OCA\\DAV\\CalDAV\\BirthdayService' => __DIR__ . '/..' . '/../lib/CalDAV/BirthdayService.php', 'OCA\\DAV\\CalDAV\\CachedSubscription' => __DIR__ . '/..' . '/../lib/CalDAV/CachedSubscription.php', + 'OCA\\DAV\\CalDAV\\CachedSubscriptionImpl' => __DIR__ . '/..' . '/../lib/CalDAV/CachedSubscriptionImpl.php', 'OCA\\DAV\\CalDAV\\CachedSubscriptionObject' => __DIR__ . '/..' . '/../lib/CalDAV/CachedSubscriptionObject.php', + 'OCA\\DAV\\CalDAV\\CachedSubscriptionProvider' => __DIR__ . '/..' . '/../lib/CalDAV/CachedSubscriptionProvider.php', 'OCA\\DAV\\CalDAV\\CalDavBackend' => __DIR__ . '/..' . '/../lib/CalDAV/CalDavBackend.php', 'OCA\\DAV\\CalDAV\\Calendar' => __DIR__ . '/..' . '/../lib/CalDAV/Calendar.php', 'OCA\\DAV\\CalDAV\\CalendarHome' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarHome.php', diff --git a/apps/dav/lib/AppInfo/Application.php b/apps/dav/lib/AppInfo/Application.php index 10e1130f90783..d543eb2a8259f 100644 --- a/apps/dav/lib/AppInfo/Application.php +++ b/apps/dav/lib/AppInfo/Application.php @@ -36,6 +36,7 @@ use OCA\DAV\BackgroundJob\UpdateCalendarResourcesRoomsBackgroundJob; use OCA\DAV\CalDAV\Activity\Backend; use OCA\DAV\CalDAV\AppCalendar\AppCalendarPlugin; +use OCA\DAV\CalDAV\CachedSubscriptionProvider; use OCA\DAV\CalDAV\CalendarManager; use OCA\DAV\CalDAV\CalendarProvider; use OCA\DAV\CalDAV\Reminder\NotificationProvider\AudioProvider; @@ -199,6 +200,7 @@ public function register(IRegistrationContext $context): void { $context->registerNotifierService(Notifier::class); $context->registerCalendarProvider(CalendarProvider::class); + $context->registerCalendarProvider(CachedSubscriptionProvider::class); $context->registerUserMigrator(CalendarMigrator::class); $context->registerUserMigrator(ContactsMigrator::class); diff --git a/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php b/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php index cdf7cb9059a60..2666b352496e5 100644 --- a/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php +++ b/apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php @@ -67,7 +67,7 @@ protected function getWrappedCalendars(string $principalUri, array $calendarUris 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 dc7f66e59b43f..8dfb8a3f78b8b 100644 --- a/apps/dav/lib/CalDAV/CachedSubscription.php +++ b/apps/dav/lib/CalDAV/CachedSubscription.php @@ -73,6 +73,11 @@ public function getACL() { 'principal' => '{DAV:}authenticated', 'protected' => true, ], + [ + 'privilege' => '{DAV:}write-properties', + 'principal' => $this->getOwner(), + 'protected' => true, + ] ]; } @@ -97,7 +102,6 @@ public function getChildACL() { '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 0000000000000..3406707d0d400 --- /dev/null +++ b/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php @@ -0,0 +1,117 @@ + + * + * @author Daniel Kesselberg + * + * @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 . + * + */ +namespace OCA\DAV\CalDAV; + +use OCP\Calendar\ICalendar; +use OCP\Constants; + +class CachedSubscriptionImpl implements ICalendar { + private CalDavBackend $backend; + private CachedSubscription $calendar; + /** @var array */ + 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 0000000000000..e2508af559258 --- /dev/null +++ b/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php @@ -0,0 +1,57 @@ + + * + * @author Daniel Kesselberg + * + * @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 . + * + */ +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 651483f000cd4..8890e1d8a95a1 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -1881,12 +1881,18 @@ public function search(array $calendarInfo, $pattern, array $searchProperties, $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 cbf5cebc9e74f..31463bcc6789a 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 @@ public function calendarSearch(array $filters, $limit = null, $offset = null) { $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 0c701d9cdcf14..bece2087e8aa0 100644 --- a/apps/dav/lib/CalDAV/CalendarRoot.php +++ b/apps/dav/lib/CalDAV/CalendarRoot.php @@ -32,6 +32,8 @@ 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 @@ public function __construct( } 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 @@ public function getName() { 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 3dd8a7c81e5a4..e7dea134011a4 100644 --- a/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php +++ b/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php @@ -26,7 +26,7 @@ */ 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 @@ public function __construct(IRequest $request) { 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 @@ public function __construct(IRequest $request) { */ public function initialize(Server $server) { $this->server = $server; - $server->on('beforeMethod:*', [$this, 'beforeMethod']); + $server->on('beforeMethod:*', [$this, 'beforeMethod'], 15); } /** @@ -103,16 +108,11 @@ public function beforeMethod(RequestInterface $request, ResponseInterface $respo 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; } diff --git a/apps/dav/lib/Connector/Sabre/DavAclPlugin.php b/apps/dav/lib/Connector/Sabre/DavAclPlugin.php index 236ca3da7fac7..8e5000fa9fb87 100644 --- a/apps/dav/lib/Connector/Sabre/DavAclPlugin.php +++ b/apps/dav/lib/Connector/Sabre/DavAclPlugin.php @@ -27,6 +27,8 @@ */ namespace OCA\DAV\Connector\Sabre; +use OCA\DAV\CalDAV\CachedSubscription; +use OCA\DAV\CalDAV\Calendar; use OCA\DAV\CardDAV\AddressBook; use Sabre\CalDAV\Principal\User; use Sabre\DAV\Exception\NotFound; @@ -59,6 +61,10 @@ public function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, case AddressBook::class: $type = 'Addressbook'; break; + case Calendar::class: + case CachedSubscription::class: + $type = 'Calendar'; + break; default: $type = 'Node'; break; diff --git a/apps/dav/tests/unit/CalDAV/CachedSubscriptionImplTest.php b/apps/dav/tests/unit/CalDAV/CachedSubscriptionImplTest.php new file mode 100644 index 0000000000000..1d612585c4999 --- /dev/null +++ b/apps/dav/tests/unit/CalDAV/CachedSubscriptionImplTest.php @@ -0,0 +1,96 @@ + + * + * @author Daniel Kesselberg + * + * @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 . + * + */ + +namespace OCA\DAV\Tests\unit\CalDAV; + +use OCA\DAV\CalDAV\CachedSubscription; +use OCA\DAV\CalDAV\CachedSubscriptionImpl; +use OCA\DAV\CalDAV\CalDavBackend; +use Test\TestCase; + +class CachedSubscriptionImplTest extends TestCase { + private CachedSubscription $cachedSubscription; + private array $cachedSubscriptionInfo; + private CachedSubscriptionImpl $cachedSubscriptionImpl; + private CalDavBackend $backend; + + protected function setUp(): void { + parent::setUp(); + + $this->cachedSubscription = $this->createMock(CachedSubscription::class); + $this->cachedSubscriptionInfo = [ + 'id' => 'fancy_id_123', + '{DAV:}displayname' => 'user readable name 123', + '{http://apple.com/ns/ical/}calendar-color' => '#AABBCC', + 'uri' => '/this/is/a/uri', + 'source' => 'https://test.localhost/calendar1', + ]; + $this->backend = $this->createMock(CalDavBackend::class); + + $this->cachedSubscriptionImpl = new CachedSubscriptionImpl( + $this->cachedSubscription, + $this->cachedSubscriptionInfo, + $this->backend + ); + } + + public function testGetKey(): void { + $this->assertEquals($this->cachedSubscriptionImpl->getKey(), 'fancy_id_123'); + } + + public function testGetDisplayname(): void { + $this->assertEquals($this->cachedSubscriptionImpl->getDisplayName(), 'user readable name 123'); + } + + public function testGetDisplayColor(): void { + $this->assertEquals($this->cachedSubscriptionImpl->getDisplayColor(), '#AABBCC'); + } + + public function testGetSource(): void { + $this->assertEquals($this->cachedSubscriptionImpl->getSource(), 'https://test.localhost/calendar1'); + } + + public function testSearch(): void { + $this->backend->expects($this->once()) + ->method('search') + ->with($this->cachedSubscriptionInfo, 'abc', ['def'], ['ghi'], 42, 1337) + ->willReturn(['SEARCHRESULTS']); + + $result = $this->cachedSubscriptionImpl->search('abc', ['def'], ['ghi'], 42, 1337); + $this->assertEquals($result, ['SEARCHRESULTS']); + } + + public function testGetPermissionRead(): void { + $this->cachedSubscription->expects($this->once()) + ->method('getACL') + ->with() + ->willReturn([ + ['privilege' => '{DAV:}read'] + ]); + + $this->assertEquals(1, $this->cachedSubscriptionImpl->getPermissions()); + } +} diff --git a/apps/dav/tests/unit/CalDAV/CachedSubscriptionProviderTest.php b/apps/dav/tests/unit/CalDAV/CachedSubscriptionProviderTest.php new file mode 100644 index 0000000000000..8331d259ce8c8 --- /dev/null +++ b/apps/dav/tests/unit/CalDAV/CachedSubscriptionProviderTest.php @@ -0,0 +1,88 @@ + + * + * @author Daniel Kesselberg + * + * @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 . + * + */ + +namespace OCA\DAV\Tests\unit\CalDAV; + +use OCA\DAV\CalDAV\CachedSubscriptionImpl; +use OCA\DAV\CalDAV\CachedSubscriptionProvider; +use OCA\DAV\CalDAV\CalDavBackend; +use Test\TestCase; + +class CachedSubscriptionProviderTest extends TestCase { + + private CalDavBackend $backend; + private CachedSubscriptionProvider $provider; + + protected function setUp(): void { + parent::setUp(); + + $this->backend = $this->createMock(CalDavBackend::class); + $this->backend + ->expects(self::once()) + ->method('getSubscriptionsForUser') + ->with('user-principal-123') + ->willReturn([ + [ + 'id' => 'subscription-1', + 'uri' => 'subscription-1', + 'principaluris' => 'user-principal-123', + 'source' => 'https://localhost/subscription-1', + // A subscription array has actually more properties. + ], + [ + 'id' => 'subscription-2', + 'uri' => 'subscription-2', + 'principaluri' => 'user-principal-123', + 'source' => 'https://localhost/subscription-2', + // A subscription array has actually more properties. + ] + ]); + + $this->provider = new CachedSubscriptionProvider($this->backend); + } + + public function testGetCalendars() { + $calendars = $this->provider->getCalendars( + 'user-principal-123', + [] + ); + + $this->assertCount(2, $calendars); + $this->assertInstanceOf(CachedSubscriptionImpl::class, $calendars[0]); + $this->assertInstanceOf(CachedSubscriptionImpl::class, $calendars[1]); + } + + public function testGetCalendarsFilterByUri() { + $calendars = $this->provider->getCalendars( + 'user-principal-123', + ['subscription-1'] + ); + + $this->assertCount(1, $calendars); + $this->assertInstanceOf(CachedSubscriptionImpl::class, $calendars[0]); + $this->assertEquals('subscription-1', $calendars[0]->getUri()); + } +} diff --git a/apps/dav/tests/unit/CalDAV/CachedSubscriptionTest.php b/apps/dav/tests/unit/CalDAV/CachedSubscriptionTest.php index 254c319947286..285609496a7bb 100644 --- a/apps/dav/tests/unit/CalDAV/CachedSubscriptionTest.php +++ b/apps/dav/tests/unit/CalDAV/CachedSubscriptionTest.php @@ -61,6 +61,11 @@ public function testGetACL(): void { 'principal' => '{DAV:}authenticated', 'protected' => true, ], + [ + 'privilege' => '{DAV:}write-properties', + 'principal' => 'user1', + 'protected' => 'true' + ] ], $calendar->getACL()); } diff --git a/apps/dav/tests/unit/CalDAV/CalendarHomeTest.php b/apps/dav/tests/unit/CalDAV/CalendarHomeTest.php index 50430029c616d..bc3082ac0ad73 100644 --- a/apps/dav/tests/unit/CalDAV/CalendarHomeTest.php +++ b/apps/dav/tests/unit/CalDAV/CalendarHomeTest.php @@ -26,6 +26,7 @@ namespace OCA\DAV\Tests\unit\CalDAV; use OCA\DAV\AppInfo\PluginManager; +use OCA\DAV\CalDAV\CachedSubscription; use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\CalendarHome; use OCA\DAV\CalDAV\Integration\ExternalCalendar; @@ -35,6 +36,7 @@ use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; use Sabre\CalDAV\Schedule\Inbox; +use Sabre\CalDAV\Subscriptions\Subscription; use Sabre\DAV\MkCol; use Test\TestCase; @@ -68,7 +70,8 @@ protected function setUp(): void { $this->calendarHome = new CalendarHome( $this->backend, $this->principalInfo, - $this->logger + $this->logger, + false ); // Replace PluginManager with our mock @@ -249,4 +252,126 @@ public function testGetChildAppGenerated():void { $actual = $this->calendarHome->getChild('app-generated--calendar_plugin_2--calendar-uri-from-backend'); $this->assertEquals($externalCalendarMock, $actual); } + + public function testGetChildrenSubscriptions(): void { + $this->backend + ->expects(self::once()) + ->method('getCalendarsForUser') + ->with('user-principal-123') + ->willReturn([]); + + $this->backend + ->expects(self::once()) + ->method('getSubscriptionsForUser') + ->with('user-principal-123') + ->willReturn([ + [ + 'id' => 'subscription-1', + 'uri' => 'subscription-1', + 'principaluri' => 'user-principal-123', + 'source' => 'https://localhost/subscription-1', + // A subscription array has actually more properties. + ], + [ + 'id' => 'subscription-2', + 'uri' => 'subscription-2', + 'principaluri' => 'user-principal-123', + 'source' => 'https://localhost/subscription-2', + // A subscription array has actually more properties. + ] + ]); + + /* + * @FIXME: PluginManager should be injected via constructor. + */ + + $pluginManager = $this->createMock(PluginManager::class); + $pluginManager + ->expects(self::once()) + ->method('getCalendarPlugins') + ->with() + ->willReturn([]); + + $calendarHome = new CalendarHome( + $this->backend, + $this->principalInfo, + $this->logger, + false + ); + + $reflection = new \ReflectionClass($calendarHome); + $reflectionProperty = $reflection->getProperty('pluginManager'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($calendarHome, $pluginManager); + + $actual = $calendarHome->getChildren(); + + $this->assertCount(5, $actual); + $this->assertInstanceOf(Inbox::class, $actual[0]); + $this->assertInstanceOf(Outbox::class, $actual[1]); + $this->assertInstanceOf(TrashbinHome::class, $actual[2]); + $this->assertInstanceOf(Subscription::class, $actual[3]); + $this->assertInstanceOf(Subscription::class, $actual[4]); + } + + public function testGetChildrenCachedSubscriptions(): void { + $this->backend + ->expects(self::once()) + ->method('getCalendarsForUser') + ->with('user-principal-123') + ->willReturn([]); + + $this->backend + ->expects(self::once()) + ->method('getSubscriptionsForUser') + ->with('user-principal-123') + ->willReturn([ + [ + 'id' => 'subscription-1', + 'uri' => 'subscription-1', + 'principaluris' => 'user-principal-123', + 'source' => 'https://localhost/subscription-1', + // A subscription array has actually more properties. + ], + [ + 'id' => 'subscription-2', + 'uri' => 'subscription-2', + 'principaluri' => 'user-principal-123', + 'source' => 'https://localhost/subscription-2', + // A subscription array has actually more properties. + ] + ]); + + /* + * @FIXME: PluginManager should be injected via constructor. + */ + + $pluginManager = $this->createMock(PluginManager::class); + $pluginManager + ->expects(self::once()) + ->method('getCalendarPlugins') + ->with() + ->willReturn([]); + + $calendarHome = new CalendarHome( + $this->backend, + $this->principalInfo, + $this->logger, + true + ); + + $reflection = new \ReflectionClass($calendarHome); + $reflectionProperty = $reflection->getProperty('pluginManager'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($calendarHome, $pluginManager); + + $actual = $calendarHome->getChildren(); + + $this->assertCount(5, $actual); + $this->assertInstanceOf(Inbox::class, $actual[0]); + $this->assertInstanceOf(Outbox::class, $actual[1]); + $this->assertInstanceOf(TrashbinHome::class, $actual[2]); + $this->assertInstanceOf(CachedSubscription::class, $actual[3]); + $this->assertInstanceOf(CachedSubscription::class, $actual[4]); + } } diff --git a/apps/dav/tests/unit/CalDAV/CalendarImplTest.php b/apps/dav/tests/unit/CalDAV/CalendarImplTest.php index 132526e604f60..85f2b1aedaf58 100644 --- a/apps/dav/tests/unit/CalDAV/CalendarImplTest.php +++ b/apps/dav/tests/unit/CalDAV/CalendarImplTest.php @@ -39,9 +39,6 @@ use Sabre\VObject\ITip\Message; use Sabre\VObject\Reader; -/** - * @group DB - */ class CalendarImplTest extends \Test\TestCase { /** @var CalendarImpl */ private $calendarImpl; diff --git a/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php b/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php index c99a859ac163f..f3f74d00cdc44 100644 --- a/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php +++ b/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php @@ -44,17 +44,64 @@ public function testDisabled(): void { $this->assertEquals(false, $plugin->isCachingEnabledForThisRequest()); } - public function testEnabled(): void { + public function testEnabledUserAgent(): void { $request = $this->createMock(IRequest::class); $request->expects($this->once()) ->method('isUserAgent') ->with(Plugin::ENABLE_FOR_CLIENTS) - ->willReturn(false); + ->willReturn(true); + $request->expects($this->once()) + ->method('getHeader') + ->with('X-NC-CalDAV-Webcal-Caching') + ->willReturn(''); + $request->expects($this->once()) + ->method('getMethod') + ->willReturn('REPORT'); + $request->expects($this->never()) + ->method('getParams'); + + $plugin = new Plugin($request); + $this->assertEquals(true, $plugin->isCachingEnabledForThisRequest()); + } + + public function testEnabledWebcalCachingHeader(): void { + $request = $this->createMock(IRequest::class); + $request->expects($this->once()) + ->method('isUserAgent') + ->with(Plugin::ENABLE_FOR_CLIENTS) + ->willReturn(false); $request->expects($this->once()) ->method('getHeader') ->with('X-NC-CalDAV-Webcal-Caching') ->willReturn('On'); + $request->expects($this->once()) + ->method('getMethod') + ->willReturn('REPORT'); + $request->expects($this->never()) + ->method('getParams'); + + $plugin = new Plugin($request); + + $this->assertEquals(true, $plugin->isCachingEnabledForThisRequest()); + } + + public function testEnabledExportRequest(): void { + $request = $this->createMock(IRequest::class); + $request->expects($this->once()) + ->method('isUserAgent') + ->with(Plugin::ENABLE_FOR_CLIENTS) + ->willReturn(false); + $request->expects($this->once()) + ->method('getHeader') + ->with('X-NC-CalDAV-Webcal-Caching') + ->willReturn(''); + $request->expects($this->once()) + ->method('getMethod') + ->willReturn('GET'); + $request->expects($this->once()) + ->method('getParams') + ->willReturn(['export' => '']); $plugin = new Plugin($request); diff --git a/build/integration/features/caldav.feature b/build/integration/features/caldav.feature index e2cb4f8dc9235..fffdd89d36748 100644 --- a/build/integration/features/caldav.feature +++ b/build/integration/features/caldav.feature @@ -13,7 +13,7 @@ Feature: caldav When "user0" requests calendar "admin/MyCalendar" on the endpoint "/remote.php/dav/calendars/" Then The CalDAV HTTP status code should be "404" And The exception is "Sabre\DAV\Exception\NotFound" - And The error message is "Node with name 'MyCalendar' could not be found" + And The error message is "Calendar with name 'MyCalendar' could not be found" Scenario: Accessing a not shared calendar of another user via the legacy endpoint Given user "user0" exists @@ -22,7 +22,7 @@ Feature: caldav When "user0" requests calendar "admin/MyCalendar" on the endpoint "/remote.php/caldav/calendars/" Then The CalDAV HTTP status code should be "404" And The exception is "Sabre\DAV\Exception\NotFound" - And The error message is "Node with name 'MyCalendar' could not be found" + And The error message is "Calendar with name 'MyCalendar' could not be found" Scenario: Accessing a not existing calendar of another user Given user "user0" exists