summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Steinmetz <richard@steinmetz.cloud>2023-09-20 17:45:54 +0200
committerbackportbot-nextcloud[bot] <backportbot-nextcloud[bot]@users.noreply.github.com>2023-09-26 08:04:33 +0000
commit28f58a8af9b3ec2bd73176ba97982368a557f86e (patch)
tree93517e658adbf80ca93222441bcffb39875c9b43
parent2ebd5bb939a2e57b569bc6713290af67a3d91689 (diff)
downloadnextcloud-server-28f58a8af9b3ec2bd73176ba97982368a557f86e.tar.gz
nextcloud-server-28f58a8af9b3ec2bd73176ba97982368a557f86e.zip
fix(dav): expand recurrences when searching
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
-rw-r--r--apps/dav/lib/CalDAV/CalDavBackend.php13
-rw-r--r--apps/dav/tests/unit/CalDAV/CalDavBackendTest.php69
2 files changed, 81 insertions, 1 deletions
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php
index 4c1acfbfbfe..672543460c3 100644
--- a/apps/dav/lib/CalDAV/CalDavBackend.php
+++ b/apps/dav/lib/CalDAV/CalDavBackend.php
@@ -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 = [];
diff --git a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php
index 1be42c22ed7..868205301dd 100644
--- a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php
+++ b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php
@@ -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',
+ );
+ }
+ }
+ }
}