Carefully filter out non matching time ranges for CalDAV search

When we search for CalDAV objects in the DB we take the first and last
occurence into account. For recurring events that is when they take
place the very first time and the very last time. Searching in a more
specific time range will still match this condition, because the
recurring event starts before the end of the requested range but ends
after the start of the requested range.

Sabre has filters for this. If we apply them on all seach objects of a
search with a time range, then only the recurring events actually taking
place at the time of the requested time range will be returned.

Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
This commit is contained in:
Christoph Wurst 2021-12-02 15:06:05 +01:00 committed by backportbot[bot]
parent 5282fcec05
commit 593b4e53b3

View file

@ -100,7 +100,9 @@ use function array_merge;
use function array_values;
use function explode;
use function is_array;
use function is_resource;
use function pathinfo;
use function rewind;
use function sprintf;
use function str_replace;
use function strtolower;
@ -1900,7 +1902,39 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
}
$result = $outerQuery->executeQuery();
$calendarObjects = $result->fetchAll();
$calendarObjects = array_filter($result->fetchAll(), function (array $row) use ($options) {
$start = $options['timerange']['start'] ?? null;
$end = $options['timerange']['end'] ?? null;
if ($start === null || !($start instanceof DateTimeInterface) || $end === null || !($end instanceof DateTimeInterface)) {
// No filter required
return true;
}
$isValid = $this->validateFilterForObject($row, [
'name' => 'VCALENDAR',
'comp-filters' => [
[
'name' => 'VEVENT',
'comp-filters' => [],
'prop-filters' => [],
'is-not-defined' => false,
'time-range' => [
'start' => $start,
'end' => $end,
],
],
],
'prop-filters' => [],
'is-not-defined' => false,
'time-range' => null,
]);
if (is_resource($row['calendardata'])) {
// Put the stream back to the beginning so it can be read another time
rewind($row['calendardata']);
}
return $isValid;
});
$result->closeCursor();
return array_map(function ($o) {