From 39d84069337d7d6ddcaed7b1daba37cfeb26dcc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 9 Feb 2015 22:48:27 +0100 Subject: [PATCH] don't allow installation of already installed apps - fixes #14004 --- lib/private/app.php | 13 +- lib/private/installer.php | 11 +- lib/private/ocsclient.php | 185 +++++++++--------- settings/controller/appsettingscontroller.php | 35 +++- 4 files changed, 139 insertions(+), 105 deletions(-) diff --git a/lib/private/app.php b/lib/private/app.php index 2b6c675488..365b0d0906 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -45,6 +45,7 @@ */ use OC\App\DependencyAnalyzer; use OC\App\Platform; +use OC\OCSClient; /** * This class manages the apps. It allows them to register and integrate in the @@ -290,9 +291,9 @@ class OC_App { * @return int */ public static function downloadApp($app) { - $appData = OC_OCSClient::getApplication($app); - $download = OC_OCSClient::getApplicationDownload($app, 1); - if (isset($download['downloadlink']) and $download['downloadlink'] != '') { + $appData= OCSClient::getApplication($app); + $download= OCSClient::getApplicationDownload($app, 1); + 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); @@ -904,7 +905,7 @@ class OC_App { public static function getAppstoreApps($filter = 'approved', $category = null) { $categories = array($category); if (is_null($category)) { - $categoryNames = OC_OCSClient::getCategories(); + $categoryNames = OCSClient::getCategories(); if (is_array($categoryNames)) { // Check that categories of apps were retrieved correctly if (!$categories = array_keys($categoryNames)) { @@ -916,7 +917,7 @@ class OC_App { } $page = 0; - $remoteApps = OC_OCSClient::getApplications($categories, $page, $filter); + $remoteApps = OCSClient::getApplications($categories, $page, $filter); $app1 = array(); $i = 0; $l = \OC::$server->getL10N('core'); @@ -1098,7 +1099,7 @@ class OC_App { public static function installApp($app) { $l = \OC::$server->getL10N('core'); $config = \OC::$server->getConfig(); - $appData = OC_OCSClient::getApplication($app); + $appData=OCSClient::getApplication($app); // 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)) { diff --git a/lib/private/installer.php b/lib/private/installer.php index cbd47f5b14..7f2fc6a73d 100644 --- a/lib/private/installer.php +++ b/lib/private/installer.php @@ -36,6 +36,11 @@ * along with this program. If not, see * */ +use OC\OCSClient; + +/** + * This class provides the functionality needed to install, update and remove plugins/apps + */ class OC_Installer{ /** @@ -215,8 +220,8 @@ class OC_Installer{ * @throws Exception */ public static function updateAppByOCSId($ocsid) { - $appdata = OC_OCSClient::getApplication($ocsid); - $download = OC_OCSClient::getApplicationDownload($ocsid, 1); + $appdata = OCSClient::getApplication($ocsid); + $download = OCSClient::getApplicationDownload($ocsid, 1); if (isset($download['downloadlink']) && trim($download['downloadlink']) !== '') { $download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']); @@ -378,7 +383,7 @@ class OC_Installer{ if($ocsid<>'') { - $ocsdata=OC_OCSClient::getApplication($ocsid); + $ocsdata=OCSClient::getApplication($ocsid); $ocsversion= (string) $ocsdata['version']; $currentversion=OC_App::getAppVersion($app); if (version_compare($ocsversion, $currentversion, '>')) { diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php index 11accdd05e..c62cae15e4 100644 --- a/lib/private/ocsclient.php +++ b/lib/private/ocsclient.php @@ -33,14 +33,25 @@ * along with this program. If not, see * */ -class OC_OCSClient{ + +namespace OC; + +/** + * This class provides an easy way for apps to store config values in the + * database. + */ + +class OCSClient { /** * Returns whether the AppStore is enabled (i.e. because the AppStore is disabled for EE) + * * @return bool */ - protected static function isAppstoreEnabled() { - if(OC::$server->getConfig()->getSystemValue('appstoreenabled', true) === false OR OC_Util::getEditionString() !== '') { + public static function isAppStoreEnabled() { + if (\OC::$server->getConfig()->getSystemValue('appstoreenabled', true) === false || + \OC_Util::getEditionString() !== '' + ) { return false; } @@ -49,53 +60,44 @@ class OC_OCSClient{ /** * Get the url of the OCS AppStore server. + * * @return string of the AppStore server * * This function returns the url of the OCS AppStore server. It´s possible * to set it in the config file or it will fallback to the default */ private static function getAppStoreURL() { - return OC::$server->getConfig()->getSystemValue('appstoreurl', 'https://api.owncloud.com/v1'); - } - - /** - * Get the content of an OCS url call. - * @return string of the response - * This function calls an OCS server and returns the response. It also sets a sane timeout - * @param string $url - */ - private static function getOCSresponse($url) { - $data = \OC_Util::getUrlContent($url); - return($data); + return \OC::$server->getConfig()->getSystemValue('appstoreurl', 'https://api.owncloud.com/v1'); } /** * Get all the categories from the OCS server + * * @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 static function getCategories() { - if(!self::isAppstoreEnabled()) { + if (!self::isAppStoreEnabled()) { return null; } - $url=OC_OCSClient::getAppStoreURL().'/content/categories'; - $xml=OC_OCSClient::getOCSresponse($url); - if($xml==false) { + $url = self::getAppStoreURL() . '/content/categories'; + $xml = \OC::$server->getHTTPHelper()->getUrlContent($url); + if ($xml == false) { return null; } $loadEntities = libxml_disable_entity_loader(true); - $data = simplexml_load_string($xml); + $data = simplexml_load_string($xml); libxml_disable_entity_loader($loadEntities); - $tmp=$data->data; - $cats=array(); + $tmp = $data->data; + $cats = array(); - foreach($tmp->category as $value) { + foreach ($tmp->category as $value) { - $id= (int) $value->id; - $name= (string) $value->name; - $cats[$id]=$name; + $id = (int)$value->id; + $name = (string)$value->name; + $cats[$id] = $name; } @@ -104,6 +106,7 @@ class OC_OCSClient{ /** * Get all the applications from the OCS server + * * @return array|null an array of application data or null * * This function returns a list of all the applications on the OCS server @@ -112,24 +115,24 @@ class OC_OCSClient{ * @param string $filter */ public static function getApplications($categories, $page, $filter) { - if(!self::isAppstoreEnabled()) { - return(array()); + if (!self::isAppStoreEnabled()) { + return (array()); } - if(is_array($categories)) { - $categoriesstring=implode('x', $categories); - }else{ - $categoriesstring=$categories; + if (is_array($categories)) { + $categoriesString = implode('x', $categories); + } else { + $categoriesString = $categories; } - $version='&version='.implode('x', \OC_Util::getVersion()); - $filterurl='&filter='.urlencode($filter); - $url=OC_OCSClient::getAppStoreURL().'/content/data?categories='.urlencode($categoriesstring) - .'&sortmode=new&page='.urlencode($page).'&pagesize=100'.$filterurl.$version; - $apps=array(); - $xml=OC_OCSClient::getOCSresponse($url); + $version = '&version=' . implode('x', \OC_Util::getVersion()); + $filterUrl = '&filter=' . urlencode($filter); + $url = self::getAppStoreURL() . '/content/data?categories=' . urlencode($categoriesString) + . '&sortmode=new&page=' . urlencode($page) . '&pagesize=100' . $filterUrl . $version; + $apps = array(); + $xml = \OC::$server->getHTTPHelper()->getUrlContent($url); - if($xml==false) { + if ($xml == false) { return null; } $loadEntities = libxml_disable_entity_loader(true); @@ -138,25 +141,25 @@ class OC_OCSClient{ $tmp = $data->data->content; $tmpCount = count($tmp); - for($i = 0; $i < $tmpCount; $i++) { - $app=array(); - $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['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; + for ($i = 0; $i < $tmpCount; $i++) { + $app = array(); + $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['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; - $apps[]=$app; + $apps[] = $app; } return $apps; } @@ -164,53 +167,55 @@ class OC_OCSClient{ /** * Get an the applications from the OCS server + * * @param string $id * @return array|null an array of application data or null * * This function returns an applications from the OCS server */ public static function getApplication($id) { - if(!self::isAppstoreEnabled()) { + if (!self::isAppStoreEnabled()) { return null; } - $url=OC_OCSClient::getAppStoreURL().'/content/data/'.urlencode($id); - $xml=OC_OCSClient::getOCSresponse($url); + $url = self::getAppStoreURL() . '/content/data/' . urlencode($id); + $xml = \OC::$server->getHTTPHelper()->getUrlContent($url); - if($xml==false) { - OC_Log::write('core', 'Unable to parse OCS content for app ' . $id, OC_Log::FATAL); + if ($xml == false) { + \OC_Log::write('core', 'Unable to parse OCS content for app ' . $id, \OC_Log::FATAL); return null; } $loadEntities = libxml_disable_entity_loader(true); $data = simplexml_load_string($xml); libxml_disable_entity_loader($loadEntities); - $tmp=$data->data->content; + $tmp = $data->data->content; if (is_null($tmp)) { - OC_Log::write('core', 'Invalid OCS content returned for app ' . $id, OC_Log::FATAL); + \OC_Log::write('core', 'Invalid OCS content returned for app ' . $id, \OC_Log::FATAL); return null; } - $app=array(); - $app['id']=$tmp->id; - $app['name']=$tmp->name; - $app['version']=$tmp->version; - $app['type']=$tmp->typeid; - $app['label']=$tmp->label; - $app['typename']=$tmp->typename; - $app['personid']=$tmp->personid; - $app['detailpage']=$tmp->detailpage; - $app['preview1']=$tmp->smallpreviewpic1; - $app['preview2']=$tmp->smallpreviewpic2; - $app['preview3']=$tmp->smallpreviewpic3; - $app['changed']=strtotime($tmp->changed); - $app['description']=$tmp->description; - $app['detailpage']=$tmp->detailpage; - $app['score']=$tmp->score; + $app = array(); + $app['id'] = $tmp->id; + $app['name'] = $tmp->name; + $app['version'] = $tmp->version; + $app['type'] = $tmp->typeid; + $app['label'] = $tmp->label; + $app['typename'] = $tmp->typename; + $app['personid'] = $tmp->personid; + $app['detailpage'] = $tmp->detailpage; + $app['preview1'] = $tmp->smallpreviewpic1; + $app['preview2'] = $tmp->smallpreviewpic2; + $app['preview3'] = $tmp->smallpreviewpic3; + $app['changed'] = strtotime($tmp->changed); + $app['description'] = $tmp->description; + $app['detailpage'] = $tmp->detailpage; + $app['score'] = $tmp->score; return $app; } /** * Get the download url for an application from the OCS server + * * @return array|null an array of application data or null * * This function returns an download url for an applications from the OCS server @@ -218,26 +223,26 @@ class OC_OCSClient{ * @param integer $item */ public static function getApplicationDownload($id, $item) { - if(!self::isAppstoreEnabled()) { + if (!self::isAppStoreEnabled()) { return null; } - $url=OC_OCSClient::getAppStoreURL().'/content/download/'.urlencode($id).'/'.urlencode($item); - $xml=OC_OCSClient::getOCSresponse($url); + $url = self::getAppStoreURL() . '/content/download/' . urlencode($id) . '/' . urlencode($item); + $xml = \OC::$server->getHTTPHelper()->getUrlContent($url); - if($xml==false) { - OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL); + if ($xml == false) { + \OC_Log::write('core', 'Unable to parse OCS content', \OC_Log::FATAL); return null; } $loadEntities = libxml_disable_entity_loader(true); $data = simplexml_load_string($xml); libxml_disable_entity_loader($loadEntities); - $tmp=$data->data->content; - $app=array(); - if(isset($tmp->downloadlink)) { - $app['downloadlink']=$tmp->downloadlink; - }else{ - $app['downloadlink']=''; + $tmp = $data->data->content; + $app = array(); + if (isset($tmp->downloadlink)) { + $app['downloadlink'] = $tmp->downloadlink; + } else { + $app['downloadlink'] = ''; } return $app; } diff --git a/settings/controller/appsettingscontroller.php b/settings/controller/appsettingscontroller.php index 8be3d61da2..a7f709cc15 100644 --- a/settings/controller/appsettingscontroller.php +++ b/settings/controller/appsettingscontroller.php @@ -24,6 +24,7 @@ namespace OC\Settings\Controller; use OC\App\DependencyAnalyzer; use OC\App\Platform; +use OC\OCSClient; use \OCP\AppFramework\Controller; use OCP\ICacheFactory; use OCP\IRequest; @@ -74,10 +75,10 @@ class AppSettingsController extends Controller { ['id' => 1, 'displayName' => (string)$this->l10n->t('Not enabled')], ]; - if($this->config->getSystemValue('appstoreenabled', true)) { + if(OCSClient::isAppStoreEnabled()) { $categories[] = ['id' => 2, 'displayName' => (string)$this->l10n->t('Recommended')]; // apps from external repo via OCS - $ocs = \OC_OCSClient::getCategories(); + $ocs = OCSClient::getCategories(); if ($ocs) { foreach($ocs as $k => $v) { $categories[] = array( @@ -106,10 +107,7 @@ class AppSettingsController extends Controller { switch ($category) { // installed apps case 0: - $apps = \OC_App::listAllApps(true); - $apps = array_filter($apps, function ($app) { - return $app['active']; - }); + $apps = $this->getInstalledApps(); usort($apps, function ($a, $b) { $a = (string)$a['name']; $b = (string)$b['name']; @@ -147,7 +145,21 @@ class AppSettingsController extends Controller { } if (!$apps) { $apps = array(); + } else { + // don't list installed apps + $installedApps = $this->getInstalledApps(); + $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); + }); } + + // sort by score usort($apps, function ($a, $b) { $a = (int)$a['score']; $b = (int)$b['score']; @@ -189,4 +201,15 @@ class AppSettingsController extends Controller { return ['apps' => $apps, 'status' => 'success']; } + + /** + * @return array + */ + private function getInstalledApps() { + $apps = \OC_App::listAllApps(true); + $apps = array_filter($apps, function ($app) { + return $app['active']; + }); + return $apps; + } }