]> source.dussan.org Git - nextcloud-server.git/commitdiff
Provide dav setting for user's default calendar
authorThomas Citharel <tcit@tcit.fr>
Sun, 8 Mar 2020 16:33:27 +0000 (17:33 +0100)
committerThomas Citharel <tcit@tcit.fr>
Mon, 13 Apr 2020 13:07:42 +0000 (15:07 +0200)
And add tests to handle schedule-default-calendar-URL

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
apps/dav/appinfo/v1/caldav.php
apps/dav/lib/AppInfo/Application.php
apps/dav/lib/CalDAV/InvitationResponse/InvitationResponseServer.php
apps/dav/lib/CalDAV/Schedule/Plugin.php
apps/dav/lib/Server.php
apps/dav/tests/unit/CalDAV/Schedule/PluginTest.php

index 82fddd152e64927649763a9497cedbde14df10b6..29733a3a6235c9c468ec1656c8be739ffcbbc7e5 100644 (file)
@@ -92,7 +92,7 @@ if ($debugging) {
 
 $server->addPlugin(new \Sabre\DAV\Sync\Plugin());
 $server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
-$server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
+$server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin(\OC::$server->getConfig()));
 
 if ($sendInvitations) {
        $server->addPlugin(\OC::$server->query(\OCA\DAV\CalDAV\Schedule\IMipPlugin::class));
index 29c77cad07f624ae9a6d3e474e710973c821566c..c22afa755cbb38633b441ab3a597059a5483276f 100644 (file)
@@ -49,6 +49,7 @@ use OCA\DAV\HookManager;
 use OCP\AppFramework\App;
 use OCP\Calendar\IManager as ICalendarManager;
 use OCP\Contacts\IManager as IContactsManager;
+use OCP\IConfig;
 use OCP\IUser;
 use Symfony\Component\EventDispatcher\GenericEvent;
 
@@ -244,6 +245,19 @@ class Application extends App {
                $dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', $listener);
                $dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', $listener);
                $dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject', $listener);
+
+               /**
+                * In case the user has set their default calendar to this one
+                */
+               $dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar', function (GenericEvent $event) {
+                       /** @var IConfig $config */
+                       $config = $this->getContainer()->getServer()->getConfig();
+                       $principalUri = $event->getArgument('calendarData')['principaluri'];
+                       if (strpos($principalUri, 'principals/users') === 0) {
+                               list(, $UID) = \Sabre\Uri\split($principalUri);
+                               $config->deleteUserValue($UID, 'dav', 'defaultCalendar');
+                       }
+               });
        }
 
        public function getSyncService() {
index e285bbc378c9f8729c88d7c971b7e25e3d140fae..ce8d0542eaf47f8327985af736c9847020456302 100644 (file)
@@ -84,7 +84,7 @@ class InvitationResponseServer {
                // calendar plugins
                $this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin());
                $this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
-               $this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
+               $this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin(\OC::$server->getConfig()));
                $this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
                $this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
                //$this->server->addPlugin(new \OCA\DAV\DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
index 3b2f0374b46164a2c4560adc85da1eb22bc3073b..9c5968a333cfb119797e7e636ea8c24125e6306c 100644 (file)
@@ -29,6 +29,7 @@ namespace OCA\DAV\CalDAV\Schedule;
 use DateTimeZone;
 use OCA\DAV\CalDAV\CalDavBackend;
 use OCA\DAV\CalDAV\CalendarHome;
+use OCP\IConfig;
 use Sabre\CalDAV\ICalendar;
 use Sabre\DAV\INode;
 use Sabre\DAV\IProperties;
@@ -47,15 +48,31 @@ use Sabre\VObject\ITip;
 use Sabre\VObject\Parameter;
 use Sabre\VObject\Property;
 use Sabre\VObject\Reader;
+use function \Sabre\Uri\split;
 
 class Plugin extends \Sabre\CalDAV\Schedule\Plugin {
 
+       /**
+        * @var IConfig
+        */
+       private $config;
+
        /** @var ITip\Message[] */
        private $schedulingResponses = [];
 
        /** @var string|null */
        private $pathOfCalendarObjectChange = null;
 
+       public const CALENDAR_USER_TYPE = '{' . self::NS_CALDAV . '}calendar-user-type';
+       public const SCHEDULE_DEFAULT_CALENDAR_URL = '{' . Plugin::NS_CALDAV . '}schedule-default-calendar-URL';
+
+       /**
+        * @param IConfig $config
+        */
+       public function __construct(IConfig $config) {
+               $this->config = $config;
+       }
+
        /**
         * Initializes the plugin
         *
@@ -81,13 +98,12 @@ class Plugin extends \Sabre\CalDAV\Schedule\Plugin {
        public function propFind(PropFind $propFind, INode $node) {
                if ($node instanceof IPrincipal) {
                        // overwrite Sabre/Dav's implementation
-                       $propFind->handle('{' . self::NS_CALDAV . '}calendar-user-type', function () use ($node) {
+                       $propFind->handle(self::CALENDAR_USER_TYPE, function () use ($node) {
                                if ($node instanceof IProperties) {
-                                       $calendarUserType = '{' . self::NS_CALDAV . '}calendar-user-type';
-                                       $props = $node->getProperties([$calendarUserType]);
+                                       $props = $node->getProperties([self::CALENDAR_USER_TYPE]);
 
-                                       if (isset($props[$calendarUserType])) {
-                                               return $props[$calendarUserType];
+                                       if (isset($props[self::CALENDAR_USER_TYPE])) {
+                                               return $props[self::CALENDAR_USER_TYPE];
                                        }
                                }
 
@@ -261,7 +277,7 @@ EOF;
         */
        public function propFindDefaultCalendarUrl(PropFind $propFind, INode $node) {
                if ($node instanceof IPrincipal) {
-                       $propFind->handle('{' . self::NS_CALDAV . '}schedule-default-calendar-URL', function () use ($node) {
+                       $propFind->handle(self::SCHEDULE_DEFAULT_CALENDAR_URL, function () use ($node) {
                                /** @var \OCA\DAV\CalDAV\Plugin $caldavPlugin */
                                $caldavPlugin = $this->server->getPlugin('caldav');
                                $principalUrl = $node->getPrincipalUrl();
@@ -272,12 +288,13 @@ EOF;
                                }
 
                                if (strpos($principalUrl, 'principals/users') === 0) {
-                                       $uri = CalDavBackend::PERSONAL_CALENDAR_URI;
-                                       $displayname = CalDavBackend::PERSONAL_CALENDAR_NAME;
+                                       list(, $userId) = split($principalUrl);
+                                       $uri = $this->config->getUserValue($userId, 'dav', 'defaultCalendar', CalDavBackend::PERSONAL_CALENDAR_URI);
+                                       $displayName = CalDavBackend::PERSONAL_CALENDAR_NAME;
                                } elseif (strpos($principalUrl, 'principals/calendar-resources') === 0 ||
                                                  strpos($principalUrl, 'principals/calendar-rooms') === 0) {
                                        $uri = CalDavBackend::RESOURCE_BOOKING_CALENDAR_URI;
-                                       $displayname = CalDavBackend::RESOURCE_BOOKING_CALENDAR_NAME;
+                                       $displayName = CalDavBackend::RESOURCE_BOOKING_CALENDAR_NAME;
                                } else {
                                        // How did we end up here?
                                        // TODO - throw exception or just ignore?
@@ -288,7 +305,7 @@ EOF;
                                $calendarHome = $this->server->tree->getNodeForPath($calendarHomePath);
                                if (!$calendarHome->childExists($uri)) {
                                        $calendarHome->getCalDAVBackend()->createCalendar($principalUrl, $uri, [
-                                               '{DAV:}displayname' => $displayname,
+                                               '{DAV:}displayname' => $displayName,
                                        ]);
                                }
 
index b71c16e2319b1f288fb8129278d8126db2dd18c8..9d120ddbdbf433753d562faa141c1e3a9eb52a17 100644 (file)
@@ -151,7 +151,7 @@ class Server {
                if ($this->requestIsForSubtree(['calendars', 'public-calendars', 'system-calendars', 'principals'])) {
                        $this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin());
                        $this->server->addPlugin(new \OCA\DAV\CalDAV\ICSExportPlugin\ICSExportPlugin(\OC::$server->getConfig(), \OC::$server->getLogger()));
-                       $this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
+                       $this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin(\OC::$server->getConfig()));
                        if (\OC::$server->getConfig()->getAppValue('dav', 'sendInvitations', 'yes') === 'yes') {
                                $this->server->addPlugin(\OC::$server->query(\OCA\DAV\CalDAV\Schedule\IMipPlugin::class));
                        }
index 859dccbe48911422f6c3c4ac8d2b5a6ae7815bf2..aa245b71419db98df04586019ff53a7234d27cd6 100644 (file)
 
 namespace OCA\DAV\Tests\unit\CalDAV\Schedule;
 
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\CalDAV\CalendarHome;
+use OCA\DAV\CalDAV\Plugin as CalDAVPlugin;
 use OCA\DAV\CalDAV\Schedule\Plugin;
+use OCP\IConfig;
+use PHPUnit\Framework\MockObject\MockObject;
+use Sabre\DAV\PropFind;
 use Sabre\DAV\Server;
+use Sabre\DAV\Tree;
 use Sabre\DAV\Xml\Property\Href;
+use Sabre\DAV\Xml\Property\LocalHref;
+use Sabre\DAVACL\IPrincipal;
+use Sabre\HTTP\ResponseInterface;
 use Sabre\VObject\Parameter;
 use Sabre\VObject\Property\ICalendar\CalAddress;
+use Sabre\Xml\Service;
 use Test\TestCase;
 
 class PluginTest extends TestCase {
        /** @var Plugin */
        private $plugin;
-       /** @var Server|\PHPUnit_Framework_MockObject_MockObject */
+       /** @var Server|MockObject */
        private $server;
 
+       /** @var IConfig|MockObject  */
+       private $config;
+
        protected function setUp(): void {
                parent::setUp();
 
                $this->server = $this->createMock(Server::class);
+               $this->config = $this->createMock(IConfig::class);
+
+               $response = $this->getMockBuilder(ResponseInterface::class)
+                       ->disableOriginalConstructor()
+                       ->getMock();
 
-               $this->plugin = new Plugin();
+               $this->server->httpResponse = $response;
+               $this->server->xml = new Service();
+
+               $this->plugin = new Plugin($this->config);
                $this->plugin->initialize($this->server);
        }
 
+       public function testInitialize() {
+               $plugin = new Plugin($this->config);
+
+               $this->server->expects($this->at(7))
+                       ->method('on')
+                       ->with('propFind', [$plugin, 'propFindDefaultCalendarUrl'], 90);
+
+               $this->server->expects($this->at(8))
+                       ->method('on')
+                       ->with('afterWriteContent', [$plugin, 'dispatchSchedulingResponses']);
+
+               $this->server->expects($this->at(9))
+                       ->method('on')
+                       ->with('afterCreateFile', [$plugin, 'dispatchSchedulingResponses']);
+
+               $plugin->initialize($this->server);
+       }
+
        public function testGetAddressesForPrincipal() {
                $href = $this->createMock(Href::class);
                $href
@@ -125,4 +165,183 @@ class PluginTest extends TestCase {
                $this->assertFalse($this->invokePrivate($this->plugin, 'getAttendeeRSVP', [$property2]));
                $this->assertFalse($this->invokePrivate($this->plugin, 'getAttendeeRSVP', [$property3]));
        }
+
+       public function propFindDefaultCalendarUrlProvider(): array {
+               return [
+                       [
+                               'principals/users/myuser',
+                               'calendars/myuser',
+                               false,
+                               CalDavBackend::PERSONAL_CALENDAR_URI,
+                               CalDavBackend::PERSONAL_CALENDAR_NAME,
+                               true
+                       ],
+                       [
+                               'principals/users/myuser',
+                               'calendars/myuser',
+                               false,
+                               CalDavBackend::PERSONAL_CALENDAR_URI,
+                               CalDavBackend::PERSONAL_CALENDAR_NAME,
+                               false
+                       ],
+                       [
+                               'principals/users/myuser',
+                               null,
+                               false,
+                               CalDavBackend::PERSONAL_CALENDAR_URI,
+                               CalDavBackend::PERSONAL_CALENDAR_NAME,
+                               true
+                       ],
+                       [
+                               'principals/users/myuser',
+                               'calendars/myuser',
+                               false,
+                               CalDavBackend::PERSONAL_CALENDAR_URI,
+                               CalDavBackend::PERSONAL_CALENDAR_NAME,
+                               true,
+                               false,
+                       ],
+                       [
+                               'principals/users/myuser',
+                               'calendars/myuser',
+                               false,
+                               'my_other_calendar',
+                               'My Other Calendar',
+                               true
+                       ],
+                       [
+                               'principals/calendar-resources',
+                               'system-calendars/calendar-resources/myuser',
+                               true,
+                               CalDavBackend::RESOURCE_BOOKING_CALENDAR_URI,
+                               CalDavBackend::RESOURCE_BOOKING_CALENDAR_NAME,
+                               true
+                       ],
+                       [
+                               'principals/calendar-resources',
+                               'system-calendars/calendar-resources/myuser',
+                               true,
+                               CalDavBackend::RESOURCE_BOOKING_CALENDAR_URI,
+                               CalDavBackend::RESOURCE_BOOKING_CALENDAR_NAME,
+                               false
+                       ],
+                       [
+                               'principals/something-else',
+                               'calendars/whatever',
+                               false,
+                               CalDavBackend::PERSONAL_CALENDAR_URI,
+                               CalDavBackend::PERSONAL_CALENDAR_NAME,
+                               true
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider propFindDefaultCalendarUrlProvider
+        * @param string $principalUri
+        * @param string $calendarHome
+        * @param bool $isResource
+        * @param string $calendarUri
+        * @param string $displayName
+        * @param bool $exists
+        * @param bool $propertiesForPath
+        */
+       public function testPropFindDefaultCalendarUrl(string $principalUri, ?string $calendarHome, bool $isResource, string $calendarUri, string $displayName, bool $exists, bool $propertiesForPath = true) {
+               /** @var PropFind $propFind */
+               $propFind = new PropFind(
+                       $principalUri,
+                       [
+                               Plugin::SCHEDULE_DEFAULT_CALENDAR_URL
+                       ],
+                       0
+               );
+               /** @var IPrincipal|MockObject $node */
+               $node = $this->getMockBuilder(IPrincipal::class)
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $node->expects($this->once())
+                       ->method('getPrincipalUrl')
+                       ->with()
+                       ->willReturn($principalUri);
+
+               $calDAVPlugin = $this->getMockBuilder(CalDAVPlugin::class)
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $calDAVPlugin->expects($this->once())
+                       ->method('getCalendarHomeForPrincipal')
+                       ->willReturn($calendarHome);
+
+               $this->server->expects($this->once())
+                       ->method('getPlugin')
+                       ->with('caldav')
+                       ->willReturn($calDAVPlugin);
+               if (!$calendarHome) {
+                       $this->plugin->propFindDefaultCalendarUrl($propFind, $node);
+
+                       $this->assertNull($propFind->get(Plugin::SCHEDULE_DEFAULT_CALENDAR_URL));
+                       return;
+               }
+               if ($principalUri === 'principals/something-else') {
+                       $this->plugin->propFindDefaultCalendarUrl($propFind, $node);
+
+                       $this->assertNull($propFind->get(Plugin::SCHEDULE_DEFAULT_CALENDAR_URL));
+                       return;
+               }
+               if (!$isResource) {
+                       $this->config->expects($this->once())
+                               ->method('getUserValue')
+                               ->with('myuser', 'dav', 'defaultCalendar', CalDavBackend::PERSONAL_CALENDAR_URI)
+                               ->willReturn($calendarUri);
+               }
+
+               $calendarHomeObject = $this->createMock(CalendarHome::class);
+               $calendarHomeObject->expects($this->once())
+                       ->method('childExists')
+                       ->with($calendarUri)
+                       ->willReturn($exists);
+
+               if (!$exists) {
+                       $calendarBackend = $this->createMock(CalDavBackend::class);
+                       $calendarBackend->expects($this->once())
+                               ->method('createCalendar')
+                               ->with($principalUri, $calendarUri, [
+                                       '{DAV:}displayname' => $displayName,
+                               ]);
+
+                       $calendarHomeObject->expects($this->once())
+                               ->method('getCalDAVBackend')
+                               ->with()
+                               ->willReturn($calendarBackend);
+               }
+
+               /** @var Tree|MockObject $tree */
+               $tree = $this->createMock(Tree::class);
+               $tree->expects($this->once())
+                       ->method('getNodeForPath')
+                       ->with($calendarHome)
+                       ->willReturn($calendarHomeObject);
+               $this->server->tree = $tree;
+
+               $properties = $propertiesForPath ? [
+                       ['href' => '/remote.php/dav/' . $calendarHome . '/' . $calendarUri]
+               ] : [];
+
+               $this->server->expects($this->once())
+                       ->method('getPropertiesForPath')
+                       ->with($calendarHome .'/' . $calendarUri, [], 1)
+                       ->willReturn($properties);
+
+               $this->plugin->propFindDefaultCalendarUrl($propFind, $node);
+
+               if (!$propertiesForPath) {
+                       $this->assertNull($propFind->get(Plugin::SCHEDULE_DEFAULT_CALENDAR_URL));
+                       return;
+               }
+
+               /** @var LocalHref $result */
+               $result = $propFind->get(Plugin::SCHEDULE_DEFAULT_CALENDAR_URL);
+               $this->assertEquals('/remote.php/dav/'. $calendarHome . '/' . $calendarUri, $result->getHref());
+       }
 }