From 744eb7a4af37a72cac845cc194f47b06e8d2b2b0 Mon Sep 17 00:00:00 2001 From: mykh-hailo Date: Tue, 31 Mar 2026 11:41:27 +0200 Subject: [PATCH 1/2] fix: duplicate dashboard widget Signed-off-by: mykh-hailo --- .../lib/Controller/DashboardApiController.php | 1 + .../lib/Service/DashboardService.php | 32 +++++++++++++++++-- apps/dashboard/tests/DashboardServiceTest.php | 19 +++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/apps/dashboard/lib/Controller/DashboardApiController.php b/apps/dashboard/lib/Controller/DashboardApiController.php index d39441ddb47ba..0fd6130d9c42a 100644 --- a/apps/dashboard/lib/Controller/DashboardApiController.php +++ b/apps/dashboard/lib/Controller/DashboardApiController.php @@ -202,6 +202,7 @@ public function getLayout(): DataResponse { #[NoAdminRequired] #[ApiRoute(verb: 'POST', url: '/api/v3/layout')] public function updateLayout(array $layout): DataResponse { + $layout = $this->service->sanitizeLayout($layout); $this->userConfig->setValueString($this->userId, 'dashboard', 'layout', implode(',', $layout)); return new DataResponse(['layout' => $layout]); } diff --git a/apps/dashboard/lib/Service/DashboardService.php b/apps/dashboard/lib/Service/DashboardService.php index feb8cf307d480..46c46f54eb02f 100644 --- a/apps/dashboard/lib/Service/DashboardService.php +++ b/apps/dashboard/lib/Service/DashboardService.php @@ -31,12 +31,19 @@ public function __construct( */ public function getLayout(): array { $systemDefault = $this->appConfig->getAppValueString('layout', 'recommendations,spreed,mail,calendar'); - return array_values(array_filter( + return $this->sanitizeStringList( explode(',', $this->userConfig->getValueString($this->userId, 'dashboard', 'layout', $systemDefault)), - fn (string $value) => $value !== '') ); } + /** + * @param list $layout + * @return list + */ + public function sanitizeLayout(array $layout): array { + return $this->sanitizeStringList($layout); + } + /** * @return list */ @@ -73,4 +80,25 @@ public function getBirthdate(): string { return $birthdate->getValue(); } + + /** + * Keep insertion order while removing empty and duplicate values. + * + * @param list $values + * @return list + */ + private function sanitizeStringList(array $values): array { + $seen = []; + $result = []; + foreach ($values as $value) { + if ($value === '' || isset($seen[$value])) { + continue; + } + + $seen[$value] = true; + $result[] = $value; + } + + return $result; + } } diff --git a/apps/dashboard/tests/DashboardServiceTest.php b/apps/dashboard/tests/DashboardServiceTest.php index 4c53644995b1f..15cf3382f403c 100644 --- a/apps/dashboard/tests/DashboardServiceTest.php +++ b/apps/dashboard/tests/DashboardServiceTest.php @@ -44,6 +44,25 @@ protected function setUp(): void { ); } + public function testGetLayoutRemovesEmptyAndDuplicateEntries(): void { + $this->appConfig->method('getAppValueString') + ->with('layout', 'recommendations,spreed,mail,calendar') + ->willReturn('recommendations,spreed,mail,calendar'); + $this->userConfig->method('getValueString') + ->with('alice', 'dashboard', 'layout', 'recommendations,spreed,mail,calendar') + ->willReturn('spreed,,mail,mail,calendar,spreed'); + + $layout = $this->service->getLayout(); + + $this->assertSame(['spreed', 'mail', 'calendar'], $layout); + } + + public function testSanitizeLayoutRemovesEmptyAndDuplicateEntries(): void { + $layout = $this->service->sanitizeLayout(['files', 'calendar', 'files', '', 'mail', 'calendar']); + + $this->assertSame(['files', 'calendar', 'mail'], $layout); + } + public function testGetBirthdate(): void { $user = $this->createMock(IUser::class); $this->userManager->method('get') From cf0e579619237d3baa93626d8a80eb04da6019c6 Mon Sep 17 00:00:00 2001 From: mykh-hailo Date: Tue, 31 Mar 2026 12:00:07 +0200 Subject: [PATCH 2/2] fix: move sanitize directly to sanitizeLayout Signed-off-by: mykh-hailo --- .../lib/Service/DashboardService.php | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/apps/dashboard/lib/Service/DashboardService.php b/apps/dashboard/lib/Service/DashboardService.php index 46c46f54eb02f..c94617d69417b 100644 --- a/apps/dashboard/lib/Service/DashboardService.php +++ b/apps/dashboard/lib/Service/DashboardService.php @@ -31,7 +31,7 @@ public function __construct( */ public function getLayout(): array { $systemDefault = $this->appConfig->getAppValueString('layout', 'recommendations,spreed,mail,calendar'); - return $this->sanitizeStringList( + return $this->sanitizeLayout( explode(',', $this->userConfig->getValueString($this->userId, 'dashboard', 'layout', $systemDefault)), ); } @@ -41,7 +41,18 @@ public function getLayout(): array { * @return list */ public function sanitizeLayout(array $layout): array { - return $this->sanitizeStringList($layout); + $seen = []; + $result = []; + foreach ($layout as $value) { + if ($value === '' || isset($seen[$value])) { + continue; + } + + $seen[$value] = true; + $result[] = $value; + } + + return $result; } /** @@ -80,25 +91,4 @@ public function getBirthdate(): string { return $birthdate->getValue(); } - - /** - * Keep insertion order while removing empty and duplicate values. - * - * @param list $values - * @return list - */ - private function sanitizeStringList(array $values): array { - $seen = []; - $result = []; - foreach ($values as $value) { - if ($value === '' || isset($seen[$value])) { - continue; - } - - $seen[$value] = true; - $result[] = $value; - } - - return $result; - } }