From 7c34fee7ebc09ffaaf14019ae195b1b42e138e3f Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Thu, 27 Nov 2014 16:06:48 +0100 Subject: use extended info.xml instead of app.json --- appinfo/app.json | 49 ------- appinfo/app.php | 1 - appinfo/application.php | 17 +-- appinfo/info.xml | 55 ++++++- config/appconfig.php | 212 +++------------------------ controller/pagecontroller.php | 8 +- tests/classloader.php | 10 ++ tests/unit/config/AppConfigTest.php | 189 ------------------------ tests/unit/controller/PageControllerTest.php | 6 +- 9 files changed, 94 insertions(+), 453 deletions(-) delete mode 100644 appinfo/app.json delete mode 100644 tests/unit/config/AppConfigTest.php diff --git a/appinfo/app.json b/appinfo/app.json deleted file mode 100644 index c2c3489d1..000000000 --- a/appinfo/app.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "News", - "id": "news", - "description": "An RSS/Atom feed reader. Requires ownCloud backgroundjobs or an updater script to be enabled to update your feeds. See the README.md in the apps top directory", - "licence": "AGPL", - "version": "4.2.1", - "authors": [ - { - "name": "Bernhard Posselt", - "email": "dev@bernhard-posselt.com" - }, - { - "name": "Alessandro Cosentino", - "email": "cosenal@gmail.com" - }, - { - "name": "Jan-Christoph Borchardt", - "email": "hey@jancborchardt.net" - } - ], - "homepage": "https://github.com/owncloud/news", - "bugs": "https://github.com/owncloud/news/issues", - "repository": { - "type": "git", - "url": "https://github.com/owncloud/news.git" - }, - "navigation": {}, - "documentation": { - "user": "https://github.com/owncloud/news/wiki#user-documentation", - "admin": "https://github.com/owncloud/news#readme", - "developer": "https://github.com/owncloud/news/wiki" - }, - "jobs": ["OCA\\News\\Cron\\Updater"], - "hooks": { - "OC_User::pre_deleteUser": "OCA\\News\\Hooks\\User::deleteUser" - }, - "admin": true, - "categories": ["Multimedia"], - "dependencies": { - "databases": ["pgsql", "sqlite3", "mysql"], - "php": ">=5.4", - "owncloud": ">=7.0.3", - "libs": { - "curl": "*", - "libxml": ">=2.7.8", - "SimpleXML": "*" - } - } -} \ No newline at end of file diff --git a/appinfo/app.php b/appinfo/app.php index 2809795fb..66c0ef166 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -27,4 +27,3 @@ $container = new Application(); $config = $container->getAppConfig(); $config->registerAll(); -$config->testDependencies(); \ No newline at end of file diff --git a/appinfo/application.php b/appinfo/application.php index e4972d8fc..ccaae0f09 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -265,25 +265,12 @@ class Application extends App { * App config parser */ $container->registerService('AppConfig', function($c) { - // order extensions in name => version - $loadedExtensions = get_loaded_extensions(); - $extensions = []; - foreach ($loadedExtensions as $extension) { - $extensions[$extension] = phpversion($extension); - } - - $extensions['libxml'] = LIBXML_DOTTED_VERSION; - $config = new AppConfig( $c->query('ServerContainer')->getNavigationManager(), - $c->query('URLGenerator'), - phpversion(), - implode('.', Util::getVersion()), - $extensions, - $c->query('DatabaseType') + $c->query('URLGenerator') ); - $config->loadConfig(__DIR__ . '/app.json'); + $config->loadConfig(__DIR__ . '/info.xml'); return $config; }); diff --git a/appinfo/info.xml b/appinfo/info.xml index 3ccb782b2..f082b7be5 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -1,10 +1,63 @@ + news News An RSS/Atom feed reader. Requires ownCloud backgroundjobs or an updater script to be enabled to update your feeds. See the README.md in the apps top directory + Bernhard Posselt, Alessandro Cosentino, Jan-Christoph Borchardt + + Multimedia + AGPL 4.2.1 + + + + https://github.com/owncloud/news/wiki#user-documentation + https://github.com/owncloud/news#readme + https://github.com/owncloud/news/wiki#developer-documentation + + https://github.com/owncloud/news + https://github.com/owncloud/news/issues + https://github.com/owncloud/news.git + + 7.0.3 - Bernhard Posselt, Alessandro Cosentino, Jan-Christoph Borchardt + + + pgsql + sqlite3 + mysql + + + libxml + curl + SimpleXML + + + + + news + news.page.index + 10 + app.svg + News + + + + admin/admin + + + + OCA\News\Cron\Updater + + + + + + OC_User::pre_deleteUser + OCA\News\Hooks\User::deleteUser + + + diff --git a/config/appconfig.php b/config/appconfig.php index 62e1490ee..b1195f8bb 100644 --- a/config/appconfig.php +++ b/config/appconfig.php @@ -13,6 +13,8 @@ namespace OCA\News\Config; +use SimpleXMLElement; + use \OCP\INavigationManager; use \OCP\IURLGenerator; use \OCP\Backgroundjob; @@ -25,10 +27,6 @@ class AppConfig { private $config; private $navigationManager; private $urlGenerator; - private $phpVersion; - private $ownCloudVersion; - private $installedExtensions; - private $databaseType; /** * TODO: External deps that are needed: @@ -36,21 +34,23 @@ class AppConfig { * - connect to hooks */ public function __construct(INavigationManager $navigationManager, - IURLGenerator $urlGenerator, - $phpVersion, - $ownCloudVersion, - $installedExtensions, - $databaseType) { + IURLGenerator $urlGenerator) { $this->navigationManager = $navigationManager; $this->urlGenerator = $urlGenerator; - $this->ownCloudVersion = $ownCloudVersion; - $this->phpVersion = $phpVersion; - $this->installedExtensions = $installedExtensions; - $this->databaseType = $databaseType; $this->config = []; } + /** + * Parse an xml config + */ + private function parseConfig($string) { + // no need to worry about XXE since local file + $xml = simplexml_load_string($string, 'SimpleXMLElement'); + return json_decode(json_encode((array)$xml), TRUE); + } + + /** * @param string|array $data path to the config file or an array with the * config @@ -59,31 +59,12 @@ class AppConfig { if(is_array($data)) { $this->config = $data; } else { - $json = file_get_contents($data); - $this->config = json_decode($json, true); - } - - // fill config with default values if no navigation is added - if(array_key_exists('navigation', $this->config)) { - $nav =& $this->config['navigation']; - - // add defaults - $defaults = [ - 'id' => $this->config['id'], - 'route' => $this->config['id'] . '.page.index', - 'order' => 10, - 'icon' => 'app.svg', - 'name' => $this->config['name'] - ]; - - foreach($defaults as $key => $value) { - if(!array_key_exists($key, $nav)) { - $nav[$key] = $value; - } - } + $xml = file_get_contents($data); + $this->config = $this->parseConfig($xml); } } + /** * @param string $key if given returns the value of the config at index $key * @return array|mixed the config @@ -103,9 +84,10 @@ class AppConfig { */ public function registerAll() { $this->registerNavigation(); - $this->registerBackgroundJobs(); $this->registerHooks(); - $this->registerAdmin(); + // Fuck it lets just do this quick and dirty until core supports this + Backgroundjob::addRegularTask($job['cron'][0]['job'], 'run'); + App::registerAdmin($this->config['id'], $this->config['admin']); } @@ -113,8 +95,7 @@ class AppConfig { * Parses the navigation and creates a navigation entry if needed */ public function registerNavigation() { - // if key is missing, don't create a navigation - if(array_key_exists('navigation', $this->config)) { + if (array_key_exists('navigation', $this->config)) { $nav =& $this->config['navigation']; $navConfig = [ @@ -130,28 +111,6 @@ class AppConfig { $this->navigationManager->add($navConfig); } - - } - - /** - * Registers admin pages - */ - public function registerAdmin() { - if ($this->config['admin']) { - App::registerAdmin($this->config['id'], 'admin/admin'); - } - } - - - /** - * Registers all jobs in the config - */ - public function registerBackgroundJobs() { - // FIXME: this is temporarily static because core jobs are not public - // yet, therefore legacy code - foreach ($this->config['jobs'] as $job) { - Backgroundjob::addRegularTask($job, 'run'); - } } @@ -161,9 +120,9 @@ class AppConfig { public function registerHooks() { // FIXME: this is temporarily static because core emitters are not // future proof, therefore legacy code in here - foreach ($this->config['hooks'] as $listen => $react) { - $listener = explode('::', $listen); - $reaction = explode('::', $react); + foreach ($this->config['hooks'] as $hook) { + $listener = explode('::', $hook['channel']); + $reaction = explode('::', $hook['subscriber']); // config is written like HookNamespace::method => Class::method Util::connectHook($listener[0], $listener[1], $reaction[0], @@ -172,129 +131,4 @@ class AppConfig { } - private function testDatabaseDependencies($deps) { - if(array_key_exists('databases', $deps)) { - $databases = $deps['databases']; - $databaseType = $this->databaseType; - - if(!in_array($databaseType, $databases)) { - return 'Database ' . $databaseType . ' not supported.' . - 'App is only compatible with ' . - implode(', ', $databases); - } - } - - return ''; - } - - - private function testPHPDependencies($deps) { - if (array_key_exists('php', $deps)) { - return $this->requireVersion($this->phpVersion, $deps['php'], - 'PHP'); - } - - return ''; - } - - - private function testLibraryDependencies($deps) { - if (array_key_exists('libs', $deps)) { - foreach ($deps['libs'] as $lib => $versions) { - if(array_key_exists($lib, $this->installedExtensions)) { - return $this->requireVersion( - $this->installedExtensions[$lib], - $versions, 'PHP extension ' . $lib - ); - } else { - return 'PHP extension ' . $lib . - ' required but not installed'; - } - } - } - - return ''; - } - - - /** - * Validates all dependencies that the app has - * @throws DependencyException if one version is not satisfied - */ - public function testDependencies() { - if(array_key_exists('dependencies', $this->config)) { - $deps = $this->config['dependencies']; - - $msg = $this->testDatabaseDependencies($deps); - $msg .= $this->testPHPDependencies($deps); - $msg .= $this->testLibraryDependencies($deps); - - if($msg !== '') { - throw new DependencyException($msg); - } - } - } - - - /** - * Compares a version with a version requirement string - * @param string $actual the actual version that is there - * @param string $required a version requirement in the form of - * <=5.3,>4.5 versions are separated with a comma - * @param string $versionType a description of the string that is prepended - * to the error message - * @return string an error message if the version is not met, - * empty string if ok - */ - private function requireVersion($actual, $required, $versionType) { - $requiredVersions = $this->splitVersions($required); - - foreach($requiredVersions as $version) { - // accept * as wildcard for any version - if($version['version'] === '*') { - continue; - } - $operator = $version['operator']; - $requiredVersion = $version['version']; - if(!version_compare($actual, $requiredVersion, $operator)) { - return $versionType . ' Version not satisfied: ' . $operator . - $requiredVersion . ' required but found ' . $actual . '\n'; - } - } - - return ''; - } - - - /** - * Versions can be separated by a comma so split them - * @param string $versions a version requirement in the form of - * <=5.3,>4.5 versions are separated with a comma - * @return array of arrays with key=version value=operator - */ - private function splitVersions($versions) { - $result = []; - $versions = explode(',', $versions); - - foreach($versions as $version) { - preg_match('/^(?<|<=|>=|>|<>)?(?.*)$/', $version, - $matches); - if($matches['operator'] !== '') { - $required = [ - 'version' => $matches['version'], - 'operator' => $matches['operator'], - ]; - } else { - $required = [ - 'version' => $matches['version'], - 'operator' => '==', - ]; - } - $result[] = $required; - } - - return $result; - } - - } \ No newline at end of file diff --git a/controller/pagecontroller.php b/controller/pagecontroller.php index 6599a4e49..861fa285f 100644 --- a/controller/pagecontroller.php +++ b/controller/pagecontroller.php @@ -155,10 +155,6 @@ class PageController extends Controller { } } - $authors = []; - foreach ($config['authors'] as $author) { - $authors[] = $author['name']; - } $data = [ "name" => $config['name'], @@ -166,10 +162,10 @@ class PageController extends Controller { "default_locale" => $locale, "description" => $config['description'], "launch_path" => $this->urlGenerator->linkToRoute( - $config['id'] . '.page.index'), + $config['navigation']['route']), "icons" => $icons, "developer" => [ - "name" => implode(', ', $authors), + "name" => $config['author'], "url" => $config['homepage'] ] ]; diff --git a/tests/classloader.php b/tests/classloader.php index a576eb8d0..648b7432d 100644 --- a/tests/classloader.php +++ b/tests/classloader.php @@ -34,6 +34,16 @@ spl_autoload_register(function ($className){ ); $relPath = __DIR__ . '/../../../lib/public' . $path; + if(file_exists($relPath)){ + require_once $relPath; + } + } else if(strpos($className, 'Test\\') === 0) { + $path = strtolower( + str_replace('\\', '/', substr($className, 4)) . '.php' + ); + echo $path; + $relPath = __DIR__ . '/../../../tests/lib' . $path; + if(file_exists($relPath)){ require_once $relPath; } diff --git a/tests/unit/config/AppConfigTest.php b/tests/unit/config/AppConfigTest.php deleted file mode 100644 index 01bacbf5c..000000000 --- a/tests/unit/config/AppConfigTest.php +++ /dev/null @@ -1,189 +0,0 @@ - - * @author Bernhard Posselt - * @copyright Alessandro Cosentino 2012 - * @copyright Bernhard Posselt 2012, 2014 - */ - -namespace OCA\News\Config; - - -class AppConfigTest extends \PHPUnit_Framework_TestCase { - - private $nav; - private $config; - private $url; - - public function setUp() { - $this->nav = $this->getMockBuilder('\OCP\INavigationManager') - ->disableOriginalConstructor() - ->getMock(); - $this->url = $this->getMockBuilder('\OCP\IURLGenerator') - ->disableOriginalConstructor() - ->getMock(); - $phpVersion = '5.3'; - $ownCloudVersion = '6.0.3'; - $installedExtensions = ['curl' => '4.3']; - $databaseType = 'oracle'; - - $this->config = new AppConfig($this->nav, $this->url, $phpVersion, - $ownCloudVersion, $installedExtensions, $databaseType); - } - - public function testGetId() { - $this->config->loadConfig(__DIR__ . '/../../../appinfo/app.json'); - $this->assertEquals('news', $this->config->getConfig('id')); - } - - - public function testGetConfig() { - $config = file_get_contents(__DIR__ . '/../../../appinfo/app.json'); - $config = json_decode($config, true); - $this->config->loadConfig($config); - $config['navigation'] = [ - 'id' => 'news', - 'order' => 10, - 'route' => 'news.page.index', - 'icon' => 'app.svg', - 'name' => 'News', - ]; - $this->assertEquals($config, $this->config->getConfig()); - } - - - public function testNoNavigation() { - $this->config->loadConfig([]); - - $this->nav->expects($this->never()) - ->method('add'); - } - - - public function testDefaultNavigation() { - $expected = [ - 'id' => 'news', - 'href' => 'news.page.index', - 'order' => 10, - 'icon' => 'app.svg', - 'name' => 'News' - ]; - - $this->url->expects($this->once()) - ->method('linkToRoute') - ->with($this->equalTo('news.page.index')) - ->will($this->returnValue('news.page.index')); - - $this->url->expects($this->once()) - ->method('imagePath') - ->with($this->equalTo('news'), - $this->equalTo('app.svg')) - ->will($this->returnValue('app.svg')); - - $this->nav->expects($this->once()) - ->method('add') - ->with($this->equalTo($expected)); - - $this->config->loadConfig([ - 'id' => 'news', - 'name' => 'News', - 'navigation' => [] - ]); - $this->config->registerNavigation(); - } - - - public function testCustomNavigation() { - $expected = [ - 'id' => 'abc', - 'href' => 'abc.page.index', - 'order' => 1, - 'icon' => 'test.svg', - 'name' => 'haha' - ]; - - $this->url->expects($this->once()) - ->method('linkToRoute') - ->with($this->equalTo('abc.page.index')) - ->will($this->returnValue('abc.page.index')); - - $this->url->expects($this->once()) - ->method('imagePath') - ->with($this->equalTo('abc'), - $this->equalTo('test.svg')) - ->will($this->returnValue('test.svg')); - - $this->nav->expects($this->once()) - ->method('add') - ->with($this->equalTo($expected)); - - $this->config->loadConfig([ - 'id' => 'abc', - 'name' => 'News', - 'navigation' => $expected - ]); - $this->config->registerNavigation(); - } - - - /** - * @expectedException \OCA\News\Config\DependencyException - */ - public function testPHPVersion() { - $this->config->loadConfig([ - 'dependencies' => [ - 'php' => '5.7' - ] - ]); - $this->config->testDependencies(); - } - - - /** - * @expectedException \OCA\News\Config\DependencyException - */ - public function testLibsVersion() { - $this->config->loadConfig([ - 'dependencies' => [ - 'libs' => [ - 'curl' => '>=4.3,<=4.3' - ] - ] - ]); - $this->config->testDependencies(); - } - - - /** - * @expectedException \OCA\News\Config\DependencyException - */ - public function testLibsExistence() { - $this->config->loadConfig([ - 'dependencies' => [ - 'libs' => [ - 'dope' => '>=4.3,<=4.3' - ] - ] - ]); - $this->config->testDependencies(); - } - - - - /** - * @expectedException \OCA\News\Config\DependencyException - */ - public function testSupportedDb() { - $this->config->loadConfig([ - 'dependencies' => [ - "databases" => ['pgsql', 'sqlite'] - ] - ]); - $this->config->testDependencies(); - } -} \ No newline at end of file diff --git a/tests/unit/controller/PageControllerTest.php b/tests/unit/controller/PageControllerTest.php index 3b3a38782..ee138fded 100644 --- a/tests/unit/controller/PageControllerTest.php +++ b/tests/unit/controller/PageControllerTest.php @@ -39,10 +39,10 @@ class PageControllerTest extends \PHPUnit_Framework_TestCase { $this->configData = [ 'name' => 'AppTest', 'id' => 'apptest', - 'authors' => [ - ['name' => 'john'], - ['name' => 'test'] + 'navigation' => [ + 'route' => 'apptest.index.php' ], + 'author' => 'john, test', 'description' => 'This is a test app', 'homepage' => 'https://github.com/owncloud/test' ]; -- cgit v1.2.3