From a7cc035f079590c2b515c2ce4259f303ffb07660 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Thu, 5 Dec 2024 17:07:28 +0100 Subject: [PATCH] feat(profilepicker): check fields visibility in reference provider Signed-off-by: Julien Veyssier --- .../ProfilePickerReferenceProvider.php | 44 +++++++++------- .../ProfilePickerReferenceProviderTest.php | 51 +++++++++++++++++-- 2 files changed, 75 insertions(+), 20 deletions(-) diff --git a/lib/Reference/ProfilePickerReferenceProvider.php b/lib/Reference/ProfilePickerReferenceProvider.php index ad84b9a0f..217615014 100644 --- a/lib/Reference/ProfilePickerReferenceProvider.php +++ b/lib/Reference/ProfilePickerReferenceProvider.php @@ -18,6 +18,7 @@ use OCP\IL10N; use OCP\IURLGenerator; use OCP\IUserManager; +use OCP\Profile\IProfileManager; class ProfilePickerReferenceProvider extends ADiscoverableReferenceProvider { public const RICH_OBJECT_TYPE = 'users_picker_profile'; @@ -27,6 +28,7 @@ public function __construct( private IURLGenerator $urlGenerator, private IUserManager $userManager, private IAccountManager $accountManager, + private IProfileManager $profileManager, private ?string $userId, ) { } @@ -79,11 +81,12 @@ public function resolveReference(string $referenceText): ?IReference { if ($user === null) { return null; } - $account = $this->accountManager->getAccount($user); - $profileEnabled = $account->getProperty(IAccountManager::PROPERTY_PROFILE_ENABLED)->getValue() === '1'; - if (!$profileEnabled) { + if (!$this->profileManager->isProfileEnabled($user)) { return null; } + $account = $this->accountManager->getAccount($user); + + $currentUser = $this->userManager->get($this->userId); $reference = new Reference($referenceText); @@ -91,8 +94,17 @@ public function resolveReference(string $referenceText): ?IReference { $userEmail = $user->getEMailAddress(); $userAvatarUrl = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $userId, 'size' => '64']); - $bio = $account->getProperty(IAccountManager::PROPERTY_BIOGRAPHY); - $bio = $bio->getScope() !== IAccountManager::SCOPE_PRIVATE ? $bio->getValue() : null; + $bioProperty = $account->getProperty(IAccountManager::PROPERTY_BIOGRAPHY); + $bio = null; + $fullBio = null; + if ($this->profileManager->isProfileFieldVisible(IAccountManager::PROPERTY_BIOGRAPHY, $user, $currentUser)) { + $fullBio = $bioProperty->getValue(); + $bio = $fullBio !== '' + ? (mb_strlen($fullBio) > 80 + ? (mb_substr($fullBio, 0, 80) . '...') + : $fullBio) + : null; + } $headline = $account->getProperty(IAccountManager::PROPERTY_HEADLINE); $location = $account->getProperty(IAccountManager::PROPERTY_ADDRESS); $website = $account->getProperty(IAccountManager::PROPERTY_WEBSITE); @@ -104,6 +116,8 @@ public function resolveReference(string $referenceText): ?IReference { $reference->setDescription($userEmail ?? $userDisplayName); $reference->setImageUrl($userAvatarUrl); + $isLocationVisible = $this->profileManager->isProfileFieldVisible(IAccountManager::PROPERTY_ADDRESS, $user, $currentUser); + // for the Vue reference widget $reference->setRichObject( self::RICH_OBJECT_TYPE, @@ -112,18 +126,14 @@ public function resolveReference(string $referenceText): ?IReference { 'title' => $userDisplayName, 'subline' => $userEmail ?? $userDisplayName, 'email' => $userEmail, - 'bio' => isset($bio) && $bio !== '' - ? (mb_strlen($bio) > 80 - ? (mb_substr($bio, 0, 80) . '...') - : $bio) - : null, - 'full_bio' => $bio, - 'headline' => $headline->getScope() !== IAccountManager::SCOPE_PRIVATE ? $headline->getValue() : null, - 'location' => $location->getScope() !== IAccountManager::SCOPE_PRIVATE ? $location->getValue() : null, - 'location_url' => $location->getScope() !== IAccountManager::SCOPE_PRIVATE ? $this->getOpenStreetLocationUrl($location->getValue()) : null, - 'website' => $website->getScope() !== IAccountManager::SCOPE_PRIVATE ? $website->getValue() : null, - 'organisation' => $organisation->getScope() !== IAccountManager::SCOPE_PRIVATE ? $organisation->getValue() : null, - 'role' => $role->getScope() !== IAccountManager::SCOPE_PRIVATE ? $role->getValue() : null, + 'bio' => $bio, + 'full_bio' => $fullBio, + 'headline' => $this->profileManager->isProfileFieldVisible(IAccountManager::PROPERTY_HEADLINE, $user, $currentUser) ? $headline->getValue() : null, + 'location' => $isLocationVisible ? $location->getValue() : null, + 'location_url' => $isLocationVisible ? $this->getOpenStreetLocationUrl($location->getValue()) : null, + 'website' => $this->profileManager->isProfileFieldVisible(IAccountManager::PROPERTY_WEBSITE, $user, $currentUser) ? $website->getValue() : null, + 'organisation' => $this->profileManager->isProfileFieldVisible(IAccountManager::PROPERTY_ORGANISATION, $user, $currentUser) ? $organisation->getValue() : null, + 'role' => $this->profileManager->isProfileFieldVisible(IAccountManager::PROPERTY_ROLE, $user, $currentUser) ? $role->getValue() : null, 'url' => $referenceText, ] ); diff --git a/tests/unit/Reference/ProfilePickerReferenceProviderTest.php b/tests/unit/Reference/ProfilePickerReferenceProviderTest.php index 13a0bfcae..df3b2147e 100644 --- a/tests/unit/Reference/ProfilePickerReferenceProviderTest.php +++ b/tests/unit/Reference/ProfilePickerReferenceProviderTest.php @@ -17,14 +17,17 @@ use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; +use OCP\Profile\IProfileManager; use PHPUnit\Framework\MockObject\MockObject; class ProfilePickerReferenceProviderTest extends TestCase { private string $userId = 'admin'; + private IUser|MockObject $adminUser; private IL10N|MockObject $l10n; private IURLGenerator|MockObject $urlGenerator; private IUserManager|MockObject $userManager; private IAccountManager|MockObject $accountManager; + private IProfileManager|MockObject $profileManager; private ProfilePickerReferenceProvider $referenceProvider; private array $testUsersData = [ @@ -46,60 +49,74 @@ class ProfilePickerReferenceProviderTest extends TestCase { 'user1' => [ IAccountManager::PROPERTY_BIOGRAPHY => [ 'scope' => IAccountManager::SCOPE_PRIVATE, + 'visible' => true, 'value' => 'This is a first test user', ], IAccountManager::PROPERTY_HEADLINE => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => false, 'value' => 'I\'m a first test user', ], IAccountManager::PROPERTY_ADDRESS => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'Odessa', ], IAccountManager::PROPERTY_WEBSITE => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'https://domain.co/testuser1', ], IAccountManager::PROPERTY_ORGANISATION => [ 'scope' => IAccountManager::SCOPE_PRIVATE, + 'visible' => true, 'value' => 'Nextcloud GmbH', ], IAccountManager::PROPERTY_ROLE => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'Non-existing user', ], IAccountManager::PROPERTY_PROFILE_ENABLED => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => '1', ], ], 'user2' => [ IAccountManager::PROPERTY_BIOGRAPHY => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'This is a test user', ], IAccountManager::PROPERTY_HEADLINE => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'Second test user', ], IAccountManager::PROPERTY_ADDRESS => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'Berlin', ], IAccountManager::PROPERTY_WEBSITE => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'https://domain.co/testuser2', ], IAccountManager::PROPERTY_ORGANISATION => [ 'scope' => IAccountManager::SCOPE_PRIVATE, + 'visible' => true, 'value' => 'Nextcloud GmbH', ], IAccountManager::PROPERTY_ROLE => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => 'Non-existing user', ], IAccountManager::PROPERTY_PROFILE_ENABLED => [ 'scope' => IAccountManager::SCOPE_LOCAL, + 'visible' => true, 'value' => '1', ], ], @@ -120,22 +137,44 @@ public function setUp(): void { $this->urlGenerator = $this->createMock(IURLGenerator::class); $this->userManager = $this->createMock(IUserManager::class); $this->accountManager = $this->createMock(IAccountManager::class); + $this->profileManager = $this->createMock(IProfileManager::class); $this->referenceProvider = new ProfilePickerReferenceProvider( $this->l10n, $this->urlGenerator, $this->userManager, $this->accountManager, + $this->profileManager, $this->userId ); $this->urlGenerator->expects($this->any()) ->method('getBaseUrl') ->willReturn($this->baseUrl); + + $this->profileManager->expects($this->any()) + ->method('isProfileEnabled') + ->willReturn(true); + + $this->profileManager->expects($this->any()) + ->method('isProfileFieldVisible') + ->willReturnCallback(function (string $profileField, IUser $targetUser, ?IUser $visitingUser) { + return $this->testAccountsData[$targetUser->getUID()][$profileField]['visible'] + && $this->testAccountsData[$targetUser->getUID()][$profileField]['scope'] !== IAccountManager::SCOPE_PRIVATE; + }); + + $this->adminUser = $this->createMock(IUser::class); + $this->adminUser->expects($this->any()) + ->method('getUID') + ->willReturn('admin'); + $this->adminUser->expects($this->any()) + ->method('getDisplayName') + ->willReturn('admin'); } private function getTestAccountPropertyValue(string $testUserId, string $property): mixed { - if ($this->testAccountsData[$testUserId][$property]['scope'] === IAccountManager::SCOPE_PRIVATE) { + if (!$this->testAccountsData[$testUserId][$property]['visible'] + || $this->testAccountsData[$testUserId][$property]['scope'] === IAccountManager::SCOPE_PRIVATE) { return null; } return $this->testAccountsData[$testUserId][$property]['value']; @@ -163,8 +202,14 @@ private function setupUserAccountReferenceExpectation(string $userId): ?IReferen $this->userManager->expects($this->any()) ->method('get') - ->with($userId) - ->willReturn($user); + ->willReturnCallback(function (string $uid) use ($user, $userId) { + if ($uid === $userId) { + return $user; + } elseif ($uid === 'admin') { + return $this->adminUser; + } + return null; + }); // setup account expectations $account = $this->createMock(IAccount::class);