From 3a2739fdd80954906b17d428e8b1a2cb4754e980 Mon Sep 17 00:00:00 2001 From: Sebastian Krupinski Date: Wed, 4 Mar 2026 20:35:00 -0500 Subject: [PATCH] fix: user settings Signed-off-by: Sebastian Krupinski --- core/lib/Controllers/InitController.php | 2 +- .../Controllers/UserSettingsController.php | 20 +++++------ core/lib/Service/UserAccountsService.php | 4 +-- core/lib/Stores/UserAccountsStore.php | 33 +++++++++++++++++-- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/core/lib/Controllers/InitController.php b/core/lib/Controllers/InitController.php index 7defcf3..3f375a4 100644 --- a/core/lib/Controllers/InitController.php +++ b/core/lib/Controllers/InitController.php @@ -60,7 +60,7 @@ class InitController extends ControllerAbstract 'permissions' => $this->userIdentity->identity()->getPermissions(), ], 'profile' => $this->userService->getEditableFields($this->userIdentity->identifier()), - 'settings' => $this->userService->fetchSettings(), + 'settings' => $this->userService->fetchSettings([], true), ]; return new JsonResponse($configuration); diff --git a/core/lib/Controllers/UserSettingsController.php b/core/lib/Controllers/UserSettingsController.php index ce0ef04..b71aa83 100644 --- a/core/lib/Controllers/UserSettingsController.php +++ b/core/lib/Controllers/UserSettingsController.php @@ -2,6 +2,7 @@ namespace KTXC\Controllers; +use KTXC\Http\Request\Request; use KTXC\Http\Response\JsonResponse; use KTXC\Service\UserAccountsService; use KTXC\SessionIdentity; @@ -18,7 +19,7 @@ class UserSettingsController extends ControllerAbstract ) {} /** - * Retrieve user settings + * Retrieve user settings, with optional filtering * If no specific settings are requested, all settings are returned * * @return JsonResponse Settings data as key-value pairs @@ -29,10 +30,9 @@ class UserSettingsController extends ControllerAbstract methods: ['GET'], permissions: ['user.settings.read'] )] - public function read(): JsonResponse + public function read(bool $flatten = false): JsonResponse { - // Fetch all settings (no filter) - $settings = $this->userService->fetchSettings(); + $settings = $this->userService->fetchSettings(flatten: $flatten); return new JsonResponse($settings, JsonResponse::HTTP_OK); } @@ -55,17 +55,17 @@ class UserSettingsController extends ControllerAbstract */ #[AuthenticatedRoute( '/user/settings', - name: 'user.settings.update', - methods: ['PUT', 'PATCH'], - permissions: ['user.settings.update'] + name: 'user.settings.write', + methods: ['POST', 'PUT', 'PATCH'], + permissions: ['user.settings.write'] )] - public function update(array $data): JsonResponse + public function write(array $data): JsonResponse { $this->userService->storeSettings($data); // Return updated settings - $updatedSettings = $this->userService->fetchSettings(array_keys($data)); + $settings = $this->userService->fetchSettings(array_keys($data)); - return new JsonResponse($updatedSettings, JsonResponse::HTTP_OK); + return new JsonResponse($settings, JsonResponse::HTTP_OK); } } diff --git a/core/lib/Service/UserAccountsService.php b/core/lib/Service/UserAccountsService.php index 70ec62d..7936b5c 100644 --- a/core/lib/Service/UserAccountsService.php +++ b/core/lib/Service/UserAccountsService.php @@ -116,9 +116,9 @@ class UserAccountsService // Settings Operations // ========================================================================= - public function fetchSettings(array $settings = []): array | null + public function fetchSettings(array $settings = [], bool $flatten = false): array | null { - return $this->userStore->fetchSettings($this->tenantIdentity->identifier(), $this->userIdentity->identifier(), $settings); + return $this->userStore->fetchSettings($this->tenantIdentity->identifier(), $this->userIdentity->identifier(), $settings, $flatten); } public function storeSettings(array $settings): bool diff --git a/core/lib/Stores/UserAccountsStore.php b/core/lib/Stores/UserAccountsStore.php index bda6f8f..743c48d 100644 --- a/core/lib/Stores/UserAccountsStore.php +++ b/core/lib/Stores/UserAccountsStore.php @@ -249,7 +249,7 @@ class UserAccountsStore // Settings Operations // ========================================================================= - public function fetchSettings(string $tenant, string $uid, array $settings = []): ?array + public function fetchSettings(string $tenant, string $uid, array $settings = [], bool $flatten = false): ?array { // Only fetch the settings field from the database $user = $this->store->selectCollection('user_accounts')->findOne( @@ -264,12 +264,39 @@ class UserAccountsStore $userSettings = $user['settings'] ?? []; if (empty($settings)) { - return $userSettings; + return $flatten ? $this->flattenSettings($userSettings) : $userSettings; } + // Specific keys are always returned in dot-notation (already flat) $result = []; foreach ($settings as $key) { - $result[$key] = $userSettings[$key] ?? null; + $parts = explode('.', $key); + $value = $userSettings; + foreach ($parts as $part) { + if (!is_array($value) || !array_key_exists($part, $value)) { + $value = null; + break; + } + $value = $value[$part]; + } + $result[$key] = $value; + } + return $result; + } + + /** + * Recursively flatten a nested settings array into dot-notation keys. + */ + private function flattenSettings(array $settings, string $prefix = ''): array + { + $result = []; + foreach ($settings as $key => $value) { + $fullKey = $prefix !== '' ? "{$prefix}.{$key}" : (string) $key; + if (is_array($value)) { + $result = array_merge($result, $this->flattenSettings($value, $fullKey)); + } else { + $result[$fullKey] = $value; + } } return $result; } -- 2.39.5