diff --git a/apps/dav/appinfo/v2/remote.php b/apps/dav/appinfo/v2/remote.php index 3a00c8006e..c1b29a4a17 100644 --- a/apps/dav/appinfo/v2/remote.php +++ b/apps/dav/appinfo/v2/remote.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Thomas Müller + * @author Vincent Petry * * @license AGPL-3.0 * diff --git a/apps/dav/lib/AppInfo/PluginManager.php b/apps/dav/lib/AppInfo/PluginManager.php new file mode 100644 index 0000000000..9cdf358c80 --- /dev/null +++ b/apps/dav/lib/AppInfo/PluginManager.php @@ -0,0 +1,170 @@ + + * + * @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 + * + */ +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"); + } + } + } + } + +} diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 6f3ab3971e..162833951a 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -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); + } }); } diff --git a/apps/dav/tests/unit/AppInfo/PluginManagerTest.php b/apps/dav/tests/unit/AppInfo/PluginManagerTest.php new file mode 100644 index 0000000000..5776b93912 --- /dev/null +++ b/apps/dav/tests/unit/AppInfo/PluginManagerTest.php @@ -0,0 +1,104 @@ + + * + * @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 + * + */ + +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()); + } +} diff --git a/apps/dav/tests/unit/ServerTest.php b/apps/dav/tests/unit/ServerTest.php index 19e75c7b24..1b430b0f19 100644 --- a/apps/dav/tests/unit/ServerTest.php +++ b/apps/dav/tests/unit/ServerTest.php @@ -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); }