This change introduces the new appstore API in Nextcloud. Signed-off-by: Lukas Reschke <lukas@statuscode.ch>pull/1940/head
parent
357a823457
commit
32cf661215
@ -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) |
||||
); |
||||
} |
||||
} |
||||
@ -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'; |
||||
} |
||||
} |
||||
@ -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 []; |
||||
} |
||||
} |
||||
} |
||||
@ -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; |
||||
} |
||||
} |
||||
@ -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'); |
||||
} |
||||
} |
||||
@ -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; |
||||
} |
||||
|
||||
} |
||||
File diff suppressed because one or more lines are too long
@ -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 |
||||
); |
||||
} |
||||
} |
||||
@ -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 |
||||
); |
||||
} |
||||
} |
||||
@ -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()); |
||||
} |
||||
} |
||||
@ -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)); |
||||
} |
||||
|
||||
} |
||||
@ -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()); |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue