From 331c9a0dab4a949e716d9433d02a8ac3a6207d5d Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 26 May 2026 09:46:24 +0200 Subject: [PATCH 1/4] fix(MailPlugin): Use correct type for exact id match Signed-off-by: provokateurin --- lib/private/Collaboration/Collaborators/MailPlugin.php | 2 +- tests/lib/Collaboration/Collaborators/MailPluginTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index 84ff487203f58..d8a185102fd08 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -153,7 +153,7 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b ]]; $searchResult->addResultSet($userType, [], $singleResult); - $searchResult->markExactIdMatch($emailType); + $searchResult->markExactIdMatch($userType); } return false; } diff --git a/tests/lib/Collaboration/Collaborators/MailPluginTest.php b/tests/lib/Collaboration/Collaborators/MailPluginTest.php index 9672bbfcd6bda..28527ada719d9 100644 --- a/tests/lib/Collaboration/Collaborators/MailPluginTest.php +++ b/tests/lib/Collaboration/Collaborators/MailPluginTest.php @@ -606,7 +606,7 @@ function ($appName, $key, $default) use ($shareeEnumeration) { $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult); $result = $this->searchResult->asArray(); - $this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails'))); + $this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('users'))); $this->assertEquals($expectedResult, $result); $this->assertSame($expectedMoreResults, $moreResults); } From 103db55e4b98eed88150211cea730cedd975cb1a Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 26 May 2026 09:46:03 +0200 Subject: [PATCH 2/4] refactor(MailPlugin): Continue execution after extracting email instead of calling itself Signed-off-by: provokateurin --- lib/private/Collaboration/Collaborators/MailPlugin.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index d8a185102fd08..0309813c01331 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -65,9 +65,8 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b } // Extract the email address from "Foo Bar " and then search with "foo.bar@example.tld" instead - $result = preg_match('/<([^@]+@.+)>$/', $search, $matches); - if ($result && filter_var($matches[1], FILTER_VALIDATE_EMAIL)) { - return $this->search($matches[1], $limit, $offset, $searchResult); + if (preg_match('/<([^@]+@.+)>$/', $search, $matches) && filter_var($matches[1], FILTER_VALIDATE_EMAIL)) { + $search = $matches[1]; } $currentUserId = $this->userSession->getUser()->getUID(); From b21788970281bfe9274b470aca1c05d5210f3146 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Thu, 21 May 2026 09:22:39 +0200 Subject: [PATCH 3/4] perf(MailPlugin): Optimize checking group memberships Signed-off-by: provokateurin --- .../Collaborators/MailByMailPlugin.php | 3 + .../Collaborators/MailPlugin.php | 40 +++++------- .../Collaborators/UserByMailPlugin.php | 3 + .../Collaborators/MailPluginTest.php | 63 ++++++++----------- 4 files changed, 46 insertions(+), 63 deletions(-) diff --git a/lib/private/Collaboration/Collaborators/MailByMailPlugin.php b/lib/private/Collaboration/Collaborators/MailByMailPlugin.php index 53f90e33c57f4..72175e61d5ca1 100644 --- a/lib/private/Collaboration/Collaborators/MailByMailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailByMailPlugin.php @@ -11,6 +11,7 @@ use OCP\Federation\ICloudIdManager; use OCP\IConfig; use OCP\IGroupManager; +use OCP\IUserManager; use OCP\IUserSession; use OCP\Mail\IEmailValidator; use OCP\Share\IShare; @@ -28,6 +29,7 @@ public function __construct( KnownUserService $knownUserService, IUserSession $userSession, IEmailValidator $emailValidator, + IUserManager $userManager, mixed $shareWithGroupOnlyExcludeGroupsList = [], ) { parent::__construct( @@ -38,6 +40,7 @@ public function __construct( $knownUserService, $userSession, $emailValidator, + $userManager, $shareWithGroupOnlyExcludeGroupsList, IShare::TYPE_EMAIL, ); diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index 0309813c01331..dc621e83ca6ee 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -16,6 +16,7 @@ use OCP\IConfig; use OCP\IGroupManager; use OCP\IUser; +use OCP\IUserManager; use OCP\IUserSession; use OCP\Mail\IEmailValidator; use OCP\Share\IShare; @@ -41,6 +42,7 @@ public function __construct( private KnownUserService $knownUserService, private IUserSession $userSession, private IEmailValidator $emailValidator, + private IUserManager $userManager, private mixed $shareWithGroupOnlyExcludeGroupsList, private int $shareType, ) { @@ -70,6 +72,7 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b } $currentUserId = $this->userSession->getUser()->getUID(); + $userGroups = null; $result = $userResults = ['wide' => [], 'exact' => []]; $userType = new SearchResultType('users'); @@ -112,26 +115,19 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b $exactEmailMatch = strtolower($emailAddress) === $lowerSearch; if (isset($contact['isLocalSystemBook'])) { + $contactUser = $this->userManager->get($contact['UID']); + if ($contactUser === null) { + continue; + } + $contactGroups = $this->groupManager->getUserGroupIds($contactUser); + if ($this->shareWithGroupOnly) { - /* - * Check if the user may share with the user associated with the e-mail of the just found contact - */ - $userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser()); - - // ShareWithGroupOnly filtering - $userGroups = array_diff($userGroups, $this->shareWithGroupOnlyExcludeGroupsList); - - $found = false; - foreach ($userGroups as $userGroup) { - if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) { - $found = true; - break; - } - } - if (!$found) { + $userGroups ??= $this->groupManager->getUserGroupIds($this->userSession->getUser()); + if (array_intersect($contactGroups, array_diff($userGroups, $this->shareWithGroupOnlyExcludeGroupsList)) === []) { continue; } } + if ($exactEmailMatch && $this->shareeEnumerationFullMatch) { try { $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? ''); @@ -173,14 +169,8 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b } if (!$addToWide && $this->shareeEnumerationInGroupOnly) { - $addToWide = false; - $userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser()); - foreach ($userGroups as $userGroup) { - if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) { - $addToWide = true; - break; - } - } + $userGroups ??= $this->groupManager->getUserGroupIds($this->userSession->getUser()); + $addToWide = array_intersect($contactGroups, $userGroups) !== []; } if ($addToWide && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) { if ($this->shareType === IShare::TYPE_USER) { @@ -246,7 +236,7 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b } if ($this->shareType === IShare::TYPE_EMAIL - && !$searchResult->hasExactIdMatch($emailType) && $this->emailValidator->isValid($search)) { + && !$searchResult->hasExactIdMatch($emailType) && $this->emailValidator->isValid($search)) { $result['exact'][] = [ 'label' => $search, 'uuid' => $search, diff --git a/lib/private/Collaboration/Collaborators/UserByMailPlugin.php b/lib/private/Collaboration/Collaborators/UserByMailPlugin.php index 44c1a95221c7d..b8d64584ef248 100644 --- a/lib/private/Collaboration/Collaborators/UserByMailPlugin.php +++ b/lib/private/Collaboration/Collaborators/UserByMailPlugin.php @@ -11,6 +11,7 @@ use OCP\Federation\ICloudIdManager; use OCP\IConfig; use OCP\IGroupManager; +use OCP\IUserManager; use OCP\IUserSession; use OCP\Mail\IEmailValidator; use OCP\Share\IShare; @@ -28,6 +29,7 @@ public function __construct( KnownUserService $knownUserService, IUserSession $userSession, IEmailValidator $emailValidator, + IUserManager $userManager, mixed $shareWithGroupOnlyExcludeGroupsList = [], ) { parent::__construct( @@ -38,6 +40,7 @@ public function __construct( $knownUserService, $userSession, $emailValidator, + $userManager, $shareWithGroupOnlyExcludeGroupsList, IShare::TYPE_USER, ); diff --git a/tests/lib/Collaboration/Collaborators/MailPluginTest.php b/tests/lib/Collaboration/Collaborators/MailPluginTest.php index 28527ada719d9..e1210e2b0a120 100644 --- a/tests/lib/Collaboration/Collaborators/MailPluginTest.php +++ b/tests/lib/Collaboration/Collaborators/MailPluginTest.php @@ -23,35 +23,22 @@ use OCP\IUserManager; use OCP\IUserSession; use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; use Test\Traits\EmailValidatorTrait; class MailPluginTest extends TestCase { use EmailValidatorTrait; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $contactsManager; - - /** @var ICloudIdManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $cloudIdManager; - - /** @var MailPlugin */ - protected $plugin; - - /** @var SearchResult */ - protected $searchResult; - - /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $groupManager; - - /** @var KnownUserService|\PHPUnit\Framework\MockObject\MockObject */ - protected $knownUserService; - - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ - protected $userSession; + protected IConfig&MockObject $config; + protected IManager&MockObject $contactsManager; + protected ICloudIdManager $cloudIdManager; + protected MailPlugin $plugin; + protected SearchResult $searchResult; + protected IGroupManager&MockObject $groupManager; + protected KnownUserService&MockObject $knownUserService; + protected IUserSession&MockObject $userSession; + protected IUserManager&MockObject $userManager; protected function setUp(): void { parent::setUp(); @@ -61,6 +48,17 @@ protected function setUp(): void { $this->groupManager = $this->createMock(IGroupManager::class); $this->knownUserService = $this->createMock(KnownUserService::class); $this->userSession = $this->createMock(IUserSession::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->userManager + ->method('get') + ->willReturnCallback(function (string $uid): IUser { + $user = $this->createMock(IUser::class); + $user + ->method('getUID') + ->willReturn($uid); + + return $user; + }); $this->cloudIdManager = new CloudIdManager( $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), @@ -81,6 +79,7 @@ public function instantiatePlugin(int $shareType) { $this->knownUserService, $this->userSession, $this->getEmailValidatorWithStrictEmailCheck(), + $this->userManager, [], $shareType, ); @@ -758,7 +757,7 @@ public static function dataSearchUser(): array { ] ], false, - ['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User (test@example.com)','value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => 'test@example.com']]]], + ['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User (test@example.com)', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => 'test@example.com']]]], true, false, ], @@ -913,12 +912,6 @@ function ($appName, $key, $default) { return $userToGroupMapping[$user->getUID()]; }); - $this->groupManager->expects($this->any()) - ->method('isInGroup') - ->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) { - return in_array($group, $userToGroupMapping[$userId]); - }); - $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult); $result = $this->searchResult->asArray(); @@ -983,7 +976,7 @@ public static function dataSearchEmailGroupsOnly(): array { 'UID' => 'User', ] ], - ['emails' => [], 'exact' => ['emails' => [['label' => 'test@example.com', 'uuid' => 'test@example.com', 'value' => ['shareType' => IShare::TYPE_EMAIL,'shareWith' => 'test@example.com']]]]], + ['emails' => [], 'exact' => ['emails' => [['label' => 'test@example.com', 'uuid' => 'test@example.com', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => 'test@example.com']]]]], false, false, [ @@ -1047,12 +1040,6 @@ function ($appName, $key, $default) { return $userToGroupMapping[$user->getUID()]; }); - $this->groupManager->expects($this->any()) - ->method('isInGroup') - ->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) { - return in_array($group, $userToGroupMapping[$userId]); - }); - $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult); $result = $this->searchResult->asArray(); @@ -1075,7 +1062,7 @@ public static function dataSearchUserGroupsOnly(): array { 'UID' => 'User', ] ], - ['users' => [['label' => 'User (test@example.com)', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'],'shareWithDisplayNameUnique' => 'test@example.com',]], 'exact' => ['users' => []]], + ['users' => [['label' => 'User (test@example.com)', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => 'test@example.com',]], 'exact' => ['users' => []]], false, false, [ From a0a84f70413d008395f3dc920d42869a77c3bac9 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 26 May 2026 10:27:38 +0200 Subject: [PATCH 4/4] fix(MailPlugin): Stop applying the offset twice and the limit per wide/exact Signed-off-by: provokateurin --- .../Collaborators/MailPlugin.php | 263 +++++++++--------- .../Collaborators/MailPluginTest.php | 22 +- 2 files changed, 144 insertions(+), 141 deletions(-) diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index dc621e83ca6ee..1e08aff726b11 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -20,6 +20,7 @@ use OCP\IUserSession; use OCP\Mail\IEmailValidator; use OCP\Share\IShare; +use RuntimeException; class MailPlugin implements ISearchPlugin { protected bool $shareWithGroupOnly; @@ -74,16 +75,22 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b $currentUserId = $this->userSession->getUser()->getUID(); $userGroups = null; - $result = $userResults = ['wide' => [], 'exact' => []]; - $userType = new SearchResultType('users'); - $emailType = new SearchResultType('emails'); + $hasMore = false; + $count = 0; + $results = ['wide' => [], 'exact' => []]; + $type = match ($this->shareType) { + IShare::TYPE_USER => new SearchResultType('users'), + IShare::TYPE_EMAIL => new SearchResultType('emails'), + default => throw new RuntimeException(), + }; // Search in contacts $addressBookContacts = $this->contactsManager->search( $search, ['EMAIL', 'FN'], [ - 'limit' => $limit, + // We request one more, so we can check if there are more results available + 'limit' => $limit + 1, 'offset' => $offset, 'enumeration' => $this->shareeEnumeration, 'fullmatch' => $this->shareeEnumerationFullMatch, @@ -91,52 +98,95 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b ); $lowerSearch = strtolower($search); foreach ($addressBookContacts as $contact) { - if (isset($contact['EMAIL'])) { - $emailAddresses = $contact['EMAIL']; - if (\is_string($emailAddresses)) { - $emailAddresses = [$emailAddresses]; + if (!isset($contact['EMAIL'])) { + continue; + } + + $emailAddresses = $contact['EMAIL']; + if (\is_string($emailAddresses)) { + $emailAddresses = [$emailAddresses]; + } + foreach ($emailAddresses as $emailAddress) { + $displayName = $emailAddress; + $emailAddressType = null; + if (\is_array($emailAddress)) { + $emailAddressData = $emailAddress; + $emailAddress = $emailAddressData['value']; + $emailAddressType = $emailAddressData['type']; + } + + if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) { + continue; } - foreach ($emailAddresses as $type => $emailAddress) { - $displayName = $emailAddress; - $emailAddressType = null; - if (\is_array($emailAddress)) { - $emailAddressData = $emailAddress; - $emailAddress = $emailAddressData['value']; - $emailAddressType = $emailAddressData['type']; - } - if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) { + if (isset($contact['FN'])) { + $displayName = $contact['FN'] . ' (' . $emailAddress . ')'; + } + $exactEmailMatch = strtolower($emailAddress) === $lowerSearch; + + if (isset($contact['isLocalSystemBook'])) { + $contactUser = $this->userManager->get($contact['UID']); + if ($contactUser === null) { continue; } - if (isset($contact['FN'])) { - $displayName = $contact['FN'] . ' (' . $emailAddress . ')'; + $contactGroups = $this->groupManager->getUserGroupIds($contactUser); + if ($this->shareWithGroupOnly) { + $userGroups ??= $this->groupManager->getUserGroupIds($this->userSession->getUser()); + if (array_intersect($contactGroups, array_diff($userGroups, $this->shareWithGroupOnlyExcludeGroupsList)) === []) { + continue; + } } - $exactEmailMatch = strtolower($emailAddress) === $lowerSearch; - if (isset($contact['isLocalSystemBook'])) { - $contactUser = $this->userManager->get($contact['UID']); - if ($contactUser === null) { + if ($exactEmailMatch && $this->shareeEnumerationFullMatch) { + try { + $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? ''); + } catch (\InvalidArgumentException $e) { continue; } - $contactGroups = $this->groupManager->getUserGroupIds($contactUser); - if ($this->shareWithGroupOnly) { - $userGroups ??= $this->groupManager->getUserGroupIds($this->userSession->getUser()); - if (array_intersect($contactGroups, array_diff($userGroups, $this->shareWithGroupOnlyExcludeGroupsList)) === []) { - continue; - } + if ($this->shareType === IShare::TYPE_USER && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($type, $cloud->getUser())) { + $singleResult = [[ + 'label' => $displayName, + 'uuid' => $contact['UID'] ?? $emailAddress, + 'name' => $contact['FN'] ?? $displayName, + 'value' => [ + 'shareType' => IShare::TYPE_USER, + 'shareWith' => $cloud->getUser(), + ], + 'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser() + ]]; + $searchResult->addResultSet($type, [], $singleResult); + $searchResult->markExactIdMatch($type); } + return false; + } - if ($exactEmailMatch && $this->shareeEnumerationFullMatch) { - try { - $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? ''); - } catch (\InvalidArgumentException $e) { + if ($this->shareeEnumeration && $this->shareType === IShare::TYPE_USER) { + try { + if (!isset($contact['CLOUD'])) { continue; } + $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? ''); + } catch (\InvalidArgumentException $e) { + continue; + } + $addToWide = !($this->shareeEnumerationInGroupOnly || $this->shareeEnumerationPhone); - if ($this->shareType === IShare::TYPE_USER && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) { - $singleResult = [[ + if (!$addToWide && $this->shareeEnumerationPhone && $this->knownUserService->isKnownToUser($currentUserId, $contact['UID'])) { + $addToWide = true; + } + + if (!$addToWide && $this->shareeEnumerationInGroupOnly) { + $userGroups ??= $this->groupManager->getUserGroupIds($this->userSession->getUser()); + $addToWide = array_intersect($contactGroups, $userGroups) !== []; + } + + if ($addToWide && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($type, $cloud->getUser())) { + if ($count++ >= $limit) { + $hasMore = true; + } else { + $results['wide'][] = [ 'label' => $displayName, 'uuid' => $contact['UID'] ?? $emailAddress, 'name' => $contact['FN'] ?? $displayName, @@ -145,116 +195,69 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b 'shareWith' => $cloud->getUser(), ], 'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser() - - ]]; - $searchResult->addResultSet($userType, [], $singleResult); - $searchResult->markExactIdMatch($userType); + ]; } - return false; } + } - if ($this->shareeEnumeration) { - try { - if (!isset($contact['CLOUD'])) { - continue; - } - $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? ''); - } catch (\InvalidArgumentException $e) { - continue; - } - - $addToWide = !($this->shareeEnumerationInGroupOnly || $this->shareeEnumerationPhone); - if (!$addToWide && $this->shareeEnumerationPhone && $this->knownUserService->isKnownToUser($currentUserId, $contact['UID'])) { - $addToWide = true; - } + continue; + } - if (!$addToWide && $this->shareeEnumerationInGroupOnly) { - $userGroups ??= $this->groupManager->getUserGroupIds($this->userSession->getUser()); - $addToWide = array_intersect($contactGroups, $userGroups) !== []; - } - if ($addToWide && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) { - if ($this->shareType === IShare::TYPE_USER) { - $userResults['wide'][] = [ - 'label' => $displayName, - 'uuid' => $contact['UID'] ?? $emailAddress, - 'name' => $contact['FN'] ?? $displayName, - 'value' => [ - 'shareType' => IShare::TYPE_USER, - 'shareWith' => $cloud->getUser(), - ], - 'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser() - ]; - } - continue; - } - } - continue; - } + if ($this->shareType !== IShare::TYPE_EMAIL) { + continue; + } - if ($this->shareType !== IShare::TYPE_EMAIL) { - continue; + if ($count++ >= $limit) { + $hasMore = true; + } elseif ($exactEmailMatch || (isset($contact['FN']) && strtolower($contact['FN']) === $lowerSearch)) { + if ($exactEmailMatch) { + $searchResult->markExactIdMatch($type); } - if ($exactEmailMatch - || (isset($contact['FN']) && strtolower($contact['FN']) === $lowerSearch)) { - if ($exactEmailMatch) { - $searchResult->markExactIdMatch($emailType); - } - $result['exact'][] = [ - 'label' => $displayName, - 'uuid' => $contact['UID'] ?? $emailAddress, - 'name' => $contact['FN'] ?? $displayName, - 'type' => $emailAddressType ?? '', - 'value' => [ - 'shareType' => IShare::TYPE_EMAIL, - 'shareWith' => $emailAddress, - ], - ]; - } else { - $result['wide'][] = [ - 'label' => $displayName, - 'uuid' => $contact['UID'] ?? $emailAddress, - 'name' => $contact['FN'] ?? $displayName, - 'type' => $emailAddressType ?? '', - 'value' => [ - 'shareType' => IShare::TYPE_EMAIL, - 'shareWith' => $emailAddress, - ], - ]; - } + $results['exact'][] = [ + 'label' => $displayName, + 'uuid' => $contact['UID'] ?? $emailAddress, + 'name' => $contact['FN'] ?? $displayName, + 'type' => $emailAddressType ?? '', + 'value' => [ + 'shareType' => IShare::TYPE_EMAIL, + 'shareWith' => $emailAddress, + ], + ]; + } else { + $results['wide'][] = [ + 'label' => $displayName, + 'uuid' => $contact['UID'] ?? $emailAddress, + 'name' => $contact['FN'] ?? $displayName, + 'type' => $emailAddressType ?? '', + 'value' => [ + 'shareType' => IShare::TYPE_EMAIL, + 'shareWith' => $emailAddress, + ], + ]; } } } - $reachedEnd = true; - if ($this->shareeEnumeration) { - $reachedEnd = (count($result['wide']) < $offset + $limit) - && (count($userResults['wide']) < $offset + $limit); - - $result['wide'] = array_slice($result['wide'], $offset, $limit); - $userResults['wide'] = array_slice($userResults['wide'], $offset, $limit); - } - if ($this->shareType === IShare::TYPE_EMAIL - && !$searchResult->hasExactIdMatch($emailType) && $this->emailValidator->isValid($search)) { - $result['exact'][] = [ - 'label' => $search, - 'uuid' => $search, - 'value' => [ - 'shareType' => IShare::TYPE_EMAIL, - 'shareWith' => $search, - ], - ]; + && !$searchResult->hasExactIdMatch($type) && $this->emailValidator->isValid($search)) { + if ($count++ >= $limit) { + $hasMore = true; + } else { + $results['exact'][] = [ + 'label' => $search, + 'uuid' => $search, + 'value' => [ + 'shareType' => IShare::TYPE_EMAIL, + 'shareWith' => $search, + ], + ]; + } } - if ($this->shareType === IShare::TYPE_USER && !empty($userResults['wide'])) { - $searchResult->addResultSet($userType, $userResults['wide'], []); - } - if ($this->shareType === IShare::TYPE_EMAIL) { - $searchResult->addResultSet($emailType, $result['wide'], $result['exact']); - } + $searchResult->addResultSet($type, $results['wide'], $results['exact']); - return !$reachedEnd; + return $hasMore; } public function isCurrentUser(ICloudId $cloud): bool { diff --git a/tests/lib/Collaboration/Collaborators/MailPluginTest.php b/tests/lib/Collaboration/Collaborators/MailPluginTest.php index e1210e2b0a120..78d728179eccd 100644 --- a/tests/lib/Collaboration/Collaborators/MailPluginTest.php +++ b/tests/lib/Collaboration/Collaborators/MailPluginTest.php @@ -613,15 +613,15 @@ function ($appName, $key, $default) use ($shareeEnumeration) { public static function dataSearchUser(): array { return [ // data set 0 - ['test', [], true, ['exact' => []], false, false], + ['test', [], true, ['users' => [], 'exact' => ['users' => [],]], false, false], // data set 1 - ['test', [], false, ['exact' => []], false, false], + ['test', [], false, ['users' => [], 'exact' => ['users' => [],]], false, false], // data set 2 [ 'test@remote.com', [], true, - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, ], @@ -630,7 +630,7 @@ public static function dataSearchUser(): array { 'test@remote.com', [], false, - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, ], @@ -657,7 +657,7 @@ public static function dataSearchUser(): array { ], ], true, - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, ], @@ -685,7 +685,7 @@ public static function dataSearchUser(): array { ], ], false, - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, ], @@ -712,7 +712,7 @@ public static function dataSearchUser(): array { ], ], true, - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, ], @@ -739,7 +739,7 @@ public static function dataSearchUser(): array { ], ], true, - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, ], @@ -852,7 +852,7 @@ public static function dataSearchUser(): array { ], ], true, - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, ], @@ -1082,7 +1082,7 @@ public static function dataSearchUserGroupsOnly(): array { 'UID' => 'User', ] ], - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, [ @@ -1102,7 +1102,7 @@ public static function dataSearchUserGroupsOnly(): array { 'UID' => 'User', ] ], - ['exact' => []], + ['users' => [], 'exact' => ['users' => [],]], false, false, [