Merge pull request #8095 from nextcloud/webapps-capabilities
Expose navigation entries as API endpoint
This commit is contained in:
commit
14bc9b1714
11 changed files with 292 additions and 48 deletions
92
core/Controller/NavigationController.php
Normal file
92
core/Controller/NavigationController.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
|
||||
*
|
||||
* @author Julius Härtl <jus@bitgrid.net>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
namespace OC\Core\Controller;
|
||||
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
class NavigationController extends OCSController {
|
||||
|
||||
/** @var INavigationManager */
|
||||
private $navigationManager;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
public function __construct(string $appName, IRequest $request, INavigationManager $navigationManager, IURLGenerator $urlGenerator) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->navigationManager = $navigationManager;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*
|
||||
* @param bool $absolute
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function getAppsNavigation(bool $absolute = false): DataResponse {
|
||||
$navigation = $this->navigationManager->getAll();
|
||||
if ($absolute) {
|
||||
$navigation = $this->rewriteToAbsoluteUrls($navigation);
|
||||
}
|
||||
return new DataResponse($navigation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*
|
||||
* @param bool $absolute
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function getSettingsNavigation(bool $absolute = false): DataResponse {
|
||||
$navigation = $this->navigationManager->getAll('settings');
|
||||
if ($absolute) {
|
||||
$navigation = $this->rewriteToAbsoluteUrls($navigation);
|
||||
}
|
||||
return new DataResponse($navigation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite href attribute of navigation entries to an absolute URL
|
||||
*
|
||||
* @param array $navigation
|
||||
* @return array
|
||||
*/
|
||||
private function rewriteToAbsoluteUrls(array $navigation): array {
|
||||
foreach ($navigation as &$entry) {
|
||||
if (0 !== strpos($entry['href'], $this->urlGenerator->getBaseUrl())) {
|
||||
$entry['href'] = $this->urlGenerator->getAbsoluteURL($entry['href']);
|
||||
}
|
||||
if (0 !== strpos($entry['icon'], $this->urlGenerator->getBaseUrl())) {
|
||||
$entry['icon'] = $this->urlGenerator->getAbsoluteURL($entry['icon']);
|
||||
}
|
||||
}
|
||||
return $navigation;
|
||||
}
|
||||
}
|
|
@ -71,6 +71,8 @@ $application->registerRoutes($this, [
|
|||
['root' => '', 'name' => 'OCS#getConfig', 'url' => '/config', 'verb' => 'GET'],
|
||||
['root' => '/person', 'name' => 'OCS#personCheck', 'url' => '/check', 'verb' => 'POST'],
|
||||
['root' => '/identityproof', 'name' => 'OCS#getIdentityProof', 'url' => '/key/{cloudId}', 'verb' => 'GET'],
|
||||
['root' => '/core', 'name' => 'Navigation#getAppsNavigation', 'url' => '/navigation/apps', 'verb' => 'GET'],
|
||||
['root' => '/core', 'name' => 'Navigation#getSettingsNavigation', 'url' => '/navigation/settings', 'verb' => 'GET'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
|
|
@ -521,6 +521,7 @@ return array(
|
|||
'OC\\Core\\Controller\\JsController' => $baseDir . '/core/Controller/JsController.php',
|
||||
'OC\\Core\\Controller\\LoginController' => $baseDir . '/core/Controller/LoginController.php',
|
||||
'OC\\Core\\Controller\\LostController' => $baseDir . '/core/Controller/LostController.php',
|
||||
'OC\\Core\\Controller\\NavigationController' => $baseDir . '/core/Controller/NavigationController.php',
|
||||
'OC\\Core\\Controller\\OCJSController' => $baseDir . '/core/Controller/OCJSController.php',
|
||||
'OC\\Core\\Controller\\OCSController' => $baseDir . '/core/Controller/OCSController.php',
|
||||
'OC\\Core\\Controller\\PreviewController' => $baseDir . '/core/Controller/PreviewController.php',
|
||||
|
|
|
@ -551,6 +551,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Core\\Controller\\JsController' => __DIR__ . '/../../..' . '/core/Controller/JsController.php',
|
||||
'OC\\Core\\Controller\\LoginController' => __DIR__ . '/../../..' . '/core/Controller/LoginController.php',
|
||||
'OC\\Core\\Controller\\LostController' => __DIR__ . '/../../..' . '/core/Controller/LostController.php',
|
||||
'OC\\Core\\Controller\\NavigationController' => __DIR__ . '/../../..' . '/core/Controller/NavigationController.php',
|
||||
'OC\\Core\\Controller\\OCJSController' => __DIR__ . '/../../..' . '/core/Controller/OCJSController.php',
|
||||
'OC\\Core\\Controller\\OCSController' => __DIR__ . '/../../..' . '/core/Controller/OCSController.php',
|
||||
'OC\\Core\\Controller\\PreviewController' => __DIR__ . '/../../..' . '/core/Controller/PreviewController.php',
|
||||
|
|
|
@ -104,26 +104,61 @@ class NavigationManager implements INavigationManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* returns all the added Menu entries
|
||||
* @param string $type
|
||||
* @return array an array of the added entries
|
||||
* Get a list of navigation entries
|
||||
*
|
||||
* @param string $type type of the navigation entries
|
||||
* @return array
|
||||
*/
|
||||
public function getAll($type = 'link') {
|
||||
public function getAll(string $type = 'link'): array {
|
||||
$this->init();
|
||||
foreach ($this->closureEntries as $c) {
|
||||
$this->add($c());
|
||||
}
|
||||
$this->closureEntries = array();
|
||||
|
||||
if ($type === 'all') {
|
||||
return $this->entries;
|
||||
$result = $this->entries;
|
||||
if ($type !== 'all') {
|
||||
$result = array_filter($this->entries, function($entry) use ($type) {
|
||||
return $entry['type'] === $type;
|
||||
});
|
||||
}
|
||||
|
||||
return array_filter($this->entries, function($entry) use ($type) {
|
||||
return $entry['type'] === $type;
|
||||
});
|
||||
return $this->proceedNavigation($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort navigation entries by order, name and set active flag
|
||||
*
|
||||
* @param array $list
|
||||
* @return array
|
||||
*/
|
||||
private function proceedNavigation(array $list): array {
|
||||
usort($list, function($a, $b) {
|
||||
if (isset($a['order']) && isset($b['order'])) {
|
||||
return ($a['order'] < $b['order']) ? -1 : 1;
|
||||
} else if (isset($a['order']) || isset($b['order'])) {
|
||||
return isset($a['order']) ? -1 : 1;
|
||||
} else {
|
||||
return ($a['name'] < $b['name']) ? -1 : 1;
|
||||
}
|
||||
});
|
||||
|
||||
$activeApp = $this->getActiveEntry();
|
||||
if ($activeApp !== null) {
|
||||
foreach ($list as $index => &$navEntry) {
|
||||
if ($navEntry['id'] == $activeApp) {
|
||||
$navEntry['active'] = true;
|
||||
} else {
|
||||
$navEntry['active'] = false;
|
||||
}
|
||||
}
|
||||
unset($navEntry);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* removes all the entries
|
||||
*/
|
||||
|
|
|
@ -80,9 +80,9 @@ class TemplateLayout extends \OC_Template {
|
|||
// Add navigation entry
|
||||
$this->assign( 'application', '');
|
||||
$this->assign( 'appid', $appId );
|
||||
$navigation = \OC_App::getNavigation();
|
||||
$navigation = \OC::$server->getNavigationManager()->getAll();
|
||||
$this->assign( 'navigation', $navigation);
|
||||
$settingsNavigation = \OC_App::getSettingsNavigation();
|
||||
$settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
|
||||
$this->assign( 'settingsnavigation', $settingsNavigation);
|
||||
foreach($navigation as $entry) {
|
||||
if ($entry['active']) {
|
||||
|
|
|
@ -445,31 +445,6 @@ class OC_App {
|
|||
$appManager->disableApp($app);
|
||||
}
|
||||
|
||||
// This is private as well. It simply works, so don't ask for more details
|
||||
private static function proceedNavigation($list) {
|
||||
usort($list, function($a, $b) {
|
||||
if (isset($a['order']) && isset($b['order'])) {
|
||||
return ($a['order'] < $b['order']) ? -1 : 1;
|
||||
} else if (isset($a['order']) || isset($b['order'])) {
|
||||
return isset($a['order']) ? -1 : 1;
|
||||
} else {
|
||||
return ($a['name'] < $b['name']) ? -1 : 1;
|
||||
}
|
||||
});
|
||||
|
||||
$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
|
||||
foreach ($list as $index => &$navEntry) {
|
||||
if ($navEntry['id'] == $activeApp) {
|
||||
$navEntry['active'] = true;
|
||||
} else {
|
||||
$navEntry['active'] = false;
|
||||
}
|
||||
}
|
||||
unset($navEntry);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path where to install apps
|
||||
*
|
||||
|
@ -613,6 +588,7 @@ class OC_App {
|
|||
* Returns the navigation
|
||||
*
|
||||
* @return array
|
||||
* @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
|
||||
*
|
||||
* This function returns an array containing all entries added. The
|
||||
* entries are sorted by the key 'order' ascending. Additional to the keys
|
||||
|
@ -620,21 +596,20 @@ class OC_App {
|
|||
* - active: boolean, signals if the user is on this navigation entry
|
||||
*/
|
||||
public static function getNavigation() {
|
||||
$entries = OC::$server->getNavigationManager()->getAll();
|
||||
return self::proceedNavigation($entries);
|
||||
return OC::$server->getNavigationManager()->getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Settings Navigation
|
||||
*
|
||||
* @return string[]
|
||||
* @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
|
||||
*
|
||||
* This function returns an array containing all settings pages added. The
|
||||
* entries are sorted by the key 'order' ascending.
|
||||
*/
|
||||
public static function getSettingsNavigation() {
|
||||
$entries = OC::$server->getNavigationManager()->getAll('settings');
|
||||
return self::proceedNavigation($entries);
|
||||
return OC::$server->getNavigationManager()->getAll('settings');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,4 +57,13 @@ interface INavigationManager {
|
|||
* @since 6.0.0
|
||||
*/
|
||||
public function setActiveEntry($appId);
|
||||
|
||||
/**
|
||||
* Get a list of navigation entries
|
||||
*
|
||||
* @param string $type type of the navigation entries
|
||||
* @return array
|
||||
* @since 14.0.0
|
||||
*/
|
||||
public function getAll(string $type = 'link'): array;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
OC_Util::checkAdminUser();
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$navigation = \OC_App::getNavigation();
|
||||
$navigation = \OC::$server->getNavigationManager()->getAll();
|
||||
|
||||
OCP\JSON::success(['nav_entries' => $navigation]);
|
||||
|
|
129
tests/Core/Controller/NavigationControllerTest.php
Normal file
129
tests/Core/Controller/NavigationControllerTest.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
|
||||
*
|
||||
* @author Julius Härtl <jus@bitgrid.net>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
namespace Tests\Core\Controller;
|
||||
|
||||
use OC\Core\Controller\NavigationController;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\INavigationManager;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use Test\TestCase;
|
||||
|
||||
class NavigationControllerTest extends TestCase {
|
||||
|
||||
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
|
||||
private $request;
|
||||
|
||||
/** @var INavigationManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
private $navigationManager;
|
||||
|
||||
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
|
||||
private $urlGenerator;
|
||||
|
||||
/** @var NavigationController */
|
||||
private $controller;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->request = $this->createMock(IRequest::class);
|
||||
$this->navigationManager = $this->createMock(INavigationManager::class);
|
||||
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||
|
||||
$this->controller = new NavigationController(
|
||||
'core',
|
||||
$this->request,
|
||||
$this->navigationManager,
|
||||
$this->urlGenerator
|
||||
);
|
||||
}
|
||||
|
||||
public function dataGetNavigation() {
|
||||
return [
|
||||
[false], [true]
|
||||
];
|
||||
}
|
||||
/** @dataProvider dataGetNavigation */
|
||||
public function testGetAppNavigation($absolute) {
|
||||
$this->navigationManager->expects($this->once())
|
||||
->method('getAll')
|
||||
->with('link')
|
||||
->willReturn([ ['id' => 'files', 'href' => '/index.php/apps/files', 'icon' => 'icon' ] ]);
|
||||
if ($absolute) {
|
||||
$this->urlGenerator->expects($this->any())
|
||||
->method('getBaseURL')
|
||||
->willReturn('http://localhost/');
|
||||
$this->urlGenerator->expects($this->at(1))
|
||||
->method('getAbsoluteURL')
|
||||
->with('/index.php/apps/files')
|
||||
->willReturn('http://localhost/index.php/apps/files');
|
||||
$this->urlGenerator->expects($this->at(3))
|
||||
->method('getAbsoluteURL')
|
||||
->with('icon')
|
||||
->willReturn('http://localhost/icon');
|
||||
$actual = $this->controller->getAppsNavigation($absolute);
|
||||
$this->assertInstanceOf(DataResponse::class, $actual);
|
||||
$this->assertEquals('http://localhost/index.php/apps/files', $actual->getData()[0]['href']);
|
||||
$this->assertEquals('http://localhost/icon', $actual->getData()[0]['icon']);
|
||||
|
||||
|
||||
} else {
|
||||
$actual = $this->controller->getAppsNavigation($absolute);
|
||||
$this->assertInstanceOf(DataResponse::class, $actual);
|
||||
$this->assertEquals('/index.php/apps/files', $actual->getData()[0]['href']);
|
||||
$this->assertEquals('icon', $actual->getData()[0]['icon']);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** @dataProvider dataGetNavigation */
|
||||
public function testGetSettingsNavigation($absolute) {
|
||||
$this->navigationManager->expects($this->once())
|
||||
->method('getAll')
|
||||
->with('settings')
|
||||
->willReturn([ ['id' => 'settings', 'href' => '/index.php/settings/user', 'icon' => '/core/img/settings.svg'] ]);
|
||||
if ($absolute) {
|
||||
$this->urlGenerator->expects($this->any())
|
||||
->method('getBaseURL')
|
||||
->willReturn('http://localhost/');
|
||||
$this->urlGenerator->expects($this->at(1))
|
||||
->method('getAbsoluteURL')
|
||||
->with('/index.php/settings/user')
|
||||
->willReturn('http://localhost/index.php/settings/user');
|
||||
$this->urlGenerator->expects($this->at(3))
|
||||
->method('getAbsoluteURL')
|
||||
->with('/core/img/settings.svg')
|
||||
->willReturn('http://localhost/core/img/settings.svg');
|
||||
$actual = $this->controller->getSettingsNavigation($absolute);
|
||||
$this->assertInstanceOf(DataResponse::class, $actual);
|
||||
$this->assertEquals('http://localhost/index.php/settings/user', $actual->getData()[0]['href']);
|
||||
$this->assertEquals('http://localhost/core/img/settings.svg', $actual->getData()[0]['icon']);
|
||||
} else {
|
||||
$actual = $this->controller->getSettingsNavigation($absolute);
|
||||
$this->assertInstanceOf(DataResponse::class, $actual);
|
||||
$this->assertEquals('/index.php/settings/user', $actual->getData()[0]['href']);
|
||||
$this->assertEquals('/core/img/settings.svg', $actual->getData()[0]['icon']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -284,7 +284,7 @@ class NavigationManagerTest extends TestCase {
|
|||
],
|
||||
];
|
||||
return [
|
||||
'minimalistic' => [array_merge($defaults, [[
|
||||
'minimalistic' => [array_merge([$defaults[0]], [[
|
||||
'id' => 'test',
|
||||
'order' => 100,
|
||||
'href' => '/apps/test/',
|
||||
|
@ -293,8 +293,8 @@ class NavigationManagerTest extends TestCase {
|
|||
'active' => false,
|
||||
'type' => 'link',
|
||||
'classes' => '',
|
||||
]]), ['navigations' => [['route' => 'test.page.index', 'name' => 'Test']]]],
|
||||
'minimalistic-settings' => [array_merge($defaults, [[
|
||||
]], [$defaults[1]]), ['navigations' => [['route' => 'test.page.index', 'name' => 'Test']]]],
|
||||
'minimalistic-settings' => [array_merge([$defaults[0]], [[
|
||||
'id' => 'test',
|
||||
'order' => 100,
|
||||
'href' => '/apps/test/',
|
||||
|
@ -303,8 +303,8 @@ class NavigationManagerTest extends TestCase {
|
|||
'active' => false,
|
||||
'type' => 'settings',
|
||||
'classes' => '',
|
||||
]]), ['navigations' => [['route' => 'test.page.index', 'name' => 'Test', 'type' => 'settings']]]],
|
||||
'admin' => [array_merge($apps, $defaults, [[
|
||||
]], [$defaults[1]]), ['navigations' => [['route' => 'test.page.index', 'name' => 'Test', 'type' => 'settings']]]],
|
||||
'admin' => [array_merge([$defaults[0]], $apps, [[
|
||||
'id' => 'test',
|
||||
'order' => 100,
|
||||
'href' => '/apps/test/',
|
||||
|
@ -313,8 +313,8 @@ class NavigationManagerTest extends TestCase {
|
|||
'active' => false,
|
||||
'type' => 'link',
|
||||
'classes' => '',
|
||||
]]), ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']]], true],
|
||||
'no name' => [array_merge($apps, $defaults), ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index']]], true],
|
||||
]], [$defaults[1]]), ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']]], true],
|
||||
'no name' => [array_merge([$defaults[0]], $apps, [$defaults[1]]), ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index']]], true],
|
||||
'no admin' => [$defaults, ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']]]]
|
||||
];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue