From fc94930b16b4ec313cdb3a7eea5dd852ee0e42f6 Mon Sep 17 00:00:00 2001 From: Elizabeth Danzberger Date: Tue, 13 Jan 2026 14:06:54 -0500 Subject: [PATCH 1/3] fix(app-settings): provide groups by initial state Signed-off-by: Elizabeth Danzberger --- .../lib/Controller/AppSettingsController.php | 8 +++++++ .../Controller/AppSettingsControllerTest.php | 23 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php index b0a1b5a49dbf7..5f687cd00ca56 100644 --- a/apps/settings/lib/Controller/AppSettingsController.php +++ b/apps/settings/lib/Controller/AppSettingsController.php @@ -69,6 +69,7 @@ public function __construct( private CategoryFetcher $categoryFetcher, private AppFetcher $appFetcher, private IFactory $l10nFactory, + private IGroupManager $groupManager, private BundleFetcher $bundleFetcher, private Installer $installer, private IURLGenerator $urlGenerator, @@ -94,6 +95,13 @@ public function viewApps(): TemplateResponse { $this->initialState->provideInitialState('appstoreBundles', $this->getBundles()); $this->initialState->provideInitialState('appstoreUpdateCount', count($this->getAppsWithUpdates())); + $groups = array_map(static fn (IGroup $group): array => [ + 'id' => $group->getGID(), + 'name' => $group->getDisplayName(), + ], $this->groupManager->search('', 5)); + + $this->initialState->provideInitialState('usersSettings', [ 'systemGroups' => $groups]); + if ($this->appManager->isEnabledForAnyone('app_api')) { try { Server::get(ExAppsPageService::class)->provideAppApiState($this->initialState); diff --git a/apps/settings/tests/Controller/AppSettingsControllerTest.php b/apps/settings/tests/Controller/AppSettingsControllerTest.php index 63094264ebfd8..357e05733d7de 100644 --- a/apps/settings/tests/Controller/AppSettingsControllerTest.php +++ b/apps/settings/tests/Controller/AppSettingsControllerTest.php @@ -21,6 +21,8 @@ use OCP\Files\AppData\IAppDataFactory; use OCP\Http\Client\IClientService; use OCP\IConfig; +use OCP\IGroup; +use OCP\IGroupManager; use OCP\IL10N; use OCP\INavigationManager; use OCP\IRequest; @@ -45,6 +47,7 @@ class AppSettingsControllerTest extends TestCase { private CategoryFetcher&MockObject $categoryFetcher; private AppFetcher&MockObject $appFetcher; private IFactory&MockObject $l10nFactory; + private IGroupManager&MockObject $groupManager; private BundleFetcher&MockObject $bundleFetcher; private Installer&MockObject $installer; private IURLGenerator&MockObject $urlGenerator; @@ -70,6 +73,7 @@ protected function setUp(): void { $this->categoryFetcher = $this->createMock(CategoryFetcher::class); $this->appFetcher = $this->createMock(AppFetcher::class); $this->l10nFactory = $this->createMock(IFactory::class); + $this->groupManager = $this->createMock(IGroupManager::class); $this->bundleFetcher = $this->createMock(BundleFetcher::class); $this->installer = $this->createMock(Installer::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); @@ -89,6 +93,7 @@ protected function setUp(): void { $this->categoryFetcher, $this->appFetcher, $this->l10nFactory, + $this->groupManager, $this->bundleFetcher, $this->installer, $this->urlGenerator, @@ -168,9 +173,16 @@ public function testViewApps(): void { ->expects($this->once()) ->method('setActiveEntry') ->with('core_apps'); + $this->groupManager->expects($this->once()) + ->method('search') + ->with($this->equalTo(''), $this->equalTo(5)) + ->willReturn([ + $this->createMock(IGroup::class), + $this->createMock(IGroup::class), + ]); $this->initialState - ->expects($this->exactly(3)) + ->expects($this->exactly(4)) ->method('provideInitialState'); $policy = new ContentSecurityPolicy(); @@ -201,9 +213,16 @@ public function testViewAppsAppstoreNotEnabled(): void { ->expects($this->once()) ->method('setActiveEntry') ->with('core_apps'); + $this->groupManager->expects($this->once()) + ->method('search') + ->with($this->equalTo(''), $this->equalTo(5)) + ->willReturn([ + $this->createMock(IGroup::class), + $this->createMock(IGroup::class), + ]); $this->initialState - ->expects($this->exactly(3)) + ->expects($this->exactly(4)) ->method('provideInitialState'); $policy = new ContentSecurityPolicy(); From 90deae46c5631fc1eb0843152b0562e5c8d0a009 Mon Sep 17 00:00:00 2001 From: Elizabeth Danzberger Date: Fri, 23 Jan 2026 16:53:20 -0500 Subject: [PATCH 2/3] test: limit app to group Signed-off-by: Elizabeth Danzberger --- cypress/e2e/settings/apps.cy.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/cypress/e2e/settings/apps.cy.ts b/cypress/e2e/settings/apps.cy.ts index 604017015b66b..b40e3a1c8eeb6 100644 --- a/cypress/e2e/settings/apps.cy.ts +++ b/cypress/e2e/settings/apps.cy.ts @@ -142,6 +142,32 @@ describe('Settings: App management', { testIsolation: true }, () => { cy.get('#app-sidebar-vue').contains(/Version \d+\.\d+\.\d+/).should('be.visible') }) + it('Limit app usage to group', () => { + // When I open the "Active apps" section + cy.get('#app-category-enabled a') + .should('contain', 'Active apps') + .click({ force: true }) + // Then I see that the current section is "Active apps" + cy.url().should('match', /settings\/apps\/enabled$/) + cy.get('#app-category-enabled').find('.active').should('exist') + // Then I select the app + cy.get('#apps-list') + .should('exist') + .contains('tr', 'Dashboard', { timeout: 10000 }) + .click() + // Then I enable "limit app to group" + cy.get('[for="groups_enable_dashboard"]').click() + // Then I select a group + cy.get('#limitToGroups').click() + cy.get('ul[role="listbox"]') + .find('span') + .contains('admin') + .click() + cy.get('span.name-parts__first') + .contains('admin') + .should('be.visible') + }) + /* * TODO: Improve testing with app store as external API * The following scenarios require the files_antivirus and calendar app From b7c6240327fed8c791abc2c6e9b40ffc903218f8 Mon Sep 17 00:00:00 2001 From: Elizabeth Danzberger Date: Mon, 26 Jan 2026 13:46:59 -0500 Subject: [PATCH 3/3] fix(test): remove group limitation when done Signed-off-by: Elizabeth Danzberger --- cypress/e2e/settings/apps.cy.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cypress/e2e/settings/apps.cy.ts b/cypress/e2e/settings/apps.cy.ts index b40e3a1c8eeb6..bfff8befaac94 100644 --- a/cypress/e2e/settings/apps.cy.ts +++ b/cypress/e2e/settings/apps.cy.ts @@ -166,6 +166,8 @@ describe('Settings: App management', { testIsolation: true }, () => { cy.get('span.name-parts__first') .contains('admin') .should('be.visible') + // Then I disable the group limitation + cy.get('button[title="Deselect admin"]').click() }) /*