mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-17 21:12:20 +01:00
336 lines
9.1 KiB
PHP
336 lines
9.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
/**
|
|
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
namespace OCA\Talk\Chat\AutoComplete;
|
|
|
|
use OCA\Talk\Federation\Authenticator;
|
|
use OCA\Talk\Files\Util;
|
|
use OCA\Talk\GuestManager;
|
|
use OCA\Talk\Model\Attendee;
|
|
use OCA\Talk\Room;
|
|
use OCA\Talk\Service\ParticipantService;
|
|
use OCA\Talk\TalkSession;
|
|
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
|
use OCP\Collaboration\Collaborators\ISearchResult;
|
|
use OCP\Collaboration\Collaborators\SearchResultType;
|
|
use OCP\IL10N;
|
|
use OCP\IUserManager;
|
|
|
|
class SearchPlugin implements ISearchPlugin {
|
|
|
|
protected ?Room $room = null;
|
|
|
|
public function __construct(
|
|
protected IUserManager $userManager,
|
|
protected GuestManager $guestManager,
|
|
protected TalkSession $talkSession,
|
|
protected ParticipantService $participantService,
|
|
protected Util $util,
|
|
protected ?string $userId,
|
|
protected IL10N $l,
|
|
protected Authenticator $federationAuthenticator,
|
|
) {
|
|
}
|
|
|
|
public function setContext(array $context): void {
|
|
$this->room = $context['room'];
|
|
}
|
|
|
|
/**
|
|
* @param string $search
|
|
* @param int $limit
|
|
* @param int $offset
|
|
* @param ISearchResult $searchResult
|
|
* @return bool whether the plugin has more results
|
|
* @since 13.0.0
|
|
*/
|
|
public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
|
|
if ($this->room->getObjectType() === 'file') {
|
|
$usersWithFileAccess = $this->util->getUsersWithAccessFile($this->room->getObjectId());
|
|
if (!empty($usersWithFileAccess)) {
|
|
$users = [];
|
|
foreach ($usersWithFileAccess as $userId) {
|
|
$users[$userId] = $this->userManager->getDisplayName($userId) ?? $userId;
|
|
}
|
|
$this->searchUsers($search, $users, $searchResult);
|
|
}
|
|
}
|
|
|
|
/** @var array<string, string> $userIds */
|
|
$userIds = [];
|
|
/** @var array<string, string> $groupIds */
|
|
$groupIds = [];
|
|
/** @var array<string, string> $cloudIds */
|
|
$cloudIds = [];
|
|
/** @var list<Attendee> $guestAttendees */
|
|
$guestAttendees = [];
|
|
|
|
if ($this->room->getType() === Room::TYPE_ONE_TO_ONE) {
|
|
// Add potential leavers of one-to-one rooms again.
|
|
$participants = json_decode($this->room->getName(), true);
|
|
foreach ($participants as $userId) {
|
|
$userIds[$userId] = $this->userManager->getDisplayName($userId) ?? $userId;
|
|
}
|
|
} else {
|
|
$participants = $this->participantService->getParticipantsForRoom($this->room);
|
|
foreach ($participants as $participant) {
|
|
$attendee = $participant->getAttendee();
|
|
if ($attendee->getActorType() === Attendee::ACTOR_GUESTS) {
|
|
$guestAttendees[] = $attendee;
|
|
} elseif ($attendee->getActorType() === Attendee::ACTOR_USERS) {
|
|
$userIds[$attendee->getActorId()] = $attendee->getDisplayName();
|
|
} elseif ($attendee->getActorType() === Attendee::ACTOR_FEDERATED_USERS) {
|
|
$cloudIds[$attendee->getActorId()] = $attendee->getDisplayName();
|
|
} elseif ($attendee->getActorType() === Attendee::ACTOR_GROUPS) {
|
|
$groupIds[$attendee->getActorId()] = $attendee->getDisplayName();
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->searchUsers($search, $userIds, $searchResult);
|
|
$this->searchGroups($search, $groupIds, $searchResult);
|
|
$this->searchGuests($search, $guestAttendees, $searchResult);
|
|
$this->searchFederatedUsers($search, $cloudIds, $searchResult);
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param array<string|int, string> $users
|
|
*/
|
|
protected function searchUsers(string $search, array $users, ISearchResult $searchResult): void {
|
|
$search = strtolower($search);
|
|
|
|
$type = new SearchResultType('users');
|
|
|
|
$matches = $exactMatches = [];
|
|
foreach ($users as $userId => $displayName) {
|
|
$userId = (string) $userId;
|
|
if ($this->userId !== '' && $this->userId === $userId) {
|
|
// Do not suggest the current user
|
|
continue;
|
|
}
|
|
|
|
if ($searchResult->hasResult($type, $userId)) {
|
|
continue;
|
|
}
|
|
|
|
if ($search === '') {
|
|
$matches[] = $this->createResult('user', $userId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (strtolower($userId) === $search) {
|
|
$exactMatches[] = $this->createResult('user', $userId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (stripos($userId, $search) !== false) {
|
|
$matches[] = $this->createResult('user', $userId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if ($displayName === '') {
|
|
continue;
|
|
}
|
|
|
|
if (strtolower($displayName) === $search) {
|
|
$exactMatches[] = $this->createResult('user', $userId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (stripos($displayName, $search) !== false) {
|
|
$matches[] = $this->createResult('user', $userId, $displayName);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$searchResult->addResultSet($type, $matches, $exactMatches);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, string> $cloudIds
|
|
*/
|
|
protected function searchFederatedUsers(string $search, array $cloudIds, ISearchResult $searchResult): void {
|
|
$search = strtolower($search);
|
|
|
|
$type = new SearchResultType('federated_users');
|
|
|
|
$matches = $exactMatches = [];
|
|
foreach ($cloudIds as $cloudId => $displayName) {
|
|
if ($this->federationAuthenticator->getCloudId() === $cloudId) {
|
|
// Do not suggest the current user
|
|
continue;
|
|
}
|
|
|
|
if ($searchResult->hasResult($type, $cloudId)) {
|
|
continue;
|
|
}
|
|
|
|
if ($search === '') {
|
|
$matches[] = $this->createResult('federated_user', $cloudId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (strtolower($cloudId) === $search) {
|
|
$exactMatches[] = $this->createResult('federated_user', $cloudId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (stripos($cloudId, $search) !== false) {
|
|
$matches[] = $this->createResult('federated_user', $cloudId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if ($displayName === '') {
|
|
continue;
|
|
}
|
|
|
|
if (strtolower($displayName) === $search) {
|
|
$exactMatches[] = $this->createResult('federated_user', $cloudId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (stripos($displayName, $search) !== false) {
|
|
$matches[] = $this->createResult('federated_user', $cloudId, $displayName);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$searchResult->addResultSet($type, $matches, $exactMatches);
|
|
}
|
|
|
|
/**
|
|
* @param array<string|int, string> $groups
|
|
*/
|
|
protected function searchGroups(string $search, array $groups, ISearchResult $searchResult): void {
|
|
$search = strtolower($search);
|
|
|
|
$type = new SearchResultType('groups');
|
|
|
|
$matches = $exactMatches = [];
|
|
foreach ($groups as $groupId => $displayName) {
|
|
if ($displayName === '') {
|
|
continue;
|
|
}
|
|
|
|
$groupId = (string) $groupId;
|
|
if ($searchResult->hasResult($type, $groupId)) {
|
|
continue;
|
|
}
|
|
|
|
if ($search === '') {
|
|
$matches[] = $this->createGroupResult($groupId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (strtolower($groupId) === $search) {
|
|
$exactMatches[] = $this->createGroupResult($groupId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (stripos($groupId, $search) !== false) {
|
|
$matches[] = $this->createGroupResult($groupId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (strtolower($displayName) === $search) {
|
|
$exactMatches[] = $this->createGroupResult($groupId, $displayName);
|
|
continue;
|
|
}
|
|
|
|
if (stripos($displayName, $search) !== false) {
|
|
$matches[] = $this->createGroupResult($groupId, $displayName);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$searchResult->addResultSet($type, $matches, $exactMatches);
|
|
}
|
|
|
|
/**
|
|
* @param string $search
|
|
* @param list<Attendee> $attendees
|
|
* @param ISearchResult $searchResult
|
|
*/
|
|
protected function searchGuests(string $search, array $attendees, ISearchResult $searchResult): void {
|
|
if (empty($attendees)) {
|
|
$type = new SearchResultType('guests');
|
|
$searchResult->addResultSet($type, [], []);
|
|
return;
|
|
}
|
|
|
|
$search = strtolower($search);
|
|
$currentSessionHash = null;
|
|
if (!$this->userId) {
|
|
// Best effort: Might not work on guests that reloaded but not worth too much performance impact atm.
|
|
$currentSessionHash = sha1($this->talkSession->getSessionForRoom($this->room->getToken()));
|
|
}
|
|
|
|
$matches = $exactMatches = [];
|
|
foreach ($attendees as $attendee) {
|
|
if ($currentSessionHash === $attendee->getActorId()) {
|
|
// Do not suggest the current guest
|
|
continue;
|
|
}
|
|
|
|
$name = $attendee->getDisplayName() ?: $this->l->t('Guest');
|
|
if ($search === '') {
|
|
$matches[] = $this->createGuestResult($attendee->getActorId(), $name);
|
|
continue;
|
|
}
|
|
|
|
if (strtolower($name) === $search) {
|
|
$exactMatches[] = $this->createGuestResult($attendee->getActorId(), $name);
|
|
continue;
|
|
}
|
|
|
|
if (stripos($name, $search) !== false) {
|
|
$matches[] = $this->createGuestResult($attendee->getActorId(), $name);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$type = new SearchResultType('guests');
|
|
$searchResult->addResultSet($type, $matches, $exactMatches);
|
|
}
|
|
|
|
protected function createResult(string $type, string $uid, string $name): array {
|
|
if ($type === 'user' && $name === '') {
|
|
$name = $this->userManager->getDisplayName($uid) ?? $uid;
|
|
}
|
|
|
|
return [
|
|
'label' => $name,
|
|
'value' => [
|
|
'shareType' => $type,
|
|
'shareWith' => $uid,
|
|
],
|
|
];
|
|
}
|
|
|
|
protected function createGroupResult(string $groupId, string $name): array {
|
|
return [
|
|
'label' => $name,
|
|
'value' => [
|
|
'shareType' => 'group',
|
|
'shareWith' => 'group/' . $groupId,
|
|
],
|
|
];
|
|
}
|
|
|
|
protected function createGuestResult(string $actorId, string $name): array {
|
|
return [
|
|
'label' => $name,
|
|
'value' => [
|
|
'shareType' => 'guest',
|
|
'shareWith' => 'guest/' . $actorId,
|
|
],
|
|
];
|
|
}
|
|
}
|