Merge pull request #58006 from nextcloud/backport/57533/stable31

[stable31] fix(app-settings): limit app to group initial state
This commit is contained in:
Anna 2026-02-04 07:07:24 +01:00 committed by GitHub
commit 5a438b7af4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 60 additions and 2 deletions

View file

@ -37,6 +37,7 @@ use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\INavigationManager;
use OCP\IRequest;
@ -67,6 +68,7 @@ class AppSettingsController extends Controller {
private CategoryFetcher $categoryFetcher,
private AppFetcher $appFetcher,
private IFactory $l10nFactory,
private IGroupManager $groupManager,
private BundleFetcher $bundleFetcher,
private Installer $installer,
private IURLGenerator $urlGenerator,
@ -93,6 +95,13 @@ class AppSettingsController extends Controller {
$this->initialState->provideInitialState('appstoreDeveloperDocs', $this->urlGenerator->linkToDocs('developer-manual'));
$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->isInstalled('app_api')) {
try {
Server::get(\OCA\AppAPI\Service\ExAppsPageService::class)->provideAppApiState($this->initialState);

View file

@ -20,6 +20,8 @@ use OCP\AppFramework\Services\IInitialState;
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;
@ -54,6 +56,8 @@ class AppSettingsControllerTest extends TestCase {
private $appFetcher;
/** @var IFactory|MockObject */
private $l10nFactory;
/** IGroupManager|MockObject */
private $groupManager;
/** @var BundleFetcher|MockObject */
private $bundleFetcher;
/** @var Installer|MockObject */
@ -71,6 +75,7 @@ class AppSettingsControllerTest extends TestCase {
/** @var IClientService|MockObject */
private $clientService;
protected function setUp(): void {
parent::setUp();
@ -86,6 +91,7 @@ class AppSettingsControllerTest extends TestCase {
$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);
@ -105,6 +111,7 @@ class AppSettingsControllerTest extends TestCase {
$this->categoryFetcher,
$this->appFetcher,
$this->l10nFactory,
$this->groupManager,
$this->bundleFetcher,
$this->installer,
$this->urlGenerator,
@ -184,9 +191,16 @@ class AppSettingsControllerTest extends TestCase {
->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(4))
->expects($this->exactly(5))
->method('provideInitialState');
$policy = new ContentSecurityPolicy();
@ -217,9 +231,16 @@ class AppSettingsControllerTest extends TestCase {
->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(4))
->expects($this->exactly(5))
->method('provideInitialState');
$policy = new ContentSecurityPolicy();

View file

@ -142,6 +142,34 @@ 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')
// Then I disable the group limitation
cy.get('button[title="Deselect admin"]').click()
})
/*
* TODO: Improve testing with app store as external API
* The following scenarios require the files_antivirus and calendar app