diff --git a/apps/appstore/appinfo/info.xml b/apps/appstore/appinfo/info.xml index a59246caa10..65e4a8f2d6e 100644 --- a/apps/appstore/appinfo/info.xml +++ b/apps/appstore/appinfo/info.xml @@ -19,21 +19,4 @@ - - - - Appstore - appstore.page.viewApps - app.svg - 99 - - - - Apps - appstore.page.viewApps - app.svg - 5 - settings - - diff --git a/apps/appstore/lib/Controller/PageController.php b/apps/appstore/lib/Controller/PageController.php index d218e612ac1..f77d004626c 100644 --- a/apps/appstore/lib/Controller/PageController.php +++ b/apps/appstore/lib/Controller/PageController.php @@ -23,6 +23,7 @@ use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; use OCP\IConfig; use OCP\IL10N; +use OCP\INavigationManager; use OCP\IRequest; use OCP\IURLGenerator; use OCP\Server; @@ -40,6 +41,7 @@ final class PageController extends Controller { private readonly IURLGenerator $urlGenerator, private readonly IInitialState $initialState, private readonly BundleFetcher $bundleFetcher, + private readonly INavigationManager $navigationManager, ) { parent::__construct(Application::APP_ID, $request); } @@ -49,6 +51,8 @@ final class PageController extends Controller { #[FrontpageRoute(verb: 'GET', url: '/settings/apps/{category}', defaults: ['category' => ''], root: '')] #[FrontpageRoute(verb: 'GET', url: '/settings/apps/{category}/{id}', defaults: ['category' => '', 'id' => ''], root: '')] public function viewApps(): TemplateResponse { + $this->navigationManager->setActiveEntry('core_apps'); + $this->initialState->provideInitialState('appstoreEnabled', $this->config->getSystemValueBool('appstoreenabled', true)); $this->initialState->provideInitialState('appstoreBundles', $this->getBundles()); $this->initialState->provideInitialState('appstoreDeveloperDocs', $this->urlGenerator->linkToDocs('developer-manual')); diff --git a/apps/appstore/tests/Controller/PageControllerTest.php b/apps/appstore/tests/Controller/PageControllerTest.php index b41683fa616..1e5edfe061f 100644 --- a/apps/appstore/tests/Controller/PageControllerTest.php +++ b/apps/appstore/tests/Controller/PageControllerTest.php @@ -16,6 +16,7 @@ use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; use OCP\IConfig; use OCP\IL10N; +use OCP\INavigationManager; use OCP\IRequest; use OCP\IURLGenerator; use PHPUnit\Framework\MockObject\MockObject; @@ -29,6 +30,8 @@ final class PageControllerTest extends TestCase { private IConfig&MockObject $config; + private INavigationManager&MockObject $navigationManager; + private IAppManager&MockObject $appManager; private BundleFetcher&MockObject $bundleFetcher; @@ -51,6 +54,7 @@ final class PageControllerTest extends TestCase { ->method('t') ->willReturnArgument(0); $this->config = $this->createMock(IConfig::class); + $this->navigationManager = $this->createMock(INavigationManager::class); $this->appManager = $this->createMock(IAppManager::class); $this->bundleFetcher = $this->createMock(BundleFetcher::class); $this->installer = $this->createMock(Installer::class); @@ -66,6 +70,7 @@ final class PageControllerTest extends TestCase { $this->urlGenerator, $this->initialState, $this->bundleFetcher, + $this->navigationManager, ); } @@ -79,6 +84,10 @@ final class PageControllerTest extends TestCase { ->method('getSystemValueBool') ->with('appstoreenabled', true) ->willReturn(true); + $this->navigationManager + ->expects($this->once()) + ->method('setActiveEntry') + ->with('core_apps'); $this->initialState ->expects($this->exactly(4)) @@ -108,6 +117,10 @@ final class PageControllerTest extends TestCase { ->method('getSystemValueBool') ->with('appstoreenabled', true) ->willReturn(false); + $this->navigationManager + ->expects($this->once()) + ->method('setActiveEntry') + ->with('core_apps'); $this->initialState ->expects($this->exactly(4)) diff --git a/apps/profile/lib/AppInfo/Application.php b/apps/profile/lib/AppInfo/Application.php index 8eb075ff59e..ff2d3f86016 100644 --- a/apps/profile/lib/AppInfo/Application.php +++ b/apps/profile/lib/AppInfo/Application.php @@ -16,11 +16,6 @@ use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\Collaboration\Reference\RenderReferenceEvent; -use OCP\INavigationManager; -use OCP\IURLGenerator; -use OCP\IUserSession; -use OCP\L10N\IFactory; -use OCP\Server; class Application extends App implements IBootstrap { public const APP_ID = 'profile'; @@ -37,33 +32,5 @@ class Application extends App implements IBootstrap { #[\Override] public function boot(IBootContext $context): void { - $context->injectFn($this->registerNavigationEntry(...)); - } - - /** - * Registers the navigation entry for the profile app in the user settings. - * Needed as the href is dynamic and thus we cannot use the appinfo/info.xml - */ - public function registerNavigationEntry( - INavigationManager $navigationManager, - IUserSession $userSession, - IURLGenerator $urlGenerator, - ): void { - if (!$userSession->isLoggedIn()) { - return; - } - - $l = Server::get(IFactory::class)->get('profile'); - // Profile - $navigationManager->add([ - 'type' => 'settings', - 'id' => 'profile', - 'order' => 1, - 'href' => $urlGenerator->linkToRoute( - 'profile.ProfilePage.index', - ['targetUserId' => $userSession->getUser()->getUID()], - ), - 'name' => $l->t('View profile'), - ]); } } diff --git a/apps/settings/appinfo/info.xml b/apps/settings/appinfo/info.xml index 10b1e0be9fc..879859fe1c8 100644 --- a/apps/settings/appinfo/info.xml +++ b/apps/settings/appinfo/info.xml @@ -74,5 +74,6 @@ OCA\Settings\Activity\Provider OCA\Settings\Activity\SecurityProvider + diff --git a/apps/settings/appinfo/routes.php b/apps/settings/appinfo/routes.php index 85604ab7585..abe000122cb 100644 --- a/apps/settings/appinfo/routes.php +++ b/apps/settings/appinfo/routes.php @@ -33,7 +33,7 @@ return [ ['name' => 'CheckSetup#getFailedIntegrityCheckFiles', 'url' => '/settings/integrity/failed', 'verb' => 'GET' , 'root' => ''], ['name' => 'CheckSetup#rescanFailedIntegrityCheck', 'url' => '/settings/integrity/rescan', 'verb' => 'GET' , 'root' => ''], ['name' => 'PersonalSettings#index', 'url' => '/settings/user/{section}', 'verb' => 'GET', 'defaults' => ['section' => 'personal-info'] , 'root' => ''], - ['name' => 'AdminSettings#index', 'url' => '/settings/admin/{section}', 'verb' => 'GET', 'defaults' => ['section' => 'overview'] , 'root' => ''], + ['name' => 'AdminSettings#index', 'url' => '/settings/admin/{section}', 'verb' => 'GET', 'defaults' => ['section' => 'server'] , 'root' => ''], ['name' => 'AdminSettings#form', 'url' => '/settings/admin/{section}', 'verb' => 'GET' , 'root' => ''], ['name' => 'ChangePassword#changePersonalPassword', 'url' => '/settings/personal/changepassword', 'verb' => 'POST' , 'root' => ''], ['name' => 'ChangePassword#changeUserPassword', 'url' => '/settings/users/changepassword', 'verb' => 'POST' , 'root' => ''], diff --git a/apps/settings/lib/AppInfo/Application.php b/apps/settings/lib/AppInfo/Application.php index ca005642a0f..ed746572ff4 100644 --- a/apps/settings/lib/AppInfo/Application.php +++ b/apps/settings/lib/AppInfo/Application.php @@ -90,12 +90,8 @@ use OCP\Defaults; use OCP\Group\Events\GroupDeletedEvent; use OCP\Group\Events\UserAddedEvent; use OCP\Group\Events\UserRemovedEvent; -use OCP\Group\ISubAdmin; use OCP\IConfig; -use OCP\IGroupManager; -use OCP\INavigationManager; use OCP\IURLGenerator; -use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Mail\IMailer; use OCP\Security\ICrypto; @@ -230,93 +226,5 @@ class Application extends App implements IBootstrap { #[\Override] public function boot(IBootContext $context): void { - $context->injectFn($this->registerNavigationEntries(...)); - } - - /** - * Registers the navigation entries for the user settings. - * Needed as some entries are dynamic and thus we cannot use the appinfo/info.xml - * - * Registers the following entries: - * - Appearance and accessibility - * - Personal settings (named "Settings" for non-admins) - * - Accounts (only for subadmins) - * - Help & privacy (conditionally enabled based on config) - */ - public function registerNavigationEntries( - INavigationManager $navigationManager, - IURLGenerator $urlGenerator, - IUserSession $userSession, - IConfig $config, - ): void { - if ($userSession->getUser() === null) { - return; - } - - $l = Server::get(IFactory::class) - ->get('settings'); - $groupManager = Server::get(IGroupManager::class); - $subAdmin = Server::get(ISubAdmin::class); - $isAdmin = $groupManager->isAdmin($userSession->getUser()->getUID()); - $isSubAdmin = $subAdmin->isSubAdmin($userSession->getUser()); - - // Accessibility settings - the URL is dynamic (route parameters) which is currently not supported by appinfo.xml - $navigationManager->add([ - 'type' => 'settings', - 'id' => 'accessibility_settings', - 'order' => 2, - 'href' => $urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'theming']), - 'name' => $l->t('Appearance and accessibility'), - 'icon' => $urlGenerator->imagePath('theming', 'accessibility-dark.svg'), - ]); - - // Personal settings - this entry is dynamic so we cannot use appinfo - $navigationManager->add([ - 'type' => 'settings', - 'id' => 'settings_personal', - 'order' => 3, - 'href' => $urlGenerator->linkToRoute('settings.PersonalSettings.index'), - 'name' => $isAdmin - ? $l->t('Personal settings') - : $l->t('Settings'), - 'icon' => $isAdmin - ? $urlGenerator->imagePath('settings', 'personal.svg') - : $urlGenerator->imagePath('settings', 'admin.svg'), - ]); - - if ($isAdmin) { - $navigationManager->add([ - 'type' => 'settings', - 'id' => 'settings_administration', - 'order' => 4, - 'href' => $urlGenerator->linkToRoute('settings.adminSettings.index'), - 'name' => $l->t('Administration settings'), - 'icon' => $urlGenerator->imagePath('settings', 'admin.svg'), - ]); - } - - // User management is conditionally enabled for subadmins, but appinfo currently only supports full admins - if ($isSubAdmin) { - $navigationManager->add([ - 'type' => 'settings', - 'id' => 'core_users', - 'order' => 6, - 'href' => $urlGenerator->linkToRoute('settings.Users.usersList'), - 'name' => $l->t('Accounts'), - 'icon' => $urlGenerator->imagePath('settings', 'users.svg'), - ]); - } - - // conditionally enabled navigation entry - if ($config->getSystemValueBool('knowledgebaseenabled', true)) { - $navigationManager->add([ - 'type' => 'settings', - 'id' => 'help', - 'order' => 99998, - 'href' => $urlGenerator->linkToRoute('settings.Help.help'), - 'name' => $l->t('Help & privacy'), - 'icon' => $urlGenerator->imagePath('settings', 'help.svg'), - ]); - } } } diff --git a/core/AppInfo/Application.php b/core/AppInfo/Application.php index 83edd25dd8c..15cf42c4a55 100644 --- a/core/AppInfo/Application.php +++ b/core/AppInfo/Application.php @@ -32,11 +32,6 @@ use OCP\AppFramework\Http\Events\BeforeLoginTemplateRenderedEvent; use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; use OCP\DB\Events\AddMissingIndicesEvent; use OCP\DB\Events\AddMissingPrimaryKeyEvent; -use OCP\INavigationManager; -use OCP\IURLGenerator; -use OCP\IUserSession; -use OCP\L10N\IFactory; -use OCP\Server; use OCP\User\Events\BeforeUserDeletedEvent; use OCP\User\Events\PasswordUpdatedEvent; use OCP\User\Events\UserDeletedEvent; @@ -98,36 +93,7 @@ class Application extends App implements IBootstrap { #[\Override] public function boot(IBootContext $context): void { - $context->injectFn($this->registerNavigationEntries(...)); - } - - /** - * Registers the navigation entries for the core app: - * - The logout button in the settings menu - */ - public function registerNavigationEntries( - INavigationManager $navigationManager, - IUserSession $userSession, - IURLGenerator $urlGenerator, - ): void { - if (!$userSession->isLoggedIn()) { - return; - } - - $l = Server::get(IFactory::class)->get('core'); - - // Register the logout button in the user settings - $logoutUrl = \OC_User::getLogoutUrl($urlGenerator); - if ($logoutUrl !== '') { - $navigationManager->add([ - 'type' => 'settings', - 'id' => 'logout', - 'order' => 99999, - 'href' => $logoutUrl, - 'name' => $l->t('Log out'), - 'icon' => $urlGenerator->imagePath('core', 'actions/logout.svg'), - ]); - } + // ... } } diff --git a/cypress/e2e/systemtags/admin-settings.cy.ts b/cypress/e2e/systemtags/admin-settings.cy.ts index c8b74335a5a..c2e6c89a580 100644 --- a/cypress/e2e/systemtags/admin-settings.cy.ts +++ b/cypress/e2e/systemtags/admin-settings.cy.ts @@ -21,7 +21,7 @@ describe('Create system tags', () => { // login as admin and go to admin settings cy.login(admin) - cy.visit('/settings/admin/server') + cy.visit('/settings/admin') }) it('Can create a tag', () => { @@ -48,7 +48,7 @@ describe('Create system tags', () => { describe('Update system tags', { testIsolation: false }, () => { before(() => { cy.login(admin) - cy.visit('/settings/admin/server') + cy.visit('/settings/admin') }) it('select the tag', () => { @@ -92,7 +92,7 @@ describe('Update system tags', { testIsolation: false }, () => { describe('Delete system tags', { testIsolation: false }, () => { before(() => { cy.login(admin) - cy.visit('/settings/admin/server') + cy.visit('/settings/admin') }) it('select the tag', () => { diff --git a/cypress/e2e/theming/admin-settings_branding.cy.ts b/cypress/e2e/theming/admin-settings_branding.cy.ts index 1f21045edf1..314a7e2224b 100644 --- a/cypress/e2e/theming/admin-settings_branding.cy.ts +++ b/cypress/e2e/theming/admin-settings_branding.cy.ts @@ -154,7 +154,7 @@ describe('Admin theming: Change the login fields then reset them', function() { it('See the admin theming section', function() { cy.visit('/settings/admin/theming') - cy.findByRole('heading', { name: /^Theming/, level: 2 }) + cy.findByRole('heading', { name: /^Theming/ }) .should('exist') .scrollIntoView() }) diff --git a/lib/base.php b/lib/base.php index 3277f0c42e0..b945ba3ee1d 100644 --- a/lib/base.php +++ b/lib/base.php @@ -850,7 +850,6 @@ class OC { // Make sure that the application class is not loaded before the database is setup if ($systemConfig->getValue('installed', false)) { - $appManager->loadApp('core'); $appManager->loadApp('settings'); } diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index d4521edabfc..1f918257337 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -1187,11 +1187,8 @@ class AppManager implements IAppManager { #[\Override] public function getAppNamespace(string $appId): string { - if ($appId === 'core') { - return 'OC\\Core'; - } - $topNamespace = 'OCA\\'; + // Hit the cache! if (isset($this->namespaceCache[$appId])) { return $topNamespace . $this->namespaceCache[$appId]; diff --git a/lib/private/NavigationManager.php b/lib/private/NavigationManager.php index f5a9d995c7b..f1047d17a53 100644 --- a/lib/private/NavigationManager.php +++ b/lib/private/NavigationManager.php @@ -8,6 +8,7 @@ namespace OC; use InvalidArgumentException; +use OC\Group\Manager; use OCP\App\IAppManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; @@ -202,6 +203,109 @@ class NavigationManager implements INavigationManager { $this->init = true; $l = $this->l10nFac->get('lib'); + if ($this->config->getSystemValueBool('knowledgebaseenabled', true)) { + $this->add([ + 'type' => 'settings', + 'id' => 'help', + 'order' => 99998, + 'href' => $this->urlGenerator->linkToRoute('settings.Help.help'), + 'name' => $l->t('Help & privacy'), + 'icon' => $this->urlGenerator->imagePath('settings', 'help.svg'), + ]); + } + + if ($this->userSession->isLoggedIn()) { + // Profile + $this->add([ + 'type' => 'settings', + 'id' => 'profile', + 'order' => 1, + 'href' => $this->urlGenerator->linkToRoute( + 'profile.ProfilePage.index', + ['targetUserId' => $this->userSession->getUser()->getUID()], + ), + 'name' => $l->t('View profile'), + ]); + + // Accessibility settings + if ($this->appManager->isEnabledForUser('theming', $this->userSession->getUser())) { + $this->add([ + 'type' => 'settings', + 'id' => 'accessibility_settings', + 'order' => 2, + 'href' => $this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'theming']), + 'name' => $l->t('Appearance and accessibility'), + 'icon' => $this->urlGenerator->imagePath('theming', 'accessibility-dark.svg'), + ]); + } + + if ($this->isAdmin()) { + // App management + $this->add([ + 'type' => 'settings', + 'id' => 'core_apps', + 'order' => 5, + 'href' => $this->urlGenerator->linkToRoute('appstore.Page.viewApps'), + 'icon' => $this->urlGenerator->imagePath('appstore', 'app.svg'), + 'name' => $l->t('Apps'), + ]); + + // Personal settings + $this->add([ + 'type' => 'settings', + 'id' => 'settings', + 'order' => 3, + 'href' => $this->urlGenerator->linkToRoute('settings.PersonalSettings.index'), + 'name' => $l->t('Personal settings'), + 'icon' => $this->urlGenerator->imagePath('settings', 'personal.svg'), + ]); + + // Admin settings + $this->add([ + 'type' => 'settings', + 'id' => 'admin_settings', + 'order' => 4, + 'href' => $this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'overview']), + 'name' => $l->t('Administration settings'), + 'icon' => $this->urlGenerator->imagePath('settings', 'admin.svg'), + ]); + } else { + // Personal settings + $this->add([ + 'type' => 'settings', + 'id' => 'settings', + 'order' => 3, + 'href' => $this->urlGenerator->linkToRoute('settings.PersonalSettings.index'), + 'name' => $l->t('Settings'), + 'icon' => $this->urlGenerator->imagePath('settings', 'admin.svg'), + ]); + } + + $logoutUrl = \OC_User::getLogoutUrl($this->urlGenerator); + if ($logoutUrl !== '') { + // Logout + $this->add([ + 'type' => 'settings', + 'id' => 'logout', + 'order' => 99999, + 'href' => $logoutUrl, + 'name' => $l->t('Log out'), + 'icon' => $this->urlGenerator->imagePath('core', 'actions/logout.svg'), + ]); + } + + if ($this->isSubadmin()) { + // User management + $this->add([ + 'type' => 'settings', + 'id' => 'core_users', + 'order' => 6, + 'href' => $this->urlGenerator->linkToRoute('settings.Users.usersList'), + 'name' => $l->t('Accounts'), + 'icon' => $this->urlGenerator->imagePath('settings', 'users.svg'), + ]); + } + } $this->eventDispatcher->dispatchTyped(new LoadAdditionalEntriesEvent()); if ($this->userSession->isLoggedIn()) { @@ -212,6 +316,10 @@ class NavigationManager implements INavigationManager { } foreach ($apps as $app) { + if (!$this->userSession->isLoggedIn() && !$this->appManager->isEnabledForUser($app, $this->userSession->getUser())) { + continue; + } + // load plugins and collections from info.xml $info = $this->appManager->getAppInfo($app); if (!isset($info['navigations']['navigation'])) { @@ -257,14 +365,14 @@ class NavigationManager implements INavigationManager { 'order' => $order, // Target of the navigation entry 'href' => $route, - // The icon used for the navigation entry + // The icon used for the naviation entry 'icon' => $icon, // Type of the navigation entry ('link' vs 'settings') 'type' => $type, // Localized name of the navigation entry 'name' => $l->t($nav['name']), ], $type === 'link' ? [ - // App that registered this navigation entry (not necessarily the same as the id) + // App that registered this navigation entry (not necessarly the same as the id) 'app' => $app, ] : [] )); @@ -280,6 +388,14 @@ class NavigationManager implements INavigationManager { return false; } + private function isSubadmin(): bool { + $user = $this->userSession->getUser(); + if ($user !== null && $this->groupManager instanceof Manager) { + return $this->groupManager->getSubAdmin()->isSubAdmin($user); + } + return false; + } + #[Override] public function setUnreadCounter(string $id, int $unreadCounter): void { $this->unreadCounters[$id] = $unreadCounter; diff --git a/tests/lib/NavigationManagerTest.php b/tests/lib/NavigationManagerTest.php index 1b2805f9c08..4322791e29e 100644 --- a/tests/lib/NavigationManagerTest.php +++ b/tests/lib/NavigationManagerTest.php @@ -11,6 +11,8 @@ namespace Test; use OC\App\AppManager; use OC\Group\Manager; use OC\NavigationManager; +use OC\Security\CSRF\CsrfTokenManager; +use OC\SubAdmin; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IGroupManager; @@ -20,6 +22,7 @@ use OCP\IUser; use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Navigation\Events\LoadAdditionalEntriesEvent; +use OCP\Server; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; @@ -257,6 +260,9 @@ class NavigationManagerTest extends TestCase { ->with($user) ->willReturn(['test']); $this->groupManager->expects($this->any())->method('isAdmin')->willReturn($isAdmin); + $subadmin = $this->createMock(SubAdmin::class); + $subadmin->expects($this->any())->method('isSubAdmin')->with($user)->willReturn(false); + $this->groupManager->expects($this->any())->method('getSubAdmin')->willReturn($subadmin); $this->navigationManager->clear(); $this->dispatcher->expects($this->once()) @@ -269,21 +275,112 @@ class NavigationManagerTest extends TestCase { } public static function providesNavigationConfig(): array { + $apps = [ + 'core_apps' => [ + 'id' => 'core_apps', + 'order' => 5, + 'href' => '/apps/test/', + 'icon' => '/apps/appstore/img/app.svg', + 'name' => 'Apps', + 'active' => false, + 'type' => 'settings', + 'classes' => '', + 'unread' => 0 + ] + ]; + $defaults = [ + 'profile' => [ + 'type' => 'settings', + 'id' => 'profile', + 'order' => 1, + 'href' => '/apps/test/', + 'name' => 'View profile', + 'icon' => '', + 'active' => false, + 'classes' => '', + 'unread' => 0, + ], + 'accessibility_settings' => [ + 'type' => 'settings', + 'id' => 'accessibility_settings', + 'order' => 2, + 'href' => '/apps/test/', + 'name' => 'Appearance and accessibility', + 'icon' => '/apps/theming/img/accessibility-dark.svg', + 'active' => false, + 'classes' => '', + 'unread' => 0, + ], + 'settings' => [ + 'id' => 'settings', + 'order' => 3, + 'href' => '/apps/test/', + 'icon' => '/apps/settings/img/admin.svg', + 'name' => 'Settings', + 'active' => false, + 'type' => 'settings', + 'classes' => '', + 'unread' => 0 + ], + 'logout' => [ + 'id' => 'logout', + 'order' => 99999, + 'href' => 'https://example.com/logout?requesttoken=' . urlencode(Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue()), + 'icon' => '/apps/core/img/actions/logout.svg', + 'name' => 'Log out', + 'active' => false, + 'type' => 'settings', + 'classes' => '', + 'unread' => 0 + ] + ]; + $adminSettings = [ + 'accessibility_settings' => $defaults['accessibility_settings'], + 'settings' => [ + 'id' => 'settings', + 'order' => 3, + 'href' => '/apps/test/', + 'icon' => '/apps/settings/img/personal.svg', + 'name' => 'Personal settings', + 'active' => false, + 'type' => 'settings', + 'classes' => '', + 'unread' => 0 + ], + 'admin_settings' => [ + 'id' => 'admin_settings', + 'order' => 4, + 'href' => '/apps/test/', + 'icon' => '/apps/settings/img/admin.svg', + 'name' => 'Administration settings', + 'active' => false, + 'type' => 'settings', + 'classes' => '', + 'unread' => 0 + ] + ]; + return [ 'minimalistic' => [ - ['test' => [ - 'id' => 'test', - 'order' => 100, - 'href' => '/apps/test/', - 'icon' => '/apps/test/img/app.svg', - 'name' => 'Test', - 'active' => false, - 'type' => 'link', - 'classes' => '', - 'unread' => 0, - 'default' => true, - 'app' => 'test', - ]], + array_merge( + ['profile' => $defaults['profile']], + ['accessibility_settings' => $defaults['accessibility_settings']], + ['settings' => $defaults['settings']], + ['test' => [ + 'id' => 'test', + 'order' => 100, + 'href' => '/apps/test/', + 'icon' => '/apps/test/img/app.svg', + 'name' => 'Test', + 'active' => false, + 'type' => 'link', + 'classes' => '', + 'unread' => 0, + 'default' => true, + 'app' => 'test', + ]], + ['logout' => $defaults['logout']] + ), ['navigations' => [ 'navigation' => [ ['route' => 'test.page.index', 'name' => 'Test'] @@ -291,17 +388,23 @@ class NavigationManagerTest extends TestCase { ]] ], 'minimalistic-settings' => [ - ['test' => [ - 'id' => 'test', - 'order' => 100, - 'href' => '/apps/test/', - 'icon' => '/apps/test/img/app.svg', - 'name' => 'Test', - 'active' => false, - 'type' => 'settings', - 'classes' => '', - 'unread' => 0, - ]], + array_merge( + ['profile' => $defaults['profile']], + ['accessibility_settings' => $defaults['accessibility_settings']], + ['settings' => $defaults['settings']], + ['test' => [ + 'id' => 'test', + 'order' => 100, + 'href' => '/apps/test/', + 'icon' => '/apps/test/img/app.svg', + 'name' => 'Test', + 'active' => false, + 'type' => 'settings', + 'classes' => '', + 'unread' => 0, + ]], + ['logout' => $defaults['logout']] + ), ['navigations' => [ 'navigation' => [ ['route' => 'test.page.index', 'name' => 'Test', 'type' => 'settings'] @@ -309,32 +412,38 @@ class NavigationManagerTest extends TestCase { ]] ], 'with-multiple' => [ - ['test' => [ - 'id' => 'test', - 'order' => 100, - 'href' => '/apps/test/', - 'icon' => '/apps/test/img/app.svg', - 'name' => 'Test', - 'active' => false, - 'type' => 'link', - 'classes' => '', - 'unread' => 0, - 'default' => false, - 'app' => 'test', - ], - 'test1' => [ - 'id' => 'test1', - 'order' => 50, + array_merge( + ['profile' => $defaults['profile']], + ['accessibility_settings' => $defaults['accessibility_settings']], + ['settings' => $defaults['settings']], + ['test' => [ + 'id' => 'test', + 'order' => 100, 'href' => '/apps/test/', 'icon' => '/apps/test/img/app.svg', - 'name' => 'Other test', + 'name' => 'Test', 'active' => false, 'type' => 'link', 'classes' => '', 'unread' => 0, - 'default' => true, // because of order + 'default' => false, 'app' => 'test', - ]], + ], + 'test1' => [ + 'id' => 'test1', + 'order' => 50, + 'href' => '/apps/test/', + 'icon' => '/apps/test/img/app.svg', + 'name' => 'Other test', + 'active' => false, + 'type' => 'link', + 'classes' => '', + 'unread' => 0, + 'default' => true, // because of order + 'app' => 'test', + ]], + ['logout' => $defaults['logout']] + ), ['navigations' => [ 'navigation' => [ ['route' => 'test.page.index', 'name' => 'Test'], @@ -343,19 +452,25 @@ class NavigationManagerTest extends TestCase { ]] ], 'admin' => [ - ['test' => [ - 'id' => 'test', - 'order' => 100, - 'href' => '/apps/test/', - 'icon' => '/apps/test/img/app.svg', - 'name' => 'Test', - 'active' => false, - 'type' => 'link', - 'classes' => '', - 'unread' => 0, - 'default' => true, - 'app' => 'test', - ]], + array_merge( + ['profile' => $defaults['profile']], + $adminSettings, + $apps, + ['test' => [ + 'id' => 'test', + 'order' => 100, + 'href' => '/apps/test/', + 'icon' => '/apps/test/img/app.svg', + 'name' => 'Test', + 'active' => false, + 'type' => 'link', + 'classes' => '', + 'unread' => 0, + 'default' => true, + 'app' => 'test', + ]], + ['logout' => $defaults['logout']] + ), ['navigations' => [ 'navigation' => [ ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test'] @@ -364,7 +479,12 @@ class NavigationManagerTest extends TestCase { true ], 'no name' => [ - [], // nothing because the entry is not added because it has no name + array_merge( + ['profile' => $defaults['profile']], + $adminSettings, + $apps, + ['logout' => $defaults['logout']] + ), ['navigations' => [ 'navigation' => [ ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index'] @@ -373,13 +493,12 @@ class NavigationManagerTest extends TestCase { true ], 'no admin' => [ - [], // nothing because user is not an admin + $defaults, ['navigations' => [ 'navigation' => [ ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test'] ], ]], - false, ] ]; } @@ -448,6 +567,9 @@ class NavigationManagerTest extends TestCase { ->with($user) ->willReturn(['test']); $this->groupManager->expects($this->any())->method('isAdmin')->willReturn(false); + $subadmin = $this->createMock(SubAdmin::class); + $subadmin->expects($this->any())->method('isSubAdmin')->with($user)->willReturn(false); + $this->groupManager->expects($this->any())->method('getSubAdmin')->willReturn($subadmin); $this->navigationManager->clear(); $this->dispatcher->expects($this->once())