]> source.dussan.org Git - nextcloud-server.git/commitdiff
Use new appstore API
authorLukas Reschke <lukas@statuscode.ch>
Thu, 27 Oct 2016 15:41:15 +0000 (17:41 +0200)
committerLukas Reschke <lukas@statuscode.ch>
Mon, 31 Oct 2016 16:17:44 +0000 (17:17 +0100)
This change introduces the new appstore API in Nextcloud.

Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
30 files changed:
apps/provisioning_api/lib/Controller/AppsController.php
apps/provisioning_api/tests/Controller/AppsControllerTest.php
config/config.sample.php
lib/composer/composer/autoload_classmap.php
lib/composer/composer/autoload_static.php
lib/private/App/AppStore/Fetcher/AppFetcher.php [new file with mode: 0644]
lib/private/App/AppStore/Fetcher/CategoryFetcher.php [new file with mode: 0644]
lib/private/App/AppStore/Fetcher/Fetcher.php [new file with mode: 0644]
lib/private/App/AppStore/Version/Version.php [new file with mode: 0644]
lib/private/App/AppStore/Version/VersionParser.php [new file with mode: 0644]
lib/private/Installer.php
lib/private/OCSClient.php [deleted file]
lib/private/Server.php
lib/private/legacy/app.php
settings/Application.php
settings/Controller/AppSettingsController.php
settings/ajax/enableapp.php
settings/ajax/installapp.php
settings/css/settings.css
settings/js/apps.js
settings/routes.php
settings/templates/apps.php
tests/Settings/Controller/AppSettingsControllerTest.php
tests/lib/App/AppStore/Fetcher/AppFetcherTest.php [new file with mode: 0644]
tests/lib/App/AppStore/Fetcher/CategoryFetcherTest.php [new file with mode: 0644]
tests/lib/App/AppStore/Fetcher/FetcherBase.php [new file with mode: 0644]
tests/lib/App/AppStore/Version/VersionParserTest.php [new file with mode: 0644]
tests/lib/App/AppStore/Version/VersionTest.php [new file with mode: 0644]
tests/lib/OCSClientTest.php [deleted file]
tests/lib/ServerTest.php

index 3821fc343ad86d2c3c0e1b9dfd3626890233a0f8..7d11d92b55acc2524a10cb9c4e7da3080f0d4cc5 100644 (file)
@@ -37,25 +37,20 @@ use OCP\IRequest;
 class AppsController extends OCSController {
        /** @var \OCP\App\IAppManager */
        private $appManager;
-       /** @var OCSClient */
-       private $ocsClient;
 
        /**
         * @param string $appName
         * @param IRequest $request
         * @param IAppManager $appManager
-        * @param OCSClient $ocsClient
         */
        public function __construct(
                $appName,
                IRequest $request,
-               IAppManager $appManager,
-               OCSClient $ocsClient
+               IAppManager $appManager
        ) {
                parent::__construct($appName, $request);
 
                $this->appManager = $appManager;
-               $this->ocsClient = $ocsClient;
        }
 
        /**
@@ -64,7 +59,7 @@ class AppsController extends OCSController {
         * @throws OCSException
         */
        public function getApps($filter = null) {
-               $apps = OC_App::listAllApps(false, true, $this->ocsClient);
+               $apps = (new OC_App())->listAllApps();
                $list = [];
                foreach($apps as $app) {
                        $list[] = $app['id'];
index 9ac4a8290e424cd3081560a39cbb2729e53bbf8f..c891433258f6df5847eec1ef2de73adc421e73f5 100644 (file)
@@ -48,8 +48,6 @@ class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
        private $api;
        /** @var IUserSession */
        private $userSession;
-       /** @var OCSClient|\PHPUnit_Framework_MockObject_MockObject */
-       private $ocsClient;
 
        protected function setUp() {
                parent::setUp();
@@ -57,9 +55,6 @@ class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
                $this->appManager = \OC::$server->getAppManager();
                $this->groupManager = \OC::$server->getGroupManager();
                $this->userSession = \OC::$server->getUserSession();
-               $this->ocsClient = $this->getMockBuilder('OC\OCSClient')
-                       ->disableOriginalConstructor()
-                       ->getMock();
 
                $request = $this->getMockBuilder('OCP\IRequest')
                        ->disableOriginalConstructor()
@@ -68,8 +63,7 @@ class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
                $this->api = new AppsController(
                        'provisioning_api',
                        $request,
-                       $this->appManager,
-                       $this->ocsClient
+                       $this->appManager
                );
        }
 
@@ -88,10 +82,6 @@ class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
        }
 
        public function testGetApps() {
-               $this->ocsClient
-                               ->expects($this->any())
-                               ->method($this->anything())
-                               ->will($this->returnValue(null));
                $user = $this->generateUsers();
                $this->groupManager->get('admin')->addUser($user);
                $this->userSession->setUser($user);
@@ -99,7 +89,7 @@ class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
                $result = $this->api->getApps();
 
                $data = $result->getData();
-               $this->assertEquals(count(\OC_App::listAllApps(false, true, $this->ocsClient)), count($data['apps']));
+               $this->assertEquals(count((new \OC_App())->listAllApps()), count($data['apps']));
        }
 
        public function testGetAppsEnabled() {
@@ -109,13 +99,9 @@ class AppsControllerTest extends \OCA\Provisioning_API\Tests\TestCase {
        }
 
        public function testGetAppsDisabled() {
-               $this->ocsClient
-                               ->expects($this->any())
-                               ->method($this->anything())
-                               ->will($this->returnValue(null));
                $result = $this->api->getApps('disabled');
                $data = $result->getData();
-               $apps = \OC_App::listAllApps(false, true, $this->ocsClient);
+               $apps = (new \OC_App)->listAllApps();
                $list =  array();
                foreach($apps as $app) {
                        $list[] = $app['id'];
index 7f4b3345642ab1a9f01169a6e577aeb183d34c69..fc52edbc7785d17c7037b32ef71e374f92a5d81e 100644 (file)
@@ -673,20 +673,6 @@ $CONFIG = array(
  */
 'appstoreenabled' => true,
 
-/**
- * The URL of the appstore to use.
- */
-'appstoreurl' => 'https://api.owncloud.com/v1',
-
-/**
- * Whether to show experimental apps in the appstore interface
- *
- * Experimental apps are not checked for security issues and are new or known
- * to be unstable and under heavy development. Installing these can cause data
- * loss or security breaches.
- */
-'appstore.experimental.enabled' => false,
-
 /**
  * Use the ``apps_paths`` parameter to set the location of the Apps directory,
  * which should be scanned for available apps, and where user-specific apps
index 532a6f39848ef3e080cdd177a1687bb6710e8e8a..ddd531868d4f20dc02b41ec210320e1eb8f4708f 100644 (file)
@@ -279,6 +279,11 @@ return array(
     'OC\\AppFramework\\Utility\\TimeFactory' => $baseDir . '/lib/private/AppFramework/Utility/TimeFactory.php',
     'OC\\AppHelper' => $baseDir . '/lib/private/AppHelper.php',
     'OC\\App\\AppManager' => $baseDir . '/lib/private/App/AppManager.php',
+    'OC\\App\\AppStore\\Fetcher\\AppFetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/AppFetcher.php',
+    'OC\\App\\AppStore\\Fetcher\\CategoryFetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/CategoryFetcher.php',
+    'OC\\App\\AppStore\\Fetcher\\Fetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/Fetcher.php',
+    'OC\\App\\AppStore\\Version\\Version' => $baseDir . '/lib/private/App/AppStore/Version/Version.php',
+    'OC\\App\\AppStore\\Version\\VersionParser' => $baseDir . '/lib/private/App/AppStore/Version/VersionParser.php',
     'OC\\App\\CodeChecker\\AbstractCheck' => $baseDir . '/lib/private/App/CodeChecker/AbstractCheck.php',
     'OC\\App\\CodeChecker\\CodeChecker' => $baseDir . '/lib/private/App/CodeChecker/CodeChecker.php',
     'OC\\App\\CodeChecker\\DeprecationCheck' => $baseDir . '/lib/private/App/CodeChecker/DeprecationCheck.php',
@@ -602,7 +607,6 @@ return array(
     'OC\\Notification\\Action' => $baseDir . '/lib/private/Notification/Action.php',
     'OC\\Notification\\Manager' => $baseDir . '/lib/private/Notification/Manager.php',
     'OC\\Notification\\Notification' => $baseDir . '/lib/private/Notification/Notification.php',
-    'OC\\OCSClient' => $baseDir . '/lib/private/OCSClient.php',
     'OC\\OCS\\CoreCapabilities' => $baseDir . '/lib/private/OCS/CoreCapabilities.php',
     'OC\\OCS\\Exception' => $baseDir . '/lib/private/OCS/Exception.php',
     'OC\\OCS\\Person' => $baseDir . '/lib/private/OCS/Person.php',
index c0a3e9b50c662b58a5f0b4383081a40b5f13fdb5..99a3c3d540ef677af8828061d542872496eb33bb 100644 (file)
@@ -309,6 +309,11 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
         'OC\\AppFramework\\Utility\\TimeFactory' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/TimeFactory.php',
         'OC\\AppHelper' => __DIR__ . '/../../..' . '/lib/private/AppHelper.php',
         'OC\\App\\AppManager' => __DIR__ . '/../../..' . '/lib/private/App/AppManager.php',
+        'OC\\App\\AppStore\\Fetcher\\AppFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/AppFetcher.php',
+        'OC\\App\\AppStore\\Fetcher\\CategoryFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/CategoryFetcher.php',
+        'OC\\App\\AppStore\\Fetcher\\Fetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/Fetcher.php',
+        'OC\\App\\AppStore\\Version\\Version' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Version/Version.php',
+        'OC\\App\\AppStore\\Version\\VersionParser' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Version/VersionParser.php',
         'OC\\App\\CodeChecker\\AbstractCheck' => __DIR__ . '/../../..' . '/lib/private/App/CodeChecker/AbstractCheck.php',
         'OC\\App\\CodeChecker\\CodeChecker' => __DIR__ . '/../../..' . '/lib/private/App/CodeChecker/CodeChecker.php',
         'OC\\App\\CodeChecker\\DeprecationCheck' => __DIR__ . '/../../..' . '/lib/private/App/CodeChecker/DeprecationCheck.php',
@@ -632,7 +637,6 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
         'OC\\Notification\\Action' => __DIR__ . '/../../..' . '/lib/private/Notification/Action.php',
         'OC\\Notification\\Manager' => __DIR__ . '/../../..' . '/lib/private/Notification/Manager.php',
         'OC\\Notification\\Notification' => __DIR__ . '/../../..' . '/lib/private/Notification/Notification.php',
-        'OC\\OCSClient' => __DIR__ . '/../../..' . '/lib/private/OCSClient.php',
         'OC\\OCS\\CoreCapabilities' => __DIR__ . '/../../..' . '/lib/private/OCS/CoreCapabilities.php',
         'OC\\OCS\\Exception' => __DIR__ . '/../../..' . '/lib/private/OCS/Exception.php',
         'OC\\OCS\\Person' => __DIR__ . '/../../..' . '/lib/private/OCS/Person.php',
diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php
new file mode 100644 (file)
index 0000000..2a39b04
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\App\AppStore\Fetcher;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\IAppData;
+use OCP\Http\Client\IClientService;
+use OCP\IConfig;
+
+class AppFetcher extends Fetcher {
+       /**
+        * @param IAppData $appData
+        * @param IClientService $clientService
+        * @param ITimeFactory $timeFactory
+        * @param IConfig $config;
+        */
+       public function __construct(IAppData $appData,
+                                                               IClientService $clientService,
+                                                               ITimeFactory $timeFactory,
+                                                               IConfig $config) {
+               parent::__construct(
+                       $appData,
+                       $clientService,
+                       $timeFactory
+               );
+
+               $this->fileName = 'apps.json';
+               $this->endpointUrl = sprintf(
+                       'https://apps.nextcloud.com/api/v1/platform/%s/apps.json',
+                       substr(implode(\OC_Util::getVersion(), '.'), 0, 5)
+               );
+       }
+}
diff --git a/lib/private/App/AppStore/Fetcher/CategoryFetcher.php b/lib/private/App/AppStore/Fetcher/CategoryFetcher.php
new file mode 100644 (file)
index 0000000..74201ec
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\App\AppStore\Fetcher;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\IAppData;
+use OCP\Http\Client\IClientService;
+
+class CategoryFetcher extends Fetcher {
+       /**
+        * @param IAppData $appData
+        * @param IClientService $clientService
+        * @param ITimeFactory $timeFactory
+        */
+       public function __construct(IAppData $appData,
+                                                               IClientService $clientService,
+                                                               ITimeFactory $timeFactory) {
+               parent::__construct(
+                       $appData,
+                       $clientService,
+                       $timeFactory
+               );
+               $this->fileName = 'categories.json';
+               $this->endpointUrl = 'https://apps.nextcloud.com/api/v1/categories.json';
+       }
+}
diff --git a/lib/private/App/AppStore/Fetcher/Fetcher.php b/lib/private/App/AppStore/Fetcher/Fetcher.php
new file mode 100644 (file)
index 0000000..cffff91
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\App\AppStore\Fetcher;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Http\Client\IClientService;
+
+abstract class Fetcher {
+       const INVALIDATE_AFTER_SECONDS = 300;
+
+       /** @var IAppData */
+       private $appData;
+       /** @var IClientService */
+       private $clientService;
+       /** @var ITimeFactory */
+       private $timeFactory;
+       /** @var string */
+       protected $fileName;
+       /** @var string */
+       protected $endpointUrl;
+
+       /**
+        * @param IAppData $appData
+        * @param IClientService $clientService
+        * @param ITimeFactory $timeFactory
+        */
+       public function __construct(IAppData $appData,
+                                                               IClientService $clientService,
+                                                               ITimeFactory $timeFactory) {
+               $this->appData = $appData;
+               $this->clientService = $clientService;
+               $this->timeFactory = $timeFactory;
+       }
+
+       /**
+        * Returns the array with the categories on the appstore server
+        *
+        * @return array
+        */
+        public function get() {
+               $rootFolder = $this->appData->getFolder('/');
+
+               try {
+                       // File does already exists
+                       $file = $rootFolder->getFile($this->fileName);
+                       $jsonBlob = json_decode($file->getContent(), true);
+                       if(is_array($jsonBlob)) {
+                               // If the timestamp is older than 300 seconds request the files new
+                               if((int)$jsonBlob['timestamp'] > ($this->timeFactory->getTime() - self::INVALIDATE_AFTER_SECONDS)) {
+                                       return $jsonBlob['data'];
+                               }
+                       }
+               } catch (NotFoundException $e) {
+                       // File does not already exists
+                       $file = $rootFolder->newFile($this->fileName);
+               }
+
+               // Refresh the file content
+               $client = $this->clientService->newClient();
+               try {
+                       $response = $client->get($this->endpointUrl);
+                       $responseJson = [];
+                       $responseJson['data'] = json_decode($response->getBody(), true);
+                       $responseJson['timestamp'] = $this->timeFactory->getTime();
+                       $file->putContent(json_encode($responseJson));
+                       return json_decode($file->getContent(), true)['data'];
+               } catch (\Exception $e) {
+                       return [];
+               }
+       }
+}
diff --git a/lib/private/App/AppStore/Version/Version.php b/lib/private/App/AppStore/Version/Version.php
new file mode 100644 (file)
index 0000000..ca182ae
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\App\AppStore\Version;
+
+class Version {
+       /** @var string */
+       private $minVersion;
+       /** @var string */
+       private $maxVersion;
+
+       /**
+        * @param string $minVersion
+        * @param string $maxVersion
+        */
+       public function __construct($minVersion, $maxVersion) {
+               $this->minVersion = $minVersion;
+               $this->maxVersion = $maxVersion;
+       }
+
+       /**
+        * @return string
+        */
+       public function getMinimumVersion() {
+               return $this->minVersion;
+       }
+
+       /**
+        * @return string
+        */
+       public function getMaximumVersion() {
+               return $this->maxVersion;
+       }
+}
diff --git a/lib/private/App/AppStore/Version/VersionParser.php b/lib/private/App/AppStore/Version/VersionParser.php
new file mode 100644 (file)
index 0000000..1058a8b
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\App\AppStore\Version;
+
+/**
+ * Class VersionParser parses the versions as sent by the Nextcloud app store
+ *
+ * @package OC\App\AppStore
+ */
+class VersionParser {
+       /**
+        * Returns the version for a version string
+        *
+        * @param string $versionSpec
+        * @return Version
+        * @throws \Exception If the version cannot be parsed
+        */
+       public function getVersion($versionSpec) {
+               // * indicates that the version is compatible with all versions
+               if($versionSpec === '*') {
+                       return new Version('', '');
+               }
+
+               // Count the amount of =, if it is one then it's either maximum or minimum
+               // version. If it is two then it is maximum and minimum.
+               if (preg_match_all('/(?:>|<)(?:=|)[0-9.]+/', $versionSpec, $matches)) {
+                       switch(count($matches[0])) {
+                               case 1:
+                                       if(substr($matches[0][0], 0, 1) === '>') {
+                                               return new Version(substr($matches[0][0], 2), '');
+                                       } else {
+                                               return new Version('', substr($matches[0][0], 2));
+                                       }
+                                       break;
+                               case 2:
+                                       return new Version(substr($matches[0][0], 2), substr($matches[0][1], 2));
+                                       break;
+                               default:
+                                       throw new \Exception('Version cannot be parsed');
+                       }
+               }
+
+               throw new \Exception('Version cannot be parsed');
+       }
+}
index 009df7905854d1be436055306904d2aa3bcb299f..02dbd670a0a30b1a9f35bc50b287b6723fc70830 100644 (file)
 
 namespace OC;
 
+use OC\App\AppStore\Fetcher\AppFetcher;
 use OC\App\CodeChecker\CodeChecker;
 use OC\App\CodeChecker\EmptyCheck;
 use OC\App\CodeChecker\PrivateCheck;
+use OC\Archive\Archive;
 use OC_App;
 use OC_DB;
 use OC_Helper;
+use OCP\Http\Client\IClientService;
+use OCP\ILogger;
+use OCP\ITempManager;
+use phpseclib\File\X509;
 
 /**
  * This class provides the functionality needed to install, update and remove plugins/apps
@@ -81,49 +87,13 @@ class Installer {
         * needed to get the app working.
         *
         * Installs an app
-        * @param array $data with all information
+        * @param string $appId App to install
         * @throws \Exception
         * @return integer
         */
-       public static function installApp( $data = array()) {
-               $l = \OC::$server->getL10N('lib');
-
-               list($extractDir, $path) = self::downloadApp($data);
-
-               $info = self::checkAppsIntegrity($data, $extractDir, $path);
-               $appId = OC_App::cleanAppId($info['id']);
+       public function installApp($appId) {
                $basedir = OC_App::getInstallPath().'/'.$appId;
-               //check if the destination directory already exists
-               if(is_dir($basedir)) {
-                       OC_Helper::rmdirr($extractDir);
-                       if($data['source']=='http') {
-                               unlink($path);
-                       }
-                       throw new \Exception($l->t("App directory already exists"));
-               }
-
-               if(!empty($data['pretent'])) {
-                       return false;
-               }
-
-               //copy the app to the correct place
-               if(@!mkdir($basedir)) {
-                       OC_Helper::rmdirr($extractDir);
-                       if($data['source']=='http') {
-                               unlink($path);
-                       }
-                       throw new \Exception($l->t("Can't create app folder. Please fix permissions. %s", array($basedir)));
-               }
-
-               $extractDir .= '/' . $info['id'];
-               if(!file_exists($extractDir)) {
-                       OC_Helper::rmdirr($basedir);
-                       throw new \Exception($l->t("Archive does not contain a directory named %s", $info['id']));
-               }
-               OC_Helper::copyr($extractDir, $basedir);
-
-               //remove temporary files
-               OC_Helper::rmdirr($extractDir);
+               $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
 
                //install the database
                if(is_file($basedir.'/appinfo/database.xml')) {
@@ -168,7 +138,7 @@ class Installer {
         *
         * Checks whether or not an app is installed, i.e. registered in apps table.
         */
-       public static function  isInstalled( $app ) {
+       public static function isInstalled( $app ) {
                return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
        }
 
@@ -265,58 +235,148 @@ class Installer {
        }
 
        /**
-        * @param array $data
-        * @return array
+        * Downloads an app and puts it into the app directory
+        *
+        * @param string $appId
+        * @param AppFetcher $appFetcher
+        * @param IClientService $clientService
+        * @param ITempManager $tempManager
+        * @param ILogger $logger
+        *
+        * @return bool Whether the installation was successful or not
         * @throws \Exception
         */
-       public static function downloadApp($data = array()) {
-               $l = \OC::$server->getL10N('lib');
-
-               if(!isset($data['source'])) {
-                       throw new \Exception($l->t("No source specified when installing app"));
-               }
+       public function downloadApp($appId,
+                                                               AppFetcher $appFetcher,
+                                                               IClientService $clientService,
+                                                               ITempManager $tempManager,
+                                                               ILogger $logger) {
+               $appId = strtolower($appId);
+
+               $apps = $appFetcher->get();
+               foreach($apps as $app) {
+                       if($app['id'] === $appId) {
+                               // Verify if the certificate has been issued by the Nextcloud Code Authority CA
+                               $x509 = new X509();
+                               $x509->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
+                               $x509->loadX509($app['certificate']);
+                               if($x509->validateSignature() !== true) {
+                                       $logger->error(
+                                               sprintf(
+                                                       'App with id %s has a certificate not issued by a trusted Code Signing Authority',
+                                                       $appId
+                                               ),
+                                               [
+                                                       'app' => 'core',
+                                               ]
+                                       );
+                                       return false;
+                               }
 
-               //download the file if necessary
-               if($data['source']=='http') {
-                       $pathInfo = pathinfo($data['href']);
-                       $extension = isset($pathInfo['extension']) ? '.' . $pathInfo['extension'] : '';
-                       $path = \OC::$server->getTempManager()->getTemporaryFile($extension);
-                       if(!isset($data['href'])) {
-                               throw new \Exception($l->t("No href specified when installing app from http"));
-                       }
-                       $client = \OC::$server->getHTTPClientService()->newClient();
-                       $client->get($data['href'], ['save_to' => $path]);
-               } else {
-                       if(!isset($data['path'])) {
-                               throw new \Exception($l->t("No path specified when installing app from local file"));
-                       }
-                       $path=$data['path'];
-               }
+                               // Verify if the certificate is issued for the requested app id
+                               $certInfo = openssl_x509_parse($app['certificate']);
+                               if(!isset($certInfo['subject']['CN'])) {
+                                       $logger->error(
+                                               sprintf(
+                                                       'App with id %s has a cert with no CN',
+                                                       $appId
+                                               ),
+                                               [
+                                                       'app' => 'core',
+                                               ]
+                                       );
+                                       return false;
+                               }
+                               if($certInfo['subject']['CN'] !== $appId) {
+                                       $logger->error(
+                                               sprintf(
+                                                       'App with id %s has a cert issued to %s',
+                                                       $appId,
+                                                       $certInfo['subject']['CN']
+                                               ),
+                                               [
+                                                       'app' => 'core',
+                                               ]
+                                       );
+                                       return false;
+                               }
 
-               //detect the archive type
-               $mime = \OC::$server->getMimeTypeDetector()->detect($path);
-               if ($mime !=='application/zip' && $mime !== 'application/x-gzip' && $mime !== 'application/x-bzip2') {
-                       throw new \Exception($l->t("Archives of type %s are not supported", array($mime)));
-               }
+                               // Download the release
+                               $tempFile = $tempManager->getTemporaryFile('.tar.gz');
+                               $client = $clientService->newClient();
+                               // FIXME: Proper way to determine what the latest release is
+                               $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]);
+
+                               // Check if the signature actually matches the downloaded content
+                               $certificate = openssl_get_publickey($app['certificate']);
+                               $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
+                               openssl_free_key($certificate);
+
+                               if($verified === true) {
+                                       // Seems to match, let's proceed
+                                       $extractDir = $tempManager->getTemporaryFolder();
+                                       $archive = Archive::open($tempFile);
+
+                                       if($archive) {
+                                               $archive->extract($extractDir);
+
+                                               // Check if appinfo/info.xml has the same app ID as well
+                                               $loadEntities = libxml_disable_entity_loader(false);
+                                               $xml = simplexml_load_file($extractDir . '/' . $appId . '/appinfo/info.xml');
+                                               libxml_disable_entity_loader($loadEntities);
+                                               if((string)$xml->id !== $appId) {
+                                                       $logger->error(
+                                                               sprintf(
+                                                                       'App for id %s has a wrong app ID in info.xml: %s',
+                                                                       $appId,
+                                                                       (string)$xml->id
+                                                               ),
+                                                               [
+                                                                       'app' => 'core',
+                                                               ]
+                                                       );
+                                                       return false;
+                                               }
 
-               //extract the archive in a temporary folder
-               $extractDir = \OC::$server->getTempManager()->getTemporaryFolder();
-               OC_Helper::rmdirr($extractDir);
-               mkdir($extractDir);
-               if($archive=\OC\Archive\Archive::open($path)) {
-                       $archive->extract($extractDir);
-               } else {
-                       OC_Helper::rmdirr($extractDir);
-                       if($data['source']=='http') {
-                               unlink($path);
+                                               // Move to app folder
+                                               $baseDir = OC_App::getInstallPath().'/'.$appId;
+                                               //copy the app to the correct place
+                                               if(@mkdir($baseDir)) {
+                                                       $extractDir .= '/' . $appId;
+                                                       OC_Helper::copyr($extractDir, $baseDir);
+                                               }
+                                               OC_Helper::copyr($extractDir, $baseDir);
+                                               OC_Helper::rmdirr($extractDir);
+                                               return true;
+                                       } else {
+                                               $logger->error(
+                                                       sprintf(
+                                                               'Could not extract app with ID %s to %s',
+                                                               $appId,
+                                                               $extractDir
+                                                       ),
+                                                       [
+                                                               'app' => 'core',
+                                                       ]
+                                               );
+                                               return false;
+                                       }
+                               } else {
+                                       // Signature does not match
+                                       $logger->error(
+                                               sprintf(
+                                                       'App with id %s has invalid signature',
+                                                       $appId
+                                               ),
+                                               [
+                                                       'app' => 'core',
+                                               ]
+                                       );
+                               }
                        }
-                       throw new \Exception($l->t("Failed to open archive when installing app"));
                }
 
-               return array(
-                       $extractDir,
-                       $path
-               );
+               return false;
        }
 
        /**
@@ -466,7 +526,7 @@ class Installer {
         *
         * The function will check if the app is already downloaded in the apps repository
         */
-       public static function isDownloaded( $name ) {
+       public function isDownloaded($name) {
                foreach(\OC::$APPSROOTS as $dir) {
                        $dirToTest  = $dir['path'];
                        $dirToTest .= '/';
diff --git a/lib/private/OCSClient.php b/lib/private/OCSClient.php
deleted file mode 100644 (file)
index 76c0b13..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Brice Maron <brice@bmaron.net>
- * @author Felix Moeller <mail@felixmoeller.de>
- * @author Frank Karlitschek <frank@karlitschek.de>
- * @author Jarrett <JetUni@users.noreply.github.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Kamil Domanski <kdomanski@kdemail.net>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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 OC;
-
-use OCP\Http\Client\IClientService;
-use OCP\IConfig;
-use OCP\ILogger;
-
-/**
- * Class OCSClient is a class for communication with the ownCloud appstore
- *
- * @package OC
- */
-class OCSClient {
-       /** @var IClientService */
-       private $httpClientService;
-       /** @var IConfig */
-       private $config;
-       /** @var ILogger */
-       private $logger;
-
-       /**
-        * @param IClientService $httpClientService
-        * @param IConfig $config
-        * @param ILogger $logger
-        */
-       public function __construct(IClientService $httpClientService,
-                                                               IConfig $config,
-                                                               ILogger $logger) {
-               $this->httpClientService = $httpClientService;
-               $this->config = $config;
-               $this->logger = $logger;
-       }
-
-       /**
-        * Returns whether the AppStore is enabled (i.e. because the AppStore is disabled for EE)
-        *
-        * @return bool
-        */
-       public function isAppStoreEnabled() {
-               return $this->config->getSystemValue('appstoreenabled', true) === true;
-       }
-
-       /**
-        * Get the url of the OCS AppStore server.
-        *
-        * @return string of the AppStore server
-        */
-       private function getAppStoreUrl() {
-               return $this->config->getSystemValue('appstoreurl', 'https://api.owncloud.com/v1');
-       }
-
-       /**
-        * @param string $body
-        * @param string $action
-        * @return null|\SimpleXMLElement
-        */
-       private function loadData($body, $action) {
-               $loadEntities = libxml_disable_entity_loader(true);
-               $data = @simplexml_load_string($body);
-               libxml_disable_entity_loader($loadEntities);
-
-               if($data === false) {
-                       libxml_clear_errors();
-                       $this->logger->error(
-                               sprintf('Could not get %s, content was no valid XML', $action),
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-                       return null;
-               }
-
-               return $data;
-       }
-
-       /**
-        * Get all the categories from the OCS server
-        *
-        * @param array $targetVersion The target ownCloud version
-        * @return array|null an array of category ids or null
-        * @note returns NULL if config value appstoreenabled is set to false
-        * This function returns a list of all the application categories on the OCS server
-        */
-       public function getCategories(array $targetVersion) {
-               if (!$this->isAppStoreEnabled()) {
-                       return null;
-               }
-
-               $client = $this->httpClientService->newClient();
-               try {
-                       $response = $client->get(
-                               $this->getAppStoreUrl() . '/content/categories',
-                               [
-                                       'timeout' => 20,
-                                       'query' => [
-                                               'version' => implode('x', $targetVersion),
-                                       ],
-                               ]
-                       );
-               } catch(\Exception $e) {
-                       $this->logger->error(
-                               sprintf('Could not get categories: %s', $e->getMessage()),
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-                       return null;
-               }
-
-               $data = $this->loadData($response->getBody(), 'categories');
-               if($data === null) {
-                       return null;
-               }
-
-               $tmp = $data->data;
-               $cats = [];
-
-               foreach ($tmp->category as $value) {
-                       $id = (int)$value->id;
-                       $name = (string)$value->name;
-                       $cats[$id] = $name;
-               }
-
-               return $cats;
-       }
-
-       /**
-        * Get all the applications from the OCS server
-        * @param array $categories
-        * @param int $page
-        * @param string $filter
-        * @param array $targetVersion The target ownCloud version
-        * @return array An array of application data
-        */
-       public function getApplications(array $categories, $page, $filter, array $targetVersion) {
-               if (!$this->isAppStoreEnabled()) {
-                       return [];
-               }
-
-               $client = $this->httpClientService->newClient();
-               try {
-                       $response = $client->get(
-                               $this->getAppStoreUrl() . '/content/data',
-                               [
-                                       'timeout' => 20,
-                                       'query' => [
-                                               'version' => implode('x', $targetVersion),
-                                               'filter' => $filter,
-                                               'categories' => implode('x', $categories),
-                                               'sortmode' => 'new',
-                                               'page' => $page,
-                                               'pagesize' => 100,
-                                               'approved' => $filter
-                                       ],
-                               ]
-                       );
-               } catch(\Exception $e) {
-                       $this->logger->error(
-                               sprintf('Could not get applications: %s', $e->getMessage()),
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-                       return [];
-               }
-
-               $data = $this->loadData($response->getBody(), 'applications');
-               if($data === null) {
-                       return [];
-               }
-
-               $tmp = $data->data->content;
-               $tmpCount = count($tmp);
-
-               $apps = [];
-               for ($i = 0; $i < $tmpCount; $i++) {
-                       $app = [];
-                       $app['id'] = (string)$tmp[$i]->id;
-                       $app['name'] = (string)$tmp[$i]->name;
-                       $app['label'] = (string)$tmp[$i]->label;
-                       $app['version'] = (string)$tmp[$i]->version;
-                       $app['type'] = (string)$tmp[$i]->typeid;
-                       $app['typename'] = (string)$tmp[$i]->typename;
-                       $app['personid'] = (string)$tmp[$i]->personid;
-                       $app['profilepage'] = (string)$tmp[$i]->profilepage;
-                       $app['license'] = (string)$tmp[$i]->license;
-                       $app['detailpage'] = (string)$tmp[$i]->detailpage;
-                       $app['preview'] = (string)$tmp[$i]->smallpreviewpic1;
-                       $app['preview-full'] = (string)$tmp[$i]->previewpic1;
-                       $app['changed'] = strtotime($tmp[$i]->changed);
-                       $app['description'] = (string)$tmp[$i]->description;
-                       $app['score'] = (string)$tmp[$i]->score;
-                       $app['downloads'] = (int)$tmp[$i]->downloads;
-                       $app['level'] = (int)$tmp[$i]->approved;
-
-                       $apps[] = $app;
-               }
-
-               return $apps;
-       }
-
-
-       /**
-        * Get an the applications from the OCS server
-        *
-        * @param string $id
-        * @param array $targetVersion The target ownCloud version
-        * @return array|null an array of application data or null
-        *
-        * This function returns an applications from the OCS server
-        */
-       public function getApplication($id, array $targetVersion) {
-               if (!$this->isAppStoreEnabled()) {
-                       return null;
-               }
-
-               $client = $this->httpClientService->newClient();
-               try {
-                       $response = $client->get(
-                               $this->getAppStoreUrl() . '/content/data/' . urlencode($id),
-                               [
-                                       'timeout' => 20,
-                                       'query' => [
-                                               'version' => implode('x', $targetVersion),
-                                       ],
-                               ]
-                       );
-               } catch(\Exception $e) {
-                       $this->logger->error(
-                               sprintf('Could not get application: %s', $e->getMessage()),
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-                       return null;
-               }
-
-               $data = $this->loadData($response->getBody(), 'application');
-               if($data === null) {
-                       return null;
-               }
-
-               $tmp = $data->data->content;
-               if (is_null($tmp)) {
-                       \OCP\Util::writeLog('core', 'No update found at the ownCloud appstore for app ' . $id, \OCP\Util::DEBUG);
-                       return null;
-               }
-
-               $app = [];
-               $app['id'] = (int)$id;
-               $app['name'] = (string)$tmp->name;
-               $app['version'] = (string)$tmp->version;
-               $app['type'] = (string)$tmp->typeid;
-               $app['label'] = (string)$tmp->label;
-               $app['typename'] = (string)$tmp->typename;
-               $app['personid'] = (string)$tmp->personid;
-               $app['profilepage'] = (string)$tmp->profilepage;
-               $app['detailpage'] = (string)$tmp->detailpage;
-               $app['preview1'] = (string)$tmp->smallpreviewpic1;
-               $app['preview2'] = (string)$tmp->smallpreviewpic2;
-               $app['preview3'] = (string)$tmp->smallpreviewpic3;
-               $app['changed'] = strtotime($tmp->changed);
-               $app['description'] = (string)$tmp->description;
-               $app['detailpage'] = (string)$tmp->detailpage;
-               $app['score'] = (int)$tmp->score;
-               $app['level'] = (int)$tmp->approved;
-
-               return $app;
-       }
-
-       /**
-        * Get the download url for an application from the OCS server
-        * @param string $id
-        * @param array $targetVersion The target ownCloud version
-        * @return array|null an array of application data or null
-        */
-       public function getApplicationDownload($id, array $targetVersion) {
-               if (!$this->isAppStoreEnabled()) {
-                       return null;
-               }
-               $url = $this->getAppStoreUrl() . '/content/download/' . urlencode($id) . '/1';
-               $client = $this->httpClientService->newClient();
-               try {
-                       $response = $client->get(
-                               $url,
-                               [
-                                       'timeout' => 20,
-                                       'query' => [
-                                               'version' => implode('x', $targetVersion),
-                                       ],
-                               ]
-                       );
-               } catch(\Exception $e) {
-                       $this->logger->error(
-                               sprintf('Could not get application download URL: %s', $e->getMessage()),
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-                       return null;
-               }
-
-               $data = $this->loadData($response->getBody(), 'application download URL');
-               if($data === null) {
-                       return null;
-               }
-
-               $tmp = $data->data->content;
-               $app = [];
-               if (isset($tmp->downloadlink)) {
-                       $app['downloadlink'] = (string)$tmp->downloadlink;
-               } else {
-                       $app['downloadlink'] = '';
-               }
-               return $app;
-       }
-
-}
index 21ec311401dac6926deec8d5f70ef60b71a57caa..39905dcf7ce8e016f9de56bbf46264922ba04b98 100644 (file)
@@ -580,13 +580,6 @@ class Server extends ServerContainer implements IServerContainer {
                                $c->getThemingDefaults()
                        );
                });
-               $this->registerService('OcsClient', function (Server $c) {
-                       return new OCSClient(
-                               $this->getHTTPClientService(),
-                               $this->getConfig(),
-                               $this->getLogger()
-                       );
-               });
                $this->registerService('LDAPProvider', function(Server $c) {
                        $config = $c->getConfig();
                        $factoryClass = $config->getSystemValue('ldapProviderFactory', null);
index d25534aa82264316ccfd34bd61e79fa9d778bb90..1db1ce74cdc5cc9d1668db9207171df601d39d2e 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 /**
  * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
  *
  * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  * @author Bart Visscher <bartv@thisnet.nl>
@@ -326,24 +327,59 @@ class OC_App {
        /**
         * enables an app
         *
-        * @param mixed $app app
+        * @param string $appId
         * @param array $groups (optional) when set, only these groups will have access to the app
         * @throws \Exception
         * @return void
         *
         * This function set an app as enabled in appconfig.
         */
-       public static function enable($app, $groups = null) {
+       public function enable($appId,
+                                                  $groups = null) {
                self::$enabledAppsCache = []; // flush
-               if (!Installer::isInstalled($app)) {
-                       $app = self::installApp($app);
+               $l = \OC::$server->getL10N('core');
+               $config = \OC::$server->getConfig();
+
+               // Check if app is already downloaded
+               $installer = new Installer();
+               $isDownloaded = $installer->isDownloaded($appId);
+
+               if(!$isDownloaded) {
+                       $state = $installer->downloadApp(
+                               $appId,
+                               new \OC\App\AppStore\Fetcher\AppFetcher(
+                                       \OC::$server->getAppDataDir('appstore'),
+                                       \OC::$server->getHTTPClientService(),
+                                       new \OC\AppFramework\Utility\TimeFactory(),
+                                       $config
+                               ),
+                               \OC::$server->getHTTPClientService(),
+                               \OC::$server->getTempManager(),
+                               \OC::$server->getLogger()
+                       );
+
+                       if($state !== true) {
+                               throw new \Exception(
+                                       sprintf(
+                                               'Could not download app with id: %s',
+                                               $appId
+                                       )
+                               );
+                       }
+               }
+
+               if (!Installer::isInstalled($appId)) {
+                       $appId = self::installApp(
+                               $appId,
+                               $config,
+                               $l
+                       );
+                       $installer->installApp($appId);
                } else {
                        // check for required dependencies
-                       $config = \OC::$server->getConfig();
-                       $l = \OC::$server->getL10N('core');
-                       $info = self::getAppInfo($app);
-
+                       $info = self::getAppInfo($appId);
                        self::checkAppDependencies($config, $l, $info);
+                       $installer->installApp($appId);
                }
 
                $appManager = \OC::$server->getAppManager();
@@ -356,40 +392,19 @@ class OC_App {
                                        $groupsList[] = $groupManager->get($group);
                                }
                        }
-                       $appManager->enableAppForGroups($app, $groupsList);
+                       $appManager->enableAppForGroups($appId, $groupsList);
                } else {
-                       $appManager->enableApp($app);
+                       $appManager->enableApp($appId);
                }
 
-               $info = self::getAppInfo($app);
+               $info = self::getAppInfo($appId);
                if(isset($info['settings']) && is_array($info['settings'])) {
-                       $appPath = self::getAppPath($app);
-                       self::registerAutoloading($app, $appPath);
+                       $appPath = self::getAppPath($appId);
+                       self::registerAutoloading($appId, $appPath);
                        \OC::$server->getSettingsManager()->setupSettings($info['settings']);
                }
        }
 
-       /**
-        * @param string $app
-        * @return int
-        */
-       private static function downloadApp($app) {
-               $ocsClient = new OCSClient(
-                       \OC::$server->getHTTPClientService(),
-                       \OC::$server->getConfig(),
-                       \OC::$server->getLogger()
-               );
-               $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
-               $download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
-               if(isset($download['downloadlink']) and $download['downloadlink']!='') {
-                       // Replace spaces in download link without encoding entire URL
-                       $download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
-                       $info = array('source' => 'http', 'href' => $download['downloadlink'], 'appdata' => $appData);
-                       $app = Installer::installApp($info);
-               }
-               return $app;
-       }
-
        /**
         * @param string $app
         * @return bool
@@ -409,11 +424,6 @@ class OC_App {
         * @throws Exception
         */
        public static function disable($app) {
-               // Convert OCS ID to regular application identifier
-               if(self::getInternalAppIdByOcs($app) !== false) {
-                       $app = self::getInternalAppIdByOcs($app);
-               }
-
                // flush
                self::$enabledAppsCache = array();
 
@@ -613,18 +623,6 @@ class OC_App {
                return false;
        }
 
-
-       /**
-        * check if an app's directory is writable
-        *
-        * @param string $appId
-        * @return bool
-        */
-       public static function isAppDirWritable($appId) {
-               $path = self::getAppPath($appId);
-               return ($path !== false) ? is_writable($path) : false;
-       }
-
        /**
         * Get the path for the given app on the access
         * If the app is defined in multiple directories, the first one is taken. (false if not found)
@@ -837,20 +835,11 @@ class OC_App {
        /**
         * List all apps, this is used in apps.php
         *
-        * @param bool $onlyLocal
-        * @param bool $includeUpdateInfo Should we check whether there is an update
-        *                                in the app store?
-        * @param OCSClient $ocsClient
         * @return array
         */
-       public static function listAllApps($onlyLocal = false,
-                                                                          $includeUpdateInfo = true,
-                                                                          OCSClient $ocsClient) {
+       public function listAllApps() {
                $installedApps = OC_App::getAllApps();
 
-               //TODO which apps do we want to blacklist and how do we integrate
-               // blacklisting with the multi apps folder feature?
-
                //we don't want to show configuration for these
                $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
                $appList = array();
@@ -893,8 +882,6 @@ class OC_App {
                                        $info['removable'] = true;
                                }
 
-                               $info['update'] = ($includeUpdateInfo) ? Installer::isUpdateAvailable($app) : null;
-
                                $appPath = self::getAppPath($app);
                                if($appPath !== false) {
                                        $appIcon = $appPath . '/img/' . $app . '.svg';
@@ -926,29 +913,8 @@ class OC_App {
                                $appList[] = $info;
                        }
                }
-               if ($onlyLocal) {
-                       $remoteApps = [];
-               } else {
-                       $remoteApps = OC_App::getAppstoreApps('approved', null, $ocsClient);
-               }
-               if ($remoteApps) {
-                       // Remove duplicates
-                       foreach ($appList as $app) {
-                               foreach ($remoteApps AS $key => $remote) {
-                                       if ($app['name'] === $remote['name'] ||
-                                               (isset($app['ocsid']) &&
-                                                       $app['ocsid'] === $remote['id'])
-                                       ) {
-                                               unset($remoteApps[$key]);
-                                       }
-                               }
-                       }
-                       $combinedApps = array_merge($appList, $remoteApps);
-               } else {
-                       $combinedApps = $appList;
-               }
 
-               return $combinedApps;
+               return $appList;
        }
 
        /**
@@ -966,70 +932,6 @@ class OC_App {
                return false;
        }
 
-       /**
-        * Get a list of all apps on the appstore
-        * @param string $filter
-        * @param string|null $category
-        * @param OCSClient $ocsClient
-        * @return array|bool  multi-dimensional array of apps.
-        *                     Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
-        */
-       public static function getAppstoreApps($filter = 'approved',
-                                                                                  $category = null,
-                                                                                  OCSClient $ocsClient) {
-               $categories = [$category];
-
-               if (is_null($category)) {
-                       $categoryNames = $ocsClient->getCategories(\OCP\Util::getVersion());
-                       if (is_array($categoryNames)) {
-                               // Check that categories of apps were retrieved correctly
-                               if (!$categories = array_keys($categoryNames)) {
-                                       return false;
-                               }
-                       } else {
-                               return false;
-                       }
-               }
-
-               $page = 0;
-               $remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OCP\Util::getVersion());
-               $apps = [];
-               $i = 0;
-               $l = \OC::$server->getL10N('core');
-               foreach ($remoteApps as $app) {
-                       $potentialCleanId = self::getInternalAppIdByOcs($app['id']);
-                       // enhance app info (for example the description)
-                       $apps[$i] = OC_App::parseAppInfo($app);
-                       $apps[$i]['author'] = $app['personid'];
-                       $apps[$i]['ocs_id'] = $app['id'];
-                       $apps[$i]['internal'] = 0;
-                       $apps[$i]['active'] = ($potentialCleanId !== false) ? self::isEnabled($potentialCleanId) : false;
-                       $apps[$i]['update'] = false;
-                       $apps[$i]['groups'] = false;
-                       $apps[$i]['score'] = $app['score'];
-                       $apps[$i]['removable'] = false;
-                       if ($app['label'] == 'recommended') {
-                               $apps[$i]['internallabel'] = (string)$l->t('Recommended');
-                               $apps[$i]['internalclass'] = 'recommendedapp';
-                       }
-
-                       // Apps from the appstore are always assumed to be compatible with the
-                       // the current release as the initial filtering is done on the appstore
-                       $apps[$i]['dependencies']['owncloud']['@attributes']['min-version'] = implode('.', \OCP\Util::getVersion());
-                       $apps[$i]['dependencies']['owncloud']['@attributes']['max-version'] = implode('.', \OCP\Util::getVersion());
-
-                       $i++;
-               }
-
-
-
-               if (empty($apps)) {
-                       return false;
-               } else {
-                       return $apps;
-               }
-       }
-
        public static function shouldUpgrade($app) {
                $versions = self::getAppVersions();
                $currentVersion = OC_App::getAppVersion($app);
@@ -1132,46 +1034,16 @@ class OC_App {
 
        /**
         * @param string $app
+        * @param \OCP\IConfig $config
+        * @param \OCP\IL10N $l
         * @return bool
+        *
         * @throws Exception if app is not compatible with this version of ownCloud
         * @throws Exception if no app-name was specified
         */
-       public static function installApp($app) {
-               $appName = $app; // $app will be overwritten, preserve name for error logging
-               $l = \OC::$server->getL10N('core');
-               $config = \OC::$server->getConfig();
-               $ocsClient = new OCSClient(
-                       \OC::$server->getHTTPClientService(),
-                       $config,
-                       \OC::$server->getLogger()
-               );
-               $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
-
-               // check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
-               if (!is_numeric($app)) {
-                       $shippedVersion = self::getAppVersion($app);
-                       if ($appData && version_compare($shippedVersion, $appData['version'], '<')) {
-                               $app = self::downloadApp($app);
-                       } else {
-                               $app = Installer::installShippedApp($app);
-                       }
-               } else {
-                       // Maybe the app is already installed - compare the version in this
-                       // case and use the local already installed one.
-                       // FIXME: This is a horrible hack. I feel sad. The god of code cleanness may forgive me.
-                       $internalAppId = self::getInternalAppIdByOcs($app);
-                       if($internalAppId !== false) {
-                               if($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
-                                       $app = self::downloadApp($app);
-                               } else {
-                                       self::enable($internalAppId);
-                                       $app = $internalAppId;
-                               }
-                       } else {
-                               $app = self::downloadApp($app);
-                       }
-               }
-
+       public function installApp($app,
+                                                          \OCP\IConfig $config,
+                                                          \OCP\IL10N $l) {
                if ($app !== false) {
                        // check if the app is compatible with this version of ownCloud
                        $info = self::getAppInfo($app);
index dd237e40c9d6e0beb8ff690dd8e1b428c1a4b810..3dbf9acc5247eff2476e1001d38b9ced2839d542 100644 (file)
 
 namespace OC\Settings;
 
+use OC\App\AppStore\Fetcher\AppFetcher;
+use OC\App\AppStore\Fetcher\CategoryFetcher;
+use OC\AppFramework\Utility\TimeFactory;
 use OC\Authentication\Token\IProvider;
+use OC\Server;
 use OC\Settings\Middleware\SubadminMiddleware;
 use OCP\AppFramework\App;
 use OCP\IContainer;
@@ -86,5 +90,24 @@ class Application extends App {
                $container->registerService(IManager::class, function (IContainer $c) {
                        return $c->query('ServerContainer')->getSettingsManager();
                });
+               $container->registerService(AppFetcher::class, function (IContainer $c) {
+                       /** @var Server $server */
+                       $server = $c->query('ServerContainer');
+                       return new AppFetcher(
+                               $server->getAppDataDir('appstore'),
+                               $server->getHTTPClientService(),
+                               new TimeFactory(),
+                               $server->getConfig()
+                       );
+               });
+               $container->registerService(CategoryFetcher::class, function (IContainer $c) {
+                       /** @var Server $server */
+                       $server = $c->query('ServerContainer');
+                       return new CategoryFetcher(
+                               $server->getAppDataDir('appstore'),
+                               $server->getHTTPClientService(),
+                               new TimeFactory()
+                       );
+               });
        }
 }
index 2efd3b8a847d583a7d8663621fb9548595e7986d..16d4780c5f996a9b9e423c1813924a151ce2c3e8 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 /**
  * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
  *
  * @author Christoph Wurst <christoph@owncloud.com>
  * @author Joas Schilling <coding@schilljs.com>
 
 namespace OC\Settings\Controller;
 
+use OC\App\AppStore\Fetcher\AppFetcher;
+use OC\App\AppStore\Fetcher\CategoryFetcher;
+use OC\App\AppStore\Version\VersionParser;
 use OC\App\DependencyAnalyzer;
 use OC\App\Platform;
-use OC\OCSClient;
 use OCP\App\IAppManager;
 use \OCP\AppFramework\Controller;
 use OCP\AppFramework\Http\ContentSecurityPolicy;
-use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\JSONResponse;
 use OCP\AppFramework\Http\TemplateResponse;
 use OCP\ICacheFactory;
 use OCP\INavigationManager;
 use OCP\IRequest;
 use OCP\IL10N;
 use OCP\IConfig;
+use OCP\L10N\IFactory;
 
 /**
  * @package OC\Settings\Controller
@@ -57,8 +61,12 @@ class AppSettingsController extends Controller {
        private $navigationManager;
        /** @var IAppManager */
        private $appManager;
-       /** @var OCSClient */
-       private $ocsClient;
+       /** @var CategoryFetcher */
+       private $categoryFetcher;
+       /** @var AppFetcher */
+       private $appFetcher;
+       /** @var IFactory */
+       private $l10nFactory;
 
        /**
         * @param string $appName
@@ -68,7 +76,9 @@ class AppSettingsController extends Controller {
         * @param ICacheFactory $cache
         * @param INavigationManager $navigationManager
         * @param IAppManager $appManager
-        * @param OCSClient $ocsClient
+        * @param CategoryFetcher $categoryFetcher
+        * @param AppFetcher $appFetcher
+        * @param IFactory $l10nFactory
         */
        public function __construct($appName,
                                                                IRequest $request,
@@ -77,69 +87,39 @@ class AppSettingsController extends Controller {
                                                                ICacheFactory $cache,
                                                                INavigationManager $navigationManager,
                                                                IAppManager $appManager,
-                                                               OCSClient $ocsClient) {
+                                                               CategoryFetcher $categoryFetcher,
+                                                               AppFetcher $appFetcher,
+                                                               IFactory $l10nFactory) {
                parent::__construct($appName, $request);
                $this->l10n = $l10n;
                $this->config = $config;
                $this->cache = $cache->create($appName);
                $this->navigationManager = $navigationManager;
                $this->appManager = $appManager;
-               $this->ocsClient = $ocsClient;
-       }
-
-       /**
-        * Enables or disables the display of experimental apps
-        * @param bool $state
-        * @return DataResponse
-        */
-       public function changeExperimentalConfigState($state) {
-               $this->config->setSystemValue('appstore.experimental.enabled', $state);
-               $this->appManager->clearAppsCache();
-               return new DataResponse();
-       }
-
-       /**
-        * @param string|int $category
-        * @return int
-        */
-       protected function getCategory($category) {
-               if (is_string($category)) {
-                       foreach ($this->listCategories() as $cat) {
-                               if (isset($cat['ident']) && $cat['ident'] === $category) {
-                                       $category = (int) $cat['id'];
-                                       break;
-                               }
-                       }
-
-                       // Didn't find the category, falling back to enabled
-                       if (is_string($category)) {
-                               $category = self::CAT_ENABLED;
-                       }
-               }
-               return (int) $category;
+               $this->categoryFetcher = $categoryFetcher;
+               $this->appFetcher = $appFetcher;
+               $this->l10nFactory = $l10nFactory;
        }
 
        /**
         * @NoCSRFRequired
+        *
         * @param string $category
         * @return TemplateResponse
         */
        public function viewApps($category = '') {
-               $categoryId = $this->getCategory($category);
-               if ($categoryId === self::CAT_ENABLED) {
-                       // Do not use an arbitrary input string, because we put the category in html
+               if ($category === '') {
                        $category = 'enabled';
                }
 
                $params = [];
-               $params['experimentalEnabled'] = $this->config->getSystemValue('appstore.experimental.enabled', false);
                $params['category'] = $category;
                $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
                $this->navigationManager->setActiveEntry('core_apps');
 
                $templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user');
                $policy = new ContentSecurityPolicy();
-               $policy->addAllowedImageDomain('https://apps.owncloud.com');
+               $policy->addAllowedImageDomain('*');
                $templateResponse->setContentSecurityPolicy($policy);
 
                return $templateResponse;
@@ -147,139 +127,171 @@ class AppSettingsController extends Controller {
 
        /**
         * Get all available categories
-        * @return array
+        *
+        * @return JSONResponse
         */
        public function listCategories() {
+               $currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
 
-               if(!is_null($this->cache->get('listCategories'))) {
-                       return $this->cache->get('listCategories');
-               }
-               $categories = [
+               $formattedCategories = [
                        ['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled')],
                        ['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Not enabled')],
                ];
+               $categories = $this->categoryFetcher->get();
+               foreach($categories as $category) {
+                       $formattedCategories[] = [
+                               'id' => $category['id'],
+                               'ident' => $category['id'],
+                               'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
+                       ];
+               }
 
-               if($this->ocsClient->isAppStoreEnabled()) {
-                       // apps from external repo via OCS
-                       $ocs = $this->ocsClient->getCategories(\OCP\Util::getVersion());
-                       if ($ocs) {
-                               foreach($ocs as $k => $v) {
-                                       $name = str_replace('ownCloud ', '', $v);
-                                       $ident = str_replace(' ', '-', urlencode(strtolower($name)));
-                                       $categories[] = [
-                                               'id' => $k,
-                                               'ident' => $ident,
-                                               'displayName' => $name,
-                                       ];
+               return new JSONResponse($formattedCategories);
+       }
+
+       /**
+        * Get all apps for a category
+        *
+        * @param string $requestedCategory
+        * @return array
+        */
+       private function getAppsForCategory($requestedCategory) {
+               $versionParser = new VersionParser();
+               $formattedApps = [];
+               $apps = $this->appFetcher->get();
+               foreach($apps as $app) {
+
+                       // Skip all apps not in the requested category
+                       $isInCategory = false;
+                       foreach($app['categories'] as $category) {
+                               if($category === $requestedCategory) {
+                                       $isInCategory = true;
+                               }
+                       }
+                       if(!$isInCategory) {
+                               continue;
+                       }
+
+                       $nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
+                       $nextCloudVersionDependencies = [];
+                       if($nextCloudVersion->getMinimumVersion() !== '') {
+                               $nextCloudVersionDependencies['owncloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
+                       }
+                       if($nextCloudVersion->getMaximumVersion() !== '') {
+                               $nextCloudVersionDependencies['owncloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
+                       }
+                       $phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
+                       $existsLocally = (\OC_App::getAppPath($app['id']) !== false) ? true : false;
+                       $phpDependencies = [];
+                       if($phpVersion->getMinimumVersion() !== '') {
+                               $phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
+                       }
+                       if($phpVersion->getMaximumVersion() !== '') {
+                               $phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
+                       }
+                       if(isset($app['releases'][0]['minIntSize'])) {
+                               $phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
+                       }
+                       $authors = '';
+                       foreach($app['authors'] as $key => $author) {
+                               $authors .= $author['name'];
+                               if($key !== count($app['authors']) - 1) {
+                                       $authors .= ', ';
                                }
                        }
-               }
 
-               $this->cache->set('listCategories', $categories, 3600);
+                       $currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
+
+                       $formattedApps[] = [
+                               'id' => $app['id'],
+                               'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
+                               'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
+                               'license' => $app['releases'][0]['licenses'],
+                               'author' => $authors,
+                               'shipped' => false,
+                               'version' => $app['releases'][0]['version'],
+                               'default_enable' => '',
+                               'types' => [],
+                               'documentation' => [
+                                       'admin' => $app['adminDocs'],
+                                       'user' => $app['userDocs'],
+                                       'developer' => $app['developerDocs']
+                               ],
+                               'website' => $app['website'],
+                               'bugs' => $app['issueTracker'],
+                               'detailpage' => $app['website'],
+                               'dependencies' => array_merge(
+                                       $nextCloudVersionDependencies,
+                                       $phpDependencies
+                               ),
+                               'level' => ($app['featured'] === true) ? 200 : 100,
+                               'missingMaxOwnCloudVersion' => false,
+                               'missingMinOwnCloudVersion' => false,
+                               'canInstall' => true,
+                               'preview' => $app['screenshots'][0]['url'],
+                               'score' => $app['ratingOverall'],
+                               'removable' => $existsLocally,
+                               'active' => $this->appManager->isEnabledForUser($app['id']),
+                               'needsDownload' => !$existsLocally,
+                       ];
+               }
 
-               return $categories;
+               return $formattedApps;
        }
 
        /**
         * Get all available apps in a category
         *
         * @param string $category
-        * @param bool $includeUpdateInfo Should we check whether there is an update
-        *                                in the app store?
-        * @return array
+        * @return JSONResponse
         */
-       public function listApps($category = '', $includeUpdateInfo = true) {
-               $category = $this->getCategory($category);
-               $cacheName = 'listApps-' . $category . '-' . (int) $includeUpdateInfo;
-
-               if(!is_null($this->cache->get($cacheName))) {
-                       $apps = $this->cache->get($cacheName);
-               } else {
-                       switch ($category) {
-                               // installed apps
-                               case 0:
-                                       $apps = $this->getInstalledApps($includeUpdateInfo);
-                                       usort($apps, function ($a, $b) {
-                                               $a = (string)$a['name'];
-                                               $b = (string)$b['name'];
-                                               if ($a === $b) {
-                                                       return 0;
-                                               }
-                                               return ($a < $b) ? -1 : 1;
-                                       });
-                                       $version = \OCP\Util::getVersion();
-                                       foreach($apps as $key => $app) {
-                                               if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
-                                                       $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], $version);
-
-                                                       if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) {
-                                                               $apps[$key]['level'] = $remoteAppEntry['level'];
-                                                       }
-                                               }
+       public function listApps($category = '') {
+               $appClass = new \OC_App();
+
+               switch ($category) {
+                       // installed apps
+                       case 'enabled':
+                               $apps = $appClass->listAllApps();
+                               $apps = array_filter($apps, function ($app) {
+                                       return $app['active'];
+                               });
+                               usort($apps, function ($a, $b) {
+                                       $a = (string)$a['name'];
+                                       $b = (string)$b['name'];
+                                       if ($a === $b) {
+                                               return 0;
                                        }
-                                       break;
-                               // not-installed apps
-                               case 1:
-                                       $apps = \OC_App::listAllApps(true, $includeUpdateInfo, $this->ocsClient);
-                                       $apps = array_filter($apps, function ($app) {
-                                               return !$app['active'];
-                                       });
-                                       $version = \OCP\Util::getVersion();
-                                       foreach($apps as $key => $app) {
-                                               if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
-                                                       $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], $version);
-
-                                                       if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) {
-                                                               $apps[$key]['level'] = $remoteAppEntry['level'];
-                                                       }
-                                               }
+                                       return ($a < $b) ? -1 : 1;
+                               });
+                               break;
+                       // disabled  apps
+                       case 'disabled':
+                               $apps = $appClass->listAllApps();
+                               $apps = array_filter($apps, function ($app) {
+                                       return !$app['active'];
+                               });
+                               usort($apps, function ($a, $b) {
+                                       $a = (string)$a['name'];
+                                       $b = (string)$b['name'];
+                                       if ($a === $b) {
+                                               return 0;
                                        }
-                                       usort($apps, function ($a, $b) {
-                                               $a = (string)$a['name'];
-                                               $b = (string)$b['name'];
-                                               if ($a === $b) {
-                                                       return 0;
-                                               }
-                                               return ($a < $b) ? -1 : 1;
-                                       });
-                                       break;
-                               default:
-                                       $filter = $this->config->getSystemValue('appstore.experimental.enabled', false) ? 'all' : 'approved';
-
-                                       $apps = \OC_App::getAppstoreApps($filter, $category, $this->ocsClient);
-                                       if (!$apps) {
-                                               $apps = array();
-                                       } else {
-                                               // don't list installed apps
-                                               $installedApps = $this->getInstalledApps(false);
-                                               $installedApps = array_map(function ($app) {
-                                                       if (isset($app['ocsid'])) {
-                                                               return $app['ocsid'];
-                                                       }
-                                                       return $app['id'];
-                                               }, $installedApps);
-                                               $apps = array_filter($apps, function ($app) use ($installedApps) {
-                                                       return !in_array($app['id'], $installedApps);
-                                               });
-
-                                               // show tooltip if app is downloaded from remote server
-                                               $inactiveApps = $this->getInactiveApps();
-                                               foreach ($apps as &$app) {
-                                                       $app['needsDownload'] = !in_array($app['id'], $inactiveApps);
-                                               }
+                                       return ($a < $b) ? -1 : 1;
+                               });
+                               break;
+                       default:
+                               $apps = $this->getAppsForCategory($category);
+
+                               // sort by score
+                               usort($apps, function ($a, $b) {
+                                       $a = (int)$a['score'];
+                                       $b = (int)$b['score'];
+                                       if ($a === $b) {
+                                               return 0;
                                        }
-
-                                       // sort by score
-                                       usort($apps, function ($a, $b) {
-                                               $a = (int)$a['score'];
-                                               $b = (int)$b['score'];
-                                               if ($a === $b) {
-                                                       return 0;
-                                               }
-                                               return ($a > $b) ? -1 : 1;
-                                       });
-                                       break;
-                       }
+                                       return ($a > $b) ? -1 : 1;
+                               });
+                               break;
                }
 
                // fix groups to be an array
@@ -310,40 +322,6 @@ class AppSettingsController extends Controller {
                        return $app;
                }, $apps);
 
-               $this->cache->set($cacheName, $apps, 300);
-
-               return ['apps' => $apps, 'status' => 'success'];
-       }
-
-       /**
-        * @param bool $includeUpdateInfo Should we check whether there is an update
-        *                                in the app store?
-        * @return array
-        */
-       private function getInstalledApps($includeUpdateInfo = true) {
-               $apps = \OC_App::listAllApps(true, $includeUpdateInfo, $this->ocsClient);
-               $apps = array_filter($apps, function ($app) {
-                       return $app['active'];
-               });
-               return $apps;
-       }
-
-       /**
-        * @return array
-        */
-       private function getInactiveApps() {
-               $inactiveApps = \OC_App::listAllApps(true, false, $this->ocsClient);
-               $inactiveApps = array_filter($inactiveApps,
-                       function ($app) {
-                       return !$app['active'];
-               });
-               $inactiveApps = array_map(function($app) {
-                       if (isset($app['ocsid'])) {
-                               return $app['ocsid'];
-                       }
-                       return $app['id'];
-               }, $inactiveApps);
-               return $inactiveApps;
+               return new JSONResponse(['apps' => $apps, 'status' => 'success']);
        }
-
 }
index db4503f20e79c92d9a489406a7f007d967e88d3f..b378b3c918d8d473e2db1fbfbe598ac7badcb461 100644 (file)
@@ -31,8 +31,10 @@ OCP\JSON::callCheck();
 $groups = isset($_POST['groups']) ? (array)$_POST['groups'] : null;
 
 try {
-       $app = OC_App::cleanAppId((string)$_POST['appid']);
-       OC_App::enable($app, $groups);
+       $app = new OC_App();
+       $appId = (string)$_POST['appid'];
+       $appId = OC_App::cleanAppId($appId);
+       $app->enable($appId, $groups);
        OC_JSON::success(['data' => ['update_required' => \OC_App::shouldUpgrade($app)]]);
 } catch (Exception $e) {
        \OCP\Util::writeLog('core', $e->getMessage(), \OCP\Util::ERROR);
index 8831305e223e59bf15823dc389c790950c7945cc..75f3fea83b7315e893124a1fc21956852d4c0781 100644 (file)
@@ -29,14 +29,15 @@ if (!array_key_exists('appid', $_POST)) {
        exit;
 }
 
+$app = new OC_App();
 $appId = (string)$_POST['appid'];
 $appId = OC_App::cleanAppId($appId);
-
-$result = OC_App::installApp($appId);
+$result = $app->installApp(
+       $appId,
+       \OC::$server->getConfig(),
+       \OC::$server->getL10N('core')
+);
 if($result !== false) {
-       // FIXME: Clear the cache - move that into some sane helper method
-       \OC::$server->getMemCacheFactory()->create('settings')->remove('listApps-0');
-       \OC::$server->getMemCacheFactory()->create('settings')->remove('listApps-1');
        OC_JSON::success(array('data' => array('appid' => $appId)));
 } else {
        $l = \OC::$server->getL10N('settings');
index 0dadf401c041ded7fe83d931ccd27ac173e5ebf3..fe0e40cb273252900b2dd1374b9e3d4bf471461c 100644 (file)
@@ -415,17 +415,6 @@ span.version {
        background-position: 5px center;
        padding-left: 25px;
 }
-.app-level .approved {
-       border-color: #0082c9;
-}
-.app-level .experimental {
-       background-color: #ce3702;
-       border-color: #ce3702;
-       color: #fff;
-}
-.apps-experimental {
-       color: #ce3702;
-}
 
 .app-score {
        position: relative;
index 5fc366c492149bc784a2cdc11464887cc7565b06..ecd7543c8ce94a1bc2855d50e57b3e70ab2a1d93 100644 (file)
@@ -2,7 +2,7 @@
 
 Handlebars.registerHelper('score', function() {
        if(this.score) {
-               var score = Math.round( this.score / 10 );
+               var score = Math.round( this.score * 10 );
                var imageName = 'rating/s' + score + '.svg';
 
                return new Handlebars.SafeString('<img src="' + OC.imagePath('core', imageName) + '">');
@@ -13,10 +13,6 @@ Handlebars.registerHelper('level', function() {
        if(typeof this.level !== 'undefined') {
                if(this.level === 200) {
                        return new Handlebars.SafeString('<span class="official icon-checkmark">' + t('settings', 'Official') + '</span>');
-               } else if(this.level === 100) {
-                       return new Handlebars.SafeString('<span class="approved">' + t('settings', 'Approved') + '</span>');
-               } else {
-                       return new Handlebars.SafeString('<span class="experimental">' + t('settings', 'Experimental') + '</span>');
                }
        }
 });
index 64c4e549681f9d4164aefdcb290e29c3055d2ffa..829474ce2bba238da27a52fc83bf1e72dd340714 100644 (file)
@@ -49,7 +49,6 @@ $application->registerRoutes($this, [
                ['name' => 'AppSettings#listCategories', 'url' => '/settings/apps/categories', 'verb' => 'GET'],
                ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps', 'verb' => 'GET'],
                ['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'],
-               ['name' => 'AppSettings#changeExperimentalConfigState', 'url' => '/settings/apps/experimental', 'verb' => 'POST'],
                ['name' => 'SecuritySettings#trustedDomains', 'url' => '/settings/admin/security/trustedDomains', 'verb' => 'POST'],
                ['name' => 'Users#setDisplayName', 'url' => '/settings/users/{username}/displayName', 'verb' => 'POST'],
                ['name' => 'Users#setMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'],
index 46fd5bd0e40d87a563d50a1bec7b5255e4924185..36064f0981cb1c99e8bcaad60bc1dd074f4f0ed0 100644 (file)
@@ -30,15 +30,6 @@ script(
 </script>
 
 <script id="app-template" type="text/x-handlebars">
-       {{#if firstExperimental}}
-               <div class="section apps-experimental">
-                       <h2><?php p($l->t('Experimental applications ahead')) ?></h2>
-                       <p>
-                               <?php p($l->t('Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches.')) ?>
-                       </p>
-               </div>
-       {{/if}}
-
        <div class="section" id="app-{{id}}">
        {{#if preview}}
        <div class="app-image{{#if previewAsIcon}} app-image-icon{{/if}} hidden">
@@ -160,16 +151,6 @@ script(
                <div id="app-settings-header">
                        <button class="settings-button" data-apps-slide-toggle="#app-settings-content"></button>
                </div>
-
-               <div id="app-settings-content" class="apps-experimental">
-                       <input type="checkbox" id="enable-experimental-apps" <?php if($_['experimentalEnabled']) { print_unescaped('checked="checked"'); }?> class="checkbox">
-                       <label for="enable-experimental-apps"><?php p($l->t('Enable experimental apps')) ?></label>
-                       <p>
-                               <small>
-                                       <?php p($l->t('Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches.')) ?>
-                               </small>
-                       </p>
-               </div>
        </div>
 </div>
 <div id="app-content">
index 9dcc55e135bfd0db11168b0c35aa11be6abaa10e..fc9d04fcfe79a0e0989c3309da4a0f29914c0292 100644 (file)
@@ -2,6 +2,7 @@
 /**
  * @author Lukas Reschke <lukas@owncloud.com>
  *
+ * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
  * @copyright Copyright (c) 2015, ownCloud, Inc.
  * @license AGPL-3.0
  *
 
 namespace Tests\Settings\Controller;
 
+use OC\App\AppStore\Fetcher\AppFetcher;
+use OC\App\AppStore\Fetcher\CategoryFetcher;
 use OC\Settings\Controller\AppSettingsController;
 use OCP\AppFramework\Http\ContentSecurityPolicy;
-use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\JSONResponse;
 use OCP\AppFramework\Http\TemplateResponse;
+use OCP\ICacheFactory;
 use Test\TestCase;
 use OCP\IRequest;
 use OCP\IL10N;
@@ -32,7 +36,6 @@ use OCP\IConfig;
 use OCP\ICache;
 use OCP\INavigationManager;
 use OCP\App\IAppManager;
-use OC\OCSClient;
 
 /**
  * Class AppSettingsControllerTest
@@ -42,49 +45,43 @@ use OC\OCSClient;
 class AppSettingsControllerTest extends TestCase {
        /** @var AppSettingsController */
        private $appSettingsController;
-       /** @var IRequest */
+       /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
        private $request;
-       /** @var IL10N */
+       /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */
        private $l10n;
-       /** @var IConfig */
+       /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
        private $config;
-       /** @var ICache */
+       /** @var ICache|\PHPUnit_Framework_MockObject_MockObject */
        private $cache;
-       /** @var INavigationManager */
+       /** @var INavigationManager|\PHPUnit_Framework_MockObject_MockObject */
        private $navigationManager;
-       /** @var IAppManager */
+       /** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */
        private $appManager;
-       /** @var OCSClient */
-       private $ocsClient;
+       /** @var CategoryFetcher|\PHPUnit_Framework_MockObject_MockObject */
+       private $categoryFetcher;
+       /** @var AppFetcher|\PHPUnit_Framework_MockObject_MockObject */
+       private $appFetcher;
 
        public function setUp() {
                parent::setUp();
 
-               $this->request = $this->getMockBuilder('\OCP\IRequest')
-                       ->disableOriginalConstructor()->getMock();
-               $this->l10n = $this->getMockBuilder('\OCP\IL10N')
-                       ->disableOriginalConstructor()->getMock();
+               $this->request = $this->createMock(IRequest::class);
+               $this->l10n = $this->createMock(IL10N::class);
                $this->l10n->expects($this->any())
                        ->method('t')
                        ->will($this->returnArgument(0));
-               $this->config = $this->getMockBuilder('\OCP\IConfig')
-                       ->disableOriginalConstructor()->getMock();
-               $cacheFactory = $this->getMockBuilder('\OCP\ICacheFactory')
-                       ->disableOriginalConstructor()->getMock();
-               $this->cache = $this->getMockBuilder('\OCP\ICache')
-                       ->disableOriginalConstructor()->getMock();
+               $this->config = $this->createMock(IConfig::class);
+               $cacheFactory = $this->createMock(ICacheFactory::class);
+               $this->cache = $this->createMock(ICache::class);
                $cacheFactory
                        ->expects($this->once())
                        ->method('create')
                        ->with('settings')
                        ->will($this->returnValue($this->cache));
-
-               $this->navigationManager = $this->getMockBuilder('\OCP\INavigationManager')
-                       ->disableOriginalConstructor()->getMock();
-               $this->appManager = $this->getMockBuilder('\OCP\App\IAppManager')
-                       ->disableOriginalConstructor()->getMock();
-               $this->ocsClient = $this->getMockBuilder('\OC\OCSClient')
-                       ->disableOriginalConstructor()->getMock();
+               $this->navigationManager = $this->createMock(INavigationManager::class);
+               $this->appManager = $this->createMock(IAppManager::class);
+               $this->categoryFetcher = $this->createMock(CategoryFetcher::class);
+               $this->appFetcher = $this->createMock(AppFetcher::class);
 
                $this->appSettingsController = new AppSettingsController(
                        'settings',
@@ -94,43 +91,13 @@ class AppSettingsControllerTest extends TestCase {
                        $cacheFactory,
                        $this->navigationManager,
                        $this->appManager,
-                       $this->ocsClient
+                       $this->categoryFetcher,
+                       $this->appFetcher
                );
        }
 
-       public function testChangeExperimentalConfigStateTrue() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('setSystemValue')
-                       ->with('appstore.experimental.enabled', true);
-               $this->appManager
-                       ->expects($this->once())
-                       ->method('clearAppsCache');
-               $this->assertEquals(new DataResponse(), $this->appSettingsController->changeExperimentalConfigState(true));
-       }
-
-       public function testChangeExperimentalConfigStateFalse() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('setSystemValue')
-                       ->with('appstore.experimental.enabled', false);
-               $this->appManager
-                       ->expects($this->once())
-                       ->method('clearAppsCache');
-               $this->assertEquals(new DataResponse(), $this->appSettingsController->changeExperimentalConfigState(false));
-       }
-
-       public function testListCategoriesCached() {
-               $this->cache
-                       ->expects($this->exactly(2))
-                       ->method('get')
-                       ->with('listCategories')
-                       ->will($this->returnValue(['CachedArray']));
-               $this->assertSame(['CachedArray'], $this->appSettingsController->listCategories());
-       }
-
-       public function testListCategoriesNotCachedWithoutAppStore() {
-               $expected = [
+       public function testListCategories() {
+               $expected = new JSONResponse([
                        [
                                'id' => 0,
                                'ident' => 'enabled',
@@ -141,115 +108,69 @@ class AppSettingsControllerTest extends TestCase {
                                'ident' => 'disabled',
                                'displayName' => 'Not enabled',
                        ],
-               ];
-               $this->cache
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with('listCategories')
-                       ->will($this->returnValue(null));
-               $this->cache
-                       ->expects($this->once())
-                       ->method('set')
-                       ->with('listCategories', $expected, 3600);
-
-
-               $this->assertSame($expected, $this->appSettingsController->listCategories());
-       }
-
-       public function testListCategoriesNotCachedWithAppStore() {
-               $expected = [
                        [
-                               'id' => 0,
-                               'ident' => 'enabled',
-                               'displayName' => 'Enabled',
+                               'id' => 'auth',
+                               'ident' => 'auth',
+                               'displayName' => 'Authentication & authorization',
                        ],
                        [
-                               'id' => 1,
-                               'ident' => 'disabled',
-                               'displayName' => 'Not enabled',
+                               'id' => 'customization',
+                               'ident' => 'customization',
+                               'displayName' => 'Customization',
                        ],
                        [
-                               'id' => 0,
-                               'ident' => 'tools',
-                               'displayName' => 'Tools',
+                               'id' => 'files',
+                               'ident' => 'files',
+                               'displayName' => 'Files',
                        ],
                        [
-                               'id' => 1,
-                               'ident' => 'games',
-                               'displayName' => 'Games',
+                               'id' => 'integration',
+                               'ident' => 'integration',
+                               'displayName' => 'Integration',
                        ],
                        [
-                               'id' => 2,
-                               'ident' => 'productivity',
-                               'displayName' => 'Productivity',
+                               'id' => 'monitoring',
+                               'ident' => 'monitoring',
+                               'displayName' => 'Monitoring',
                        ],
                        [
-                               'id' => 3,
+                               'id' => 'multimedia',
                                'ident' => 'multimedia',
                                'displayName' => 'Multimedia',
                        ],
-               ];
+                       [
+                               'id' => 'office',
+                               'ident' => 'office',
+                               'displayName' => 'Office & text',
+                       ],
+                       [
+                               'id' => 'organization',
+                               'ident' => 'organization',
+                               'displayName' => 'Organization',
+                       ],
+                       [
+                               'id' => 'social',
+                               'ident' => 'social',
+                               'displayName' => 'Social & communication',
+                       ],
+                       [
+                               'id' => 'tools',
+                               'ident' => 'tools',
+                               'displayName' => 'Tools',
+                       ],
+               ]);
 
-               $this->cache
+               $this->categoryFetcher
                        ->expects($this->once())
                        ->method('get')
-                       ->with('listCategories')
-                       ->will($this->returnValue(null));
-               $this->cache
-                       ->expects($this->once())
-                       ->method('set')
-                       ->with('listCategories', $expected, 3600);
+                       ->willReturn(json_decode('[{"id":"auth","translations":{"cs":{"name":"Autentizace & autorizace","description":"Aplikace poskytující služby dodatečného ověření nebo přihlášení"},"hu":{"name":"Azonosítás és hitelesítés","description":"Apps that provide additional authentication or authorization services"},"de":{"name":"Authentifizierung & Authorisierung","description":"Apps die zusätzliche Autentifizierungs- oder Autorisierungsdienste bereitstellen"},"nl":{"name":"Authenticatie & authorisatie","description":"Apps die aanvullende authenticatie- en autorisatiediensten bieden"},"nb":{"name":"Pålogging og tilgangsstyring","description":"Apper for å tilby ekstra pålogging eller tilgangsstyring"},"it":{"name":"Autenticazione e autorizzazione","description":"Apps that provide additional authentication or authorization services"},"fr":{"name":"Authentification et autorisations","description":"Applications qui fournissent des services d\'authentification ou d\'autorisations additionnels."},"ru":{"name":"Аутентификация и авторизация","description":"Apps that provide additional authentication or authorization services"},"en":{"name":"Authentication & authorization","description":"Apps that provide additional authentication or authorization services"}}},{"id":"customization","translations":{"cs":{"name":"Přizpůsobení","description":"Motivy a aplikace měnící rozvržení a uživatelské rozhraní"},"it":{"name":"Personalizzazione","description":"Applicazioni di temi, modifiche della disposizione e UX"},"de":{"name":"Anpassung","description":"Apps zur Änderung von Themen, Layout und Benutzererfahrung"},"hu":{"name":"Személyre szabás","description":"Témák, elrendezések felhasználói felület módosító alkalmazások"},"nl":{"name":"Maatwerk","description":"Thema\'s, layout en UX aanpassingsapps"},"nb":{"name":"Tilpasning","description":"Apper for å endre Tema, utseende og brukeropplevelse"},"fr":{"name":"Personalisation","description":"Thèmes, apparence et applications modifiant l\'expérience utilisateur"},"ru":{"name":"Настройка","description":"Themes, layout and UX change apps"},"en":{"name":"Customization","description":"Themes, layout and UX change apps"}}},{"id":"files","translations":{"cs":{"name":"Soubory","description":"Aplikace rozšiřující správu souborů nebo aplikaci Soubory"},"it":{"name":"File","description":"Applicazioni di gestione dei file ed estensione dell\'applicazione FIle"},"de":{"name":"Dateien","description":"Dateimanagement sowie Erweiterungs-Apps für die Dateien-App"},"hu":{"name":"Fájlok","description":"Fájl kezelő és kiegészítő alkalmazások"},"nl":{"name":"Bestanden","description":"Bestandebeheer en uitbreidingen van bestand apps"},"nb":{"name":"Filer","description":"Apper for filhåndtering og filer"},"fr":{"name":"Fichiers","description":"Applications de gestion de fichiers et extensions à l\'application Fichiers"},"ru":{"name":"Файлы","description":"Расширение: файлы и управление файлами"},"en":{"name":"Files","description":"File management and Files app extension apps"}}},{"id":"integration","translations":{"it":{"name":"Integrazione","description":"Applicazioni che collegano Nextcloud con altri servizi e piattaforme"},"hu":{"name":"Integráció","description":"Apps that connect Nextcloud with other services and platforms"},"nl":{"name":"Integratie","description":"Apps die Nextcloud verbinden met andere services en platformen"},"nb":{"name":"Integrasjon","description":"Apper som kobler Nextcloud med andre tjenester og plattformer"},"de":{"name":"Integration","description":"Apps die Nextcloud mit anderen Diensten und Plattformen verbinden"},"cs":{"name":"Propojení","description":"Aplikace propojující NextCloud s dalšími službami a platformami"},"fr":{"name":"Intégration","description":"Applications qui connectent Nextcloud avec d\'autres services et plateformes"},"ru":{"name":"Интеграция","description":"Приложения, соединяющие Nextcloud с другими службами и платформами"},"en":{"name":"Integration","description":"Apps that connect Nextcloud with other services and platforms"}}},{"id":"monitoring","translations":{"nb":{"name":"Overvåking","description":"Apper for statistikk, systemdiagnose og aktivitet"},"it":{"name":"Monitoraggio","description":"Applicazioni di statistiche, diagnostica di sistema e attività"},"de":{"name":"Überwachung","description":"Datenstatistiken-, Systemdiagnose- und Aktivitäten-Apps"},"hu":{"name":"Megfigyelés","description":"Data statistics, system diagnostics and activity apps"},"nl":{"name":"Monitoren","description":"Gegevensstatistiek, systeem diagnose en activiteit apps"},"cs":{"name":"Kontrola","description":"Datové statistiky, diagnózy systému a aktivity aplikací"},"fr":{"name":"Surveillance","description":"Applications de statistiques sur les données, de diagnostics systèmes et d\'activité."},"ru":{"name":"Мониторинг","description":"Статистика данных, диагностика системы и активность приложений"},"en":{"name":"Monitoring","description":"Data statistics, system diagnostics and activity apps"}}},{"id":"multimedia","translations":{"nb":{"name":"Multimedia","description":"Apper for lyd, film og bilde"},"it":{"name":"Multimedia","description":"Applicazioni per audio, video e immagini"},"de":{"name":"Multimedia","description":"Audio-, Video- und Bilder-Apps"},"hu":{"name":"Multimédia","description":"Hang, videó és kép alkalmazások"},"nl":{"name":"Multimedia","description":"Audio, video en afbeelding apps"},"en":{"name":"Multimedia","description":"Audio, video and picture apps"},"cs":{"name":"Multimédia","description":"Aplikace audia, videa a obrázků"},"fr":{"name":"Multimédia","description":"Applications audio, vidéo et image"},"ru":{"name":"Мультимедиа","description":"Приложение аудио, видео и изображения"}}},{"id":"office","translations":{"nb":{"name":"Kontorstøtte og tekst","description":"Apper for Kontorstøtte og tekstbehandling"},"it":{"name":"Ufficio e testo","description":"Applicazione per ufficio ed elaborazione di testi"},"de":{"name":"Büro & Text","description":"Büro- und Textverarbeitungs-Apps"},"hu":{"name":"Iroda és szöveg","description":"Irodai és szöveg feldolgozó alkalmazások"},"nl":{"name":"Office & tekst","description":"Office en tekstverwerkingsapps"},"cs":{"name":"Kancelář a text","description":"Aplikace pro kancelář a zpracování textu"},"fr":{"name":"Bureautique & texte","description":"Applications de bureautique et de traitement de texte"},"en":{"name":"Office & text","description":"Office and text processing apps"}}},{"id":"organization","translations":{"nb":{"name":"Organisering","description":"Apper for tidsstyring, oppgaveliste og kalender"},"it":{"name":"Organizzazione","description":"Applicazioni di gestione del tempo, elenco delle cose da fare e calendario"},"hu":{"name":"Szervezet","description":"Időbeosztás, teendő lista és naptár alkalmazások"},"nl":{"name":"Organisatie","description":"Tijdmanagement, takenlijsten en agenda apps"},"cs":{"name":"Organizace","description":"Aplikace pro správu času, plánování a kalendáře"},"de":{"name":"Organisation","description":"Time management, Todo list and calendar apps"},"fr":{"name":"Organisation","description":"Applications de gestion du temps, de listes de tâches et d\'agendas"},"ru":{"name":"Организация","description":"Приложения по управлению временем, список задач и календарь"},"en":{"name":"Organization","description":"Time management, Todo list and calendar apps"}}},{"id":"social","translations":{"nb":{"name":"Sosialt og kommunikasjon","description":"Apper for meldinger, kontakthåndtering og sosiale medier"},"it":{"name":"Sociale e comunicazione","description":"Applicazioni di messaggistica, gestione dei contatti e reti sociali"},"de":{"name":"Kommunikation","description":"Nachrichten-, Kontaktverwaltungs- und Social-Media-Apps"},"hu":{"name":"Közösségi és kommunikáció","description":"Üzenetküldő, kapcsolat kezelő és közösségi média alkalmazások"},"nl":{"name":"Sociaal & communicatie","description":"Messaging, contactbeheer en social media apps"},"cs":{"name":"Sociální sítě a komunikace","description":"Aplikace pro zasílání zpráv, správu kontaktů a sociální sítě"},"fr":{"name":"Social & communication","description":"Applications de messagerie, de gestion de contacts et de réseaux sociaux"},"ru":{"name":"Социальное и связь","description":"Общение, управление контактами и социальное медиа-приложение"},"en":{"name":"Social & communication","description":"Messaging, contact management and social media apps"}}},{"id":"tools","translations":{"nb":{"name":"Verktøy","description":"Alt annet"},"it":{"name":"Strumenti","description":"Tutto il resto"},"hu":{"name":"Eszközök","description":"Minden más"},"nl":{"name":"Tools","description":"De rest"},"de":{"name":"Werkzeuge","description":"Alles Andere"},"en":{"name":"Tools","description":"Everything else"},"cs":{"name":"Nástroje","description":"Vše ostatní"},"fr":{"name":"Outils","description":"Tout le reste"},"ru":{"name":"Приложения","description":"Что-то еще"}}}]', true));
 
-               $this->ocsClient
-                       ->expects($this->once())
-                       ->method('isAppStoreEnabled')
-                       ->will($this->returnValue(true));
-               $this->ocsClient
-                       ->expects($this->once())
-                       ->method('getCategories')
-                       ->will($this->returnValue(
-                               [
-                                       'ownCloud Tools',
-                                       'Games',
-                                       'ownCloud Productivity',
-                                       'Multimedia',
-                               ]
-                       ));
-
-               $this->assertSame($expected, $this->appSettingsController->listCategories());
+               $this->assertEquals($expected, $this->appSettingsController->listCategories());
        }
 
        public function testViewApps() {
                $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstore.experimental.enabled', false);
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->navigationManager
                        ->expects($this->once())
-                       ->method('setActiveEntry')
-                       ->with('core_apps');
-
-               $policy = new ContentSecurityPolicy();
-               $policy->addAllowedImageDomain('https://apps.owncloud.com');
-
-               $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'enabled', 'appstoreEnabled' => true], 'user');
-               $expected->setContentSecurityPolicy($policy);
-
-               $this->assertEquals($expected, $this->appSettingsController->viewApps());
-       }
-
-       public function testViewAppsNotEnabled() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstore.experimental.enabled', false);
-               $this->config
-                       ->expects($this->at(1))
                        ->method('getSystemValue')
                        ->with('appstoreenabled', true)
                        ->will($this->returnValue(true));
@@ -259,21 +180,17 @@ class AppSettingsControllerTest extends TestCase {
                        ->with('core_apps');
 
                $policy = new ContentSecurityPolicy();
-               $policy->addAllowedImageDomain('https://apps.owncloud.com');
+               $policy->addAllowedImageDomain('*');
 
-               $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'disabled', 'appstoreEnabled' => true], 'user');
+               $expected = new TemplateResponse('settings', 'apps', ['category' => 'enabled', 'appstoreEnabled' => true], 'user');
                $expected->setContentSecurityPolicy($policy);
 
-               $this->assertEquals($expected, $this->appSettingsController->viewApps('disabled'));
+               $this->assertEquals($expected, $this->appSettingsController->viewApps());
        }
 
        public function testViewAppsAppstoreNotEnabled() {
                $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstore.experimental.enabled', false);
-               $this->config
-                       ->expects($this->at(1))
+                       ->expects($this->once())
                        ->method('getSystemValue')
                        ->with('appstoreenabled', true)
                        ->will($this->returnValue(false));
@@ -283,9 +200,9 @@ class AppSettingsControllerTest extends TestCase {
                        ->with('core_apps');
 
                $policy = new ContentSecurityPolicy();
-               $policy->addAllowedImageDomain('https://apps.owncloud.com');
+               $policy->addAllowedImageDomain('*');
 
-               $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'enabled', 'appstoreEnabled' => false], 'user');
+               $expected = new TemplateResponse('settings', 'apps', ['category' => 'enabled', 'appstoreEnabled' => false], 'user');
                $expected->setContentSecurityPolicy($policy);
 
                $this->assertEquals($expected, $this->appSettingsController->viewApps());
diff --git a/tests/lib/App/AppStore/Fetcher/AppFetcherTest.php b/tests/lib/App/AppStore/Fetcher/AppFetcherTest.php
new file mode 100644 (file)
index 0000000..3b0418a
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\App\AppStore\Fetcher;
+
+use OC\App\AppStore\Fetcher\AppFetcher;
+
+class AppFetcherTest extends FetcherBase {
+       public function setUp() {
+               parent::setUp();
+               $this->fileName = 'apps.json';
+               $this->endpoint = 'https://apps.nextcloud.com/api/v1/platform/9.2.0/apps.json';
+
+               $this->fetcher = new AppFetcher(
+                       $this->appData,
+                       $this->clientService,
+                       $this->timeFactory,
+                       $this->config
+               );
+       }
+}
diff --git a/tests/lib/App/AppStore/Fetcher/CategoryFetcherTest.php b/tests/lib/App/AppStore/Fetcher/CategoryFetcherTest.php
new file mode 100644 (file)
index 0000000..db43541
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\App\AppStore\Fetcher;
+
+use OC\App\AppStore\Fetcher\CategoryFetcher;
+
+class CategoryFetcherTest extends FetcherBase  {
+       public function setUp() {
+               parent::setUp();
+               $this->fileName = 'categories.json';
+               $this->endpoint = 'https://apps.nextcloud.com/api/v1/categories.json';
+
+               $this->fetcher = new CategoryFetcher(
+                       $this->appData,
+                       $this->clientService,
+                       $this->timeFactory
+               );
+       }
+}
diff --git a/tests/lib/App/AppStore/Fetcher/FetcherBase.php b/tests/lib/App/AppStore/Fetcher/FetcherBase.php
new file mode 100644 (file)
index 0000000..66df81f
--- /dev/null
@@ -0,0 +1,246 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\App\AppStore\Fetcher;
+
+use OC\App\AppStore\Fetcher\AppFetcher;
+use OC\App\AppStore\Fetcher\Fetcher;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
+use OCP\Http\Client\IClient;
+use OCP\Http\Client\IClientService;
+use OCP\Http\Client\IResponse;
+use OCP\IConfig;
+use Test\TestCase;
+
+abstract class FetcherBase extends TestCase {
+       /** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */
+       protected $appData;
+       /** @var IClientService|\PHPUnit_Framework_MockObject_MockObject */
+       protected $clientService;
+       /** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */
+       protected $timeFactory;
+       /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
+       protected $config;
+       /** @var Fetcher */
+       protected $fetcher;
+       /** @var string */
+       protected $fileName;
+       /** @var string */
+       protected $endpoint;
+
+       public function setUp() {
+               parent::setUp();
+               $this->appData = $this->createMock(IAppData::class);
+               $this->clientService = $this->createMock(IClientService::class);
+               $this->timeFactory = $this->createMock(ITimeFactory::class);
+               $this->config = $this->createMock(IConfig::class);
+       }
+
+       public function testGetWithAlreadyExistingFileAndUpToDateTimestamp() {
+               $folder = $this->createMock(ISimpleFolder::class);
+               $file = $this->createMock(ISimpleFile::class);
+               $this->appData
+                       ->expects($this->once())
+                       ->method('getFolder')
+                       ->with('/')
+                       ->willReturn($folder);
+               $folder
+                       ->expects($this->once())
+                       ->method('getFile')
+                       ->with($this->fileName)
+                       ->willReturn($file);
+               $file
+                       ->expects($this->once())
+                       ->method('getContent')
+                       ->willReturn('{"timestamp":1200,"data":[{"id":"MyApp"}]}');
+               $this->timeFactory
+                       ->expects($this->once())
+                       ->method('getTime')
+                       ->willReturn(1499);
+
+               $expected = [
+                       [
+                               'id' => 'MyApp',
+                       ],
+               ];
+               $this->assertSame($expected, $this->fetcher->get());
+       }
+
+       public function testGetWithNotExistingFileAndUpToDateTimestamp() {
+               $folder = $this->createMock(ISimpleFolder::class);
+               $file = $this->createMock(ISimpleFile::class);
+               $this->appData
+                       ->expects($this->once())
+                       ->method('getFolder')
+                       ->with('/')
+                       ->willReturn($folder);
+               $folder
+                       ->expects($this->at(0))
+                       ->method('getFile')
+                       ->with($this->fileName)
+                       ->willThrowException(new NotFoundException());
+               $folder
+                       ->expects($this->at(1))
+                       ->method('newFile')
+                       ->with($this->fileName)
+                       ->willReturn($file);
+               $client = $this->createMock(IClient::class);
+               $this->clientService
+                       ->expects($this->once())
+                       ->method('newClient')
+                       ->willReturn($client);
+               $response = $this->createMock(IResponse::class);
+               $client
+                       ->expects($this->once())
+                       ->method('get')
+                       ->with($this->endpoint)
+                       ->willReturn($response);
+               $response
+                       ->expects($this->once())
+                       ->method('getBody')
+                       ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]');
+               $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502}';
+               $file
+                       ->expects($this->at(0))
+                       ->method('putContent')
+                       ->with($fileData);
+               $file
+                       ->expects($this->at(1))
+                       ->method('getContent')
+                       ->willReturn($fileData);
+               $this->timeFactory
+                       ->expects($this->at(0))
+                       ->method('getTime')
+                       ->willReturn(1502);
+
+               $expected = [
+                       [
+                               'id' => 'MyNewApp',
+                               'foo' => 'foo',
+                       ],
+                       [
+                               'id' => 'bar',
+                       ],
+               ];
+               $this->assertSame($expected, $this->fetcher->get());
+       }
+
+       public function testGetWithAlreadyExistingFileAndOutdatedTimestamp() {
+               $folder = $this->createMock(ISimpleFolder::class);
+               $file = $this->createMock(ISimpleFile::class);
+               $this->appData
+                       ->expects($this->once())
+                       ->method('getFolder')
+                       ->with('/')
+                       ->willReturn($folder);
+               $folder
+                       ->expects($this->once())
+                       ->method('getFile')
+                       ->with($this->fileName)
+                       ->willReturn($file);
+               $file
+                       ->expects($this->at(0))
+                       ->method('getContent')
+                       ->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}}}');
+               $this->timeFactory
+                       ->expects($this->at(0))
+                       ->method('getTime')
+                       ->willReturn(1501);
+               $client = $this->createMock(IClient::class);
+               $this->clientService
+                       ->expects($this->once())
+                       ->method('newClient')
+                       ->willReturn($client);
+               $response = $this->createMock(IResponse::class);
+               $client
+                       ->expects($this->once())
+                       ->method('get')
+                       ->with($this->endpoint)
+                       ->willReturn($response);
+               $response
+                       ->expects($this->once())
+                       ->method('getBody')
+                       ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]');
+               $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502}';
+               $file
+                       ->expects($this->at(1))
+                       ->method('putContent')
+                       ->with($fileData);
+               $file
+                       ->expects($this->at(2))
+                       ->method('getContent')
+                       ->willReturn($fileData);
+               $this->timeFactory
+                       ->expects($this->at(1))
+                       ->method('getTime')
+                       ->willReturn(1502);
+
+               $expected = [
+                       [
+                               'id' => 'MyNewApp',
+                               'foo' => 'foo',
+                       ],
+                       [
+                               'id' => 'bar',
+                       ],
+               ];
+               $this->assertSame($expected, $this->fetcher->get());
+       }
+
+       public function testGetWithExceptionInClient() {
+               $folder = $this->createMock(ISimpleFolder::class);
+               $file = $this->createMock(ISimpleFile::class);
+               $this->appData
+                       ->expects($this->once())
+                       ->method('getFolder')
+                       ->with('/')
+                       ->willReturn($folder);
+               $folder
+                       ->expects($this->once())
+                       ->method('getFile')
+                       ->with($this->fileName)
+                       ->willReturn($file);
+               $file
+                       ->expects($this->at(0))
+                       ->method('getContent')
+                       ->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}}}');
+               $this->timeFactory
+                       ->expects($this->at(0))
+                       ->method('getTime')
+                       ->willReturn(1501);
+               $client = $this->createMock(IClient::class);
+               $this->clientService
+                       ->expects($this->once())
+                       ->method('newClient')
+                       ->willReturn($client);
+               $client
+                       ->expects($this->once())
+                       ->method('get')
+                       ->with($this->endpoint)
+                       ->willThrowException(new \Exception());
+
+               $this->assertSame([], $this->fetcher->get());
+       }
+}
diff --git a/tests/lib/App/AppStore/Version/VersionParserTest.php b/tests/lib/App/AppStore/Version/VersionParserTest.php
new file mode 100644 (file)
index 0000000..ccf557e
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\App\AppStore\Version;
+
+use OC\App\AppStore\Version\Version;
+use OC\App\AppStore\Version\VersionParser;
+use Test\TestCase;
+
+class VersionParserTest extends TestCase  {
+       /** @var VersionParser */
+       private $versionParser;
+
+       public function setUp() {
+               parent::setUp();
+               $this->versionParser = new VersionParser();
+       }
+
+       /**
+        * @return array
+        */
+       public function versionProvider() {
+               return [
+                       [
+                               '*',
+                               new Version('', ''),
+                       ],
+                       [
+                               '<=8.1.2',
+                               new Version('', '8.1.2'),
+                       ],
+                       [
+                               '<=9',
+                               new Version('', '9'),
+                       ],
+                       [
+                               '>=9.3.2',
+                               new Version('9.3.2', ''),
+                       ],
+                       [
+                               '>=8.1.2 <=9.3.2',
+                               new Version('8.1.2', '9.3.2'),
+                       ],
+                       [
+                               '>=8.2 <=9.1',
+                               new Version('8.2', '9.1'),
+                       ],
+                       [
+                               '>=9 <=11',
+                               new Version('9', '11'),
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider versionProvider
+        *
+        * @param string $input
+        * @param Version $expected
+        */
+       public function testGetVersion($input,
+                                                                  Version $expected) {
+               $this->assertEquals($expected, $this->versionParser->getVersion($input));
+       }
+
+}
diff --git a/tests/lib/App/AppStore/Version/VersionTest.php b/tests/lib/App/AppStore/Version/VersionTest.php
new file mode 100644 (file)
index 0000000..969c96a
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\App\AppStore\Version;
+
+use OC\App\AppStore\Version\Version;
+use Test\TestCase;
+
+class VersionTest extends TestCase {
+       public function testGetMinimumVersion() {
+               $version = new Version('9', '10');
+               $this->assertSame('9', $version->getMinimumVersion());
+       }
+
+       public function testGetMaximumVersion() {
+               $version = new Version('9', '10');
+               $this->assertSame('10', $version->getMaximumVersion());
+       }
+}
diff --git a/tests/lib/OCSClientTest.php b/tests/lib/OCSClientTest.php
deleted file mode 100644 (file)
index d4bfd77..0000000
+++ /dev/null
@@ -1,1132 +0,0 @@
-<?php
-/**
- * @author Lukas Reschke <lukas@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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 Test;
-
-use OC\OCSClient;
-use OCP\Http\Client\IClient;
-use OCP\Http\Client\IClientService;
-use OCP\Http\Client\IResponse;
-use OCP\IConfig;
-use OCP\ILogger;
-
-/**
- * Class OCSClientTest
- */
-class OCSClientTest extends \Test\TestCase {
-       /** @var OCSClient */
-       private $ocsClient;
-       /** @var IConfig */
-       private $config;
-       /** @var IClientService */
-       private $clientService;
-       /** @var ILogger */
-       private $logger;
-
-       public function setUp() {
-               parent::setUp();
-
-               $this->config = $this->getMockBuilder('\OCP\IConfig')
-                       ->disableOriginalConstructor()->getMock();
-               $this->clientService = $this->createMock(IClientService::class);
-               $this->logger = $this->createMock(ILogger::class);
-
-               $this->ocsClient = new OCSClient(
-                       $this->clientService,
-                       $this->config,
-                       $this->logger
-               );
-       }
-
-       public function testIsAppStoreEnabledSuccess() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->assertTrue($this->ocsClient->isAppStoreEnabled());
-       }
-
-       public function testIsAppStoreEnabledFail() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(false));
-               $this->assertFalse($this->ocsClient->isAppStoreEnabled());
-       }
-
-       public function testGetAppStoreUrl() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-               $this->assertSame('https://api.owncloud.com/v1', self::invokePrivate($this->ocsClient, 'getAppStoreUrl'));
-       }
-
-       public function testGetCategoriesDisabledAppStore() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(false));
-               $this->assertNull($this->ocsClient->getCategories([8, 1, 0, 7]));
-       }
-
-       public function testGetCategoriesExceptionClient() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/categories',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->throwException(new \Exception('TheErrorMessage')));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get categories: TheErrorMessage',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertNull($this->ocsClient->getCategories([8, 1, 0, 7]));
-       }
-
-       public function testGetCategoriesParseError() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('MyInvalidXml'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/categories',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get categories, content was no valid XML',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertNull($this->ocsClient->getCategories([8, 1, 0, 7]));
-       }
-
-       public function testGetCategoriesSuccessful() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('<?xml version="1.0"?>
-                               <ocs>
-                                <meta>
-                                 <status>ok</status>
-                                 <statuscode>100</statuscode>
-                                 <message></message>
-                                 <totalitems>6</totalitems>
-                                </meta>
-                                <data>
-                                 <category>
-                                  <id>920</id>
-                                  <name>ownCloud Multimedia</name>
-                                 </category>
-                                 <category>
-                                  <id>921</id>
-                                  <name>ownCloud PIM</name>
-                                 </category>
-                                 <category>
-                                  <id>922</id>
-                                  <name>ownCloud Productivity</name>
-                                 </category>
-                                 <category>
-                                  <id>923</id>
-                                  <name>ownCloud Game</name>
-                                 </category>
-                                 <category>
-                                  <id>924</id>
-                                  <name>ownCloud Tool</name>
-                                 </category>
-                                 <category>
-                                  <id>925</id>
-                                  <name>ownCloud other</name>
-                                 </category>
-                                </data>
-                               </ocs>
-                               '));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/categories',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $expected = [
-                       920 => 'ownCloud Multimedia',
-                       921 => 'ownCloud PIM',
-                       922 => 'ownCloud Productivity',
-                       923 => 'ownCloud Game',
-                       924 => 'ownCloud Tool',
-                       925 => 'ownCloud other',
-               ];
-               $this->assertSame($expected, $this->ocsClient->getCategories([8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationsDisabledAppStore() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(false));
-               $this->assertSame([], $this->ocsClient->getApplications([], 1, 'approved', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationsExceptionClient() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/data',
-                               [
-                                       'timeout' => 20,
-                                       'query' => [
-                                               'version' => implode('x', [8, 1, 0, 7]),
-                                               'filter' => 'approved',
-                                               'categories' => '815x1337',
-                                               'sortmode' => 'new',
-                                               'page' => 1,
-                                               'pagesize' => 100,
-                                               'approved' => 'approved',
-                                       ],
-                               ]
-                       )
-                       ->will($this->throwException(new \Exception('TheErrorMessage')));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get applications: TheErrorMessage',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertSame([], $this->ocsClient->getApplications([815, 1337], 1, 'approved', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationsParseError() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('MyInvalidXml'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/data',
-                               [
-                                       'timeout' => 20,
-                                       'query' => [
-                                               'version' => implode('x', [8, 1, 0, 7]),
-                                               'filter' => 'approved',
-                                               'categories' => '815x1337',
-                                               'sortmode' => 'new',
-                                               'page' => 1,
-                                               'pagesize' => 100,
-                                               'approved' => 'approved',
-                                       ],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get applications, content was no valid XML',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertSame([], $this->ocsClient->getApplications([815, 1337], 1, 'approved', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationsSuccessful() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('<?xml version="1.0"?>
-                               <ocs>
-                                <meta>
-                                 <status>ok</status>
-                                 <statuscode>100</statuscode>
-                                 <message></message>
-                                 <totalitems>2</totalitems>
-                                 <itemsperpage>100</itemsperpage>
-                                </meta>
-                                <data>
-                                 <content details="summary">
-                                  <id>168707</id>
-                                  <name>Calendar 8.0</name>
-                                  <version>0.6.4</version>
-                                  <label>recommended</label>
-                                  <changed>2015-02-09T15:23:56+01:00</changed>
-                                  <created>2015-01-26T04:35:19+01:00</created>
-                                  <typeid>921</typeid>
-                                  <typename>ownCloud PIM</typename>
-                                  <language></language>
-                                  <personid>owncloud</personid>
-                                  <profilepage>http://opendesktop.org/usermanager/search.php?username=owncloud</profilepage>
-                                  <downloads>5393</downloads>
-                                  <score>60</score>
-                                  <description>Calendar App for ownCloud</description>
-                                  <comments>7</comments>
-                                  <fans>10</fans>
-                                  <licensetype>16</licensetype>
-                                  <approved>0</approved>
-                                  <category>1</category>
-                                  <license>AGPL</license>
-                                  <preview1></preview1>
-                                  <detailpage>https://apps.owncloud.com/content/show.php?content=168707</detailpage>
-                                  <downloadtype1></downloadtype1>
-                                  <downloadway1>0</downloadway1>
-                                  <downloadprice1>0</downloadprice1>
-                                  <downloadlink1>http://apps.owncloud.com/content/download.php?content=168707&amp;id=1</downloadlink1>
-                                  <downloadgpgsignature1></downloadgpgsignature1>
-                                  <downloadgpgfingerprint1></downloadgpgfingerprint1>
-                                  <downloadpackagename1></downloadpackagename1>
-                                  <downloadrepository1></downloadrepository1>
-                                  <downloadname1></downloadname1>
-                                  <downloadsize1>885</downloadsize1>
-                                 </content>
-                                 <content details="summary">
-                                  <id>168708</id>
-                                  <name>Contacts 8.0</name>
-                                  <version>0.3.0.18</version>
-                                  <label>recommended</label>
-                                  <changed>2015-02-09T15:18:58+01:00</changed>
-                                  <created>2015-01-26T04:45:17+01:00</created>
-                                  <typeid>921</typeid>
-                                  <typename>ownCloud PIM</typename>
-                                  <language></language>
-                                  <personid>owncloud</personid>
-                                  <profilepage>http://opendesktop.org/usermanager/search.php?username=owncloud</profilepage>
-                                  <downloads>4237</downloads>
-                                  <score>58</score>
-                                  <description></description>
-                                  <comments>3</comments>
-                                  <fans>6</fans>
-                                  <licensetype>16</licensetype>
-                                  <approved>200</approved>
-                                  <category>1</category>
-                                  <license>AGPL</license>
-                                  <preview1></preview1>
-                                  <detailpage>https://apps.owncloud.com/content/show.php?content=168708</detailpage>
-                                  <downloadtype1></downloadtype1>
-                                  <downloadway1>0</downloadway1>
-                                  <downloadprice1>0</downloadprice1>
-                                  <downloadlink1>http://apps.owncloud.com/content/download.php?content=168708&amp;id=1</downloadlink1>
-                                  <downloadgpgsignature1></downloadgpgsignature1>
-                                  <downloadgpgfingerprint1></downloadgpgfingerprint1>
-                                  <downloadpackagename1></downloadpackagename1>
-                                  <downloadrepository1></downloadrepository1>
-                                  <downloadname1></downloadname1>
-                                  <downloadsize1>1409</downloadsize1>
-                                 </content>
-                                </data>
-                               </ocs> '));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/data',
-                               [
-                                       'timeout' => 20,
-                                       'query' => [
-                                               'version' => implode('x', [8, 1, 0, 7]),
-                                               'filter' => 'approved',
-                                               'categories' => '815x1337',
-                                               'sortmode' => 'new',
-                                               'page' => 1,
-                                               'pagesize' => 100,
-                                               'approved' => 'approved',
-                                       ],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $expected = [
-                       [
-                               'id' => '168707',
-                               'name' => 'Calendar 8.0',
-                               'label' => 'recommended',
-                               'version' => '0.6.4',
-                               'type' => '921',
-                               'typename' => 'ownCloud PIM',
-                               'personid' => 'owncloud',
-                               'license' => 'AGPL',
-                               'detailpage' => 'https://apps.owncloud.com/content/show.php?content=168707',
-                               'preview' => '',
-                               'preview-full' => '',
-                               'changed' => 1423491836,
-                               'description' => 'Calendar App for ownCloud',
-                               'score' => '60',
-                               'downloads' => 5393,
-                               'level' => 0,
-                               'profilepage' => 'http://opendesktop.org/usermanager/search.php?username=owncloud',
-                       ],
-                       [
-                               'id' => '168708',
-                               'name' => 'Contacts 8.0',
-                               'label' => 'recommended',
-                               'version' => '0.3.0.18',
-                               'type' => '921',
-                               'typename' => 'ownCloud PIM',
-                               'personid' => 'owncloud',
-                               'license' => 'AGPL',
-                               'detailpage' => 'https://apps.owncloud.com/content/show.php?content=168708',
-                               'preview' => '',
-                               'preview-full' => '',
-                               'changed' => 1423491538,
-                               'description' => '',
-                               'score' => '58',
-                               'downloads' => 4237,
-                               'level' => 200,
-                               'profilepage' => 'http://opendesktop.org/usermanager/search.php?username=owncloud',
-                       ],
-               ];
-               $this->assertEquals($expected, $this->ocsClient->getApplications([815, 1337], 1, 'approved', [8, 1, 0, 7]));
-       }
-
-       public function tesGetApplicationDisabledAppStore() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(false));
-               $this->assertNull($this->ocsClient->getApplication('MyId', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationExceptionClient() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/data/MyId',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->throwException(new \Exception('TheErrorMessage')));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get application: TheErrorMessage',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertNull($this->ocsClient->getApplication('MyId', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationParseError() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('MyInvalidXml'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/data/MyId',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get application, content was no valid XML',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertNull($this->ocsClient->getApplication('MyId', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationSuccessful() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('<?xml version="1.0"?>
-                               <ocs>
-                                <meta>
-                                 <status>ok</status>
-                                 <statuscode>100</statuscode>
-                                 <message></message>
-                                </meta>
-                                <data>
-                                 <content details="full">
-                                  <id>166053</id>
-                                  <name>Versioning</name>
-                                  <version>0.0.1</version>
-                                  <label>recommended</label>
-                                  <typeid>925</typeid>
-                                  <typename>ownCloud other</typename>
-                          <language></language>
-                          <personid>owncloud</personid>
-                          <profilepage>http://opendesktop.org/usermanager/search.php?username=owncloud</profilepage>
-                          <created>2014-07-07T16:34:40+02:00</created>
-                          <changed>2014-07-07T16:34:40+02:00</changed>
-                          <downloads>140</downloads>
-                          <score>50</score>
-                          <description>Placeholder for future updates</description>
-                          <summary></summary>
-                          <feedbackurl></feedbackurl>
-                          <changelog></changelog>
-                          <homepage></homepage>
-                          <homepagetype></homepagetype>
-                          <homepage2></homepage2>
-                          <homepagetype2></homepagetype2>
-                          <homepage3></homepage3>
-                          <homepagetype3></homepagetype3>
-                          <homepage4></homepage4>
-                          <homepagetype4></homepagetype4>
-                          <homepage5></homepage5>
-                          <homepagetype5></homepagetype5>
-                          <homepage6></homepage6>
-                          <homepagetype6></homepagetype6>
-                          <homepage7></homepage7>
-                          <homepagetype7></homepagetype7>
-                          <homepage8></homepage8>
-                          <homepagetype8></homepagetype8>
-                          <homepage9></homepage9>
-                          <homepagetype9></homepagetype9>
-                          <homepage10></homepage10>
-                          <homepagetype10></homepagetype10>
-                          <licensetype>16</licensetype>
-                          <license>AGPL</license>
-                          <donationpage></donationpage>
-                          <comments>0</comments>
-                          <commentspage>http://apps.owncloud.com/content/show.php?content=166053</commentspage>
-                          <fans>0</fans>
-                          <fanspage>http://apps.owncloud.com/content/show.php?action=fan&amp;content=166053</fanspage>
-                          <knowledgebaseentries>0</knowledgebaseentries>
-                          <knowledgebasepage>http://apps.owncloud.com/content/show.php?action=knowledgebase&amp;content=166053</knowledgebasepage>
-                          <depend>ownCloud 7</depend>
-                          <preview1></preview1>
-                          <preview2></preview2>
-                          <preview3></preview3>
-                          <previewpic1></previewpic1>
-                          <previewpic2></previewpic2>
-                          <previewpic3></previewpic3>
-                          <picsmall1></picsmall1>
-                          <picsmall2></picsmall2>
-                          <picsmall3></picsmall3>
-                          <detailpage>https://apps.owncloud.com/content/show.php?content=166053</detailpage>
-                          <downloadtype1></downloadtype1>
-                          <downloadprice1>0</downloadprice1>
-                          <downloadlink1>http://apps.owncloud.com/content/download.php?content=166053&amp;id=1</downloadlink1>
-                          <downloadname1></downloadname1>
-                          <downloadgpgfingerprint1></downloadgpgfingerprint1>
-                          <downloadgpgsignature1></downloadgpgsignature1>
-                          <downloadpackagename1></downloadpackagename1>
-                          <downloadrepository1></downloadrepository1>
-                          <downloadsize1>1</downloadsize1>
-                          <approved>200</approved>
-                         </content>
-                        </data>
-                       </ocs>
-                       '));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/data/166053',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $expected = [
-                       'id' => 166053,
-                       'name' => 'Versioning',
-                       'version' => '0.0.1',
-                       'type' => '925',
-                       'label' => 'recommended',
-                       'typename' => 'ownCloud other',
-                       'personid' => 'owncloud',
-                       'profilepage' => 'http://opendesktop.org/usermanager/search.php?username=owncloud',
-                       'detailpage' => 'https://apps.owncloud.com/content/show.php?content=166053',
-                       'preview1' => '',
-                       'preview2' => '',
-                       'preview3' => '',
-                       'changed' => 1404743680,
-                       'description' => 'Placeholder for future updates',
-                       'score' => 50,
-                       'level' => 200,
-               ];
-               $this->assertSame($expected, $this->ocsClient->getApplication(166053, [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationSuccessfulWithOldId() {
-               $this->config
-                               ->expects($this->at(0))
-                               ->method('getSystemValue')
-                               ->with('appstoreenabled', true)
-                               ->will($this->returnValue(true));
-               $this->config
-                               ->expects($this->at(1))
-                               ->method('getSystemValue')
-                               ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                               ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                               ->expects($this->once())
-                               ->method('getBody')
-                               ->will($this->returnValue('<?xml version="1.0"?>
-                               <ocs>
-                                <meta>
-                                 <status>ok</status>
-                                 <statuscode>100</statuscode>
-                                 <message></message>
-                                </meta>
-                                <data>
-                                 <content details="full">
-                                  <id>1337</id>
-                                  <name>Versioning</name>
-                                  <version>0.0.1</version>
-                                  <label>recommended</label>
-                                  <typeid>925</typeid>
-                                  <typename>ownCloud other</typename>
-                          <language></language>
-                          <personid>owncloud</personid>
-                          <profilepage>http://opendesktop.org/usermanager/search.php?username=owncloud</profilepage>
-                          <created>2014-07-07T16:34:40+02:00</created>
-                          <changed>2014-07-07T16:34:40+02:00</changed>
-                          <downloads>140</downloads>
-                          <score>50</score>
-                          <description>Placeholder for future updates</description>
-                          <summary></summary>
-                          <feedbackurl></feedbackurl>
-                          <changelog></changelog>
-                          <homepage></homepage>
-                          <homepagetype></homepagetype>
-                          <homepage2></homepage2>
-                          <homepagetype2></homepagetype2>
-                          <homepage3></homepage3>
-                          <homepagetype3></homepagetype3>
-                          <homepage4></homepage4>
-                          <homepagetype4></homepagetype4>
-                          <homepage5></homepage5>
-                          <homepagetype5></homepagetype5>
-                          <homepage6></homepage6>
-                          <homepagetype6></homepagetype6>
-                          <homepage7></homepage7>
-                          <homepagetype7></homepagetype7>
-                          <homepage8></homepage8>
-                          <homepagetype8></homepagetype8>
-                          <homepage9></homepage9>
-                          <homepagetype9></homepagetype9>
-                          <homepage10></homepage10>
-                          <homepagetype10></homepagetype10>
-                          <licensetype>16</licensetype>
-                          <license>AGPL</license>
-                          <donationpage></donationpage>
-                          <comments>0</comments>
-                          <commentspage>http://apps.owncloud.com/content/show.php?content=166053</commentspage>
-                          <fans>0</fans>
-                          <fanspage>http://apps.owncloud.com/content/show.php?action=fan&amp;content=166053</fanspage>
-                          <knowledgebaseentries>0</knowledgebaseentries>
-                          <knowledgebasepage>http://apps.owncloud.com/content/show.php?action=knowledgebase&amp;content=166053</knowledgebasepage>
-                          <depend>ownCloud 7</depend>
-                          <preview1></preview1>
-                          <preview2></preview2>
-                          <preview3></preview3>
-                          <previewpic1></previewpic1>
-                          <previewpic2></previewpic2>
-                          <previewpic3></previewpic3>
-                          <picsmall1></picsmall1>
-                          <picsmall2></picsmall2>
-                          <picsmall3></picsmall3>
-                          <detailpage>https://apps.owncloud.com/content/show.php?content=166053</detailpage>
-                          <downloadtype1></downloadtype1>
-                          <downloadprice1>0</downloadprice1>
-                          <downloadlink1>http://apps.owncloud.com/content/download.php?content=166053&amp;id=1</downloadlink1>
-                          <downloadname1></downloadname1>
-                          <downloadgpgfingerprint1></downloadgpgfingerprint1>
-                          <downloadgpgsignature1></downloadgpgsignature1>
-                          <downloadpackagename1></downloadpackagename1>
-                          <downloadrepository1></downloadrepository1>
-                          <downloadsize1>1</downloadsize1>
-                          <approved>200</approved>
-                         </content>
-                        </data>
-                       </ocs>
-                       '));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                               ->expects($this->once())
-                               ->method('get')
-                               ->with(
-                                               'https://api.owncloud.com/v1/content/data/166053',
-                                               [
-                                                               'timeout' => 20,
-                                                               'query' => ['version' => '8x1x0x7'],
-                                               ]
-                               )
-                               ->will($this->returnValue($response));
-
-               $this->clientService
-                               ->expects($this->once())
-                               ->method('newClient')
-                               ->will($this->returnValue($client));
-
-               $expected = [
-                               'id' => 166053,
-                               'name' => 'Versioning',
-                               'version' => '0.0.1',
-                               'type' => '925',
-                               'label' => 'recommended',
-                               'typename' => 'ownCloud other',
-                               'personid' => 'owncloud',
-                               'profilepage' => 'http://opendesktop.org/usermanager/search.php?username=owncloud',
-                               'detailpage' => 'https://apps.owncloud.com/content/show.php?content=166053',
-                               'preview1' => '',
-                               'preview2' => '',
-                               'preview3' => '',
-                               'changed' => 1404743680,
-                               'description' => 'Placeholder for future updates',
-                               'score' => 50,
-                               'level' => 200,
-               ];
-               $this->assertSame($expected, $this->ocsClient->getApplication(166053, [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationEmptyXml() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('<?xml version="1.0"?>
-                               <ocs>
-                                <meta>
-                                 <status>ok</status>
-                                 <statuscode>100</statuscode>
-                                 <message></message>
-                                </meta>
-                       </ocs>
-                       '));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/data/MyId',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->assertSame(null, $this->ocsClient->getApplication('MyId', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationDownloadDisabledAppStore() {
-               $this->config
-                       ->expects($this->once())
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(false));
-               $this->assertNull($this->ocsClient->getApplicationDownload('MyId', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationDownloadExceptionClient() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/download/MyId/1',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->throwException(new \Exception('TheErrorMessage')));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get application download URL: TheErrorMessage',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertNull($this->ocsClient->getApplicationDownload('MyId', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationDownloadParseError() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('MyInvalidXml'));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/download/MyId/1',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $this->logger
-                       ->expects($this->once())
-                       ->method('error')
-                       ->with(
-                               'Could not get application download URL, content was no valid XML',
-                               [
-                                       'app' => 'core',
-                               ]
-                       );
-
-               $this->assertNull($this->ocsClient->getApplicationDownload('MyId', [8, 1, 0, 7]));
-       }
-
-       public function testGetApplicationDownloadUrlSuccessful() {
-               $this->config
-                       ->expects($this->at(0))
-                       ->method('getSystemValue')
-                       ->with('appstoreenabled', true)
-                       ->will($this->returnValue(true));
-               $this->config
-                       ->expects($this->at(1))
-                       ->method('getSystemValue')
-                       ->with('appstoreurl', 'https://api.owncloud.com/v1')
-                       ->will($this->returnValue('https://api.owncloud.com/v1'));
-
-               $response = $this->createMock(IResponse::class);
-               $response
-                       ->expects($this->once())
-                       ->method('getBody')
-                       ->will($this->returnValue('<?xml version="1.0"?>
-                               <ocs>
-                                <meta>
-                                 <status>ok</status>
-                                 <statuscode>100</statuscode>
-                                 <message></message>
-                                </meta>
-                                <data>
-                                 <content details="download">
-                                  <downloadlink>https://apps.owncloud.com/CONTENT/content-files/166052-files_trashbin.zip</downloadlink>
-                                  <mimetype>application/zip</mimetype>
-                                  <gpgfingerprint></gpgfingerprint>
-                                  <gpgsignature></gpgsignature>
-                                  <packagename></packagename>
-                                  <repository></repository>
-                                 </content>
-                                </data>
-                               </ocs>
-                               '));
-
-               $client = $this->createMock(IClient::class);
-               $client
-                       ->expects($this->once())
-                       ->method('get')
-                       ->with(
-                               'https://api.owncloud.com/v1/content/download/MyId/1',
-                               [
-                                       'timeout' => 20,
-                                       'query' => ['version' => '8x1x0x7'],
-                               ]
-                       )
-                       ->will($this->returnValue($response));
-
-               $this->clientService
-                       ->expects($this->once())
-                       ->method('newClient')
-                       ->will($this->returnValue($client));
-
-               $expected = [
-                       'downloadlink' => 'https://apps.owncloud.com/CONTENT/content-files/166052-files_trashbin.zip',
-               ];
-               $this->assertSame($expected, $this->ocsClient->getApplicationDownload('MyId', [8, 1, 0, 7]));
-       }
-}
index 2e5900c4ce51fe93f9ecdb8f098d36e82811d4ba..3ff8787b91ae7aecbf8a39dc941e4975a1f7f013 100644 (file)
@@ -122,8 +122,6 @@ class ServerTest extends \Test\TestCase {
                        ['UserCache', '\OC\Cache\File'],
                        ['UserCache', '\OCP\ICache'],
 
-                       ['OcsClient', '\OC\OCSClient'],
-
                        ['PreviewManager', '\OC\PreviewManager'],
                        ['PreviewManager', '\OCP\IPreview'],