Merge pull request #2822 from nextcloud/add-navigation-via-info.xml

Add navigation via info.xml (#26785)
This commit is contained in:
Morris Jobke 2017-01-27 11:25:26 -06:00 committed by GitHub
commit 8b95bd29ee
6 changed files with 188 additions and 20 deletions

View File

@ -26,20 +26,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
// required for translation purpose
// t('Files')
$l = \OC::$server->getL10N('files');
\OC::$server->getNavigationManager()->add(function () {
$urlGenerator = \OC::$server->getURLGenerator();
$l = \OC::$server->getL10N('files');
return [
'id' => 'files_index',
'order' => 0,
'href' => $urlGenerator->linkToRoute('files.view.index'),
'icon' => $urlGenerator->imagePath('core', 'places/files.svg'),
'name' => $l->t('Files'),
];
});
\OC::$server->getSearch()->registerProvider('OC\Search\Provider\File', array('apps' => array('files')));
$templateManager = \OC_Helper::getFileTemplateManager();

View File

@ -53,4 +53,11 @@
<command>OCA\Files\Command\DeleteOrphanedFiles</command>
<command>OCA\Files\Command\TransferOwnership</command>
</commands>
<navigation>
<name>Files</name>
<route>files.view.index</route>
<order>0</order>
</navigation>
</info>

6
apps/files/img/app.svg Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.1" viewBox="0 0 32 32">
<g fill-rule="evenodd" transform="matrix(1.7333 0 0 1.7333 -344.09 -1727.8)" fill="#fff">
<path d="m200.2 999.72c-0.28913 0-0.53125 0.2421-0.53125 0.5312v12.784c0 0.2985 0.23264 0.5312 0.53125 0.5312h15.091c0.2986 0 0.53124-0.2327 0.53124-0.5312l0.0004-10.474c0-0.2889-0.24211-0.5338-0.53124-0.5338l-7.5457 0.0005-2.3076-2.3078z" fill-rule="evenodd" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 533 B

View File

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @copyright Copyright (c) 2016, ownCloud GmbH
*
* @author Bart Visscher <bartv@thisnet.nl>
* @author Joas Schilling <coding@schilljs.com>
@ -26,13 +26,46 @@
namespace OC;
use OC\App\AppManager;
use OCP\App\IAppManager;
use OCP\IGroupManager;
use OCP\INavigationManager;
use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\L10N\IFactory;
/**
* Manages the ownCloud navigation
*/
class NavigationManager implements \OCP\INavigationManager {
protected $entries = array();
protected $closureEntries = array();
class NavigationManager implements INavigationManager {
protected $entries = [];
protected $closureEntries = [];
protected $activeEntry;
/** @var bool */
protected $init = false;
/** @var IAppManager|AppManager */
protected $appManager;
/** @var IURLGenerator */
private $urlGenerator;
/** @var IFactory */
private $l10nFac;
/** @var IUserSession */
private $userSession;
/** @var IGroupManager */
private $groupManager;
public function __construct(IAppManager $appManager = null,
IURLGenerator $urlGenerator = null,
IFactory $l10nFac = null,
IUserSession $userSession = null,
IGroupManager$groupManager = null) {
$this->appManager = $appManager;
$this->urlGenerator = $urlGenerator;
$this->l10nFac = $l10nFac;
$this->userSession = $userSession;
$this->groupManager = $groupManager;
}
/**
* Creates a new navigation entry
@ -60,6 +93,7 @@ class NavigationManager implements \OCP\INavigationManager {
* @return array an array of the added entries
*/
public function getAll() {
$this->init();
foreach ($this->closureEntries as $c) {
$this->add($c());
}
@ -71,8 +105,9 @@ class NavigationManager implements \OCP\INavigationManager {
* removes all the entries
*/
public function clear() {
$this->entries = array();
$this->closureEntries = array();
$this->entries = [];
$this->closureEntries = [];
$this->init = false;
}
/**
@ -93,4 +128,64 @@ class NavigationManager implements \OCP\INavigationManager {
public function getActiveEntry() {
return $this->activeEntry;
}
private function init() {
if ($this->init) {
return;
}
$this->init = true;
if (is_null($this->appManager)) {
return;
}
foreach ($this->appManager->getInstalledApps() as $app) {
// load plugins and collections from info.xml
$info = $this->appManager->getAppInfo($app);
if (!isset($info['navigation'])) {
continue;
}
$nav = $info['navigation'];
if (!isset($nav['name'])) {
continue;
}
if (!isset($nav['route'])) {
continue;
}
$role = isset($nav['@attributes']['role']) ? $nav['@attributes']['role'] : 'all';
if ($role === 'admin' && !$this->isAdmin()) {
continue;
}
$l = $this->l10nFac->get($app);
$order = isset($nav['order']) ? $nav['order'] : 100;
$route = $this->urlGenerator->linkToRoute($nav['route']);
$icon = isset($nav['icon']) ? $nav['icon'] : 'app.svg';
foreach ([$icon, "$app.svg"] as $i) {
try {
$icon = $this->urlGenerator->imagePath($app, $i);
break;
} catch (\RuntimeException $ex) {
// no icon? - ignore it then
}
}
if (is_null($icon)) {
$icon = $this->urlGenerator->imagePath('core', 'default-app-icon');
}
$this->add([
'id' => $app,
'order' => $order,
'href' => $route,
'icon' => $icon,
'name' => $l->t($nav['name']),
]);
}
}
private function isAdmin() {
$user = $this->userSession->getUser();
if ($user !== null) {
return $this->groupManager->isAdmin($user->getUID());
}
return false;
}
}

View File

@ -316,8 +316,12 @@ class Server extends ServerContainer implements IServerContainer {
return new \OC\Authentication\TwoFactorAuth\Manager($c->getAppManager(), $c->getSession(), $c->getConfig(), $c->getActivityManager(), $c->getLogger());
});
$this->registerService('NavigationManager', function ($c) {
return new \OC\NavigationManager();
$this->registerService('NavigationManager', function (Server $c) {
return new \OC\NavigationManager($c->getAppManager(),
$c->getURLGenerator(),
$c->getL10NFactory(),
$c->getUserSession(),
$c->getGroupManager());
});
$this->registerService('AllConfig', function (Server $c) {
return new \OC\AllConfig(

View File

@ -12,7 +12,15 @@
namespace Test;
use OC\App\AppManager;
use OC\NavigationManager;
use OCP\App\IAppManager;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserSession;
use OCP\L10N\IFactory;
class NavigationManagerTest extends TestCase {
/** @var \OC\NavigationManager */
@ -157,4 +165,62 @@ class NavigationManagerTest extends TestCase {
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()');
$this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by getAll()');
}
/**
* @dataProvider providesNavigationConfig
*/
public function testWithAppManager($expected, $config, $isAdmin = false) {
$appManager = $this->createMock(AppManager::class);
$urlGenerator = $this->createMock(IURLGenerator::class);
$l10nFac = $this->createMock(IFactory::class);
$userSession = $this->createMock(IUserSession::class);
$groupManager = $this->createMock(IGroupManager::class);
$l = $this->createMock(IL10N::class);
$l->expects($this->any())->method('t')->willReturnCallback(function($text, $parameters = []) {
return vsprintf($text, $parameters);
});
$appManager->expects($this->once())->method('getInstalledApps')->willReturn(['test']);
$appManager->expects($this->once())->method('getAppInfo')->with('test')->willReturn($config);
$l10nFac->expects($this->exactly(count($expected)))->method('get')->with('test')->willReturn($l);
$urlGenerator->expects($this->any())->method('imagePath')->willReturnCallback(function($appName, $file) {
return "/apps/$appName/img/$file";
});
$urlGenerator->expects($this->exactly(count($expected)))->method('linkToRoute')->willReturnCallback(function($route) {
return "/apps/test/";
});
$user = $this->createMock(IUser::class);
$user->expects($this->any())->method('getUID')->willReturn('user001');
$userSession->expects($this->any())->method('getUser')->willReturn($user);
$groupManager->expects($this->any())->method('isAdmin')->willReturn($isAdmin);
$navigationManager = new NavigationManager($appManager, $urlGenerator, $l10nFac, $userSession, $groupManager);
$entries = $navigationManager->getAll();
$this->assertEquals($expected, $entries);
}
public function providesNavigationConfig() {
return [
'minimalistic' => [[[
'id' => 'test',
'order' => 100,
'href' => '/apps/test/',
'icon' => '/apps/test/img/app.svg',
'name' => 'Test',
'active' => false
]], ['navigation' => ['route' => 'test.page.index', 'name' => 'Test']]],
'no admin' => [[[
'id' => 'test',
'order' => 100,
'href' => '/apps/test/',
'icon' => '/apps/test/img/app.svg',
'name' => 'Test',
'active' => false
]], ['navigation' => ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']], true],
'no name' => [[], ['navigation' => ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index']], true],
'admin' => [[], ['navigation' => ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']]]
];
}
}