feat(search): Seach for persons as event attendees and organizers

Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
pull/41374/head
Christoph Wurst 2023-11-10 12:21:22 +07:00
parent 78d5ec463b
commit 9b8cb5c819
No known key found for this signature in database
GPG Key ID: CC42AC2A7F0E56D8
2 changed files with 86 additions and 18 deletions

@ -29,19 +29,24 @@ namespace OCA\DAV\Search;
use OCA\DAV\CalDAV\CalDavBackend;
use OCP\IUser;
use OCP\Search\IFilteringProvider;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use Sabre\VObject\Component;
use Sabre\VObject\DateTimeParser;
use Sabre\VObject\Property;
use function array_combine;
use function array_fill;
use function array_key_exists;
use function array_map;
/**
* Class EventsSearchProvider
*
* @package OCA\DAV\Search
*/
class EventsSearchProvider extends ACalendarSearchProvider {
class EventsSearchProvider extends ACalendarSearchProvider implements IFilteringProvider {
/**
* @var string[]
*/
@ -106,22 +111,60 @@ class EventsSearchProvider extends ACalendarSearchProvider {
$calendarsById = $this->getSortedCalendars($principalUri);
$subscriptionsById = $this->getSortedSubscriptions($principalUri);
$searchResults = $this->backend->searchPrincipalUri(
$principalUri,
$query->getFilter('term')?->get() ?? '',
[self::$componentType],
self::$searchProperties,
self::$searchParameters,
[
'limit' => $query->getLimit(),
'offset' => $query->getCursor(),
'timerange' => [
'start' => $query->getFilter('since')?->get(),
'end' => $query->getFilter('until')?->get(),
/** @var string|null $term */
$term = $query->getFilter('term')?->get();
if ($term === null) {
$searchResults = [];
} else {
$searchResults = $this->backend->searchPrincipalUri(
$principalUri,
$term,
[self::$componentType],
self::$searchProperties,
self::$searchParameters,
[
'limit' => $query->getLimit(),
'offset' => $query->getCursor(),
'timerange' => [
'start' => $query->getFilter('since')?->get(),
'end' => $query->getFilter('until')?->get(),
],
]
);
}
/** @var IUser|null $person */
$person = $query->getFilter('person')?->get();
$personDisplayName = $person?->getDisplayName();
if ($personDisplayName !== null) {
$attendeeSearchResults = $this->backend->searchPrincipalUri(
$principalUri,
$personDisplayName,
[self::$componentType],
['ATTENDEE'],
self::$searchParameters,
[
'limit' => $query->getLimit(),
'offset' => $query->getCursor(),
'timerange' => [
'start' => $query->getFilter('since')?->get(),
'end' => $query->getFilter('until')?->get(),
],
],
]
);
$formattedResults = \array_map(function (array $eventRow) use ($calendarsById, $subscriptionsById):SearchResultEntry {
);
$searchResultIndex = array_combine(
array_map(fn($event) => $event['calendarid'] . '-' . $event['uri'], $searchResults),
array_fill(0, count($searchResults), null),
);
foreach ($attendeeSearchResults as $attendeeResult) {
if (array_key_exists($attendeeResult['calendarid'] . '-' . $attendeeResult['uri'], $searchResultIndex)) {
// Duplicate
continue;
}
$searchResults[] = $attendeeResult;
}
}
$formattedResults = \array_map(function (array $eventRow) use ($calendarsById, $subscriptionsById): SearchResultEntry {
$component = $this->getPrimaryComponent($eventRow['calendardata'], self::$componentType);
$title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled event'));
$subline = $this->generateSubline($component);
@ -228,4 +271,21 @@ class EventsSearchProvider extends ACalendarSearchProvider {
): bool {
return $dtStart->format('Y-m-d') === $dtEnd->format('Y-m-d');
}
public function getSupportedFilters(): array {
return [
'term',
'person',
'since',
'until',
];
}
public function getAlternateIds(): array {
return [];
}
public function getCustomFilters(): array {
return [];
}
}

@ -32,6 +32,7 @@ use OCP\App\IAppManager;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Search\IFilter;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
@ -293,7 +294,14 @@ class EventsSearchProviderTest extends TestCase {
$user = $this->createMock(IUser::class);
$user->method('getUID')->willReturn('john.doe');
$query = $this->createMock(ISearchQuery::class);
$query->method('getTerm')->willReturn('search term');
$seachTermFilter = $this->createMock(IFilter::class);
$query->method('getFilter')->willReturnCallback(function($name) use ($seachTermFilter) {
return match ($name) {
'term' => $seachTermFilter,
default => null,
};
});
$seachTermFilter->method('get')->willReturn('search term');
$query->method('getLimit')->willReturn(5);
$query->method('getCursor')->willReturn(20);
$this->appManager->expects($this->once())
@ -328,7 +336,7 @@ class EventsSearchProviderTest extends TestCase {
]);
$this->backend->expects($this->once())
->method('searchPrincipalUri')
->with('principals/users/john.doe', '', ['VEVENT'],
->with('principals/users/john.doe', 'search term', ['VEVENT'],
['SUMMARY', 'LOCATION', 'DESCRIPTION', 'ATTENDEE', 'ORGANIZER', 'CATEGORIES'],
['ATTENDEE' => ['CN'], 'ORGANIZER' => ['CN']],
['limit' => 5, 'offset' => 20, 'timerange' => ['start' => null, 'end' => null]])