mirror of
https://github.com/nextcloud/server.git
synced 2026-04-15 22:11:17 -04:00
Merge pull request #47523 from nextcloud/fix/theming/custom-apps-order
This commit is contained in:
commit
3a85997940
19 changed files with 484 additions and 259 deletions
|
|
@ -16,6 +16,7 @@ use OCP\IURLGenerator;
|
|||
use OCP\IUserSession;
|
||||
use OCP\L10N\IFactory;
|
||||
use OCP\Server;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class App {
|
||||
private static ?INavigationManager $navigationManager = null;
|
||||
|
|
@ -32,7 +33,8 @@ class App {
|
|||
Server::get(IFactory::class),
|
||||
Server::get(IUserSession::class),
|
||||
Server::get(IGroupManager::class),
|
||||
Server::get(IConfig::class)
|
||||
Server::get(IConfig::class),
|
||||
Server::get(LoggerInterface::class),
|
||||
);
|
||||
self::$navigationManager->clear(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use OCP\Files\NotFoundException;
|
|||
use OCP\Files\NotPermittedException;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use ScssPhp\ScssPhp\Compiler;
|
||||
|
|
@ -47,6 +48,7 @@ class ThemingController extends Controller {
|
|||
private IAppManager $appManager;
|
||||
private ImageManager $imageManager;
|
||||
private ThemesService $themesService;
|
||||
private INavigationManager $navigationManager;
|
||||
|
||||
public function __construct(
|
||||
$appName,
|
||||
|
|
@ -57,7 +59,8 @@ class ThemingController extends Controller {
|
|||
IURLGenerator $urlGenerator,
|
||||
IAppManager $appManager,
|
||||
ImageManager $imageManager,
|
||||
ThemesService $themesService
|
||||
ThemesService $themesService,
|
||||
INavigationManager $navigationManager,
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
|
||||
|
|
@ -68,6 +71,7 @@ class ThemingController extends Controller {
|
|||
$this->appManager = $appManager;
|
||||
$this->imageManager = $imageManager;
|
||||
$this->themesService = $themesService;
|
||||
$this->navigationManager = $navigationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -163,7 +167,7 @@ class ThemingController extends Controller {
|
|||
case 'defaultApps':
|
||||
if (is_array($value)) {
|
||||
try {
|
||||
$this->appManager->setDefaultApps($value);
|
||||
$this->navigationManager->setDefaultEntryIds($value);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$error = $this->l10n->t('Invalid app given');
|
||||
}
|
||||
|
|
@ -310,7 +314,7 @@ class ThemingController extends Controller {
|
|||
#[AuthorizedAdminSetting(settings: Admin::class)]
|
||||
public function undoAll(): DataResponse {
|
||||
$this->themingDefaults->undoAll();
|
||||
$this->appManager->setDefaultApps([]);
|
||||
$this->navigationManager->setDefaultEntryIds([]);
|
||||
|
||||
return new DataResponse(
|
||||
[
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use OCP\AppFramework\Http\TemplateResponse;
|
|||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\Settings\IDelegatedSettings;
|
||||
use OCP\Util;
|
||||
|
|
@ -28,6 +29,7 @@ class Admin implements IDelegatedSettings {
|
|||
private IInitialState $initialState,
|
||||
private IURLGenerator $urlGenerator,
|
||||
private ImageManager $imageManager,
|
||||
private INavigationManager $navigationManager,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +72,7 @@ class Admin implements IDelegatedSettings {
|
|||
'docUrlIcons' => $this->urlGenerator->linkToDocs('admin-theming-icons'),
|
||||
'canThemeIcons' => $this->imageManager->shouldReplaceIcons(),
|
||||
'userThemingDisabled' => $this->themingDefaults->isUserThemingDisabled(),
|
||||
'defaultApps' => array_filter(explode(',', $this->config->getSystemValueString('defaultapp', ''))),
|
||||
'defaultApps' => $this->navigationManager->getDefaultEntryIds(),
|
||||
]);
|
||||
|
||||
Util::addScript($this->appName, 'admin-theming');
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ use OCA\Theming\ITheme;
|
|||
use OCA\Theming\Service\BackgroundService;
|
||||
use OCA\Theming\Service\ThemesService;
|
||||
use OCA\Theming\ThemingDefaults;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IConfig;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\Settings\ISettings;
|
||||
use OCP\Util;
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ class Personal implements ISettings {
|
|||
private ThemesService $themesService,
|
||||
private IInitialState $initialStateService,
|
||||
private ThemingDefaults $themingDefaults,
|
||||
private IAppManager $appManager,
|
||||
private INavigationManager $navigationManager,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -49,8 +49,8 @@ class Personal implements ISettings {
|
|||
});
|
||||
}
|
||||
|
||||
// Get the default app enforced by admin
|
||||
$forcedDefaultApp = $this->appManager->getDefaultAppForUser(null, false);
|
||||
// Get the default entry enforced by admin
|
||||
$forcedDefaultEntry = $this->navigationManager->getDefaultEntryIdForUser(null, false);
|
||||
|
||||
/** List of all shipped backgrounds */
|
||||
$this->initialStateService->provideInitialState('shippedBackgrounds', BackgroundService::SHIPPED_BACKGROUNDS);
|
||||
|
|
@ -78,7 +78,7 @@ class Personal implements ISettings {
|
|||
$this->initialStateService->provideInitialState('enableBlurFilter', $this->config->getUserValue($this->userId, 'theming', 'force_enable_blur_filter', ''));
|
||||
$this->initialStateService->provideInitialState('navigationBar', [
|
||||
'userAppOrder' => json_decode($this->config->getUserValue($this->userId, 'core', 'apporder', '[]'), true, flags:JSON_THROW_ON_ERROR),
|
||||
'enforcedDefaultApp' => $forcedDefaultApp
|
||||
'enforcedDefaultApp' => $forcedDefaultEntry
|
||||
]);
|
||||
|
||||
Util::addScript($this->appName, 'personal-theming');
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ export default defineComponent({
|
|||
*/
|
||||
const initialAppOrder = loadState<INavigationEntry[]>('core', 'apps')
|
||||
.filter(({ type }) => type === 'link')
|
||||
.map((app) => ({ ...app, label: app.name, default: app.default && app.app === enforcedDefaultApp }))
|
||||
.map((app) => ({ ...app, label: app.name, default: app.default && app.id === enforcedDefaultApp }))
|
||||
|
||||
/**
|
||||
* Check if a custom app order is used or the default is shown
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use OCP\Files\NotFoundException;
|
|||
use OCP\Files\SimpleFS\ISimpleFile;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
|
@ -42,6 +43,8 @@ class ThemingControllerTest extends TestCase {
|
|||
private $urlGenerator;
|
||||
/** @var ThemesService|MockObject */
|
||||
private $themesService;
|
||||
/** @var INavigationManager|MockObject */
|
||||
private $navigationManager;
|
||||
|
||||
protected function setUp(): void {
|
||||
$this->request = $this->createMock(IRequest::class);
|
||||
|
|
@ -52,6 +55,7 @@ class ThemingControllerTest extends TestCase {
|
|||
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||
$this->imageManager = $this->createMock(ImageManager::class);
|
||||
$this->themesService = $this->createMock(ThemesService::class);
|
||||
$this->navigationManager = $this->createMock(INavigationManager::class);
|
||||
|
||||
$timeFactory = $this->createMock(ITimeFactory::class);
|
||||
$timeFactory->expects($this->any())
|
||||
|
|
@ -70,6 +74,7 @@ class ThemingControllerTest extends TestCase {
|
|||
$this->appManager,
|
||||
$this->imageManager,
|
||||
$this->themesService,
|
||||
$this->navigationManager,
|
||||
);
|
||||
|
||||
parent::setUp();
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use OCP\AppFramework\Http\TemplateResponse;
|
|||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IURLGenerator;
|
||||
use Test\TestCase;
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ class AdminTest extends TestCase {
|
|||
private IURLGenerator $urlGenerator;
|
||||
private ImageManager $imageManager;
|
||||
private IL10N $l10n;
|
||||
private INavigationManager $navigationManager;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
|
@ -33,6 +35,7 @@ class AdminTest extends TestCase {
|
|||
$this->initialState = $this->createMock(IInitialState::class);
|
||||
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||
$this->imageManager = $this->createMock(ImageManager::class);
|
||||
$this->navigationManager = $this->createMock(INavigationManager::class);
|
||||
|
||||
$this->admin = new Admin(
|
||||
Application::APP_ID,
|
||||
|
|
@ -41,7 +44,8 @@ class AdminTest extends TestCase {
|
|||
$this->themingDefaults,
|
||||
$this->initialState,
|
||||
$this->urlGenerator,
|
||||
$this->imageManager
|
||||
$this->imageManager,
|
||||
$this->navigationManager,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use OCP\AppFramework\Http\TemplateResponse;
|
|||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserSession;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
|
@ -34,7 +35,7 @@ class PersonalTest extends TestCase {
|
|||
private ThemesService&MockObject $themesService;
|
||||
private IInitialState&MockObject $initialStateService;
|
||||
private ThemingDefaults&MockObject $themingDefaults;
|
||||
private IAppManager&MockObject $appManager;
|
||||
private INavigationManager&MockObject $navigationManager;
|
||||
private Personal $admin;
|
||||
|
||||
/** @var ITheme[] */
|
||||
|
|
@ -46,7 +47,7 @@ class PersonalTest extends TestCase {
|
|||
$this->themesService = $this->createMock(ThemesService::class);
|
||||
$this->initialStateService = $this->createMock(IInitialState::class);
|
||||
$this->themingDefaults = $this->createMock(ThemingDefaults::class);
|
||||
$this->appManager = $this->createMock(IAppManager::class);
|
||||
$this->navigationManager = $this->createMock(INavigationManager::class);
|
||||
|
||||
$this->initThemes();
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ class PersonalTest extends TestCase {
|
|||
$this->themesService,
|
||||
$this->initialStateService,
|
||||
$this->themingDefaults,
|
||||
$this->appManager,
|
||||
$this->navigationManager,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -103,9 +104,9 @@ class PersonalTest extends TestCase {
|
|||
['admin', 'theming', 'background_image', BackgroundService::BACKGROUND_DEFAULT],
|
||||
]);
|
||||
|
||||
$this->appManager->expects($this->once())
|
||||
->method('getDefaultAppForUser')
|
||||
->willReturn('forcedapp');
|
||||
$this->navigationManager->expects($this->once())
|
||||
->method('getDefaultEntryIdForUser')
|
||||
->willReturn('forced_id');
|
||||
|
||||
$this->initialStateService->expects($this->exactly(8))
|
||||
->method('provideInitialState')
|
||||
|
|
@ -117,7 +118,7 @@ class PersonalTest extends TestCase {
|
|||
['themes', $themesState],
|
||||
['enforceTheme', $enforcedTheme],
|
||||
['isUserThemingDisabled', false],
|
||||
['navigationBar', ['userAppOrder' => [], 'enforcedDefaultApp' => 'forcedapp']],
|
||||
['navigationBar', ['userAppOrder' => [], 'enforcedDefaultApp' => 'forced_id']],
|
||||
]);
|
||||
|
||||
$expected = new TemplateResponse('theming', 'settings-personal');
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ $CONFIG = [
|
|||
|
||||
/**
|
||||
* Enable SMTP class debugging.
|
||||
* NOTE: ``loglevel`` will likely need to be adjusted too. See docs:
|
||||
* NOTE: ``loglevel`` will likely need to be adjusted too. See docs:
|
||||
* https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/email_configuration.html#enabling-debug-mode
|
||||
*
|
||||
* Defaults to ``false``
|
||||
|
|
@ -1167,9 +1167,9 @@ $CONFIG = [
|
|||
*/
|
||||
|
||||
/**
|
||||
* Set the default app to open on login. Use the app names as they appear in the
|
||||
* URL after clicking them in the Apps menu, such as documents, calendar, and
|
||||
* gallery. You can use a comma-separated list of app names, so if the first
|
||||
* Set the default app to open on login. The entry IDs can be retrieved from
|
||||
* the Navigations OCS API endpoint: https://docs.nextcloud.com/server/latest/develper_manual/_static/openapi.html#/operations/core-navigation-get-apps-navigation.
|
||||
* You can use a comma-separated list of app names, so if the first
|
||||
* app is not enabled for a user then Nextcloud will try the second one, and so
|
||||
* on. If no enabled apps are found it defaults to the dashboard app.
|
||||
*
|
||||
|
|
@ -1307,18 +1307,18 @@ $CONFIG = [
|
|||
/**
|
||||
* custom path for ffmpeg binary
|
||||
*
|
||||
* Defaults to ``null`` and falls back to searching ``avconv`` and ``ffmpeg``
|
||||
* Defaults to ``null`` and falls back to searching ``avconv`` and ``ffmpeg``
|
||||
* in the configured ``PATH`` environment
|
||||
*/
|
||||
'preview_ffmpeg_path' => '/usr/bin/ffmpeg',
|
||||
|
||||
/**
|
||||
* Set the URL of the Imaginary service to send image previews to.
|
||||
* Also requires the ``OC\Preview\Imaginary`` provider to be enabled in the
|
||||
* ``enabledPreviewProviders`` array, to create previews for these mimetypes: bmp,
|
||||
* Also requires the ``OC\Preview\Imaginary`` provider to be enabled in the
|
||||
* ``enabledPreviewProviders`` array, to create previews for these mimetypes: bmp,
|
||||
* x-bitmap, png, jpeg, gif, heic, heif, svg+xml, tiff, webp and illustrator.
|
||||
*
|
||||
* If you want Imaginary to also create preview images from PDF Documents, you
|
||||
* If you want Imaginary to also create preview images from PDF Documents, you
|
||||
* have to add the ``OC\Preview\ImaginaryPDF`` provider as well.
|
||||
*
|
||||
* See https://github.com/h2non/imaginary
|
||||
|
|
@ -2050,9 +2050,9 @@ $CONFIG = [
|
|||
/**
|
||||
* Deny extensions from being used for filenames.
|
||||
* Matching existing files can no longer be updated and in matching folders no files can be created anymore.
|
||||
*
|
||||
*
|
||||
* The '.part' extension is always forbidden, as this is used internally by Nextcloud.
|
||||
*
|
||||
*
|
||||
* Defaults to ``array('.filepart', '.part')``
|
||||
*/
|
||||
'forbidden_filename_extensions' => ['.part', '.filepart'],
|
||||
|
|
|
|||
4
dist/theming-personal-theming.js
vendored
4
dist/theming-personal-theming.js
vendored
File diff suppressed because one or more lines are too long
2
dist/theming-personal-theming.js.map
vendored
2
dist/theming-personal-theming.js.map
vendored
File diff suppressed because one or more lines are too long
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
namespace OC\App;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OC\AppConfig;
|
||||
use OC\AppFramework\Bootstrap\Coordinator;
|
||||
use OC\ServerNotAvailableException;
|
||||
|
|
@ -24,6 +23,7 @@ use OCP\ICacheFactory;
|
|||
use OCP\IConfig;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
|
|
@ -67,6 +67,7 @@ class AppManager implements IAppManager {
|
|||
|
||||
private ?AppConfig $appConfig = null;
|
||||
private ?IURLGenerator $urlGenerator = null;
|
||||
private ?INavigationManager $navigationManager = null;
|
||||
|
||||
/**
|
||||
* Be extremely careful when injecting classes here. The AppManager is used by the installer,
|
||||
|
|
@ -82,6 +83,13 @@ class AppManager implements IAppManager {
|
|||
) {
|
||||
}
|
||||
|
||||
private function getNavigationManager(): INavigationManager {
|
||||
if ($this->navigationManager === null) {
|
||||
$this->navigationManager = \OCP\Server::get(INavigationManager::class);
|
||||
}
|
||||
return $this->navigationManager;
|
||||
}
|
||||
|
||||
public function getAppIcon(string $appId, bool $dark = false): ?string {
|
||||
$possibleIcons = $dark ? [$appId . '-dark.svg', 'app-dark.svg'] : [$appId . '.svg', 'app.svg'];
|
||||
$icon = null;
|
||||
|
|
@ -820,60 +828,42 @@ class AppManager implements IAppManager {
|
|||
return $this->defaultEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getDefaultAppForUser(?IUser $user = null, bool $withFallbacks = true): string {
|
||||
// Set fallback to always-enabled files app
|
||||
$appId = $withFallbacks ? 'files' : '';
|
||||
$defaultApps = explode(',', $this->config->getSystemValueString('defaultapp', ''));
|
||||
$defaultApps = array_filter($defaultApps);
|
||||
$id = $this->getNavigationManager()->getDefaultEntryIdForUser($user, $withFallbacks);
|
||||
$entry = $this->getNavigationManager()->get($id);
|
||||
return (string)$entry['app'];
|
||||
}
|
||||
|
||||
$user ??= $this->userSession->getUser();
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getDefaultApps(): array {
|
||||
$ids = $this->getNavigationManager()->getDefaultEntryIds();
|
||||
|
||||
if ($user !== null) {
|
||||
$userDefaultApps = explode(',', $this->config->getUserValue($user->getUID(), 'core', 'defaultapp'));
|
||||
$defaultApps = array_filter(array_merge($userDefaultApps, $defaultApps));
|
||||
if (empty($defaultApps) && $withFallbacks) {
|
||||
/* Fallback on user defined apporder */
|
||||
$customOrders = json_decode($this->config->getUserValue($user->getUID(), 'core', 'apporder', '[]'), true, flags:JSON_THROW_ON_ERROR);
|
||||
if (!empty($customOrders)) {
|
||||
// filter only entries with app key (when added using closures or NavigationManager::add the app is not guranteed to be set)
|
||||
$customOrders = array_filter($customOrders, fn ($entry) => isset($entry['app']));
|
||||
// sort apps by order
|
||||
usort($customOrders, fn ($a, $b) => $a['order'] - $b['order']);
|
||||
// set default apps to sorted apps
|
||||
$defaultApps = array_map(fn ($entry) => $entry['app'], $customOrders);
|
||||
return array_values(array_unique(array_map(function (string $id) {
|
||||
$entry = $this->getNavigationManager()->get($id);
|
||||
return (string)$entry['app'];
|
||||
}, $ids)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function setDefaultApps(array $defaultApps): void {
|
||||
$entries = $this->getNavigationManager()->getAll();
|
||||
$ids = [];
|
||||
foreach ($defaultApps as $defaultApp) {
|
||||
foreach ($entries as $entry) {
|
||||
if ((string)$entry['app'] === $defaultApp) {
|
||||
$ids[] = (string)$entry['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($defaultApps) && $withFallbacks) {
|
||||
$defaultApps = ['dashboard','files'];
|
||||
}
|
||||
|
||||
// Find the first app that is enabled for the current user
|
||||
foreach ($defaultApps as $defaultApp) {
|
||||
$defaultApp = \OC_App::cleanAppId(strip_tags($defaultApp));
|
||||
if ($this->isEnabledForUser($defaultApp, $user)) {
|
||||
$appId = $defaultApp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $appId;
|
||||
}
|
||||
|
||||
public function getDefaultApps(): array {
|
||||
return explode(',', $this->config->getSystemValueString('defaultapp', 'dashboard,files'));
|
||||
}
|
||||
|
||||
public function setDefaultApps(array $defaultApps): void {
|
||||
foreach ($defaultApps as $app) {
|
||||
if (!$this->isInstalled($app)) {
|
||||
$this->logger->debug('Can not set not installed app as default app', ['missing_app' => $app]);
|
||||
throw new InvalidArgumentException('App is not installed');
|
||||
}
|
||||
}
|
||||
|
||||
$this->config->setSystemValue('defaultapp', join(',', $defaultApps));
|
||||
$this->getNavigationManager()->setDefaultEntryIds($ids);
|
||||
}
|
||||
|
||||
public function isBackendRequired(string $backend): bool {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
namespace OC;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OC\App\AppManager;
|
||||
use OC\Group\Manager;
|
||||
use OCP\App\IAppManager;
|
||||
|
|
@ -14,8 +15,10 @@ use OCP\IConfig;
|
|||
use OCP\IGroupManager;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use OCP\L10N\IFactory;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Manages the ownCloud navigation
|
||||
|
|
@ -41,25 +44,26 @@ class NavigationManager implements INavigationManager {
|
|||
private $groupManager;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** The default app for the current user (cached for the `add` function) */
|
||||
private ?string $defaultApp;
|
||||
/** User defined app order (cached for the `add` function) */
|
||||
private array $customAppOrder;
|
||||
private LoggerInterface $logger;
|
||||
|
||||
public function __construct(IAppManager $appManager,
|
||||
public function __construct(
|
||||
IAppManager $appManager,
|
||||
IURLGenerator $urlGenerator,
|
||||
IFactory $l10nFac,
|
||||
IUserSession $userSession,
|
||||
IGroupManager $groupManager,
|
||||
IConfig $config) {
|
||||
IConfig $config,
|
||||
LoggerInterface $logger,
|
||||
) {
|
||||
$this->appManager = $appManager;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->l10nFac = $l10nFac;
|
||||
$this->userSession = $userSession;
|
||||
$this->groupManager = $groupManager;
|
||||
$this->config = $config;
|
||||
|
||||
$this->defaultApp = null;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -92,13 +96,22 @@ class NavigationManager implements INavigationManager {
|
|||
$entry['app'] = $id;
|
||||
}
|
||||
|
||||
// This is the default app that will always be shown first
|
||||
$entry['default'] = ($entry['app'] ?? false) === $this->defaultApp;
|
||||
// Set order from user defined app order
|
||||
$entry['order'] = (int)($this->customAppOrder[$id]['order'] ?? $entry['order'] ?? 100);
|
||||
}
|
||||
|
||||
$this->entries[$id] = $entry;
|
||||
|
||||
// Needs to be done after adding the new entry to account for the default entries containing this new entry.
|
||||
$this->updateDefaultEntries();
|
||||
}
|
||||
|
||||
private function updateDefaultEntries() {
|
||||
foreach ($this->entries as $id => $entry) {
|
||||
if ($entry['type'] === 'link') {
|
||||
$this->entries[$id]['default'] = $id === $this->getDefaultEntryIdForUser($this->userSession->getUser(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -156,10 +169,10 @@ class NavigationManager implements INavigationManager {
|
|||
unset($navEntry);
|
||||
}
|
||||
|
||||
$activeApp = $this->getActiveEntry();
|
||||
if ($activeApp !== null) {
|
||||
$activeEntry = $this->getActiveEntry();
|
||||
if ($activeEntry !== null) {
|
||||
foreach ($list as $index => &$navEntry) {
|
||||
if ($navEntry['id'] == $activeApp) {
|
||||
if ($navEntry['id'] == $activeEntry) {
|
||||
$navEntry['active'] = true;
|
||||
} else {
|
||||
$navEntry['active'] = false;
|
||||
|
|
@ -213,8 +226,6 @@ class NavigationManager implements INavigationManager {
|
|||
]);
|
||||
}
|
||||
|
||||
$this->defaultApp = $this->appManager->getDefaultAppForUser($this->userSession->getUser(), false);
|
||||
|
||||
if ($this->userSession->isLoggedIn()) {
|
||||
// Profile
|
||||
$this->add([
|
||||
|
|
@ -401,4 +412,83 @@ class NavigationManager implements INavigationManager {
|
|||
public function setUnreadCounter(string $id, int $unreadCounter): void {
|
||||
$this->unreadCounters[$id] = $unreadCounter;
|
||||
}
|
||||
|
||||
public function get(string $id): array|null {
|
||||
$this->init();
|
||||
foreach ($this->closureEntries as $c) {
|
||||
$this->add($c());
|
||||
}
|
||||
$this->closureEntries = [];
|
||||
|
||||
return $this->entries[$id];
|
||||
}
|
||||
|
||||
public function getDefaultEntryIdForUser(?IUser $user = null, bool $withFallbacks = true): string {
|
||||
$this->init();
|
||||
// Disable fallbacks here, as we need to override them with the user defaults if none are configured.
|
||||
$defaultEntryIds = $this->getDefaultEntryIds(false);
|
||||
|
||||
$user ??= $this->userSession->getUser();
|
||||
|
||||
if ($user !== null) {
|
||||
$userDefaultEntryIds = explode(',', $this->config->getUserValue($user->getUID(), 'core', 'defaultapp'));
|
||||
$defaultEntryIds = array_filter(array_merge($userDefaultEntryIds, $defaultEntryIds));
|
||||
if (empty($defaultEntryIds) && $withFallbacks) {
|
||||
/* Fallback on user defined apporder */
|
||||
$customOrders = json_decode($this->config->getUserValue($user->getUID(), 'core', 'apporder', '[]'), true, flags: JSON_THROW_ON_ERROR);
|
||||
if (!empty($customOrders)) {
|
||||
// filter only entries with app key (when added using closures or NavigationManager::add the app is not guaranteed to be set)
|
||||
$customOrders = array_filter($customOrders, static fn ($entry) => isset($entry['app']));
|
||||
// sort apps by order
|
||||
usort($customOrders, static fn ($a, $b) => $a['order'] - $b['order']);
|
||||
// set default apps to sorted apps
|
||||
$defaultEntryIds = array_map(static fn ($entry) => $entry['app'], $customOrders);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($defaultEntryIds) && $withFallbacks) {
|
||||
$defaultEntryIds = ['dashboard','files'];
|
||||
}
|
||||
|
||||
$entryIds = array_keys($this->entries);
|
||||
|
||||
// Find the first app that is enabled for the current user
|
||||
foreach ($defaultEntryIds as $defaultEntryId) {
|
||||
if (in_array($defaultEntryId, $entryIds, true)) {
|
||||
return $defaultEntryId;
|
||||
}
|
||||
}
|
||||
|
||||
// Set fallback to always-enabled files app
|
||||
return $withFallbacks ? 'files' : '';
|
||||
}
|
||||
|
||||
public function getDefaultEntryIds(bool $withFallbacks = true): array {
|
||||
$this->init();
|
||||
$storedIds = explode(',', $this->config->getSystemValueString('defaultapp', $withFallbacks ? 'dashboard,files' : ''));
|
||||
$ids = [];
|
||||
$entryIds = array_keys($this->entries);
|
||||
foreach ($storedIds as $id) {
|
||||
if (in_array($id, $entryIds, true)) {
|
||||
$ids[] = $id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array_filter($ids);
|
||||
}
|
||||
|
||||
public function setDefaultEntryIds(array $ids): void {
|
||||
$this->init();
|
||||
$entryIds = array_keys($this->entries);
|
||||
|
||||
foreach ($ids as $id) {
|
||||
if (!in_array($id, $entryIds, true)) {
|
||||
$this->logger->debug('Cannot set unavailable entry as default entry', ['missing_entry' => $id]);
|
||||
throw new InvalidArgumentException('Entry not available');
|
||||
}
|
||||
}
|
||||
|
||||
$this->config->setSystemValue('defaultapp', join(',', $ids));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,11 +99,10 @@ class TemplateLayout extends \OC_Template {
|
|||
$logoUrl = $this->config->getSystemValueString('logo_url', '');
|
||||
$this->assign('logoUrl', $logoUrl);
|
||||
|
||||
// Set default app name
|
||||
$defaultApp = \OC::$server->getAppManager()->getDefaultAppForUser();
|
||||
$defaultAppInfo = \OC::$server->getAppManager()->getAppInfo($defaultApp);
|
||||
$l10n = \OC::$server->get(IFactory::class)->get($defaultApp);
|
||||
$this->assign('defaultAppName', $l10n->t($defaultAppInfo['name']));
|
||||
// Set default entry name
|
||||
$defaultEntryId = \OCP\Server::get(INavigationManager::class)->getDefaultEntryIdForUser();
|
||||
$defaultEntry = \OCP\Server::get(INavigationManager::class)->get($defaultEntryId);
|
||||
$this->assign('defaultAppName', $defaultEntry['name']);
|
||||
|
||||
// Add navigation entry
|
||||
$this->assign('application', '');
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use OCP\App\AppPathNotFoundException;
|
|||
use OCP\App\IAppManager;
|
||||
use OCP\ICacheFactory;
|
||||
use OCP\IConfig;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserSession;
|
||||
|
|
@ -36,6 +37,7 @@ class URLGenerator implements IURLGenerator {
|
|||
/** @var null|string */
|
||||
private $baseUrl = null;
|
||||
private ?IAppManager $appManager = null;
|
||||
private ?INavigationManager $navigationManager = null;
|
||||
|
||||
public function __construct(IConfig $config,
|
||||
IUserSession $userSession,
|
||||
|
|
@ -58,6 +60,14 @@ class URLGenerator implements IURLGenerator {
|
|||
return $this->appManager;
|
||||
}
|
||||
|
||||
private function getNavigationManager(): INavigationManager {
|
||||
if ($this->navigationManager !== null) {
|
||||
return $this->navigationManager;
|
||||
}
|
||||
$this->navigationManager = \OCP\Server::get(INavigationManager::class);
|
||||
return $this->navigationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an url using a defined route
|
||||
*
|
||||
|
|
@ -288,14 +298,17 @@ class URLGenerator implements IURLGenerator {
|
|||
return $this->getAbsoluteURL($defaultPage);
|
||||
}
|
||||
|
||||
$appId = $this->getAppManager()->getDefaultAppForUser();
|
||||
|
||||
if ($this->config->getSystemValueBool('htaccess.IgnoreFrontController', false)
|
||||
|| getenv('front_controller_active') === 'true') {
|
||||
return $this->getAbsoluteURL('/apps/' . $appId . '/');
|
||||
$entryId = $this->getNavigationManager()->getDefaultEntryIdForUser();
|
||||
$entry = $this->getNavigationManager()->get($entryId);
|
||||
$href = (string)$entry['href'];
|
||||
if ($href === '') {
|
||||
throw new \InvalidArgumentException('Default navigation entry is missing href: ' . $entryId);
|
||||
}
|
||||
if (str_starts_with($href, '/index.php/') && ($this->config->getSystemValueBool('htaccess.IgnoreFrontController', false) || getenv('front_controller_active') === 'true')) {
|
||||
$href = substr($href, 10);
|
||||
}
|
||||
|
||||
return $this->getAbsoluteURL('/index.php/apps/' . $appId . '/');
|
||||
return $this->getAbsoluteURL($href);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -247,6 +247,8 @@ interface IAppManager {
|
|||
*
|
||||
* @since 25.0.6
|
||||
* @since 28.0.0 Added optional $withFallbacks parameter
|
||||
* @deprecated 31.0.0
|
||||
* Use @see \OCP\INavigationManager::getDefaultEntryIdForUser() instead
|
||||
*/
|
||||
public function getDefaultAppForUser(?IUser $user = null, bool $withFallbacks = true): string;
|
||||
|
||||
|
|
@ -255,6 +257,8 @@ interface IAppManager {
|
|||
*
|
||||
* @return string[] The default applications
|
||||
* @since 28.0.0
|
||||
* @deprecated 31.0.0
|
||||
* Use @see \OCP\INavigationManager::getDefaultEntryIds() instead
|
||||
*/
|
||||
public function getDefaultApps(): array;
|
||||
|
||||
|
|
@ -264,6 +268,8 @@ interface IAppManager {
|
|||
* @param string[] $appId
|
||||
* @throws \InvalidArgumentException If any of the apps is not installed
|
||||
* @since 28.0.0
|
||||
* @deprecated 31.0.0
|
||||
* Use @see \OCP\INavigationManager::setDefaultEntryIds() instead
|
||||
*/
|
||||
public function setDefaultApps(array $defaultApps): void;
|
||||
|
||||
|
|
|
|||
|
|
@ -80,4 +80,42 @@ interface INavigationManager {
|
|||
* @since 22.0.0
|
||||
*/
|
||||
public function setUnreadCounter(string $id, int $unreadCounter): void;
|
||||
|
||||
/**
|
||||
* Get a navigation entry by id.
|
||||
*
|
||||
* @param string $id ID of the navigation entry
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public function get(string $id): array|null;
|
||||
|
||||
/**
|
||||
* Returns the id of the user's default entry
|
||||
*
|
||||
* If `user` is not passed, the currently logged in user will be used
|
||||
*
|
||||
* @param ?IUser $user User to query default entry for
|
||||
* @param bool $withFallbacks Include fallback values if no default entry was configured manually
|
||||
* Before falling back to predefined default entries,
|
||||
* the user defined entry order is considered and the first entry would be used as the fallback.
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public function getDefaultEntryIdForUser(?IUser $user = null, bool $withFallbacks = true): string;
|
||||
|
||||
/**
|
||||
* Get the global default entries with fallbacks
|
||||
*
|
||||
* @return string[] The default entries
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public function getDefaultEntryIds(): array;
|
||||
|
||||
/**
|
||||
* Set the global default entries with fallbacks
|
||||
*
|
||||
* @param string[] $ids
|
||||
* @throws \InvalidArgumentException If any of the entries is not available
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public function setDefaultEntryIds(array $ids): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -733,159 +733,6 @@ class AppManagerTest extends TestCase {
|
|||
$this->assertEquals(['foo'], $this->manager->getAppRestriction('test3'));
|
||||
}
|
||||
|
||||
public function provideDefaultApps(): array {
|
||||
return [
|
||||
// none specified, default to files
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// none specified, without fallback
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{}',
|
||||
false,
|
||||
'',
|
||||
],
|
||||
// unexisting or inaccessible app specified, default to files
|
||||
[
|
||||
'unexist',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// unexisting or inaccessible app specified, without fallbacks
|
||||
[
|
||||
'unexist',
|
||||
'',
|
||||
'{}',
|
||||
false,
|
||||
'',
|
||||
],
|
||||
// non-standard app
|
||||
[
|
||||
'settings',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
// non-standard app, without fallback
|
||||
[
|
||||
'settings',
|
||||
'',
|
||||
'{}',
|
||||
false,
|
||||
'settings',
|
||||
],
|
||||
// non-standard app with fallback
|
||||
[
|
||||
'unexist,settings',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
// system default app and user apporder
|
||||
[
|
||||
// system default is settings
|
||||
'unexist,settings',
|
||||
'',
|
||||
// apporder says default app is files (order is lower)
|
||||
'{"files_id":{"app":"files","order":1},"settings_id":{"app":"settings","order":2}}',
|
||||
true,
|
||||
// system default should override apporder
|
||||
'settings'
|
||||
],
|
||||
// user-customized defaultapp
|
||||
[
|
||||
'',
|
||||
'files',
|
||||
'',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized defaultapp with systemwide
|
||||
[
|
||||
'unexist,settings',
|
||||
'files',
|
||||
'',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized defaultapp with system wide and apporder
|
||||
[
|
||||
'unexist,settings',
|
||||
'files',
|
||||
'{"settings_id":{"app":"settings","order":1},"files_id":{"app":"files","order":2}}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized apporder fallback
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"settings_id":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
// user-customized apporder fallback with missing app key (entries added by closures does not always have an app key set (Nextcloud 27 spreed app for example))
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"spreed":{"order":1},"files":{"app":"files","order":2}}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized apporder, but called without fallback
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"settings":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
|
||||
false,
|
||||
'',
|
||||
],
|
||||
// user-customized apporder with an app that has multiple routes
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"settings_id":{"app":"settings","order":1},"settings_id_2":{"app":"settings","order":3},"id_files":{"app":"files","order":2}}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDefaultApps
|
||||
*/
|
||||
public function testGetDefaultAppForUser($defaultApps, $userDefaultApps, $userApporder, $withFallbacks, $expectedApp) {
|
||||
$user = $this->newUser('user1');
|
||||
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
|
||||
$this->config->expects($this->once())
|
||||
->method('getSystemValueString')
|
||||
->with('defaultapp', $this->anything())
|
||||
->willReturn($defaultApps);
|
||||
|
||||
$this->config->expects($this->atLeastOnce())
|
||||
->method('getUserValue')
|
||||
->willReturnMap([
|
||||
['user1', 'core', 'defaultapp', '', $userDefaultApps],
|
||||
['user1', 'core', 'apporder', '[]', $userApporder],
|
||||
]);
|
||||
|
||||
$this->assertEquals($expectedApp, $this->manager->getDefaultAppForUser(null, $withFallbacks));
|
||||
}
|
||||
|
||||
public static function isBackendRequiredDataProvider(): array {
|
||||
return [
|
||||
// backend available
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use OCP\IURLGenerator;
|
|||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use OCP\L10N\IFactory;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class NavigationManagerTest extends TestCase {
|
||||
/** @var AppManager|\PHPUnit\Framework\MockObject\MockObject */
|
||||
|
|
@ -35,6 +36,7 @@ class NavigationManagerTest extends TestCase {
|
|||
|
||||
/** @var \OC\NavigationManager */
|
||||
protected $navigationManager;
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
|
@ -45,13 +47,15 @@ class NavigationManagerTest extends TestCase {
|
|||
$this->userSession = $this->createMock(IUserSession::class);
|
||||
$this->groupManager = $this->createMock(Manager::class);
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->navigationManager = new NavigationManager(
|
||||
$this->appManager,
|
||||
$this->urlGenerator,
|
||||
$this->l10nFac,
|
||||
$this->userSession,
|
||||
$this->groupManager,
|
||||
$this->config
|
||||
$this->config,
|
||||
$this->logger,
|
||||
);
|
||||
|
||||
$this->navigationManager->clear(false);
|
||||
|
|
@ -557,4 +561,224 @@ class NavigationManagerTest extends TestCase {
|
|||
$entries = $this->navigationManager->getAll();
|
||||
$this->assertEquals($expected, $entries);
|
||||
}
|
||||
|
||||
public static function provideDefaultEntries(): array {
|
||||
return [
|
||||
// none specified, default to files
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// none specified, without fallback
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{}',
|
||||
false,
|
||||
'',
|
||||
],
|
||||
// unexisting or inaccessible app specified, default to files
|
||||
[
|
||||
'unexist',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// unexisting or inaccessible app specified, without fallbacks
|
||||
[
|
||||
'unexist',
|
||||
'',
|
||||
'{}',
|
||||
false,
|
||||
'',
|
||||
],
|
||||
// non-standard app
|
||||
[
|
||||
'settings',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
// non-standard app, without fallback
|
||||
[
|
||||
'settings',
|
||||
'',
|
||||
'{}',
|
||||
false,
|
||||
'settings',
|
||||
],
|
||||
// non-standard app with fallback
|
||||
[
|
||||
'unexist,settings',
|
||||
'',
|
||||
'{}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
// system default app and user apporder
|
||||
[
|
||||
// system default is settings
|
||||
'unexist,settings',
|
||||
'',
|
||||
// apporder says default app is files (order is lower)
|
||||
'{"files_id":{"app":"files","order":1},"settings_id":{"app":"settings","order":2}}',
|
||||
true,
|
||||
// system default should override apporder
|
||||
'settings'
|
||||
],
|
||||
// user-customized defaultapp
|
||||
[
|
||||
'',
|
||||
'files',
|
||||
'',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized defaultapp with systemwide
|
||||
[
|
||||
'unexist,settings',
|
||||
'files',
|
||||
'',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized defaultapp with system wide and apporder
|
||||
[
|
||||
'unexist,settings',
|
||||
'files',
|
||||
'{"settings_id":{"app":"settings","order":1},"files_id":{"app":"files","order":2}}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized apporder fallback
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"settings_id":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
// user-customized apporder fallback with missing app key (entries added by closures does not always have an app key set (Nextcloud 27 spreed app for example))
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"spreed":{"order":1},"files":{"app":"files","order":2}}',
|
||||
true,
|
||||
'files',
|
||||
],
|
||||
// user-customized apporder, but called without fallback
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"settings":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
|
||||
false,
|
||||
'',
|
||||
],
|
||||
// user-customized apporder with an app that has multiple routes
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'{"settings_id":{"app":"settings","order":1},"settings_id_2":{"app":"settings","order":3},"id_files":{"app":"files","order":2}}',
|
||||
true,
|
||||
'settings',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDefaultEntries
|
||||
*/
|
||||
public function testGetDefaultEntryIdForUser($defaultApps, $userDefaultApps, $userApporder, $withFallbacks, $expectedApp) {
|
||||
$this->navigationManager->add([
|
||||
'id' => 'files',
|
||||
]);
|
||||
$this->navigationManager->add([
|
||||
'id' => 'settings',
|
||||
]);
|
||||
|
||||
$this->appManager->method('getInstalledApps')->willReturn([]);
|
||||
|
||||
$user = $this->createMock(IUser::class);
|
||||
$user->method('getUID')->willReturn('user1');
|
||||
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
|
||||
$this->config->expects($this->once())
|
||||
->method('getSystemValueString')
|
||||
->with('defaultapp', $this->anything())
|
||||
->willReturn($defaultApps);
|
||||
|
||||
$this->config->expects($this->atLeastOnce())
|
||||
->method('getUserValue')
|
||||
->willReturnMap([
|
||||
['user1', 'core', 'defaultapp', '', $userDefaultApps],
|
||||
['user1', 'core', 'apporder', '[]', $userApporder],
|
||||
]);
|
||||
|
||||
$this->assertEquals($expectedApp, $this->navigationManager->getDefaultEntryIdForUser(null, $withFallbacks));
|
||||
}
|
||||
|
||||
public function testDefaultEntryUpdated() {
|
||||
$this->appManager->method('getInstalledApps')->willReturn([]);
|
||||
|
||||
$user = $this->createMock(IUser::class);
|
||||
$user->method('getUID')->willReturn('user1');
|
||||
|
||||
$this->userSession
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
|
||||
$this->config
|
||||
->method('getSystemValueString')
|
||||
->with('defaultapp', $this->anything())
|
||||
->willReturn('app4,app3,app2,app1');
|
||||
|
||||
$this->config
|
||||
->method('getUserValue')
|
||||
->willReturnMap([
|
||||
['user1', 'core', 'defaultapp', '', ''],
|
||||
['user1', 'core', 'apporder', '[]', ''],
|
||||
]);
|
||||
|
||||
$this->navigationManager->add([
|
||||
'id' => 'app1',
|
||||
]);
|
||||
|
||||
$this->assertEquals('app1', $this->navigationManager->getDefaultEntryIdForUser(null, false));
|
||||
$this->assertEquals(true, $this->navigationManager->get('app1')['default']);
|
||||
|
||||
$this->navigationManager->add([
|
||||
'id' => 'app3',
|
||||
]);
|
||||
|
||||
$this->assertEquals('app3', $this->navigationManager->getDefaultEntryIdForUser(null, false));
|
||||
$this->assertEquals(false, $this->navigationManager->get('app1')['default']);
|
||||
$this->assertEquals(true, $this->navigationManager->get('app3')['default']);
|
||||
|
||||
$this->navigationManager->add([
|
||||
'id' => 'app2',
|
||||
]);
|
||||
|
||||
$this->assertEquals('app3', $this->navigationManager->getDefaultEntryIdForUser(null, false));
|
||||
$this->assertEquals(false, $this->navigationManager->get('app1')['default']);
|
||||
$this->assertEquals(false, $this->navigationManager->get('app2')['default']);
|
||||
$this->assertEquals(true, $this->navigationManager->get('app3')['default']);
|
||||
|
||||
$this->navigationManager->add([
|
||||
'id' => 'app4',
|
||||
]);
|
||||
|
||||
$this->assertEquals('app4', $this->navigationManager->getDefaultEntryIdForUser(null, false));
|
||||
$this->assertEquals(false, $this->navigationManager->get('app1')['default']);
|
||||
$this->assertEquals(false, $this->navigationManager->get('app2')['default']);
|
||||
$this->assertEquals(false, $this->navigationManager->get('app3')['default']);
|
||||
$this->assertEquals(true, $this->navigationManager->get('app4')['default']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue