perf(MailPlugin): Optimize checking group memberships

Signed-off-by: provokateurin <kate@provokateurin.de>
This commit is contained in:
provokateurin 2026-05-21 09:22:39 +02:00
parent 1c7e381858
commit 5c21fb5062
No known key found for this signature in database
4 changed files with 37 additions and 40 deletions

View file

@ -14,6 +14,7 @@ use OCP\Contacts\IManager;
use OCP\Federation\ICloudIdManager;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Mail\IEmailValidator;
use OCP\Share\IShare;
@ -31,6 +32,7 @@ class MailByMailPlugin extends MailPlugin {
KnownUserService $knownUserService,
IUserSession $userSession,
IEmailValidator $emailValidator,
IUserManager $userManager,
mixed $shareWithGroupOnlyExcludeGroupsList = [],
) {
parent::__construct(
@ -41,6 +43,7 @@ class MailByMailPlugin extends MailPlugin {
$knownUserService,
$userSession,
$emailValidator,
$userManager,
$shareWithGroupOnlyExcludeGroupsList,
IShare::TYPE_EMAIL,
);

View file

@ -17,6 +17,7 @@ use OCP\Federation\ICloudIdManager;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Mail\IEmailValidator;
use OCP\Share\IShare;
@ -42,6 +43,7 @@ class MailPlugin implements ISearchPlugin {
private KnownUserService $knownUserService,
private IUserSession $userSession,
private IEmailValidator $emailValidator,
private IUserManager $userManager,
private mixed $shareWithGroupOnlyExcludeGroupsList,
private int $shareType,
) {
@ -72,6 +74,7 @@ class MailPlugin implements ISearchPlugin {
}
$currentUserId = $this->userSession->getUser()->getUID();
$userGroups = null;
$result = $userResults = ['wide' => [], 'exact' => []];
$userType = new SearchResultType('users');
@ -114,26 +117,19 @@ class MailPlugin implements ISearchPlugin {
$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] ?? '');
@ -174,14 +170,8 @@ class MailPlugin implements ISearchPlugin {
}
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) {
@ -247,7 +237,7 @@ class MailPlugin implements ISearchPlugin {
}
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,

View file

@ -14,6 +14,7 @@ use OCP\Contacts\IManager;
use OCP\Federation\ICloudIdManager;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Mail\IEmailValidator;
use OCP\Share\IShare;
@ -31,6 +32,7 @@ class UserByMailPlugin extends MailPlugin {
KnownUserService $knownUserService,
IUserSession $userSession,
IEmailValidator $emailValidator,
IUserManager $userManager,
mixed $shareWithGroupOnlyExcludeGroupsList = [],
) {
parent::__construct(
@ -41,6 +43,7 @@ class UserByMailPlugin extends MailPlugin {
$knownUserService,
$userSession,
$emailValidator,
$userManager,
$shareWithGroupOnlyExcludeGroupsList,
IShare::TYPE_USER,
);

View file

@ -39,6 +39,7 @@ class MailPluginTest extends TestCase {
protected IGroupManager&MockObject $groupManager;
protected KnownUserService&MockObject $knownUserService;
protected IUserSession&MockObject $userSession;
protected IUserManager&MockObject $userManager;
#[\Override]
protected function setUp(): void {
@ -49,6 +50,17 @@ class MailPluginTest extends TestCase {
$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),
@ -69,6 +81,7 @@ class MailPluginTest extends TestCase {
$this->knownUserService,
$this->userSession,
$this->getEmailValidatorWithStrictEmailCheck(),
$this->userManager,
[],
$shareType,
);
@ -727,7 +740,7 @@ class MailPluginTest extends TestCase {
]
],
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,
],
@ -872,12 +885,6 @@ class MailPluginTest extends TestCase {
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();
@ -942,7 +949,7 @@ class MailPluginTest extends TestCase {
'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,
[
@ -996,12 +1003,6 @@ class MailPluginTest extends TestCase {
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();
@ -1024,7 +1025,7 @@ class MailPluginTest extends TestCase {
'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,
[