Skip to content

Commit

Permalink
Refine profile backend for frontend visibility requirements
Browse files Browse the repository at this point in the history
- Provide metadata
  - Dynamic displayId
  - Add appId
- Filter out unused parameter config properties from the existing profile config

Signed-off-by: Christopher Ng <chrng8@gmail.com>
  • Loading branch information
Pytal committed Oct 30, 2021
1 parent 5018aa1 commit 43878e0
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 46 deletions.
2 changes: 1 addition & 1 deletion apps/settings/lib/Settings/Personal/PersonalInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public function getForm(): TemplateResponse {
];

$profileParameters = [
'profileConfig' => $this->profileManager->getProfileConfig($user, $user),
'profileConfig' => $this->profileManager->getProfileConfig($user, $user, true),
];

$this->initialStateService->provideInitialState('personalInfoParameters', $personalInfoParameters);
Expand Down
153 changes: 108 additions & 45 deletions lib/private/Profile/ProfileManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

namespace OC\Profile;

use function Safe\array_flip;
use function Safe\usort;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\Core\Db\ProfileConfig;
Expand Down Expand Up @@ -77,6 +78,8 @@ class ProfileManager {
/** @var null|ILinkAction[] */
private $sortedActions = null;

private const CORE_APP_ID = 'core';

/**
* Array of account property actions
*/
Expand Down Expand Up @@ -123,26 +126,17 @@ public function __construct(
/**
* Register an action for the user
*/
private function registerAction(IUser $targetUser, ?IUser $visitingUser, ILinkAction $action): void {
private function registerAction(ILinkAction $action, IUser $targetUser, ?IUser $visitingUser): void {
$action->preload($targetUser);

if ($action->getTarget() === null) {
// Actions without a target are not registered
return;
}

if (isset($this->actions[$action->getId()])) {
$this->logger->error('Cannot register duplicate action: ' . $action->getId());
return;
}

if ($action->getAppId() !== 'core') {
if ($action->getAppId() !== self::CORE_APP_ID) {
if (!$this->appManager->isEnabledForUser($action->getAppId(), $targetUser)) {
$this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the user: ' . $targetUser->getUID());
return;
}
if ($visitingUser === null) {
$this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not available to non logged in users');
$this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the target user: ' . $targetUser->getUID());
return;
}
if (!$this->appManager->isEnabledForUser($action->getAppId(), $visitingUser)) {
Expand All @@ -156,6 +150,11 @@ private function registerAction(IUser $targetUser, ?IUser $visitingUser, ILinkAc
return;
}

if (isset($this->actions[$action->getId()])) {
$this->logger->error('Cannot register duplicate action: ' . $action->getId());
return;
}

// Add action to associative array of actions
$this->actions[$action->getId()] = $action;
}
Expand All @@ -174,7 +173,7 @@ private function getActions(IUser $targetUser, ?IUser $visitingUser): array {
foreach (self::ACCOUNT_PROPERTY_ACTIONS as $actionClass) {
/** @var ILinkAction $action */
$action = $this->container->get($actionClass);
$this->registerAction($targetUser, $visitingUser, $action);
$this->registerAction($action, $targetUser, $visitingUser);
}

$context = $this->coordinator->getRegistrationContext();
Expand All @@ -183,7 +182,7 @@ private function getActions(IUser $targetUser, ?IUser $visitingUser): array {
foreach ($context->getProfileLinkActions() as $registration) {
/** @var ILinkAction $action */
$action = $this->container->get($registration->getService());
$this->registerAction($targetUser, $visitingUser, $action);
$this->registerAction($action, $targetUser, $visitingUser);
}
}

Expand All @@ -201,7 +200,7 @@ private function getActions(IUser $targetUser, ?IUser $visitingUser): array {
* Return whether the profile parameter of the target user
* is visible to the visiting user
*/
private function isParameterVisible(IUser $targetUser, ?IUser $visitingUser, string $paramId): bool {
private function isParameterVisible(string $paramId, IUser $targetUser, ?IUser $visitingUser): bool {
try {
$account = $this->accountManager->getAccount($targetUser);
$scope = $account->getProperty($paramId)->getScope();
Expand Down Expand Up @@ -253,6 +252,7 @@ private function isParameterVisible(IUser $targetUser, ?IUser $visitingUser, str
*/
public function getProfileParams(IUser $targetUser, ?IUser $visitingUser): array {
$account = $this->accountManager->getAccount($targetUser);

// Initialize associative array of profile parameters
$profileParameters = [
'userId' => $account->getUser()->getUID(),
Expand All @@ -268,14 +268,14 @@ public function getProfileParams(IUser $targetUser, ?IUser $visitingUser): array
case IAccountManager::PROPERTY_ORGANISATION:
case IAccountManager::PROPERTY_ROLE:
$profileParameters[$property] =
$this->isParameterVisible($targetUser, $visitingUser, $property)
$this->isParameterVisible($property, $targetUser, $visitingUser)
// Explicitly set to null when value is empty string
? ($account->getProperty($property)->getValue() ?: null)
: null;
break;
case IAccountManager::PROPERTY_AVATAR:
// Add avatar visibility
$profileParameters['isUserAvatarVisible'] = $this->isParameterVisible($targetUser, $visitingUser, $property);
$profileParameters['isUserAvatarVisible'] = $this->isParameterVisible($property, $targetUser, $visitingUser);
break;
}
}
Expand All @@ -295,7 +295,7 @@ function (ILinkAction $action) {
array_filter(
$this->getActions($targetUser, $visitingUser),
function (ILinkAction $action) use ($targetUser, $visitingUser) {
return $this->isParameterVisible($targetUser, $visitingUser, $action->getId());
return $this->isParameterVisible($action->getId(), $targetUser, $visitingUser);
}
),
)
Expand All @@ -304,55 +304,56 @@ function (ILinkAction $action) use ($targetUser, $visitingUser) {
return $profileParameters;
}

/**
* Return the filtered profile config containing only
* the properties to be stored on the database
*/
private function filterProfileConfig(array $profileConfig): array {
$dbParamConfigProperties = [
'visibility',
];

foreach ($profileConfig as $paramId => $paramConfig) {
$profileConfig[$paramId] = array_intersect_key($paramConfig, array_flip($dbParamConfigProperties));
}

return $profileConfig;
}

/**
* Return the default profile config
*/
private function getDefaultProfileConfig(IUser $targetUser, ?IUser $visitingUser): array {
// Contruct the default config for actions
$actionsConfig = [];
foreach ($this->getActions($targetUser, $visitingUser) as $action) {
$actionsConfig[$action->getId()] = [
'displayId' => $action->getDisplayId(),
'visibility' => ProfileConfig::DEFAULT_VISIBILITY,
];
$actionsConfig[$action->getId()] = ['visibility' => ProfileConfig::DEFAULT_VISIBILITY];
}

// Map of account properties to display IDs
$propertyDisplayMap = [
IAccountManager::PROPERTY_ADDRESS => $this->l10nFactory->get('core')->t('Address'),
IAccountManager::PROPERTY_AVATAR => $this->l10nFactory->get('core')->t('Avatar'),
IAccountManager::PROPERTY_BIOGRAPHY => $this->l10nFactory->get('core')->t('About'),
IAccountManager::PROPERTY_DISPLAYNAME => $this->l10nFactory->get('core')->t('Full name'),
IAccountManager::PROPERTY_HEADLINE => $this->l10nFactory->get('core')->t('Headline'),
IAccountManager::PROPERTY_ORGANISATION => $this->l10nFactory->get('core')->t('Organisation'),
IAccountManager::PROPERTY_ROLE => $this->l10nFactory->get('core')->t('Role'),
IAccountManager::PROPERTY_EMAIL => $this->l10nFactory->get('core')->t('Email'),
IAccountManager::PROPERTY_PHONE => $this->l10nFactory->get('core')->t('Phone'),
IAccountManager::PROPERTY_TWITTER => $this->l10nFactory->get('core')->t('Twitter'),
IAccountManager::PROPERTY_WEBSITE => $this->l10nFactory->get('core')->t('Website'),
];

// Contruct the default config for account properties
$propertiesConfig = [];
foreach ($propertyDisplayMap as $property => $displayId) {
$propertiesConfig[$property] = [
'displayId' => $displayId,
'visibility' => ProfileConfig::DEFAULT_PROPERTY_VISIBILITY[$property],
];
foreach (ProfileConfig::DEFAULT_PROPERTY_VISIBILITY as $property => $visibility) {
$propertiesConfig[$property] = ['visibility' => $visibility];
}

return array_merge($actionsConfig, $propertiesConfig);
}

/**
* Return the profile config
* Return the profile config of the target user,
* if a config does not already exist a default config is created and returned
*
* Passing true to `$includeMetadata` will return additional metadata
*/
public function getProfileConfig(IUser $targetUser, ?IUser $visitingUser): array {
public function getProfileConfig(IUser $targetUser, ?IUser $visitingUser, bool $includeMetadata = false): array {
$defaultProfileConfig = $this->getDefaultProfileConfig($targetUser, $visitingUser);
try {
$config = $this->configMapper->get($targetUser->getUID());
// Merge defaults with the existing config in case the defaults are missing
$config->setConfigArray(array_merge($defaultProfileConfig, $config->getConfigArray()));
$config->setConfigArray(array_merge(
$defaultProfileConfig,
$this->filterProfileConfig($config->getConfigArray()),
));
$this->configMapper->update($config);
$configArray = $config->getConfigArray();
} catch (DoesNotExistException $e) {
Expand All @@ -364,6 +365,68 @@ public function getProfileConfig(IUser $targetUser, ?IUser $visitingUser): array
$configArray = $config->getConfigArray();
}

if ($includeMetadata) {
$actionsMetadata = [];
foreach ($this->getActions($targetUser, $visitingUser) as $action) {
$actionsMetadata[$action->getId()] = [
'appId' => $action->getAppId(),
'displayId' => $action->getDisplayId(),
];
}

// Add metadata for account property actions which are always configurable
foreach (self::ACCOUNT_PROPERTY_ACTIONS as $actionClass) {
/** @var ILinkAction $action */
$action = $this->container->get($actionClass);
$actionsMetadata[$action->getId()] = [
'appId' => $action->getAppId(),
'displayId' => $action->getDisplayId(),
];
}

$propertiesMetadata = [
IAccountManager::PROPERTY_ADDRESS => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get(self::CORE_APP_ID)->t('Address'),
],
IAccountManager::PROPERTY_AVATAR => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get(self::CORE_APP_ID)->t('Profile picture'),
],
IAccountManager::PROPERTY_BIOGRAPHY => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get(self::CORE_APP_ID)->t('About'),
],
IAccountManager::PROPERTY_DISPLAYNAME => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get(self::CORE_APP_ID)->t('Full name'),
],
IAccountManager::PROPERTY_HEADLINE => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get(self::CORE_APP_ID)->t('Headline'),
],
IAccountManager::PROPERTY_ORGANISATION => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get(self::CORE_APP_ID)->t('Organisation'),
],
IAccountManager::PROPERTY_ROLE => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get(self::CORE_APP_ID)->t('Role'),
],
];

$paramMetadata = array_merge($actionsMetadata, $propertiesMetadata);

foreach ($configArray as $paramId => $paramConfig) {
if (isset($paramMetadata[$paramId])) {
$configArray[$paramId] = array_merge(
$paramConfig,
$paramMetadata[$paramId],
);
}
}
}

return $configArray;
}
}

0 comments on commit 43878e0

Please sign in to comment.