]> source.dussan.org Git - nextcloud-server.git/commitdiff
fix(dav): expand recurrences when searching 40541/head
authorRichard Steinmetz <richard@steinmetz.cloud>
Wed, 20 Sep 2023 15:45:54 +0000 (17:45 +0200)
committerRichard Steinmetz <richard@steinmetz.cloud>
Thu, 21 Sep 2023 21:28:35 +0000 (23:28 +0200)
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
apps/dav/lib/CalDAV/CalDavBackend.php
apps/dav/tests/unit/CalDAV/CalDavBackendTest.php

index 915976d7dd3e667da3cbd6275a34963ef51ddd4b..5f2fe7e5dcead00942916b7140d62aa5251fde67 100644 (file)
@@ -20,6 +20,7 @@
  * @author Thomas Citharel <nextcloud@tcit.fr>
  * @author Thomas Müller <thomas.mueller@tmit.eu>
  * @author Vinicius Cubas Brand <vinicius@eita.org.br>
+ * @author Richard Steinmetz <richard@steinmetz.cloud>
  *
  * @license AGPL-3.0
  *
@@ -1959,8 +1960,18 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
                });
                $result->closeCursor();
 
-               return array_map(function ($o) {
+               return array_map(function ($o) use ($options) {
                        $calendarData = Reader::read($o['calendardata']);
+
+                       // Expand recurrences if an explicit time range is requested
+                       if ($calendarData instanceof VCalendar
+                               && isset($options['timerange']['start'], $options['timerange']['end'])) {
+                               $calendarData = $calendarData->expand(
+                                       $options['timerange']['start'],
+                                       $options['timerange']['end'],
+                               );
+                       }
+
                        $comps = $calendarData->getComponents();
                        $objects = [];
                        $timezones = [];
index 3da6ca61b7e9cb51c7970347848cf798e3e0bc03..b23091275ef18e59665393d19f762e33bf11b9c0 100644 (file)
@@ -32,7 +32,9 @@
 
 namespace OCA\DAV\Tests\unit\CalDAV;
 
+use DateInterval;
 use DateTime;
+use DateTimeImmutable;
 use DateTimeZone;
 use OCA\DAV\CalDAV\CalDavBackend;
 use OCA\DAV\CalDAV\Calendar;
@@ -1420,4 +1422,71 @@ EOD;
                // Check that no crash occurs when prune is called without current changes
                $deleted = $this->backend->pruneOutdatedSyncTokens(1);
        }
+
+       public function testSearchAndExpandRecurrences() {
+               $calendarId = $this->createTestCalendar();
+               $calendarInfo = [
+                       'id' => $calendarId,
+                       'principaluri' => 'user1',
+                       '{http://owncloud.org/ns}owner-principal' => 'user1',
+               ];
+
+               $calData = <<<'EOD'
+BEGIN:VCALENDAR
+PRODID:-//IDN nextcloud.com//Calendar app 4.5.0-alpha.2//EN
+CALSCALE:GREGORIAN
+VERSION:2.0
+BEGIN:VEVENT
+CREATED:20230921T133401Z
+DTSTAMP:20230921T133448Z
+LAST-MODIFIED:20230921T133448Z
+SEQUENCE:2
+UID:7b7d5d12-683c-48ce-973a-b3e1cb0bae2a
+DTSTART;VALUE=DATE:20230912
+DTEND;VALUE=DATE:20230913
+STATUS:CONFIRMED
+SUMMARY:Daily Event
+RRULE:FREQ=DAILY
+END:VEVENT
+END:VCALENDAR
+EOD;
+               $uri = static::getUniqueID('calobj');
+               $this->backend->createCalendarObject($calendarId, $uri, $calData);
+
+               $start = new DateTimeImmutable('2023-09-20T00:00:00Z');
+               $end = $start->add(new DateInterval('P14D'));
+
+               $results = $this->backend->search(
+                       $calendarInfo,
+                       '',
+                       [],
+                       [
+                               'timerange' => [
+                                       'start' => $start,
+                                       'end' => $end,
+                               ]
+                       ],
+                       null,
+                       null,
+               );
+
+               $this->assertCount(1, $results);
+               $this->assertCount(14, $results[0]['objects']);
+               foreach ($results as $result) {
+                       foreach ($result['objects'] as $object) {
+                               $this->assertEquals($object['UID'][0], '7b7d5d12-683c-48ce-973a-b3e1cb0bae2a');
+                               $this->assertEquals($object['SUMMARY'][0], 'Daily Event');
+                               $this->assertGreaterThanOrEqual(
+                                       $start->getTimestamp(),
+                                       $object['DTSTART'][0]->getTimestamp(),
+                                       'Recurrence starting before requested start',
+                               );
+                               $this->assertLessThanOrEqual(
+                                       $end->getTimestamp(),
+                                       $object['DTSTART'][0]->getTimestamp(),
+                                       'Recurrence starting after requested end',
+                               );
+                       }
+               }
+       }
 }