summaryrefslogtreecommitdiffstats
path: root/settings
diff options
context:
space:
mode:
authorLukas Reschke <lukas@statuscode.ch>2016-10-27 17:41:15 +0200
committerLukas Reschke <lukas@statuscode.ch>2016-10-31 17:17:44 +0100
commit32cf661215fb3926789054a3953b465fc2665330 (patch)
tree4cf2865bef5856c59a1fdacb98208a14dfc1a128 /settings
parent357a823457397d3e93ec8cd4dc01fb6859eb0049 (diff)
downloadnextcloud-server-32cf661215fb3926789054a3953b465fc2665330.tar.gz
nextcloud-server-32cf661215fb3926789054a3953b465fc2665330.zip
Use new appstore API
This change introduces the new appstore API in Nextcloud. Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
Diffstat (limited to 'settings')
-rw-r--r--settings/Application.php23
-rw-r--r--settings/Controller/AppSettingsController.php360
-rw-r--r--settings/ajax/enableapp.php6
-rw-r--r--settings/ajax/installapp.php11
-rw-r--r--settings/css/settings.css11
-rw-r--r--settings/js/apps.js6
-rw-r--r--settings/routes.php1
-rw-r--r--settings/templates/apps.php19
8 files changed, 203 insertions, 234 deletions
diff --git a/settings/Application.php b/settings/Application.php
index dd237e40c9d..3dbf9acc524 100644
--- a/settings/Application.php
+++ b/settings/Application.php
@@ -30,7 +30,11 @@
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()
+ );
+ });
}
}
diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php
index 2efd3b8a847..16d4780c5f9 100644
--- a/settings/Controller/AppSettingsController.php
+++ b/settings/Controller/AppSettingsController.php
@@ -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>
@@ -26,19 +27,22 @@
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']);
}
-
}
diff --git a/settings/ajax/enableapp.php b/settings/ajax/enableapp.php
index db4503f20e7..b378b3c918d 100644
--- a/settings/ajax/enableapp.php
+++ b/settings/ajax/enableapp.php
@@ -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);
diff --git a/settings/ajax/installapp.php b/settings/ajax/installapp.php
index 8831305e223..75f3fea83b7 100644
--- a/settings/ajax/installapp.php
+++ b/settings/ajax/installapp.php
@@ -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');
diff --git a/settings/css/settings.css b/settings/css/settings.css
index 0dadf401c04..fe0e40cb273 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -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;
diff --git a/settings/js/apps.js b/settings/js/apps.js
index 5fc366c4921..ecd7543c8ce 100644
--- a/settings/js/apps.js
+++ b/settings/js/apps.js
@@ -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>');
}
}
});
diff --git a/settings/routes.php b/settings/routes.php
index 64c4e549681..829474ce2bb 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -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'],
diff --git a/settings/templates/apps.php b/settings/templates/apps.php
index 46fd5bd0e40..36064f0981c 100644
--- a/settings/templates/apps.php
+++ b/settings/templates/apps.php
@@ -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">