Skip to content

Commit 9c5cf4b

Browse files
authored
Merge pull request #40635 from nextcloud/fix/dav/expand-recurrences-in-search-stable25
[stable25] fix(dav): expand recurrences when searching
2 parents c60d890 + a4a0a1f commit 9c5cf4b

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

apps/dav/lib/CalDAV/CalDavBackend.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* @author Thomas Citharel <[email protected]>
2121
* @author Thomas Müller <[email protected]>
2222
* @author Vinicius Cubas Brand <[email protected]>
23+
* @author Richard Steinmetz <[email protected]>
2324
*
2425
* @license AGPL-3.0
2526
*
@@ -1951,8 +1952,18 @@ public function search(array $calendarInfo, $pattern, array $searchProperties,
19511952
});
19521953
$result->closeCursor();
19531954

1954-
return array_map(function ($o) {
1955+
return array_map(function ($o) use ($options) {
19551956
$calendarData = Reader::read($o['calendardata']);
1957+
1958+
// Expand recurrences if an explicit time range is requested
1959+
if ($calendarData instanceof VCalendar
1960+
&& isset($options['timerange']['start'], $options['timerange']['end'])) {
1961+
$calendarData = $calendarData->expand(
1962+
$options['timerange']['start'],
1963+
$options['timerange']['end'],
1964+
);
1965+
}
1966+
19561967
$comps = $calendarData->getComponents();
19571968
$objects = [];
19581969
$timezones = [];

apps/dav/tests/unit/CalDAV/CalDavBackendTest.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232

3333
namespace OCA\DAV\Tests\unit\CalDAV;
3434

35+
use DateInterval;
3536
use DateTime;
37+
use DateTimeImmutable;
3638
use DateTimeZone;
3739
use OCA\DAV\CalDAV\CalDavBackend;
3840
use OCA\DAV\CalDAV\Calendar;
@@ -1283,4 +1285,71 @@ public function testSearchPrincipal(): void {
12831285
$this->assertEquals($sharerPrivate, $sharerSearchResults[1]['calendardata']);
12841286
$this->assertEquals($sharerConfidential, $sharerSearchResults[2]['calendardata']);
12851287
}
1288+
1289+
public function testSearchAndExpandRecurrences() {
1290+
$calendarId = $this->createTestCalendar();
1291+
$calendarInfo = [
1292+
'id' => $calendarId,
1293+
'principaluri' => 'user1',
1294+
'{http://owncloud.org/ns}owner-principal' => 'user1',
1295+
];
1296+
1297+
$calData = <<<'EOD'
1298+
BEGIN:VCALENDAR
1299+
PRODID:-//IDN nextcloud.com//Calendar app 4.5.0-alpha.2//EN
1300+
CALSCALE:GREGORIAN
1301+
VERSION:2.0
1302+
BEGIN:VEVENT
1303+
CREATED:20230921T133401Z
1304+
DTSTAMP:20230921T133448Z
1305+
LAST-MODIFIED:20230921T133448Z
1306+
SEQUENCE:2
1307+
UID:7b7d5d12-683c-48ce-973a-b3e1cb0bae2a
1308+
DTSTART;VALUE=DATE:20230912
1309+
DTEND;VALUE=DATE:20230913
1310+
STATUS:CONFIRMED
1311+
SUMMARY:Daily Event
1312+
RRULE:FREQ=DAILY
1313+
END:VEVENT
1314+
END:VCALENDAR
1315+
EOD;
1316+
$uri = static::getUniqueID('calobj');
1317+
$this->backend->createCalendarObject($calendarId, $uri, $calData);
1318+
1319+
$start = new DateTimeImmutable('2023-09-20T00:00:00Z');
1320+
$end = $start->add(new DateInterval('P14D'));
1321+
1322+
$results = $this->backend->search(
1323+
$calendarInfo,
1324+
'',
1325+
[],
1326+
[
1327+
'timerange' => [
1328+
'start' => $start,
1329+
'end' => $end,
1330+
]
1331+
],
1332+
null,
1333+
null,
1334+
);
1335+
1336+
$this->assertCount(1, $results);
1337+
$this->assertCount(14, $results[0]['objects']);
1338+
foreach ($results as $result) {
1339+
foreach ($result['objects'] as $object) {
1340+
$this->assertEquals($object['UID'][0], '7b7d5d12-683c-48ce-973a-b3e1cb0bae2a');
1341+
$this->assertEquals($object['SUMMARY'][0], 'Daily Event');
1342+
$this->assertGreaterThanOrEqual(
1343+
$start->getTimestamp(),
1344+
$object['DTSTART'][0]->getTimestamp(),
1345+
'Recurrence starting before requested start',
1346+
);
1347+
$this->assertLessThanOrEqual(
1348+
$end->getTimestamp(),
1349+
$object['DTSTART'][0]->getTimestamp(),
1350+
'Recurrence starting after requested end',
1351+
);
1352+
}
1353+
}
1354+
}
12861355
}

0 commit comments

Comments
 (0)