summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernhard Posselt <dev@bernhard-posselt.com>2014-05-02 17:25:05 +0200
committerBernhard Posselt <dev@bernhard-posselt.com>2014-05-02 17:25:05 +0200
commit9c9625b0f6520f80996e17304805d8bae421f44c (patch)
tree4d2e99fdab4edf3a45d3570f534f11678f7f19c4
parentc9aead3a88405e7051529c8c4e26c69b7f6369cd (diff)
add parser for app.json file, parsing jobs and hooks still left
-rw-r--r--appinfo/app.json40
-rw-r--r--appinfo/app.php2
-rw-r--r--config/appconfig.php240
-rw-r--r--config/dependencyexception.php28
-rw-r--r--img/app.png (renamed from img/news.png)bin342 -> 342 bytes
-rw-r--r--img/app.svg (renamed from img/news.svg)0
-rw-r--r--tests/unit/config/AppConfigTest.php223
7 files changed, 532 insertions, 1 deletions
diff --git a/appinfo/app.json b/appinfo/app.json
new file mode 100644
index 000000000..dfa0945b4
--- /dev/null
+++ b/appinfo/app.json
@@ -0,0 +1,40 @@
+{
+ "name": "News",
+ "id": "news",
+ "description": "ownCloud News App",
+ "licence": "AGPL",
+ "version": "2.001",
+ "authors": [
+ {
+ "name": "Bernhard Posselt",
+ "email": "dev@bernhard-posselt.com"
+ },
+ {
+ "name": "Alessandro Cosentino",
+ "email": "cosenal@gmail.com"
+ }
+ ],
+ "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": {
+ "developer": "https://github.com/owncloud/news/wiki"
+ },
+ "cron": ["OCA\\News\\BackgroundJob\\Task"],
+ "hooks": {
+ "OC_User::pre_deleteUser": "OCA\\News\\Hooks\\User::deleteUser"
+ },
+ "databases": ["postgresql", "sqlite", "mysql"],
+ "categories": ["Multimedia"],
+ "dependencies": {
+ "php": ">=5.3",
+ "owncloud": ">=6.0.3",
+ "libs": {
+ "curl": "*"
+ }
+ }
+} \ No newline at end of file
diff --git a/appinfo/app.php b/appinfo/app.php
index e56d3ecb7..749f64601 100644
--- a/appinfo/app.php
+++ b/appinfo/app.php
@@ -28,7 +28,7 @@ namespace OCA\News;
// the icon that will be shown in the navigation
// this file needs to exist in img/example.png
- 'icon' => \OCP\Util::imagePath('news', 'news.svg'),
+ 'icon' => \OCP\Util::imagePath('news', 'app.svg'),
// the title of your application. This will be used in the
// navigation or on the settings page of your app
diff --git a/config/appconfig.php b/config/appconfig.php
new file mode 100644
index 000000000..0d4ea6537
--- /dev/null
+++ b/config/appconfig.php
@@ -0,0 +1,240 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Alessandro Cosentino <cosenal@gmail.com>
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Alessandro Cosentino 2012
+ * @copyright Bernhard Posselt 2012, 2014
+ */
+
+namespace OCA\News\Config;
+
+use OCP\AppFramework\IApi;
+use OCP\BackgroundJob\IJob;
+use OCP\BackgroundJob\IJobList;
+use OCP\INavigationManager;
+use OCP\IL10N;
+use OCP\IURLGenerator;
+
+
+// Used to parse app.json file, should be in core at some point
+class AppConfig {
+
+ public $config;
+
+ private $navigationManager;
+ private $urlGenerator;
+ private $phpVersion;
+ private $ownCloudVersion;
+ private $installedApps;
+ private $installedExtensions;
+ private $databaseType;
+
+ /**
+ * TODO: External deps that are needed:
+ * - add jobs
+ * - connect to hooks
+ */
+ public function __construct(INavigationManager $navigationManager,
+ IL10N $l10n,
+ IURLGenerator $urlGenerator,
+ $phpVersion,
+ $ownCloudVersion,
+ $installedApps,
+ $installedExtensions,
+ $databaseType) {
+ $this->navigationManager = $navigationManager;
+ $this->l10n = $l10n;
+ $this->urlGenerator = $urlGenerator;
+ $this->ownCloudVersion = $ownCloudVersion;
+ $this->phpVersion = $phpVersion;
+ $this->installedApps = $installedApps;
+ $this->installedExtensions = $installedExtensions;
+ $this->databaseType = $databaseType;
+ }
+
+
+ /**
+ * @param string|array $data path to the config file or an array with the config
+ * @throws \OCA\News\Config\DependencyException if a required lib or version
+ * is not satisfied by the current installation
+ */
+ public function load($data) {
+ if(is_array($data)) {
+ $this->config = $data;
+ } else {
+ $json = file_get_contents($data);
+ $this->config = json_decode($json, true);
+ }
+
+ $this->testDependencies();
+ $this->parseNavigation();
+ $this->parseJobs();
+ $this->parseHooks();
+ }
+
+
+ /**
+ * Parses the navigation and creates a navigation entry if needed
+ */
+ private function parseNavigation() {
+ // if key is missing, dont create a navigation
+ if(array_key_exists('navigation', $this->config)) {
+ $nav = $this->config['navigation'];
+
+ // add defaults
+ $defaults = array(
+ '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;
+ }
+ }
+
+
+ $navConfig = array(
+ 'id' => $nav['id'],
+ 'order' => $nav['order']
+ );
+
+ $navConfig['name'] = $this->l10n->t($nav['name']);
+ $navConfig['href'] = $this->urlGenerator->linkToRoute($nav['route']);
+ $navConfig['icon'] = $this->urlGenerator->imagePath($nav['id'],
+ $nav['icon']);
+
+ $this->navigationManager->add($navConfig);
+ }
+
+ }
+
+
+ private function parseJobs() {
+
+ }
+
+
+ private function parseHooks() {
+
+ }
+
+
+ /**
+ * Validates all dependencies that the app has
+ * @throws \OCA\News\DependencyException if one version is not satisfied
+ */
+ private function testDependencies() {
+ if(array_key_exists('dependencies', $this->config)) {
+
+ $deps = $this->config['dependencies'];
+
+ $msg = '';
+
+ if(array_key_exists('php', $deps)) {
+ $msg .= $this->requireVersion($this->phpVersion, $deps['php'],
+ 'PHP');
+ }
+
+ if(array_key_exists('owncloud', $deps)) {
+ $msg .= $this->requireVersion($this->ownCloudVersion,
+ $deps['owncloud'], 'ownCloud');
+ }
+
+ if(array_key_exists('apps', $deps)) {
+ foreach ($deps['apps'] as $app => $versions) {
+ if(array_key_exists($app, $this->installedApps)) {
+ $msg .= $this->requireVersion($this->installedApps[$app],
+ $versions, 'App ' . $app);
+ } else {
+ $msg .= 'ownCloud app ' . $app . ' required but not installed';
+ }
+ }
+ }
+
+ if(array_key_exists('libs', $deps)) {
+ foreach ($deps['libs'] as $lib => $versions) {
+ if(array_key_exists($lib, $this->installedExtensions)) {
+ $msg .= $this->requireVersion($this->installedExtensions[$lib],
+ $versions, 'PHP extension ' . $lib);
+ } else {
+ $msg .= 'PHP extension ' . $lib . ' required but not installed';
+ }
+ }
+ }
+
+
+ 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 seperated with a comma
+ * @param string $versionType a description of the string that is prepended
+ * to the error message
+ * @return 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;
+ }
+ if(!version_compare($actual, $version['version'], $version['operator'])) {
+ return $versionType . ' Version not satisfied: ' . $version['operator'] .
+ $version['version'] . ' required but found ' . $actual . '\n';
+ }
+ }
+
+ return '';
+ }
+
+
+ /**
+ * Versions can be seperated by a comma so split them
+ * @param string $versions a version requirement in the form of
+ * <=5.3,>4.5 versions are seperated with a comma
+ * @return array of arrays with key=version value=operator
+ */
+ private function splitVersions($versions) {
+ $result = array();
+ $versions = explode(',', $versions);
+
+ foreach($versions as $version) {
+ preg_match('/^(?<operator><|<=|>=|>|<>)?(?<version>.*)$/', $version, $matches);
+ if($matches['operator'] !== '') {
+ $required = array(
+ 'version' => $matches['version'],
+ 'operator' => $matches['operator'],
+ );
+ } else {
+ $required = array(
+ 'version' => $matches['version'],
+ 'operator' => '==',
+ );
+ }
+ $result[] = $required;
+ }
+
+ return $result;
+ }
+
+
+} \ No newline at end of file
diff --git a/config/dependencyexception.php b/config/dependencyexception.php
new file mode 100644
index 000000000..690d187c3
--- /dev/null
+++ b/config/dependencyexception.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Alessandro Cosentino <cosenal@gmail.com>
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Alessandro Cosentino 2012
+ * @copyright Bernhard Posselt 2012, 2014
+ */
+
+namespace OCA\News\Config;
+
+class DependencyException extends \Exception {
+
+
+ /**
+ * Constructor
+ * @param string $msg the error message
+ */
+ public function __construct($msg){
+ parent::__construct($msg);
+ }
+
+
+} \ No newline at end of file
diff --git a/img/news.png b/img/app.png
index c37a98699..c37a98699 100644
--- a/img/news.png
+++ b/img/app.png
Binary files differ
diff --git a/img/news.svg b/img/app.svg
index d72959977..d72959977 100644
--- a/img/news.svg
+++ b/img/app.svg
diff --git a/tests/unit/config/AppConfigTest.php b/tests/unit/config/AppConfigTest.php
new file mode 100644
index 000000000..99fba1fae
--- /dev/null
+++ b/tests/unit/config/AppConfigTest.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Alessandro Cosentino <cosenal@gmail.com>
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Alessandro Cosentino 2012
+ * @copyright Bernhard Posselt 2012, 2014
+ */
+
+namespace OCA\News\Config;
+
+
+require_once(__DIR__ . '/../../classloader.php');
+
+
+class AppConfigTest extends \PHPUnit_Framework_TestCase {
+
+ private $nav;
+ private $config;
+ private $url;
+
+ public function setUp() {
+ $this->nav = $this->getMockBuilder('\OCP\INavigationManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->l10n = $this->getMockBuilder('\OCP\IL10N')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->url = $this->getMockBuilder('\OCP\IURLGenerator')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $phpVersion = '5.3';
+ $ownCloudVersion = '6.0.3';
+ $installedApps = array(
+ 'contacts' => '5.3',
+ 'calendar' => '2.3'
+ );
+ $installedExtensions = array(
+ 'curl' => '4.3'
+ );
+ $databaseType = 'postgresql';
+
+ $this->config = new AppConfig($this->nav, $this->l10n,
+ $this->url, $phpVersion, $ownCloudVersion, $installedApps,
+ $installedExtensions, $databaseType);
+ }
+
+ public function testGetId() {
+ $this->config->load(__DIR__ . '/../../../appinfo/app.json');
+ $this->assertEquals('news', $this->config->config['id']);
+ }
+
+
+ public function testNoNavigation() {
+ $this->config->load(array());
+
+ $this->nav->expects($this->never())
+ ->method('add');
+ }
+
+
+ public function testDefaultNavigation() {
+ $expected = array(
+ 'id' => 'news',
+ 'href' => 'news.page.index',
+ 'order' => 10,
+ 'icon' => 'app.svg',
+ 'name' => 'News'
+ );
+
+ $this->l10n->expects($this->once())
+ ->method('t')
+ ->with($this->equalTo('News'))
+ ->will($this->returnValue('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->load(array(
+ 'id' => 'news',
+ 'name' => 'News',
+ 'navigation' => array()
+ ));
+ }
+
+
+ public function testCustomNavigation() {
+ $expected = array(
+ 'id' => 'abc',
+ 'href' => 'abc.page.index',
+ 'order' => 1,
+ 'icon' => 'test.svg',
+ 'name' => 'haha'
+ );
+
+ $this->l10n->expects($this->once())
+ ->method('t')
+ ->with($this->equalTo('haha'))
+ ->will($this->returnValue('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->load(array(
+ 'id' => 'abc',
+ 'name' => 'News',
+ 'navigation' => $expected
+ ));
+ }
+
+
+ /**
+ * @expectedException \OCA\News\Config\DependencyException
+ */
+ public function testPHPVersion() {
+ $this->config->load(array(
+ 'dependencies' => array(
+ 'php' => '5.7'
+ )
+ ));
+ }
+
+
+ /**
+ * @expectedException \OCA\News\Config\DependencyException
+ */
+ public function testOwnCloudVersion() {
+ $this->config->load(array(
+ 'dependencies' => array(
+ 'owncloud' => '>=4.5,<=6.0.2'
+ )
+ ));
+ }
+
+
+ /**
+ * @expectedException \OCA\News\Config\DependencyException
+ */
+ public function testAppVersion() {
+ $this->config->load(array(
+ 'dependencies' => array(
+ 'apps' =>
+ array(
+ 'contacts' => '5.3',
+ 'calendar' => '>2.3'
+ )
+ )
+ ));
+ }
+
+
+ /**
+ * @expectedException \OCA\News\Config\DependencyException
+ */
+ public function testLibsVersion() {
+ $this->config->load(array(
+ 'dependencies' => array(
+ 'libs' =>
+ array(
+ 'curl' => '>=4.3,<=4.3'
+ )
+ )
+ ));
+ }
+
+
+ /**
+ * @expectedException \OCA\News\Config\DependencyException
+ */
+ public function testLibsExistence() {
+ $this->config->load(array(
+ 'dependencies' => array(
+ 'libs' =>
+ array(
+ 'dope' => '>=4.3,<=4.3'
+ )
+ )
+ ));
+ }
+
+
+ /**
+ * @expectedException \OCA\News\Config\DependencyException
+ */
+ public function testAppsExistence() {
+ $this->config->load(array(
+ 'dependencies' => array(
+ 'apps' =>
+ array(
+ 'news' => '>=4.3,<=4.3'
+ )
+ )
+ ));
+ }
+} \ No newline at end of file