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())