From 5d206eec69760afe33b9febcd3173dec2fab989d Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Sun, 15 Oct 2017 21:58:40 +0200 Subject: [PATCH 1/6] Public interfaces for calendar API Signed-off-by: Georg Ehrke --- lib/public/Calendar/ICalendar.php | 71 ++++++++++++++++++ lib/public/Calendar/IManager.php | 121 ++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 lib/public/Calendar/ICalendar.php create mode 100644 lib/public/Calendar/IManager.php diff --git a/lib/public/Calendar/ICalendar.php b/lib/public/Calendar/ICalendar.php new file mode 100644 index 0000000000..359e40f6f1 --- /dev/null +++ b/lib/public/Calendar/ICalendar.php @@ -0,0 +1,71 @@ + + * + * @author Georg Ehrke + * + * @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 OCP\Calendar; + +/** + * Interface ICalendar + * + * @package OCP + * @since 13.0.0 + */ +interface ICalendar { + + /** + * @return string defining the technical unique key + * @since 13.0.0 + */ + public function getKey(); + + /** + * In comparison to getKey() this function returns a human readable (maybe translated) name + * @return null|string + * @since 13.0.0 + */ + public function getDisplayName(); + + /** + * Calendar color + * @return null|string + * @since 13.0.0 + */ + public function getDisplayColor(); + + /** + * @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 integer|null $limit - limit number of search results + * @param integer|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($pattern, array $searchProperties=[], array $options=[], $limit=null, $offset=null); + + /** + * @return integer build up using \OCP\Constants + * @since 13.0.0 + */ + public function getPermissions(); +} diff --git a/lib/public/Calendar/IManager.php b/lib/public/Calendar/IManager.php new file mode 100644 index 0000000000..05ccd96c41 --- /dev/null +++ b/lib/public/Calendar/IManager.php @@ -0,0 +1,121 @@ + + * + * @author Georg Ehrke + * + * @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 OCP\Calendar; + +/** + * This class provides access to the Nextcloud CalDAV backend. + * Use this class exclusively if you want to access calendars. + * + * Events/Journals/Todos in general will be expressed as an array of key-value-pairs. + * The keys will match the property names defined in https://tools.ietf.org/html/rfc5545 + * + * [ + * 'id' => 123, + * 'type' => 'VEVENT', + * 'calendar-key' => 42, + * 'objects' => [ + * [ + * 'SUMMARY' => ['FooBar', []], + * 'DTSTART' => ['20171001T123456', ['TZID' => 'EUROPE/BERLIN']], + * 'DURATION' => ['P1D', []], + * 'ATTENDEE' => [ + * ['mailto:bla@blub.com', ['CN' => 'Mr. Bla Blub']] + * ], + * 'VALARM' => [ + * [ + * 'TRIGGER' => ['19980101T050000Z', ['VALUE' => DATE-TIME]] + * ] + * ] + * ], + * ] + * ] + * + * @since 13.0.0 + */ +interface IManager { + + /** + * This function is used to search and find objects within the user's calendars. + * In case $pattern is empty all events/journals/todos will be returned. + * + * @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 integer|null $limit - limit number of search results + * @param integer|null $offset - offset for paging of search results + * @return array an array of events/journals/todos which are arrays of arrays of key-value-pairs + * @since 13.0.0 + */ + public function search($pattern, array $searchProperties=[], array $options=[], $limit=null, $offset=null); + + /** + * Check if calendars are available + * + * @return bool true if enabled, false if not + * @since 13.0.0 + */ + public function isEnabled(); + + /** + * Registers a calendar + * + * @param ICalendar $calendar + * @return void + * @since 13.0.0 + */ + public function registerCalendar(ICalendar $calendar); + + /** + * Unregisters a calendar + * + * @param ICalendar $calendar + * @return void + * @since 13.0.0 + */ + public function unregisterCalendar(ICalendar $calendar); + + /** + * In order to improve lazy loading a closure can be registered which will be called in case + * calendars are actually requested + * + * @param \Closure $callable + * @return void + * @since 13.0.0 + */ + public function register(\Closure $callable); + + /** + * @return ICalendar[] + * @since 13.0.0 + */ + public function getCalendars(); + + /** + * removes all registered calendar instances + * @return void + * @since 13.0.0 + */ + public function clear(); +} From 556b2a2b6facb147295abebb18d1b391afa3f184 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 31 Oct 2017 17:06:01 +0100 Subject: [PATCH 2/6] implement CalendarManager Signed-off-by: Georg Ehrke --- lib/private/Calendar/Manager.php | 140 +++++++++++++++++++ lib/private/Server.php | 10 ++ lib/public/IServerContainer.php | 9 ++ tests/lib/Calendar/ManagerTest.php | 214 +++++++++++++++++++++++++++++ 4 files changed, 373 insertions(+) create mode 100644 lib/private/Calendar/Manager.php create mode 100644 tests/lib/Calendar/ManagerTest.php diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php new file mode 100644 index 0000000000..85d501f8ea --- /dev/null +++ b/lib/private/Calendar/Manager.php @@ -0,0 +1,140 @@ + + * + * @author Georg Ehrke + * + * @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 OC\Calendar; + +use OCP\Calendar\ICalendar; + +class Manager implements \OCP\Calendar\IManager { + + /** + * @var ICalendar[] holds all registered calendars + */ + private $calendars=[]; + + /** + * @var \Closure[] to call to load/register calendar providers + */ + private $calendarLoaders=[]; + + /** + * This function is used to search and find objects within the user's calendars. + * In case $pattern is empty all events/journals/todos will be returned. + * + * @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 integer|null $limit - limit number of search results + * @param integer|null $offset - offset for paging of search results + * @return array an array of events/journals/todos which are arrays of arrays of key-value-pairs + * @since 13.0.0 + */ + public function search($pattern, array $searchProperties=[], array $options=[], $limit=null, $offset=null) { + $this->loadCalendars(); + $result = []; + foreach($this->calendars as $calendar) { + $r = $calendar->search($pattern, $searchProperties, $options, $limit, $offset); + foreach($r as $o) { + $o['calendar-key'] = $calendar->getKey(); + $result[] = $o; + } + } + + return $result; + } + + /** + * Check if calendars are available + * + * @return bool true if enabled, false if not + * @since 13.0.0 + */ + public function isEnabled() { + return !empty($this->calendars) || !empty($this->calendarLoaders); + } + + /** + * Registers a calendar + * + * @param ICalendar $calendar + * @return void + * @since 13.0.0 + */ + public function registerCalendar(ICalendar $calendar) { + $this->calendars[$calendar->getKey()] = $calendar; + } + + /** + * Unregisters a calendar + * + * @param ICalendar $calendar + * @return void + * @since 13.0.0 + */ + public function unregisterCalendar(ICalendar $calendar) { + unset($this->calendars[$calendar->getKey()]); + } + + /** + * In order to improve lazy loading a closure can be registered which will be called in case + * calendars are actually requested + * + * @param \Closure $callable + * @return void + * @since 13.0.0 + */ + public function register(\Closure $callable) { + $this->calendarLoaders[] = $callable; + } + + /** + * @return ICalendar[] + * @since 13.0.0 + */ + public function getCalendars() { + $this->loadCalendars(); + + return array_values($this->calendars); + } + + /** + * removes all registered calendar instances + * @return void + * @since 13.0.0 + */ + public function clear() { + $this->calendars = []; + $this->calendarLoaders = []; + } + + /** + * loads all calendars + */ + private function loadCalendars() { + foreach($this->calendarLoaders as $callable) { + $callable($this); + } + $this->calendarLoaders = []; + } +} diff --git a/lib/private/Server.php b/lib/private/Server.php index af18b1a3a1..867eee99b5 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -153,6 +153,9 @@ class Server extends ServerContainer implements IServerContainer { return $c; }); + $this->registerAlias(\OCP\Calendar\IManager::class, \OC\Calendar\Manager::class); + $this->registerAlias('CalendarManager', \OC\Calendar\Manager::class); + $this->registerAlias(\OCP\Contacts\IManager::class, \OC\ContactsManager::class); $this->registerAlias('ContactsManager', \OCP\Contacts\IManager::class); @@ -1094,6 +1097,13 @@ class Server extends ServerContainer implements IServerContainer { }); } + /** + * @return \OCP\Calendar\IManager + */ + public function getCalendarManager() { + return $this->query('CalendarManager'); + } + /** * @return \OCP\Contacts\IManager */ diff --git a/lib/public/IServerContainer.php b/lib/public/IServerContainer.php index 13abd0ff43..8c33a765d5 100644 --- a/lib/public/IServerContainer.php +++ b/lib/public/IServerContainer.php @@ -57,6 +57,15 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; */ interface IServerContainer extends IContainer { + /** + * The calendar manager will act as a broker between consumers for calendar information and + * providers which actual deliver the calendar information. + * + * @return \OCP\Calendar\IManager + * @since 13.0.0 + */ + public function getCalendarManager(); + /** * The contacts manager will act as a broker between consumers for contacts information and * providers which actual deliver the contact information. diff --git a/tests/lib/Calendar/ManagerTest.php b/tests/lib/Calendar/ManagerTest.php new file mode 100644 index 0000000000..657a50a3d8 --- /dev/null +++ b/tests/lib/Calendar/ManagerTest.php @@ -0,0 +1,214 @@ + + * + * @author Georg Ehrke + * + * @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 Test\Calendar; + +use \OC\Calendar\Manager; +use OCP\Calendar\ICalendar; +use \Test\TestCase; + +class ManagerTest extends TestCase { + + /** @var Manager */ + private $manager; + + protected function setUp() { + parent::setUp(); + + $this->manager = new Manager(); + } + + /** + * @dataProvider searchProvider + */ + public function testSearch($search1, $search2, $expected) { + /** @var ICalendar | \PHPUnit_Framework_MockObject_MockObject $calendar1 */ + $calendar1 = $this->createMock(ICalendar::class); + $calendar1->method('getKey')->will($this->returnValue('simple:1')); + $calendar1->expects($this->once()) + ->method('search') + ->with('', [], [], null, null) + ->will($this->returnValue($search1)); + + /** @var ICalendar | PHPUnit_Framework_MockObject_MockObject $calendar2 */ + $calendar2 = $this->createMock(ICalendar::class); + $calendar2->method('getKey')->will($this->returnValue('simple:2')); + $calendar2->expects($this->once()) + ->method('search') + ->with('', [], [], null, null) + ->will($this->returnValue($search2)); + + $this->manager->registerCalendar($calendar1); + $this->manager->registerCalendar($calendar2); + + $result = $this->manager->search(''); + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider searchProvider + */ + public function testSearchOptions($search1, $search2, $expected) { + /** @var ICalendar | \PHPUnit_Framework_MockObject_MockObject $calendar1 */ + $calendar1 = $this->createMock(ICalendar::class); + $calendar1->method('getKey')->will($this->returnValue('simple:1')); + $calendar1->expects($this->once()) + ->method('search') + ->with('searchTerm', ['SUMMARY', 'DESCRIPTION'], + ['timerange' => ['start' => null, 'end' => null]], 5, 20) + ->will($this->returnValue($search1)); + + /** @var ICalendar | PHPUnit_Framework_MockObject_MockObject $calendar2 */ + $calendar2 = $this->createMock(ICalendar::class); + $calendar2->method('getKey')->will($this->returnValue('simple:2')); + $calendar2->expects($this->once()) + ->method('search') + ->with('searchTerm', ['SUMMARY', 'DESCRIPTION'], + ['timerange' => ['start' => null, 'end' => null]], 5, 20) + ->will($this->returnValue($search2)); + + $this->manager->registerCalendar($calendar1); + $this->manager->registerCalendar($calendar2); + + $result = $this->manager->search('searchTerm', ['SUMMARY', 'DESCRIPTION'], + ['timerange' => ['start' => null, 'end' => null]], 5, 20); + $this->assertEquals($expected, $result); + } + + public function searchProvider() { + $search1 = [ + [ + 'id' => 1, + 'data' => 'foobar', + ], + [ + 'id' => 2, + 'data' => 'barfoo', + ] + ]; + $search2 = [ + [ + 'id' => 3, + 'data' => 'blablub', + ], + [ + 'id' => 4, + 'data' => 'blubbla', + ] + ]; + + $expected = [ + [ + 'id' => 1, + 'data' => 'foobar', + 'calendar-key' => 'simple:1', + ], + [ + 'id' => 2, + 'data' => 'barfoo', + 'calendar-key' => 'simple:1', + ], + [ + 'id' => 3, + 'data' => 'blablub', + 'calendar-key' => 'simple:2', + ], + [ + 'id' => 4, + 'data' => 'blubbla', + 'calendar-key' => 'simple:2', + ] + ]; + + return [ + [ + $search1, + $search2, + $expected + ] + ]; + } + + public function testRegisterUnregister() { + /** @var ICalendar | \PHPUnit_Framework_MockObject_MockObject $calendar1 */ + $calendar1 = $this->createMock(ICalendar::class); + $calendar1->method('getKey')->will($this->returnValue('key1')); + + /** @var ICalendar | \PHPUnit_Framework_MockObject_MockObject $calendar2 */ + $calendar2 = $this->createMock(ICalendar::class); + $calendar2->method('getKey')->will($this->returnValue('key2')); + + $this->manager->registerCalendar($calendar1); + $this->manager->registerCalendar($calendar2); + + $result = $this->manager->getCalendars(); + $this->assertCount(2, $result); + $this->assertContains($calendar1, $result); + $this->assertContains($calendar2, $result); + + $this->manager->unregisterCalendar($calendar1); + + $result = $this->manager->getCalendars(); + $this->assertCount(1, $result); + $this->assertContains($calendar2, $result); + } + + public function testGetCalendars() { + /** @var ICalendar | \PHPUnit_Framework_MockObject_MockObject $calendar1 */ + $calendar1 = $this->createMock(ICalendar::class); + $calendar1->method('getKey')->will($this->returnValue('key1')); + + /** @var ICalendar | \PHPUnit_Framework_MockObject_MockObject $calendar2 */ + $calendar2 = $this->createMock(ICalendar::class); + $calendar2->method('getKey')->will($this->returnValue('key2')); + + $this->manager->registerCalendar($calendar1); + $this->manager->registerCalendar($calendar2); + + $result = $this->manager->getCalendars(); + $this->assertCount(2, $result); + $this->assertContains($calendar1, $result); + $this->assertContains($calendar2, $result); + + $this->manager->clear(); + + $result = $this->manager->getCalendars(); + + $this->assertCount(0, $result); + } + + public function testEnabledIfNot() { + $isEnabled = $this->manager->isEnabled(); + $this->assertFalse($isEnabled); + } + + public function testIfEnabledIfSo() { + /** @var ICalendar | \PHPUnit_Framework_MockObject_MockObject $calendar */ + $calendar = $this->createMock(ICalendar::class); + $this->manager->registerCalendar($calendar); + + $isEnabled = $this->manager->isEnabled(); + $this->assertTrue($isEnabled); + } + +} From fa416e031b1d630d443c4b484f269d0290e372be Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 7 Nov 2017 01:31:28 +0100 Subject: [PATCH 3/6] integrate Dav app with Calendar API Signed-off-by: Georg Ehrke --- apps/dav/appinfo/app.php | 8 + apps/dav/lib/AppInfo/Application.php | 17 +- apps/dav/lib/CalDAV/CalDavBackend.php | 165 ++++++++++++++++++ apps/dav/lib/CalDAV/CalendarImpl.php | 119 +++++++++++++ apps/dav/lib/CalDAV/CalendarManager.php | 71 ++++++++ .../tests/unit/CalDAV/CalDavBackendTest.php | 109 ++++++++++++ .../tests/unit/CalDAV/CalendarImplTest.php | 126 +++++++++++++ .../tests/unit/CalDAV/CalendarManagerTest.php | 81 +++++++++ 8 files changed, 693 insertions(+), 3 deletions(-) create mode 100644 apps/dav/lib/CalDAV/CalendarImpl.php create mode 100644 apps/dav/lib/CalDAV/CalendarManager.php create mode 100644 apps/dav/tests/unit/CalDAV/CalendarImplTest.php create mode 100644 apps/dav/tests/unit/CalDAV/CalendarManagerTest.php diff --git a/apps/dav/appinfo/app.php b/apps/dav/appinfo/app.php index e312b48d0b..8a534a7597 100644 --- a/apps/dav/appinfo/app.php +++ b/apps/dav/appinfo/app.php @@ -55,3 +55,11 @@ $cm->register(function() use ($cm, $app) { $app->setupContactsProvider($cm, $user->getUID()); } }); + +$calendarManager = \OC::$server->getCalendarManager(); +$calendarManager->register(function() use ($calendarManager, $app) { + $user = \OC::$server->getUserSession()->getUser(); + if ($user !== null) { + $app->setupCalendarProvider($calendarManager, $user->getUID()); + } +}); diff --git a/apps/dav/lib/AppInfo/Application.php b/apps/dav/lib/AppInfo/Application.php index ae08e50d60..a6ca99bfff 100644 --- a/apps/dav/lib/AppInfo/Application.php +++ b/apps/dav/lib/AppInfo/Application.php @@ -29,13 +29,15 @@ use OC\AppFramework\Utility\SimpleContainer; use OCA\DAV\CalDAV\Activity\Backend; use OCA\DAV\CalDAV\Activity\Provider\Event; use OCA\DAV\CalDAV\BirthdayService; +use OCA\DAV\CalDAV\CalendarManager; use OCA\DAV\Capabilities; use OCA\DAV\CardDAV\ContactsManager; use OCA\DAV\CardDAV\PhotoCache; use OCA\DAV\CardDAV\SyncService; use OCA\DAV\HookManager; use \OCP\AppFramework\App; -use OCP\Contacts\IManager; +use OCP\Contacts\IManager as IContactsManager; +use OCP\Calendar\IManager as ICalendarManager; use OCP\IUser; use Symfony\Component\EventDispatcher\GenericEvent; @@ -63,16 +65,25 @@ class Application extends App { } /** - * @param IManager $contactsManager + * @param IContactsManager $contactsManager * @param string $userID */ - public function setupContactsProvider(IManager $contactsManager, $userID) { + public function setupContactsProvider(IContactsManager $contactsManager, $userID) { /** @var ContactsManager $cm */ $cm = $this->getContainer()->query(ContactsManager::class); $urlGenerator = $this->getContainer()->getServer()->getURLGenerator(); $cm->setupContactsProvider($contactsManager, $userID, $urlGenerator); } + /** + * @param ICalendarManager $calendarManager + * @param string $userId + */ + public function setupCalendarProvider(ICalendarManager $calendarManager, $userId) { + $cm = $this->getContainer()->query(CalendarManager::class); + $cm->setupCalendarProvider($calendarManager, $userId); + } + public function registerHooks() { /** @var HookManager $hm */ $hm = $this->getContainer()->query(HookManager::class); diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 9505a00ea5..ee40963dee 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -51,8 +51,12 @@ use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\PropPatch; use Sabre\HTTP\URLUtil; +use Sabre\VObject\Component; use Sabre\VObject\Component\VCalendar; +use Sabre\VObject\Component\VEvent; +use Sabre\VObject\Component\VTimeZone; use Sabre\VObject\DateTimeParser; +use Sabre\VObject\Property; use Sabre\VObject\Reader; use Sabre\VObject\Recur\EventIterator; use Sabre\Uri; @@ -1344,6 +1348,167 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription return $result; } + /** + * used for Nextcloud's calendar API + * + * @param array $calendarInfo + * @param string $pattern + * @param array $searchProperties + * @param array $options + * @param integer|null $limit + * @param integer|null $offset + * + * @return array + */ + public function search(array $calendarInfo, $pattern, array $searchProperties, + array $options, $limit, $offset) { + $outerQuery = $this->db->getQueryBuilder(); + $innerQuery = $this->db->getQueryBuilder(); + + $innerQuery->selectDistinct('op.objectid') + ->from($this->dbObjectPropertiesTable, 'op') + ->andWhere($innerQuery->expr()->eq('op.calendarid', + $outerQuery->createNamedParameter($calendarInfo['id']))); + + // only return public items for shared calendars for now + if ($calendarInfo['principaluri'] !== $calendarInfo['{http://owncloud.org/ns}owner-principal']) { + $innerQuery->andWhere($innerQuery->expr()->eq('c.classification', + $outerQuery->createNamedParameter(self::CLASSIFICATION_PUBLIC))); + } + + $or = $innerQuery->expr()->orX(); + foreach($searchProperties as $searchProperty) { + $or->add($innerQuery->expr()->eq('op.name', + $outerQuery->createNamedParameter($searchProperty))); + } + $innerQuery->andWhere($or); + + // TODO - add component-type + + if ($pattern !== '') { + $innerQuery->andWhere($innerQuery->expr()->iLike('op.value', + $outerQuery->createNamedParameter('%' . + $this->db->escapeLikeParameter($pattern) . '%'))); + } + + $outerQuery->select('c.id', 'c.calendardata', 'c.componenttype', 'c.uid', 'c.uri') + ->from('calendarobjects', 'c'); + + if (isset($options['timerange'])) { + if (isset($options['timerange']['start'])) { + $outerQuery->andWhere($outerQuery->expr()->gt('lastoccurence', + $outerQuery->createNamedParameter($options['timerange']['start']->getTimeStamp))); + + } + if (isset($options['timerange']['end'])) { + $outerQuery->andWhere($outerQuery->expr()->lt('firstoccurence', + $outerQuery->createNamedParameter($options['timerange']['end']->getTimeStamp))); + } + + } + + $outerQuery->andWhere($outerQuery->expr()->in('c.id', + $outerQuery->createFunction($innerQuery->getSQL()))); + + if ($offset) { + $outerQuery->setFirstResult($offset); + } + if ($limit) { + $outerQuery->setMaxResults($limit); + } + + $result = $outerQuery->execute(); + $calendarObjects = $result->fetchAll(); + + return array_map(function($o) { + $calendarData = Reader::read($o['calendardata']); + $comps = $calendarData->getComponents(); + $objects = []; + $timezones = []; + foreach($comps as $comp) { + if ($comp instanceof VTimeZone) { + $timezones[] = $comp; + } else { + $objects[] = $comp; + } + } + + return [ + 'id' => $o['id'], + 'type' => $o['componenttype'], + 'uid' => $o['uid'], + 'uri' => $o['uri'], + 'objects' => array_map(function($c) { + return $this->transformSearchData($c); + }, $objects), + 'timezones' => array_map(function($c) { + return $this->transformSearchData($c); + }, $timezones), + ]; + }, $calendarObjects); + } + + /** + * @param Component $comp + * @return array + */ + private function transformSearchData(Component $comp) { + $data = []; + /** @var Component[] $subComponents */ + $subComponents = $comp->getComponents(); + /** @var Property[] $properties */ + $properties = array_filter($comp->children(), function($c) { + return $c instanceof Property; + }); + $validationRules = $comp->getValidationRules(); + + foreach($subComponents as $subComponent) { + $name = $subComponent->name; + if (!isset($data[$name])) { + $data[$name] = []; + } + $data[$name][] = $this->transformSearchData($subComponent); + } + + foreach($properties as $property) { + $name = $property->name; + if (!isset($validationRules[$name])) { + $validationRules[$name] = '*'; + } + + $rule = $validationRules[$property->name]; + if ($rule === '+' || $rule === '*') { // multiple + if (!isset($data[$name])) { + $data[$name] = []; + } + + $data[$name][] = $this->transformSearchProperty($property); + } else { // once + $data[$name] = $this->transformSearchProperty($property); + } + } + + return $data; + } + + /** + * @param Property $prop + * @return array + */ + private function transformSearchProperty(Property $prop) { + // No need to check Date, as it extends DateTime + if ($prop instanceof Property\ICalendar\DateTime) { + $value = $prop->getDateTime(); + } else { + $value = $prop->getValue(); + } + + return [ + $value, + $prop->parameters() + ]; + } + /** * Searches through all of a users calendars and calendar objects to find * an object with a specific UID. diff --git a/apps/dav/lib/CalDAV/CalendarImpl.php b/apps/dav/lib/CalDAV/CalendarImpl.php new file mode 100644 index 0000000000..cfdf821a56 --- /dev/null +++ b/apps/dav/lib/CalDAV/CalendarImpl.php @@ -0,0 +1,119 @@ + + * + * @author Georg Ehrke + * + * @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\Constants; +use OCP\Calendar\ICalendar; + +class CalendarImpl implements ICalendar { + + /** @var CalDavBackend */ + private $backend; + + /** @var Calendar */ + private $calendar; + + /** @var array */ + private $calendarInfo; + + /** + * CalendarImpl constructor. + * + * @param Calendar $calendar + * @param array $calendarInfo + * @param CalDavBackend $backend + */ + public function __construct(Calendar $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() { + return $this->calendarInfo['id']; + } + + /** + * In comparison to getKey() this function returns a human readable (maybe translated) name + * @return null|string + * @since 13.0.0 + */ + public function getDisplayName() { + return $this->calendarInfo['{DAV:}displayname']; + } + + /** + * Calendar color + * @return null|string + * @since 13.0.0 + */ + public function getDisplayColor() { + 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 integer|null $limit - limit number of search results + * @param integer|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($pattern, array $searchProperties=[], array $options=[], $limit=null, $offset=null) { + return $this->backend->search($this->calendarInfo, $pattern, + $searchProperties, $options, $limit, $offset); + } + + /** + * @return integer build up using \OCP\Constants + * @since 13.0.0 + */ + public function getPermissions() { + $permissions = $this->calendar->getACL(); + $result = 0; + foreach ($permissions as $permission) { + switch($permission['privilege']) { + case '{DAV:}read': + $result |= Constants::PERMISSION_READ; + break; + case '{DAV:}write': + $result |= Constants::PERMISSION_CREATE; + $result |= Constants::PERMISSION_UPDATE; + break; + case '{DAV:}all': + $result |= Constants::PERMISSION_ALL; + break; + } + } + + return $result; + } +} diff --git a/apps/dav/lib/CalDAV/CalendarManager.php b/apps/dav/lib/CalDAV/CalendarManager.php new file mode 100644 index 0000000000..a183ecbdf4 --- /dev/null +++ b/apps/dav/lib/CalDAV/CalendarManager.php @@ -0,0 +1,71 @@ + + * + * @author Georg Ehrke + * + * @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\IManager; +use OCP\IL10N; + +class CalendarManager { + + /** @var CalDavBackend */ + private $backend; + + /** @var IL10N */ + private $l10n; + + /** + * CalendarManager constructor. + * + * @param CalDavBackend $backend + * @param IL10N $l10n + */ + public function __construct(CalDavBackend $backend, IL10N $l10n) { + $this->backend = $backend; + $this->l10n = $l10n; + } + + /** + * @param IManager $cm + * @param string $userId + */ + public function setupCalendarProvider(IManager $cm, $userId) { + $calendars = $this->backend->getCalendarsForUser("principals/users/$userId"); + $this->register($cm, $calendars); + } + + /** + * @param IManager $cm + * @param array $calendars + */ + private function register(IManager $cm, array $calendars) { + foreach($calendars as $calendarInfo) { + $calendar = new Calendar($this->backend, $calendarInfo, $this->l10n); + $cm->registerCalendar(new CalendarImpl( + $calendar, + $calendarInfo, + $this->backend + )); + } + } +} diff --git a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php index fae2156a6b..fc34a7af95 100644 --- a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php +++ b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php @@ -721,4 +721,113 @@ EOD; ]); $this->assertEquals(count($search5), 0); } + + /** + * @dataProvider searchDataProvider + */ + public function testSearch($isShared, $count) { + $calendarId = $this->createTestCalendar(); + + $uris = []; + $calData = []; + + $uris[] = static::getUniqueID('calobj'); + $calData[] = <<backend->createCalendarObject($calendarId, + $uris[$i], $calData[$i]); + } + + $calendarInfo = [ + 'id' => $calendarId, + 'principaluri' => 'user1', + '{http://owncloud.org/ns}owner-principal' => $isShared ? 'user2' : 'user1', + ]; + + $result = $this->backend->search($calendarInfo, 'Test', + ['SUMMARY', 'LOCATION', 'ATTENDEE'], [], null, null); + + $this->assertCount($count, $result); + } + + public function searchDataProvider() { + return [ + [false, 4], + [true, 2], + ]; + } } diff --git a/apps/dav/tests/unit/CalDAV/CalendarImplTest.php b/apps/dav/tests/unit/CalDAV/CalendarImplTest.php new file mode 100644 index 0000000000..ca3256773b --- /dev/null +++ b/apps/dav/tests/unit/CalDAV/CalendarImplTest.php @@ -0,0 +1,126 @@ + + * + * @author Georg Ehrke + * + * @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\CalDavBackend; +use OCA\DAV\CalDAV\Calendar; +use OCA\DAV\CalDAV\CalendarImpl; + +class CalendarImplTest extends \Test\TestCase { + + /** @var CalendarImpl */ + private $calendarImpl; + + /** @var Calendar | \PHPUnit_Framework_MockObject_MockObject */ + private $calendar; + + /** @var array */ + private $calendarInfo; + + /** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject */ + private $backend; + + protected function setUp() { + parent::setUp(); + + $this->calendar = $this->createMock(Calendar::class); + $this->calendarInfo = [ + 'id' => 'fancy_id_123', + '{DAV:}displayname' => 'user readable name 123', + '{http://apple.com/ns/ical/}calendar-color' => '#AABBCC', + ]; + $this->backend = $this->createMock(CalDavBackend::class); + + $this->calendarImpl = new CalendarImpl($this->calendar, + $this->calendarInfo, $this->backend); + } + + + public function testGetKey() { + $this->assertEquals($this->calendarImpl->getKey(), 'fancy_id_123'); + } + + public function testGetDisplayname() { + $this->assertEquals($this->calendarImpl->getDisplayName(),'user readable name 123'); + } + + public function testGetDisplayColor() { + $this->assertEquals($this->calendarImpl->getDisplayColor(), '#AABBCC'); + } + + public function testSearch() { + $this->backend->expects($this->once()) + ->method('search') + ->with($this->calendarInfo, 'abc', ['def'], ['ghi'], 42, 1337) + ->will($this->returnValue(['SEARCHRESULTS'])); + + $result = $this->calendarImpl->search('abc', ['def'], ['ghi'], 42, 1337); + $this->assertEquals($result, ['SEARCHRESULTS']); + } + + public function testGetPermissionRead() { + $this->calendar->expects($this->once()) + ->method('getACL') + ->with() + ->will($this->returnValue([ + ['privilege' => '{DAV:}read'] + ])); + + $this->assertEquals(1, $this->calendarImpl->getPermissions()); + } + + public function testGetPermissionWrite() { + $this->calendar->expects($this->once()) + ->method('getACL') + ->with() + ->will($this->returnValue([ + ['privilege' => '{DAV:}write'] + ])); + + $this->assertEquals(6, $this->calendarImpl->getPermissions()); + } + + public function testGetPermissionReadWrite() { + $this->calendar->expects($this->once()) + ->method('getACL') + ->with() + ->will($this->returnValue([ + ['privilege' => '{DAV:}read'], + ['privilege' => '{DAV:}write'] + ])); + + $this->assertEquals(7, $this->calendarImpl->getPermissions()); + } + + public function testGetPermissionAll() { + $this->calendar->expects($this->once()) + ->method('getACL') + ->with() + ->will($this->returnValue([ + ['privilege' => '{DAV:}all'] + ])); + + $this->assertEquals(31, $this->calendarImpl->getPermissions()); + } +} diff --git a/apps/dav/tests/unit/CalDAV/CalendarManagerTest.php b/apps/dav/tests/unit/CalDAV/CalendarManagerTest.php new file mode 100644 index 0000000000..db8c536da5 --- /dev/null +++ b/apps/dav/tests/unit/CalDAV/CalendarManagerTest.php @@ -0,0 +1,81 @@ + + * + * @author Georg Ehrke + * + * @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 OC\Calendar\Manager; +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CalDAV\CalendarImpl; +use OCA\DAV\CalDAV\CalendarManager; +use OCP\Calendar\IManager; +use OCP\IL10N; + +class CalendarManagerTest extends \Test\TestCase { + + /** @var CalDavBackend | \PHPUnit_Framework_MockObject_MockObject */ + private $backend; + + /** @var IL10N | \PHPUnit_Framework_MockObject_MockObject */ + private $l10n; + + /** @var CalendarManager */ + private $manager; + + protected function setUp() { + parent::setUp(); + $this->backend = $this->createMock(CalDavBackend::class); + $this->l10n = $this->createMock(IL10N::class); + $this->manager = new CalendarManager($this->backend, + $this->l10n); + } + + public function testSetupCalendarProvider() { + $this->backend->expects($this->once()) + ->method('getCalendarsForUser') + ->with('principals/users/user123') + ->will($this->returnValue([ + ['id' => 123, 'uri' => 'blablub1'], + ['id' => 456, 'uri' => 'blablub2'], + ])); + + /** @var IManager | \PHPUnit_Framework_MockObject_MockObject $calendarManager */ + $calendarManager = $this->createMock(Manager::class); + $calendarManager->expects($this->at(0)) + ->method('registerCalendar') + ->will($this->returnCallback(function() { + $parameter = func_get_arg(0); + $this->assertInstanceOf(CalendarImpl::class, $parameter); + $this->assertEquals(123, $parameter->getKey()); + })); + + $calendarManager->expects($this->at(1)) + ->method('registerCalendar') + ->will($this->returnCallback(function() { + $parameter = func_get_arg(0); + $this->assertInstanceOf(CalendarImpl::class, $parameter); + $this->assertEquals(456, $parameter->getKey()); + })); + + $this->manager->setupCalendarProvider($calendarManager, 'user123'); + } +} From f06fc67e8e34273fc1d69d3e3697a268201cb074 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Thu, 9 Nov 2017 12:35:47 +0100 Subject: [PATCH 4/6] update autoloader to included added classes and interface Signed-off-by: Georg Ehrke --- lib/composer/composer/autoload_classmap.php | 3 +++ lib/composer/composer/autoload_static.php | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 39b91f8dc9..8b5c781161 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -66,6 +66,8 @@ return array( 'OCP\\BackgroundJob' => $baseDir . '/lib/public/BackgroundJob.php', 'OCP\\BackgroundJob\\IJob' => $baseDir . '/lib/public/BackgroundJob/IJob.php', 'OCP\\BackgroundJob\\IJobList' => $baseDir . '/lib/public/BackgroundJob/IJobList.php', + 'OCP\\Calendar\\ICalendar' => $baseDir . '/lib/public/Calendar/ICalendar.php', + 'OCP\\Calendar\\IManager' => $baseDir . '/lib/public/Calendar/IManager.php', 'OCP\\Capabilities\\ICapability' => $baseDir . '/lib/public/Capabilities/ICapability.php', 'OCP\\Capabilities\\IPublicCapability' => $baseDir . '/lib/public/Capabilities/IPublicCapability.php', 'OCP\\Collaboration\\AutoComplete\\IManager' => $baseDir . '/lib/public/Collaboration/AutoComplete/IManager.php', @@ -392,6 +394,7 @@ return array( 'OC\\BackgroundJob\\TimedJob' => $baseDir . '/lib/private/BackgroundJob/TimedJob.php', 'OC\\Cache\\CappedMemoryCache' => $baseDir . '/lib/private/Cache/CappedMemoryCache.php', 'OC\\Cache\\File' => $baseDir . '/lib/private/Cache/File.php', + 'OC\\Calendar\\Manager' => $baseDir . '/lib/private/Calendar/Manager.php', 'OC\\CapabilitiesManager' => $baseDir . '/lib/private/CapabilitiesManager.php', 'OC\\Collaboration\\AutoComplete\\Manager' => $baseDir . '/lib/private/Collaboration/AutoComplete/Manager.php', 'OC\\Collaboration\\Collaborators\\GroupPlugin' => $baseDir . '/lib/private/Collaboration/Collaborators/GroupPlugin.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index e5a9808670..11e1ec6ef1 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -96,6 +96,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\BackgroundJob' => __DIR__ . '/../../..' . '/lib/public/BackgroundJob.php', 'OCP\\BackgroundJob\\IJob' => __DIR__ . '/../../..' . '/lib/public/BackgroundJob/IJob.php', 'OCP\\BackgroundJob\\IJobList' => __DIR__ . '/../../..' . '/lib/public/BackgroundJob/IJobList.php', + 'OCP\\Calendar\\ICalendar' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendar.php', + 'OCP\\Calendar\\IManager' => __DIR__ . '/../../..' . '/lib/public/Calendar/IManager.php', 'OCP\\Capabilities\\ICapability' => __DIR__ . '/../../..' . '/lib/public/Capabilities/ICapability.php', 'OCP\\Capabilities\\IPublicCapability' => __DIR__ . '/../../..' . '/lib/public/Capabilities/IPublicCapability.php', 'OCP\\Collaboration\\AutoComplete\\IManager' => __DIR__ . '/../../..' . '/lib/public/Collaboration/AutoComplete/IManager.php', @@ -422,6 +424,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\BackgroundJob\\TimedJob' => __DIR__ . '/../../..' . '/lib/private/BackgroundJob/TimedJob.php', 'OC\\Cache\\CappedMemoryCache' => __DIR__ . '/../../..' . '/lib/private/Cache/CappedMemoryCache.php', 'OC\\Cache\\File' => __DIR__ . '/../../..' . '/lib/private/Cache/File.php', + 'OC\\Calendar\\Manager' => __DIR__ . '/../../..' . '/lib/private/Calendar/Manager.php', 'OC\\CapabilitiesManager' => __DIR__ . '/../../..' . '/lib/private/CapabilitiesManager.php', 'OC\\Collaboration\\AutoComplete\\Manager' => __DIR__ . '/../../..' . '/lib/private/Collaboration/AutoComplete/Manager.php', 'OC\\Collaboration\\Collaborators\\GroupPlugin' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/GroupPlugin.php', From dd13aecc88b40bb2374a429ef4dd2dbc57e29a91 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Thu, 9 Nov 2017 13:54:35 +0100 Subject: [PATCH 5/6] update dav autoloaders after adding calendar api Signed-off-by: Georg Ehrke --- apps/dav/composer/composer/autoload_classmap.php | 2 ++ apps/dav/composer/composer/autoload_static.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php index f29e3a7b29..24a6b88502 100644 --- a/apps/dav/composer/composer/autoload_classmap.php +++ b/apps/dav/composer/composer/autoload_classmap.php @@ -25,6 +25,8 @@ return array( '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', + 'OCA\\DAV\\CalDAV\\CalendarImpl' => $baseDir . '/../lib/CalDAV/CalendarImpl.php', + 'OCA\\DAV\\CalDAV\\CalendarManager' => $baseDir . '/../lib/CalDAV/CalendarManager.php', 'OCA\\DAV\\CalDAV\\CalendarObject' => $baseDir . '/../lib/CalDAV/CalendarObject.php', 'OCA\\DAV\\CalDAV\\CalendarRoot' => $baseDir . '/../lib/CalDAV/CalendarRoot.php', 'OCA\\DAV\\CalDAV\\Plugin' => $baseDir . '/../lib/CalDAV/Plugin.php', diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php index 412666a8aa..1c76848222 100644 --- a/apps/dav/composer/composer/autoload_static.php +++ b/apps/dav/composer/composer/autoload_static.php @@ -40,6 +40,8 @@ class ComposerStaticInitDAV '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', + 'OCA\\DAV\\CalDAV\\CalendarImpl' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarImpl.php', + 'OCA\\DAV\\CalDAV\\CalendarManager' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarManager.php', 'OCA\\DAV\\CalDAV\\CalendarObject' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarObject.php', 'OCA\\DAV\\CalDAV\\CalendarRoot' => __DIR__ . '/..' . '/../lib/CalDAV/CalendarRoot.php', 'OCA\\DAV\\CalDAV\\Plugin' => __DIR__ . '/..' . '/../lib/CalDAV/Plugin.php', From 7784672cc00c83f1bfce57fc61eebe40c8f8c8a8 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Thu, 9 Nov 2017 15:08:30 +0100 Subject: [PATCH 6/6] add option to filter CalendarAPI by componenttype Signed-off-by: Georg Ehrke --- apps/dav/lib/CalDAV/CalDavBackend.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index ee40963dee..9045a62cde 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -1383,8 +1383,6 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription } $innerQuery->andWhere($or); - // TODO - add component-type - if ($pattern !== '') { $innerQuery->andWhere($innerQuery->expr()->iLike('op.value', $outerQuery->createNamedParameter('%' . @@ -1404,7 +1402,15 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription $outerQuery->andWhere($outerQuery->expr()->lt('firstoccurence', $outerQuery->createNamedParameter($options['timerange']['end']->getTimeStamp))); } + } + if (isset($options['types'])) { + $or = $outerQuery->expr()->orX(); + foreach($options['types'] as $type) { + $or->add($outerQuery->expr()->eq('componenttype', + $outerQuery->createNamedParameter($type))); + } + $outerQuery->andWhere($or); } $outerQuery->andWhere($outerQuery->expr()->in('c.id',