Merge pull request #6835 from nextcloud/dav-plugins-from-apps-only

Let apps register Sabre plugins or collections (v2)
This commit is contained in:
Lukas Reschke 2017-10-19 11:09:12 +02:00 committed by GitHub
commit 3a3e6c34d0
5 changed files with 291 additions and 4 deletions

View File

@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <pvince81@owncloud.com>
*
* @license AGPL-3.0
*

View File

@ -0,0 +1,170 @@
<?php
/**
* @author Vincent Petry <pvince81@owncloud.com>
*
* @copyright Copyright (c) 2016, ownCloud GmbH.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\DAV\AppInfo;
use OCP\App\IAppManager;
use OC\ServerContainer;
use OCP\AppFramework\QueryException;
/**
* Manager for DAV plugins from apps, used to register them
* to the Sabre server.
*/
class PluginManager {
/**
* @var ServerContainer
*/
private $container;
/**
* @var IAppManager
*/
private $appManager;
/**
* App plugins
*
* @var array
*/
private $plugins = null;
/**
* App collections
*
* @var array
*/
private $collections = null;
/**
* Contstruct a PluginManager
*
* @param ServerContainer $container server container for resolving plugin classes
* @param IAppManager $appManager app manager to loading apps and their info
*/
public function __construct(ServerContainer $container, IAppManager $appManager) {
$this->container = $container;
$this->appManager = $appManager;
}
/**
* Returns an array of app-registered plugins
*
* @return array
*/
public function getAppPlugins() {
if (null === $this->plugins) {
$this->populate();
}
return $this->plugins;
}
/**
* Returns an array of app-registered collections
*
* @return array
*/
public function getAppCollections() {
if (null === $this->collections) {
$this->populate();
}
return $this->collections;
}
/**
* Retrieve plugin and collection list and populate attributes
*/
private function populate() {
$this->plugins = [];
$this->collections = [];
foreach ($this->appManager->getInstalledApps() as $app) {
// load plugins and collections from info.xml
$info = $this->appManager->getAppInfo($app);
if (!isset($info['types']) || !in_array('dav', $info['types'], true)) {
continue;
}
// FIXME: switch to public API once available
// load app to make sure its classes are available
\OC_App::loadApp($app);
$this->loadSabrePluginsFromInfoXml($this->extractPluginList($info));
$this->loadSabreCollectionsFromInfoXml($this->extractCollectionList($info));
}
}
private function extractPluginList(array $array) {
if (isset($array['sabre']) && is_array($array['sabre'])) {
if (isset($array['sabre']['plugins']) && is_array($array['sabre']['plugins'])) {
if (isset($array['sabre']['plugins']['plugin'])) {
$items = $array['sabre']['plugins']['plugin'];
if (!is_array($items)) {
$items = [$items];
}
return $items;
}
}
}
return [];
}
private function extractCollectionList(array $array) {
if (isset($array['sabre']) && is_array($array['sabre'])) {
if (isset($array['sabre']['collections']) && is_array($array['sabre']['collections'])) {
if (isset($array['sabre']['collections']['collection'])) {
$items = $array['sabre']['collections']['collection'];
if (!is_array($items)) {
$items = [$items];
}
return $items;
}
}
}
return [];
}
private function loadSabrePluginsFromInfoXml(array $plugins) {
foreach ($plugins as $plugin) {
try {
$this->plugins[] = $this->container->query($plugin);
} catch (QueryException $e) {
if (class_exists($plugin)) {
$this->plugins[] = new $plugin();
} else {
throw new \Exception("Sabre plugin class '$plugin' is unknown and could not be loaded");
}
}
}
}
private function loadSabreCollectionsFromInfoXml(array $collections) {
foreach ($collections as $collection) {
try {
$this->collections[] = $this->container->query($collection);
} catch (QueryException $e) {
if (class_exists($collection)) {
$this->collections[] = new $collection();
} else {
throw new \Exception("Sabre collection class '$collection' is unknown and could not be loaded");
}
}
}
}
}

View File

@ -55,8 +55,8 @@ use OCP\SabrePluginEvent;
use Sabre\CardDAV\VCFExportPlugin;
use Sabre\DAV\Auth\Plugin;
use OCA\DAV\Connector\Sabre\TagsPlugin;
use Sabre\HTTP\Auth\Bearer;
use SearchDAV\DAV\SearchPlugin;
use OCA\DAV\AppInfo\PluginManager;
class Server {
@ -184,7 +184,7 @@ class Server {
}
// wait with registering these until auth is handled and the filesystem is setup
$this->server->on('beforeMethod', function () {
$this->server->on('beforeMethod', function () use ($root) {
// custom properties plugin must be the last one
$userSession = \OC::$server->getUserSession();
$user = $userSession->getUser();
@ -252,6 +252,18 @@ class Server {
)));
}
}
// register plugins from apps
$pluginManager = new PluginManager(
\OC::$server,
\OC::$server->getAppManager()
);
foreach ($pluginManager->getAppPlugins() as $appPlugin) {
$this->server->addPlugin($appPlugin);
}
foreach ($pluginManager->getAppCollections() as $appCollection) {
$root->addChild($appCollection);
}
});
}

View File

@ -0,0 +1,104 @@
<?php
/**
* @author Vincent Petry <pvince81@owncloud.com>
*
* @copyright Copyright (c) 2016, ownCloud GmbH.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\DAV\Tests\unit\AppInfo;
use Test\TestCase;
use OCP\App\IAppManager;
use OC\ServerContainer;
use OCA\DAV\AppInfo\PluginManager;
/**
* Class PluginManagerTest
*
* @package OCA\DAV\Tests\Unit\AppInfo
*/
class PluginManagerTest extends TestCase {
public function test() {
$server = $this->createMock(ServerContainer::class);
$appManager = $this->createMock(IAppManager::class);
$appManager->method('getInstalledApps')
->willReturn(['adavapp', 'adavapp2']);
$appInfo1 = [
'types' => ['dav'],
'sabre' => [
'plugins' => [
'plugin' => [
'\OCA\DAV\ADavApp\PluginOne',
'\OCA\DAV\ADavApp\PluginTwo',
],
],
'collections' => [
'collection' => [
'\OCA\DAV\ADavApp\CollectionOne',
'\OCA\DAV\ADavApp\CollectionTwo',
]
],
],
];
$appInfo2 = [
'types' => ['logging', 'dav'],
'sabre' => [
'plugins' => [
'plugin' => '\OCA\DAV\ADavApp2\PluginOne',
],
'collections' => [
'collection' => '\OCA\DAV\ADavApp2\CollectionOne',
],
],
];
$appManager->method('getAppInfo')
->will($this->returnValueMap([
['adavapp', $appInfo1],
['adavapp2', $appInfo2],
]));
$pluginManager = new PluginManager($server, $appManager);
$server->method('query')
->will($this->returnValueMap([
['\OCA\DAV\ADavApp\PluginOne', 'dummyplugin1'],
['\OCA\DAV\ADavApp\PluginTwo', 'dummyplugin2'],
['\OCA\DAV\ADavApp\CollectionOne', 'dummycollection1'],
['\OCA\DAV\ADavApp\CollectionTwo', 'dummycollection2'],
['\OCA\DAV\ADavApp2\PluginOne', 'dummy2plugin1'],
['\OCA\DAV\ADavApp2\CollectionOne', 'dummy2collection1'],
]));
$expectedPlugins = [
'dummyplugin1',
'dummyplugin2',
'dummy2plugin1',
];
$expectedCollections = [
'dummycollection1',
'dummycollection2',
'dummy2collection1',
];
$this->assertEquals($expectedPlugins, $pluginManager->getAppPlugins());
$this->assertEquals($expectedCollections, $pluginManager->getAppCollections());
}
}

View File

@ -26,6 +26,7 @@ namespace OCA\DAV\Tests\unit;
use OCA\DAV\Server;
use OCP\IRequest;
use OCA\DAV\AppInfo\PluginManager;
/**
* Class ServerTest
@ -38,8 +39,7 @@ class ServerTest extends \Test\TestCase {
public function test() {
/** @var IRequest $r */
$r = $this->getMockBuilder('\OCP\IRequest')
->disableOriginalConstructor()->getMock();
$r = $this->createMock(IRequest::class);
$s = new Server($r, '/');
$this->assertInstanceOf('OCA\DAV\Server', $s);
}