Completed
Push — master ( 3dac5b...93296c )
by John
47:41 queued 07:34
created
lib/private/Profile/ProfileManager.php 1 patch
Indentation   +388 added lines, -388 removed lines patch added patch discarded remove patch
@@ -39,392 +39,392 @@
 block discarded – undo
39 39
  * @psalm-import-type CoreProfileFields from ResponseDefinitions
40 40
  */
41 41
 class ProfileManager implements IProfileManager {
42
-	/** @var ILinkAction[] */
43
-	private array $actions = [];
44
-
45
-	/** @var null|ILinkAction[] */
46
-	private ?array $sortedActions = null;
47
-	/** @var CappedMemoryCache<ProfileConfig> */
48
-	private CappedMemoryCache $configCache;
49
-
50
-	private const CORE_APP_ID = 'core';
51
-
52
-	/**
53
-	 * Array of account property actions
54
-	 */
55
-	private const ACCOUNT_PROPERTY_ACTIONS = [
56
-		EmailAction::class,
57
-		PhoneAction::class,
58
-		WebsiteAction::class,
59
-		TwitterAction::class,
60
-		BlueskyAction::class,
61
-		FediverseAction::class,
62
-	];
63
-
64
-	/**
65
-	 * Array of account properties displayed on the profile
66
-	 */
67
-	private const PROFILE_PROPERTIES = [
68
-		IAccountManager::PROPERTY_ADDRESS,
69
-		IAccountManager::PROPERTY_AVATAR,
70
-		IAccountManager::PROPERTY_BIOGRAPHY,
71
-		IAccountManager::PROPERTY_DISPLAYNAME,
72
-		IAccountManager::PROPERTY_HEADLINE,
73
-		IAccountManager::PROPERTY_ORGANISATION,
74
-		IAccountManager::PROPERTY_ROLE,
75
-		IAccountManager::PROPERTY_PRONOUNS,
76
-	];
77
-
78
-	public function __construct(
79
-		private IAccountManager $accountManager,
80
-		private IAppManager $appManager,
81
-		private IConfig $config,
82
-		private ProfileConfigMapper $configMapper,
83
-		private ContainerInterface $container,
84
-		private KnownUserService $knownUserService,
85
-		private IFactory $l10nFactory,
86
-		private LoggerInterface $logger,
87
-		private Coordinator $coordinator,
88
-	) {
89
-		$this->configCache = new CappedMemoryCache();
90
-	}
91
-
92
-	/**
93
-	 * If no user is passed as an argument return whether profile is enabled globally in `config.php`
94
-	 */
95
-	public function isProfileEnabled(?IUser $user = null): bool {
96
-		$profileEnabledGlobally = $this->config->getSystemValueBool('profile.enabled', true);
97
-
98
-		if (empty($user) || !$profileEnabledGlobally) {
99
-			return $profileEnabledGlobally;
100
-		}
101
-
102
-		$account = $this->accountManager->getAccount($user);
103
-		return (bool)filter_var(
104
-			$account->getProperty(IAccountManager::PROPERTY_PROFILE_ENABLED)->getValue(),
105
-			FILTER_VALIDATE_BOOLEAN,
106
-			FILTER_NULL_ON_FAILURE,
107
-		);
108
-	}
109
-
110
-	/**
111
-	 * Register an action for the user
112
-	 */
113
-	private function registerAction(ILinkAction $action, IUser $targetUser, ?IUser $visitingUser): void {
114
-		$action->preload($targetUser);
115
-
116
-		if ($action->getTarget() === null) {
117
-			// Actions without a target are not registered
118
-			return;
119
-		}
120
-
121
-		if ($action->getAppId() !== self::CORE_APP_ID) {
122
-			if (!$this->appManager->isEnabledForUser($action->getAppId(), $targetUser)) {
123
-				$this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the target user: ' . $targetUser->getUID());
124
-				return;
125
-			}
126
-			if (!$this->appManager->isEnabledForUser($action->getAppId(), $visitingUser)) {
127
-				$this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the visiting user: ' . ($visitingUser ? $visitingUser->getUID() : '(user not connected)'));
128
-				return;
129
-			}
130
-		}
131
-
132
-		if (in_array($action->getId(), self::PROFILE_PROPERTIES, true)) {
133
-			$this->logger->error('Cannot register action with ID: ' . $action->getId() . ', as it is used by a core account property.');
134
-			return;
135
-		}
136
-
137
-		if (isset($this->actions[$action->getId()])) {
138
-			$this->logger->error('Cannot register duplicate action: ' . $action->getId());
139
-			return;
140
-		}
141
-
142
-		// Add action to associative array of actions
143
-		$this->actions[$action->getId()] = $action;
144
-	}
145
-
146
-	/**
147
-	 * Return an array of registered profile actions for the user
148
-	 *
149
-	 * @return ILinkAction[]
150
-	 */
151
-	private function getActions(IUser $targetUser, ?IUser $visitingUser): array {
152
-		// If actions are already registered and sorted, return them
153
-		if ($this->sortedActions !== null) {
154
-			return $this->sortedActions;
155
-		}
156
-
157
-		foreach (self::ACCOUNT_PROPERTY_ACTIONS as $actionClass) {
158
-			/** @var ILinkAction $action */
159
-			$action = $this->container->get($actionClass);
160
-			$this->registerAction($action, $targetUser, $visitingUser);
161
-		}
162
-
163
-		$context = $this->coordinator->getRegistrationContext();
164
-
165
-		if ($context !== null) {
166
-			foreach ($context->getProfileLinkActions() as $registration) {
167
-				/** @var ILinkAction $action */
168
-				$action = $this->container->get($registration->getService());
169
-				$this->registerAction($action, $targetUser, $visitingUser);
170
-			}
171
-		}
172
-
173
-		$actionsClone = $this->actions;
174
-		// Sort associative array into indexed array in ascending order of priority
175
-		usort($actionsClone, function (ILinkAction $a, ILinkAction $b) {
176
-			return $a->getPriority() === $b->getPriority() ? 0 : ($a->getPriority() < $b->getPriority() ? -1 : 1);
177
-		});
178
-
179
-		$this->sortedActions = $actionsClone;
180
-		return $this->sortedActions;
181
-	}
182
-
183
-	/**
184
-	 * Return whether the profile parameter of the target user
185
-	 * is visible to the visiting user
186
-	 */
187
-	public function isProfileFieldVisible(string $profileField, IUser $targetUser, ?IUser $visitingUser): bool {
188
-		try {
189
-			$account = $this->accountManager->getAccount($targetUser);
190
-			$scope = $account->getProperty($profileField)->getScope();
191
-		} catch (PropertyDoesNotExistException $e) {
192
-			// Allow the exception as not all profile parameters are account properties
193
-		}
194
-
195
-		$visibility = $this->getProfileConfig($targetUser, $visitingUser)[$profileField]['visibility'];
196
-		// Handle profile visibility and account property scope
197
-
198
-		if ($visibility === self::VISIBILITY_SHOW_USERS_ONLY) {
199
-			if (empty($scope)) {
200
-				return $visitingUser !== null;
201
-			}
202
-
203
-			return match ($scope) {
204
-				IAccountManager::SCOPE_PRIVATE => $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()),
205
-				IAccountManager::SCOPE_LOCAL,
206
-				IAccountManager::SCOPE_FEDERATED,
207
-				IAccountManager::SCOPE_PUBLISHED => $visitingUser !== null,
208
-				default => false,
209
-			};
210
-		}
211
-
212
-		if ($visibility === self::VISIBILITY_SHOW) {
213
-			if (empty($scope)) {
214
-				return true;
215
-			}
216
-
217
-			return match ($scope) {
218
-				IAccountManager::SCOPE_PRIVATE => $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()),
219
-				IAccountManager::SCOPE_LOCAL,
220
-				IAccountManager::SCOPE_FEDERATED,
221
-				IAccountManager::SCOPE_PUBLISHED => true,
222
-				default => false,
223
-			};
224
-		}
225
-
226
-		return false;
227
-	}
228
-
229
-	/**
230
-	 * Return the profile parameters of the target user that are visible to the visiting user
231
-	 * in an associative array
232
-	 * @psalm-return CoreProfileFields
233
-	 */
234
-	public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array {
235
-		$account = $this->accountManager->getAccount($targetUser);
236
-
237
-		// Initialize associative array of profile parameters
238
-		$profileParameters = [
239
-			'userId' => $account->getUser()->getUID(),
240
-		];
241
-
242
-		// Add account properties
243
-		foreach (self::PROFILE_PROPERTIES as $property) {
244
-			switch ($property) {
245
-				case IAccountManager::PROPERTY_ADDRESS:
246
-				case IAccountManager::PROPERTY_BIOGRAPHY:
247
-				case IAccountManager::PROPERTY_DISPLAYNAME:
248
-				case IAccountManager::PROPERTY_HEADLINE:
249
-				case IAccountManager::PROPERTY_ORGANISATION:
250
-				case IAccountManager::PROPERTY_ROLE:
251
-				case IAccountManager::PROPERTY_PRONOUNS:
252
-					$profileParameters[$property]
253
-						= $this->isProfileFieldVisible($property, $targetUser, $visitingUser)
254
-						// Explicitly set to null when value is empty string
255
-						? ($account->getProperty($property)->getValue() ?: null)
256
-						: null;
257
-					break;
258
-				case IAccountManager::PROPERTY_AVATAR:
259
-					// Add avatar visibility
260
-					$profileParameters['isUserAvatarVisible'] = $this->isProfileFieldVisible($property, $targetUser, $visitingUser);
261
-					break;
262
-			}
263
-		}
264
-
265
-		// Add actions
266
-		$profileParameters['actions'] = array_map(
267
-			function (ILinkAction $action) {
268
-				return [
269
-					'id' => $action->getId(),
270
-					'icon' => $action->getIcon(),
271
-					'title' => $action->getTitle(),
272
-					'target' => $action->getTarget(),
273
-				];
274
-			},
275
-			// This is needed to reindex the array after filtering
276
-			array_values(
277
-				array_filter(
278
-					$this->getActions($targetUser, $visitingUser),
279
-					function (ILinkAction $action) use ($targetUser, $visitingUser) {
280
-						return $this->isProfileFieldVisible($action->getId(), $targetUser, $visitingUser);
281
-					}
282
-				),
283
-			)
284
-		);
285
-
286
-		return $profileParameters;
287
-	}
288
-
289
-	/**
290
-	 * Return the filtered profile config containing only
291
-	 * the properties to be stored on the database
292
-	 */
293
-	private function filterNotStoredProfileConfig(array $profileConfig): array {
294
-		$dbParamConfigProperties = [
295
-			'visibility',
296
-		];
297
-
298
-		foreach ($profileConfig as $paramId => $paramConfig) {
299
-			$profileConfig[$paramId] = array_intersect_key($paramConfig, array_flip($dbParamConfigProperties));
300
-		}
301
-
302
-		return $profileConfig;
303
-	}
304
-
305
-	/**
306
-	 * Return the default profile config
307
-	 */
308
-	private function getDefaultProfileConfig(IUser $targetUser, ?IUser $visitingUser): array {
309
-		// Construct the default config for actions
310
-		$actionsConfig = [];
311
-		foreach ($this->getActions($targetUser, $visitingUser) as $action) {
312
-			$actionsConfig[$action->getId()] = ['visibility' => self::DEFAULT_VISIBILITY];
313
-		}
314
-
315
-		// Construct the default config for account properties
316
-		$propertiesConfig = [];
317
-		foreach (self::DEFAULT_PROPERTY_VISIBILITY as $property => $visibility) {
318
-			$propertiesConfig[$property] = ['visibility' => $visibility];
319
-		}
320
-
321
-		return array_merge($actionsConfig, $propertiesConfig);
322
-	}
323
-
324
-	/**
325
-	 * Return the profile config of the target user,
326
-	 * if a config does not already exist a default config is created and returned
327
-	 */
328
-	public function getProfileConfig(IUser $targetUser, ?IUser $visitingUser): array {
329
-		$defaultProfileConfig = $this->getDefaultProfileConfig($targetUser, $visitingUser);
330
-		try {
331
-			if (($config = $this->configCache[$targetUser->getUID()]) === null) {
332
-				$config = $this->configMapper->get($targetUser->getUID());
333
-				$this->configCache[$targetUser->getUID()] = $config;
334
-			}
335
-			// Merge defaults with the existing config in case the defaults are missing
336
-			$config->setConfigArray(array_merge(
337
-				$defaultProfileConfig,
338
-				$this->filterNotStoredProfileConfig($config->getConfigArray()),
339
-			));
340
-			$this->configMapper->update($config);
341
-			$configArray = $config->getConfigArray();
342
-		} catch (DoesNotExistException $e) {
343
-			// Create a new default config if it does not exist
344
-			$config = new ProfileConfig();
345
-			$config->setUserId($targetUser->getUID());
346
-			$config->setConfigArray($defaultProfileConfig);
347
-			$this->configMapper->insert($config);
348
-			$configArray = $config->getConfigArray();
349
-		}
350
-
351
-		return $configArray;
352
-	}
353
-
354
-	/**
355
-	 * Return the profile config of the target user with additional metadata,
356
-	 * if a config does not already exist a default config is created and returned
357
-	 */
358
-	public function getProfileConfigWithMetadata(IUser $targetUser, ?IUser $visitingUser): array {
359
-		$configArray = $this->getProfileConfig($targetUser, $visitingUser);
360
-
361
-		$actionsMetadata = [];
362
-		foreach ($this->getActions($targetUser, $visitingUser) as $action) {
363
-			$actionsMetadata[$action->getId()] = [
364
-				'appId' => $action->getAppId(),
365
-				'displayId' => $action->getDisplayId(),
366
-			];
367
-		}
368
-
369
-		// Add metadata for account property actions which are always configurable
370
-		foreach (self::ACCOUNT_PROPERTY_ACTIONS as $actionClass) {
371
-			/** @var ILinkAction $action */
372
-			$action = $this->container->get($actionClass);
373
-			if (!isset($actionsMetadata[$action->getId()])) {
374
-				$actionsMetadata[$action->getId()] = [
375
-					'appId' => $action->getAppId(),
376
-					'displayId' => $action->getDisplayId(),
377
-				];
378
-			}
379
-		}
380
-
381
-		$propertiesMetadata = [
382
-			IAccountManager::PROPERTY_ADDRESS => [
383
-				'appId' => self::CORE_APP_ID,
384
-				'displayId' => $this->l10nFactory->get('lib')->t('Address'),
385
-			],
386
-			IAccountManager::PROPERTY_AVATAR => [
387
-				'appId' => self::CORE_APP_ID,
388
-				'displayId' => $this->l10nFactory->get('lib')->t('Profile picture'),
389
-			],
390
-			IAccountManager::PROPERTY_BIOGRAPHY => [
391
-				'appId' => self::CORE_APP_ID,
392
-				'displayId' => $this->l10nFactory->get('lib')->t('About'),
393
-			],
394
-			IAccountManager::PROPERTY_DISPLAYNAME => [
395
-				'appId' => self::CORE_APP_ID,
396
-				'displayId' => $this->l10nFactory->get('lib')->t('Display name'),
397
-			],
398
-			IAccountManager::PROPERTY_HEADLINE => [
399
-				'appId' => self::CORE_APP_ID,
400
-				'displayId' => $this->l10nFactory->get('lib')->t('Headline'),
401
-			],
402
-			IAccountManager::PROPERTY_ORGANISATION => [
403
-				'appId' => self::CORE_APP_ID,
404
-				'displayId' => $this->l10nFactory->get('lib')->t('Organization'),
405
-			],
406
-			IAccountManager::PROPERTY_ROLE => [
407
-				'appId' => self::CORE_APP_ID,
408
-				'displayId' => $this->l10nFactory->get('lib')->t('Role'),
409
-			],
410
-			IAccountManager::PROPERTY_PRONOUNS => [
411
-				'appId' => self::CORE_APP_ID,
412
-				'displayId' => $this->l10nFactory->get('lib')->t('Pronouns'),
413
-			],
414
-		];
415
-
416
-		$paramMetadata = array_merge($actionsMetadata, $propertiesMetadata);
417
-		$configArray = array_intersect_key($configArray, $paramMetadata);
418
-
419
-		foreach ($configArray as $paramId => $paramConfig) {
420
-			if (isset($paramMetadata[$paramId])) {
421
-				$configArray[$paramId] = array_merge(
422
-					$paramConfig,
423
-					$paramMetadata[$paramId],
424
-				);
425
-			}
426
-		}
427
-
428
-		return $configArray;
429
-	}
42
+    /** @var ILinkAction[] */
43
+    private array $actions = [];
44
+
45
+    /** @var null|ILinkAction[] */
46
+    private ?array $sortedActions = null;
47
+    /** @var CappedMemoryCache<ProfileConfig> */
48
+    private CappedMemoryCache $configCache;
49
+
50
+    private const CORE_APP_ID = 'core';
51
+
52
+    /**
53
+     * Array of account property actions
54
+     */
55
+    private const ACCOUNT_PROPERTY_ACTIONS = [
56
+        EmailAction::class,
57
+        PhoneAction::class,
58
+        WebsiteAction::class,
59
+        TwitterAction::class,
60
+        BlueskyAction::class,
61
+        FediverseAction::class,
62
+    ];
63
+
64
+    /**
65
+     * Array of account properties displayed on the profile
66
+     */
67
+    private const PROFILE_PROPERTIES = [
68
+        IAccountManager::PROPERTY_ADDRESS,
69
+        IAccountManager::PROPERTY_AVATAR,
70
+        IAccountManager::PROPERTY_BIOGRAPHY,
71
+        IAccountManager::PROPERTY_DISPLAYNAME,
72
+        IAccountManager::PROPERTY_HEADLINE,
73
+        IAccountManager::PROPERTY_ORGANISATION,
74
+        IAccountManager::PROPERTY_ROLE,
75
+        IAccountManager::PROPERTY_PRONOUNS,
76
+    ];
77
+
78
+    public function __construct(
79
+        private IAccountManager $accountManager,
80
+        private IAppManager $appManager,
81
+        private IConfig $config,
82
+        private ProfileConfigMapper $configMapper,
83
+        private ContainerInterface $container,
84
+        private KnownUserService $knownUserService,
85
+        private IFactory $l10nFactory,
86
+        private LoggerInterface $logger,
87
+        private Coordinator $coordinator,
88
+    ) {
89
+        $this->configCache = new CappedMemoryCache();
90
+    }
91
+
92
+    /**
93
+     * If no user is passed as an argument return whether profile is enabled globally in `config.php`
94
+     */
95
+    public function isProfileEnabled(?IUser $user = null): bool {
96
+        $profileEnabledGlobally = $this->config->getSystemValueBool('profile.enabled', true);
97
+
98
+        if (empty($user) || !$profileEnabledGlobally) {
99
+            return $profileEnabledGlobally;
100
+        }
101
+
102
+        $account = $this->accountManager->getAccount($user);
103
+        return (bool)filter_var(
104
+            $account->getProperty(IAccountManager::PROPERTY_PROFILE_ENABLED)->getValue(),
105
+            FILTER_VALIDATE_BOOLEAN,
106
+            FILTER_NULL_ON_FAILURE,
107
+        );
108
+    }
109
+
110
+    /**
111
+     * Register an action for the user
112
+     */
113
+    private function registerAction(ILinkAction $action, IUser $targetUser, ?IUser $visitingUser): void {
114
+        $action->preload($targetUser);
115
+
116
+        if ($action->getTarget() === null) {
117
+            // Actions without a target are not registered
118
+            return;
119
+        }
120
+
121
+        if ($action->getAppId() !== self::CORE_APP_ID) {
122
+            if (!$this->appManager->isEnabledForUser($action->getAppId(), $targetUser)) {
123
+                $this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the target user: ' . $targetUser->getUID());
124
+                return;
125
+            }
126
+            if (!$this->appManager->isEnabledForUser($action->getAppId(), $visitingUser)) {
127
+                $this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the visiting user: ' . ($visitingUser ? $visitingUser->getUID() : '(user not connected)'));
128
+                return;
129
+            }
130
+        }
131
+
132
+        if (in_array($action->getId(), self::PROFILE_PROPERTIES, true)) {
133
+            $this->logger->error('Cannot register action with ID: ' . $action->getId() . ', as it is used by a core account property.');
134
+            return;
135
+        }
136
+
137
+        if (isset($this->actions[$action->getId()])) {
138
+            $this->logger->error('Cannot register duplicate action: ' . $action->getId());
139
+            return;
140
+        }
141
+
142
+        // Add action to associative array of actions
143
+        $this->actions[$action->getId()] = $action;
144
+    }
145
+
146
+    /**
147
+     * Return an array of registered profile actions for the user
148
+     *
149
+     * @return ILinkAction[]
150
+     */
151
+    private function getActions(IUser $targetUser, ?IUser $visitingUser): array {
152
+        // If actions are already registered and sorted, return them
153
+        if ($this->sortedActions !== null) {
154
+            return $this->sortedActions;
155
+        }
156
+
157
+        foreach (self::ACCOUNT_PROPERTY_ACTIONS as $actionClass) {
158
+            /** @var ILinkAction $action */
159
+            $action = $this->container->get($actionClass);
160
+            $this->registerAction($action, $targetUser, $visitingUser);
161
+        }
162
+
163
+        $context = $this->coordinator->getRegistrationContext();
164
+
165
+        if ($context !== null) {
166
+            foreach ($context->getProfileLinkActions() as $registration) {
167
+                /** @var ILinkAction $action */
168
+                $action = $this->container->get($registration->getService());
169
+                $this->registerAction($action, $targetUser, $visitingUser);
170
+            }
171
+        }
172
+
173
+        $actionsClone = $this->actions;
174
+        // Sort associative array into indexed array in ascending order of priority
175
+        usort($actionsClone, function (ILinkAction $a, ILinkAction $b) {
176
+            return $a->getPriority() === $b->getPriority() ? 0 : ($a->getPriority() < $b->getPriority() ? -1 : 1);
177
+        });
178
+
179
+        $this->sortedActions = $actionsClone;
180
+        return $this->sortedActions;
181
+    }
182
+
183
+    /**
184
+     * Return whether the profile parameter of the target user
185
+     * is visible to the visiting user
186
+     */
187
+    public function isProfileFieldVisible(string $profileField, IUser $targetUser, ?IUser $visitingUser): bool {
188
+        try {
189
+            $account = $this->accountManager->getAccount($targetUser);
190
+            $scope = $account->getProperty($profileField)->getScope();
191
+        } catch (PropertyDoesNotExistException $e) {
192
+            // Allow the exception as not all profile parameters are account properties
193
+        }
194
+
195
+        $visibility = $this->getProfileConfig($targetUser, $visitingUser)[$profileField]['visibility'];
196
+        // Handle profile visibility and account property scope
197
+
198
+        if ($visibility === self::VISIBILITY_SHOW_USERS_ONLY) {
199
+            if (empty($scope)) {
200
+                return $visitingUser !== null;
201
+            }
202
+
203
+            return match ($scope) {
204
+                IAccountManager::SCOPE_PRIVATE => $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()),
205
+                IAccountManager::SCOPE_LOCAL,
206
+                IAccountManager::SCOPE_FEDERATED,
207
+                IAccountManager::SCOPE_PUBLISHED => $visitingUser !== null,
208
+                default => false,
209
+            };
210
+        }
211
+
212
+        if ($visibility === self::VISIBILITY_SHOW) {
213
+            if (empty($scope)) {
214
+                return true;
215
+            }
216
+
217
+            return match ($scope) {
218
+                IAccountManager::SCOPE_PRIVATE => $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID()),
219
+                IAccountManager::SCOPE_LOCAL,
220
+                IAccountManager::SCOPE_FEDERATED,
221
+                IAccountManager::SCOPE_PUBLISHED => true,
222
+                default => false,
223
+            };
224
+        }
225
+
226
+        return false;
227
+    }
228
+
229
+    /**
230
+     * Return the profile parameters of the target user that are visible to the visiting user
231
+     * in an associative array
232
+     * @psalm-return CoreProfileFields
233
+     */
234
+    public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array {
235
+        $account = $this->accountManager->getAccount($targetUser);
236
+
237
+        // Initialize associative array of profile parameters
238
+        $profileParameters = [
239
+            'userId' => $account->getUser()->getUID(),
240
+        ];
241
+
242
+        // Add account properties
243
+        foreach (self::PROFILE_PROPERTIES as $property) {
244
+            switch ($property) {
245
+                case IAccountManager::PROPERTY_ADDRESS:
246
+                case IAccountManager::PROPERTY_BIOGRAPHY:
247
+                case IAccountManager::PROPERTY_DISPLAYNAME:
248
+                case IAccountManager::PROPERTY_HEADLINE:
249
+                case IAccountManager::PROPERTY_ORGANISATION:
250
+                case IAccountManager::PROPERTY_ROLE:
251
+                case IAccountManager::PROPERTY_PRONOUNS:
252
+                    $profileParameters[$property]
253
+                        = $this->isProfileFieldVisible($property, $targetUser, $visitingUser)
254
+                        // Explicitly set to null when value is empty string
255
+                        ? ($account->getProperty($property)->getValue() ?: null)
256
+                        : null;
257
+                    break;
258
+                case IAccountManager::PROPERTY_AVATAR:
259
+                    // Add avatar visibility
260
+                    $profileParameters['isUserAvatarVisible'] = $this->isProfileFieldVisible($property, $targetUser, $visitingUser);
261
+                    break;
262
+            }
263
+        }
264
+
265
+        // Add actions
266
+        $profileParameters['actions'] = array_map(
267
+            function (ILinkAction $action) {
268
+                return [
269
+                    'id' => $action->getId(),
270
+                    'icon' => $action->getIcon(),
271
+                    'title' => $action->getTitle(),
272
+                    'target' => $action->getTarget(),
273
+                ];
274
+            },
275
+            // This is needed to reindex the array after filtering
276
+            array_values(
277
+                array_filter(
278
+                    $this->getActions($targetUser, $visitingUser),
279
+                    function (ILinkAction $action) use ($targetUser, $visitingUser) {
280
+                        return $this->isProfileFieldVisible($action->getId(), $targetUser, $visitingUser);
281
+                    }
282
+                ),
283
+            )
284
+        );
285
+
286
+        return $profileParameters;
287
+    }
288
+
289
+    /**
290
+     * Return the filtered profile config containing only
291
+     * the properties to be stored on the database
292
+     */
293
+    private function filterNotStoredProfileConfig(array $profileConfig): array {
294
+        $dbParamConfigProperties = [
295
+            'visibility',
296
+        ];
297
+
298
+        foreach ($profileConfig as $paramId => $paramConfig) {
299
+            $profileConfig[$paramId] = array_intersect_key($paramConfig, array_flip($dbParamConfigProperties));
300
+        }
301
+
302
+        return $profileConfig;
303
+    }
304
+
305
+    /**
306
+     * Return the default profile config
307
+     */
308
+    private function getDefaultProfileConfig(IUser $targetUser, ?IUser $visitingUser): array {
309
+        // Construct the default config for actions
310
+        $actionsConfig = [];
311
+        foreach ($this->getActions($targetUser, $visitingUser) as $action) {
312
+            $actionsConfig[$action->getId()] = ['visibility' => self::DEFAULT_VISIBILITY];
313
+        }
314
+
315
+        // Construct the default config for account properties
316
+        $propertiesConfig = [];
317
+        foreach (self::DEFAULT_PROPERTY_VISIBILITY as $property => $visibility) {
318
+            $propertiesConfig[$property] = ['visibility' => $visibility];
319
+        }
320
+
321
+        return array_merge($actionsConfig, $propertiesConfig);
322
+    }
323
+
324
+    /**
325
+     * Return the profile config of the target user,
326
+     * if a config does not already exist a default config is created and returned
327
+     */
328
+    public function getProfileConfig(IUser $targetUser, ?IUser $visitingUser): array {
329
+        $defaultProfileConfig = $this->getDefaultProfileConfig($targetUser, $visitingUser);
330
+        try {
331
+            if (($config = $this->configCache[$targetUser->getUID()]) === null) {
332
+                $config = $this->configMapper->get($targetUser->getUID());
333
+                $this->configCache[$targetUser->getUID()] = $config;
334
+            }
335
+            // Merge defaults with the existing config in case the defaults are missing
336
+            $config->setConfigArray(array_merge(
337
+                $defaultProfileConfig,
338
+                $this->filterNotStoredProfileConfig($config->getConfigArray()),
339
+            ));
340
+            $this->configMapper->update($config);
341
+            $configArray = $config->getConfigArray();
342
+        } catch (DoesNotExistException $e) {
343
+            // Create a new default config if it does not exist
344
+            $config = new ProfileConfig();
345
+            $config->setUserId($targetUser->getUID());
346
+            $config->setConfigArray($defaultProfileConfig);
347
+            $this->configMapper->insert($config);
348
+            $configArray = $config->getConfigArray();
349
+        }
350
+
351
+        return $configArray;
352
+    }
353
+
354
+    /**
355
+     * Return the profile config of the target user with additional metadata,
356
+     * if a config does not already exist a default config is created and returned
357
+     */
358
+    public function getProfileConfigWithMetadata(IUser $targetUser, ?IUser $visitingUser): array {
359
+        $configArray = $this->getProfileConfig($targetUser, $visitingUser);
360
+
361
+        $actionsMetadata = [];
362
+        foreach ($this->getActions($targetUser, $visitingUser) as $action) {
363
+            $actionsMetadata[$action->getId()] = [
364
+                'appId' => $action->getAppId(),
365
+                'displayId' => $action->getDisplayId(),
366
+            ];
367
+        }
368
+
369
+        // Add metadata for account property actions which are always configurable
370
+        foreach (self::ACCOUNT_PROPERTY_ACTIONS as $actionClass) {
371
+            /** @var ILinkAction $action */
372
+            $action = $this->container->get($actionClass);
373
+            if (!isset($actionsMetadata[$action->getId()])) {
374
+                $actionsMetadata[$action->getId()] = [
375
+                    'appId' => $action->getAppId(),
376
+                    'displayId' => $action->getDisplayId(),
377
+                ];
378
+            }
379
+        }
380
+
381
+        $propertiesMetadata = [
382
+            IAccountManager::PROPERTY_ADDRESS => [
383
+                'appId' => self::CORE_APP_ID,
384
+                'displayId' => $this->l10nFactory->get('lib')->t('Address'),
385
+            ],
386
+            IAccountManager::PROPERTY_AVATAR => [
387
+                'appId' => self::CORE_APP_ID,
388
+                'displayId' => $this->l10nFactory->get('lib')->t('Profile picture'),
389
+            ],
390
+            IAccountManager::PROPERTY_BIOGRAPHY => [
391
+                'appId' => self::CORE_APP_ID,
392
+                'displayId' => $this->l10nFactory->get('lib')->t('About'),
393
+            ],
394
+            IAccountManager::PROPERTY_DISPLAYNAME => [
395
+                'appId' => self::CORE_APP_ID,
396
+                'displayId' => $this->l10nFactory->get('lib')->t('Display name'),
397
+            ],
398
+            IAccountManager::PROPERTY_HEADLINE => [
399
+                'appId' => self::CORE_APP_ID,
400
+                'displayId' => $this->l10nFactory->get('lib')->t('Headline'),
401
+            ],
402
+            IAccountManager::PROPERTY_ORGANISATION => [
403
+                'appId' => self::CORE_APP_ID,
404
+                'displayId' => $this->l10nFactory->get('lib')->t('Organization'),
405
+            ],
406
+            IAccountManager::PROPERTY_ROLE => [
407
+                'appId' => self::CORE_APP_ID,
408
+                'displayId' => $this->l10nFactory->get('lib')->t('Role'),
409
+            ],
410
+            IAccountManager::PROPERTY_PRONOUNS => [
411
+                'appId' => self::CORE_APP_ID,
412
+                'displayId' => $this->l10nFactory->get('lib')->t('Pronouns'),
413
+            ],
414
+        ];
415
+
416
+        $paramMetadata = array_merge($actionsMetadata, $propertiesMetadata);
417
+        $configArray = array_intersect_key($configArray, $paramMetadata);
418
+
419
+        foreach ($configArray as $paramId => $paramConfig) {
420
+            if (isset($paramMetadata[$paramId])) {
421
+                $configArray[$paramId] = array_merge(
422
+                    $paramConfig,
423
+                    $paramMetadata[$paramId],
424
+                );
425
+            }
426
+        }
427
+
428
+        return $configArray;
429
+    }
430 430
 }
Please login to merge, or discard this patch.
lib/public/Accounts/IAccountManager.php 1 patch
Indentation   +206 added lines, -206 removed lines patch added patch discarded remove patch
@@ -18,210 +18,210 @@
 block discarded – undo
18 18
  *
19 19
  */
20 20
 interface IAccountManager {
21
-	/**
22
-	 * Contact details visible locally only
23
-	 *
24
-	 * @since 21.0.1
25
-	 */
26
-	public const SCOPE_PRIVATE = 'v2-private';
27
-
28
-	/**
29
-	 * Contact details visible locally and through public link access on local instance
30
-	 *
31
-	 * @since 21.0.1
32
-	 */
33
-	public const SCOPE_LOCAL = 'v2-local';
34
-
35
-	/**
36
-	 * Contact details visible locally, through public link access and on trusted federated servers.
37
-	 *
38
-	 * @since 21.0.1
39
-	 */
40
-	public const SCOPE_FEDERATED = 'v2-federated';
41
-
42
-	/**
43
-	 * Contact details visible locally, through public link access, on trusted federated servers
44
-	 * and published to the public lookup server.
45
-	 *
46
-	 * @since 21.0.1
47
-	 */
48
-	public const SCOPE_PUBLISHED = 'v2-published';
49
-
50
-	/**
51
-	 * The list of allowed scopes
52
-	 *
53
-	 * @since 25.0.0
54
-	 */
55
-	public const ALLOWED_SCOPES = [
56
-		self::SCOPE_PRIVATE,
57
-		self::SCOPE_LOCAL,
58
-		self::SCOPE_FEDERATED,
59
-		self::SCOPE_PUBLISHED,
60
-	];
61
-
62
-	/**
63
-	 * @since 15.0.0
64
-	 */
65
-	public const PROPERTY_AVATAR = 'avatar';
66
-
67
-	/**
68
-	 * @since 15.0.0
69
-	 */
70
-	public const PROPERTY_DISPLAYNAME = 'displayname';
71
-
72
-	/**
73
-	 * @since 27.0.0
74
-	 * @deprecated 27.0.0 only added for backwards compatibility with provisioning_api UsersController::getCurrentUser
75
-	 */
76
-	public const PROPERTY_DISPLAYNAME_LEGACY = 'display-name';
77
-
78
-	/**
79
-	 * @since 15.0.0
80
-	 */
81
-	public const PROPERTY_PHONE = 'phone';
82
-
83
-	/**
84
-	 * @since 15.0.0
85
-	 */
86
-	public const PROPERTY_EMAIL = 'email';
87
-
88
-	/**
89
-	 * @since 15.0.0
90
-	 */
91
-	public const PROPERTY_WEBSITE = 'website';
92
-
93
-	/**
94
-	 * @since 15.0.0
95
-	 */
96
-	public const PROPERTY_ADDRESS = 'address';
97
-
98
-	/**
99
-	 * @since 15.0.0
100
-	 * @deprecated 32.0.0
101
-	 */
102
-	public const PROPERTY_TWITTER = 'twitter';
103
-
104
-	/**
105
-	 * @since 32.0.0
106
-	 */
107
-	public const PROPERTY_BLUESKY = 'bluesky';
108
-
109
-	/**
110
-	 * @since 26.0.0
111
-	 */
112
-	public const PROPERTY_FEDIVERSE = 'fediverse';
113
-
114
-	/**
115
-	 * @since 23.0.0
116
-	 */
117
-	public const PROPERTY_ORGANISATION = 'organisation';
118
-
119
-	/**
120
-	 * @since 23.0.0
121
-	 */
122
-	public const PROPERTY_ROLE = 'role';
123
-
124
-	/**
125
-	 * @since 23.0.0
126
-	 */
127
-	public const PROPERTY_HEADLINE = 'headline';
128
-
129
-	/**
130
-	 * @since 23.0.0
131
-	 */
132
-	public const PROPERTY_BIOGRAPHY = 'biography';
133
-
134
-	/**
135
-	 * @since 23.0.0
136
-	 */
137
-	public const PROPERTY_PROFILE_ENABLED = 'profile_enabled';
138
-
139
-	/**
140
-	 * @since 30.0.0
141
-	 */
142
-	public const PROPERTY_BIRTHDATE = 'birthdate';
143
-
144
-	/**
145
-	 * @since 31.0.0
146
-	 */
147
-	public const PROPERTY_PRONOUNS = 'pronouns';
148
-
149
-	/**
150
-	 * The list of allowed properties
151
-	 *
152
-	 * @since 25.0.0
153
-	 */
154
-	public const ALLOWED_PROPERTIES = [
155
-		self::PROPERTY_ADDRESS,
156
-		self::PROPERTY_AVATAR,
157
-		self::PROPERTY_BIOGRAPHY,
158
-		self::PROPERTY_BIRTHDATE,
159
-		self::PROPERTY_DISPLAYNAME,
160
-		self::PROPERTY_EMAIL,
161
-		self::PROPERTY_FEDIVERSE,
162
-		self::PROPERTY_HEADLINE,
163
-		self::PROPERTY_ORGANISATION,
164
-		self::PROPERTY_PHONE,
165
-		self::PROPERTY_PROFILE_ENABLED,
166
-		self::PROPERTY_PRONOUNS,
167
-		self::PROPERTY_ROLE,
168
-		self::PROPERTY_TWITTER,
169
-		self::PROPERTY_BLUESKY,
170
-		self::PROPERTY_WEBSITE,
171
-	];
172
-
173
-
174
-	/**
175
-	 * @since 22.0.0
176
-	 */
177
-	public const COLLECTION_EMAIL = 'additional_mail';
178
-
179
-	/**
180
-	 * @since 15.0.0
181
-	 */
182
-	public const NOT_VERIFIED = '0';
183
-
184
-	/**
185
-	 * @since 15.0.0
186
-	 */
187
-	public const VERIFICATION_IN_PROGRESS = '1';
188
-
189
-	/**
190
-	 * @since 15.0.0
191
-	 */
192
-	public const VERIFIED = '2';
193
-
194
-	/**
195
-	 * Get the account data for a given user
196
-	 *
197
-	 * @since 15.0.0
198
-	 *
199
-	 * @param IUser $user
200
-	 * @return IAccount
201
-	 */
202
-	public function getAccount(IUser $user): IAccount;
203
-
204
-	/**
205
-	 * Update the account data with for the user
206
-	 *
207
-	 * @since 21.0.1
208
-	 *
209
-	 * @param IAccount $account
210
-	 * @throws \InvalidArgumentException Message is the property that was invalid
211
-	 */
212
-	public function updateAccount(IAccount $account): void;
213
-
214
-	/**
215
-	 * Search for users based on account data
216
-	 *
217
-	 * @param string $property - property or property collection name – since
218
-	 *                         NC 22 the implementation MAY add a fitting property collection into the
219
-	 *                         search even if a property name was given e.g. email property and email
220
-	 *                         collection)
221
-	 * @param string[] $values
222
-	 * @return array
223
-	 *
224
-	 * @since 21.0.0
225
-	 */
226
-	public function searchUsers(string $property, array $values): array;
21
+    /**
22
+     * Contact details visible locally only
23
+     *
24
+     * @since 21.0.1
25
+     */
26
+    public const SCOPE_PRIVATE = 'v2-private';
27
+
28
+    /**
29
+     * Contact details visible locally and through public link access on local instance
30
+     *
31
+     * @since 21.0.1
32
+     */
33
+    public const SCOPE_LOCAL = 'v2-local';
34
+
35
+    /**
36
+     * Contact details visible locally, through public link access and on trusted federated servers.
37
+     *
38
+     * @since 21.0.1
39
+     */
40
+    public const SCOPE_FEDERATED = 'v2-federated';
41
+
42
+    /**
43
+     * Contact details visible locally, through public link access, on trusted federated servers
44
+     * and published to the public lookup server.
45
+     *
46
+     * @since 21.0.1
47
+     */
48
+    public const SCOPE_PUBLISHED = 'v2-published';
49
+
50
+    /**
51
+     * The list of allowed scopes
52
+     *
53
+     * @since 25.0.0
54
+     */
55
+    public const ALLOWED_SCOPES = [
56
+        self::SCOPE_PRIVATE,
57
+        self::SCOPE_LOCAL,
58
+        self::SCOPE_FEDERATED,
59
+        self::SCOPE_PUBLISHED,
60
+    ];
61
+
62
+    /**
63
+     * @since 15.0.0
64
+     */
65
+    public const PROPERTY_AVATAR = 'avatar';
66
+
67
+    /**
68
+     * @since 15.0.0
69
+     */
70
+    public const PROPERTY_DISPLAYNAME = 'displayname';
71
+
72
+    /**
73
+     * @since 27.0.0
74
+     * @deprecated 27.0.0 only added for backwards compatibility with provisioning_api UsersController::getCurrentUser
75
+     */
76
+    public const PROPERTY_DISPLAYNAME_LEGACY = 'display-name';
77
+
78
+    /**
79
+     * @since 15.0.0
80
+     */
81
+    public const PROPERTY_PHONE = 'phone';
82
+
83
+    /**
84
+     * @since 15.0.0
85
+     */
86
+    public const PROPERTY_EMAIL = 'email';
87
+
88
+    /**
89
+     * @since 15.0.0
90
+     */
91
+    public const PROPERTY_WEBSITE = 'website';
92
+
93
+    /**
94
+     * @since 15.0.0
95
+     */
96
+    public const PROPERTY_ADDRESS = 'address';
97
+
98
+    /**
99
+     * @since 15.0.0
100
+     * @deprecated 32.0.0
101
+     */
102
+    public const PROPERTY_TWITTER = 'twitter';
103
+
104
+    /**
105
+     * @since 32.0.0
106
+     */
107
+    public const PROPERTY_BLUESKY = 'bluesky';
108
+
109
+    /**
110
+     * @since 26.0.0
111
+     */
112
+    public const PROPERTY_FEDIVERSE = 'fediverse';
113
+
114
+    /**
115
+     * @since 23.0.0
116
+     */
117
+    public const PROPERTY_ORGANISATION = 'organisation';
118
+
119
+    /**
120
+     * @since 23.0.0
121
+     */
122
+    public const PROPERTY_ROLE = 'role';
123
+
124
+    /**
125
+     * @since 23.0.0
126
+     */
127
+    public const PROPERTY_HEADLINE = 'headline';
128
+
129
+    /**
130
+     * @since 23.0.0
131
+     */
132
+    public const PROPERTY_BIOGRAPHY = 'biography';
133
+
134
+    /**
135
+     * @since 23.0.0
136
+     */
137
+    public const PROPERTY_PROFILE_ENABLED = 'profile_enabled';
138
+
139
+    /**
140
+     * @since 30.0.0
141
+     */
142
+    public const PROPERTY_BIRTHDATE = 'birthdate';
143
+
144
+    /**
145
+     * @since 31.0.0
146
+     */
147
+    public const PROPERTY_PRONOUNS = 'pronouns';
148
+
149
+    /**
150
+     * The list of allowed properties
151
+     *
152
+     * @since 25.0.0
153
+     */
154
+    public const ALLOWED_PROPERTIES = [
155
+        self::PROPERTY_ADDRESS,
156
+        self::PROPERTY_AVATAR,
157
+        self::PROPERTY_BIOGRAPHY,
158
+        self::PROPERTY_BIRTHDATE,
159
+        self::PROPERTY_DISPLAYNAME,
160
+        self::PROPERTY_EMAIL,
161
+        self::PROPERTY_FEDIVERSE,
162
+        self::PROPERTY_HEADLINE,
163
+        self::PROPERTY_ORGANISATION,
164
+        self::PROPERTY_PHONE,
165
+        self::PROPERTY_PROFILE_ENABLED,
166
+        self::PROPERTY_PRONOUNS,
167
+        self::PROPERTY_ROLE,
168
+        self::PROPERTY_TWITTER,
169
+        self::PROPERTY_BLUESKY,
170
+        self::PROPERTY_WEBSITE,
171
+    ];
172
+
173
+
174
+    /**
175
+     * @since 22.0.0
176
+     */
177
+    public const COLLECTION_EMAIL = 'additional_mail';
178
+
179
+    /**
180
+     * @since 15.0.0
181
+     */
182
+    public const NOT_VERIFIED = '0';
183
+
184
+    /**
185
+     * @since 15.0.0
186
+     */
187
+    public const VERIFICATION_IN_PROGRESS = '1';
188
+
189
+    /**
190
+     * @since 15.0.0
191
+     */
192
+    public const VERIFIED = '2';
193
+
194
+    /**
195
+     * Get the account data for a given user
196
+     *
197
+     * @since 15.0.0
198
+     *
199
+     * @param IUser $user
200
+     * @return IAccount
201
+     */
202
+    public function getAccount(IUser $user): IAccount;
203
+
204
+    /**
205
+     * Update the account data with for the user
206
+     *
207
+     * @since 21.0.1
208
+     *
209
+     * @param IAccount $account
210
+     * @throws \InvalidArgumentException Message is the property that was invalid
211
+     */
212
+    public function updateAccount(IAccount $account): void;
213
+
214
+    /**
215
+     * Search for users based on account data
216
+     *
217
+     * @param string $property - property or property collection name – since
218
+     *                         NC 22 the implementation MAY add a fitting property collection into the
219
+     *                         search even if a property name was given e.g. email property and email
220
+     *                         collection)
221
+     * @param string[] $values
222
+     * @return array
223
+     *
224
+     * @since 21.0.0
225
+     */
226
+    public function searchUsers(string $property, array $values): array;
227 227
 }
Please login to merge, or discard this patch.
lib/public/Profile/IProfileManager.php 1 patch
Indentation   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -18,76 +18,76 @@
 block discarded – undo
18 18
  * @since 28.0.0
19 19
  */
20 20
 interface IProfileManager {
21
-	/**
22
-	 * Visible to users, guests, and public access
23
-	 *
24
-	 * @since 28.0.0
25
-	 */
26
-	public const VISIBILITY_SHOW = 'show';
21
+    /**
22
+     * Visible to users, guests, and public access
23
+     *
24
+     * @since 28.0.0
25
+     */
26
+    public const VISIBILITY_SHOW = 'show';
27 27
 
28
-	/**
29
-	 * Visible to users and guests
30
-	 *
31
-	 * @since 28.0.0
32
-	 */
33
-	public const VISIBILITY_SHOW_USERS_ONLY = 'show_users_only';
28
+    /**
29
+     * Visible to users and guests
30
+     *
31
+     * @since 28.0.0
32
+     */
33
+    public const VISIBILITY_SHOW_USERS_ONLY = 'show_users_only';
34 34
 
35
-	/**
36
-	 * Visible to nobody
37
-	 *
38
-	 * @since 28.0.0
39
-	 */
40
-	public const VISIBILITY_HIDE = 'hide';
35
+    /**
36
+     * Visible to nobody
37
+     *
38
+     * @since 28.0.0
39
+     */
40
+    public const VISIBILITY_HIDE = 'hide';
41 41
 
42
-	/**
43
-	 * Default account property visibility
44
-	 *
45
-	 * @since 28.0.0
46
-	 */
47
-	public const DEFAULT_PROPERTY_VISIBILITY = [
48
-		IAccountManager::PROPERTY_ADDRESS => self::VISIBILITY_SHOW_USERS_ONLY,
49
-		IAccountManager::PROPERTY_AVATAR => self::VISIBILITY_SHOW,
50
-		IAccountManager::PROPERTY_BIOGRAPHY => self::VISIBILITY_SHOW,
51
-		IAccountManager::PROPERTY_DISPLAYNAME => self::VISIBILITY_SHOW,
52
-		IAccountManager::PROPERTY_HEADLINE => self::VISIBILITY_SHOW,
53
-		IAccountManager::PROPERTY_ORGANISATION => self::VISIBILITY_SHOW,
54
-		IAccountManager::PROPERTY_ROLE => self::VISIBILITY_SHOW,
55
-		IAccountManager::PROPERTY_EMAIL => self::VISIBILITY_SHOW_USERS_ONLY,
56
-		IAccountManager::PROPERTY_PHONE => self::VISIBILITY_SHOW_USERS_ONLY,
57
-		IAccountManager::PROPERTY_TWITTER => self::VISIBILITY_SHOW,
58
-		IAccountManager::PROPERTY_BLUESKY => self::VISIBILITY_SHOW,
59
-		IAccountManager::PROPERTY_WEBSITE => self::VISIBILITY_SHOW,
60
-		IAccountManager::PROPERTY_PRONOUNS => self::VISIBILITY_SHOW,
61
-	];
42
+    /**
43
+     * Default account property visibility
44
+     *
45
+     * @since 28.0.0
46
+     */
47
+    public const DEFAULT_PROPERTY_VISIBILITY = [
48
+        IAccountManager::PROPERTY_ADDRESS => self::VISIBILITY_SHOW_USERS_ONLY,
49
+        IAccountManager::PROPERTY_AVATAR => self::VISIBILITY_SHOW,
50
+        IAccountManager::PROPERTY_BIOGRAPHY => self::VISIBILITY_SHOW,
51
+        IAccountManager::PROPERTY_DISPLAYNAME => self::VISIBILITY_SHOW,
52
+        IAccountManager::PROPERTY_HEADLINE => self::VISIBILITY_SHOW,
53
+        IAccountManager::PROPERTY_ORGANISATION => self::VISIBILITY_SHOW,
54
+        IAccountManager::PROPERTY_ROLE => self::VISIBILITY_SHOW,
55
+        IAccountManager::PROPERTY_EMAIL => self::VISIBILITY_SHOW_USERS_ONLY,
56
+        IAccountManager::PROPERTY_PHONE => self::VISIBILITY_SHOW_USERS_ONLY,
57
+        IAccountManager::PROPERTY_TWITTER => self::VISIBILITY_SHOW,
58
+        IAccountManager::PROPERTY_BLUESKY => self::VISIBILITY_SHOW,
59
+        IAccountManager::PROPERTY_WEBSITE => self::VISIBILITY_SHOW,
60
+        IAccountManager::PROPERTY_PRONOUNS => self::VISIBILITY_SHOW,
61
+    ];
62 62
 
63
-	/**
64
-	 * Default visibility
65
-	 *
66
-	 * @since 28.0.0
67
-	 */
68
-	public const DEFAULT_VISIBILITY = self::VISIBILITY_SHOW_USERS_ONLY;
63
+    /**
64
+     * Default visibility
65
+     *
66
+     * @since 28.0.0
67
+     */
68
+    public const DEFAULT_VISIBILITY = self::VISIBILITY_SHOW_USERS_ONLY;
69 69
 
70
-	/**
71
-	 * If no user is passed as an argument return whether profile is enabled globally in `config.php`
72
-	 *
73
-	 * @since 28.0.0
74
-	 */
75
-	public function isProfileEnabled(?IUser $user = null): bool;
70
+    /**
71
+     * If no user is passed as an argument return whether profile is enabled globally in `config.php`
72
+     *
73
+     * @since 28.0.0
74
+     */
75
+    public function isProfileEnabled(?IUser $user = null): bool;
76 76
 
77
-	/**
78
-	 * Return whether the profile parameter of the target user
79
-	 * is visible to the visiting user
80
-	 *
81
-	 * @since 28.0.0
82
-	 */
83
-	public function isProfileFieldVisible(string $profileField, IUser $targetUser, ?IUser $visitingUser): bool;
77
+    /**
78
+     * Return whether the profile parameter of the target user
79
+     * is visible to the visiting user
80
+     *
81
+     * @since 28.0.0
82
+     */
83
+    public function isProfileFieldVisible(string $profileField, IUser $targetUser, ?IUser $visitingUser): bool;
84 84
 
85
-	/**
86
-	 * Return the profile parameters of the target user that are visible to the visiting user
87
-	 * in an associative array
88
-	 *
89
-	 * @psalm-return CoreProfileFields
90
-	 * @since 28.0.0
91
-	 */
92
-	public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array;
85
+    /**
86
+     * Return the profile parameters of the target user that are visible to the visiting user
87
+     * in an associative array
88
+     *
89
+     * @psalm-return CoreProfileFields
90
+     * @since 28.0.0
91
+     */
92
+    public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array;
93 93
 }
Please login to merge, or discard this patch.