From bbf7f56f949f48ec0cf95d416b431d0cd739582f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas.mueller@tmit.eu>
Date: Tue, 17 Feb 2015 12:00:39 +0100
Subject: [PATCH] 3rd-party apps are disabled on upgrade - refs #14026

---
 core/ajax/update.php           | 26 +++++++---
 core/command/upgrade.php       | 10 ++--
 core/js/update.js              |  3 ++
 lib/private/app.php            | 33 ------------
 lib/private/templatelayout.php |  3 +-
 lib/private/updater.php        | 93 ++++++++++++++++++++--------------
 tests/lib/updater.php          |  4 +-
 7 files changed, 87 insertions(+), 85 deletions(-)

diff --git a/core/ajax/update.php b/core/ajax/update.php
index baa01b4f208..656fe2736ac 100644
--- a/core/ajax/update.php
+++ b/core/ajax/update.php
@@ -36,9 +36,12 @@ if (OC::checkUpgrade(false)) {
 	$eventSource = \OC::$server->createEventSource();
 	$updater = new \OC\Updater(
 			\OC::$server->getHTTPHelper(),
-			\OC::$server->getAppConfig(),
+			\OC::$server->getConfig(),
 			\OC_Log::$object
 	);
+	$incompatibleApps = [];
+	$disabledThirdPartyApps = [];
+
 	$updater->listen('\OC\Updater', 'maintenanceStart', function () use ($eventSource, $l) {
 		$eventSource->send('success', (string)$l->t('Turned on maintenance mode'));
 	});
@@ -57,13 +60,11 @@ if (OC::checkUpgrade(false)) {
 	$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) {
 		$eventSource->send('success', (string)$l->t('Updated "%s" to %s', array($app, $version)));
 	});
-	$updater->listen('\OC\Updater', 'disabledApps', function ($appList) use ($eventSource, $l) {
-		$list = array();
-		foreach ($appList as $appId) {
-			$info = OC_App::getAppInfo($appId);
-			$list[] = $info['name'] . ' (' . $info['id'] . ')';
-		}
-		$eventSource->send('success', (string)$l->t('Disabled incompatible apps: %s', implode(', ', $list)));
+	$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) {
+		$incompatibleApps[]= $app;
+	});
+	$updater->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use (&$disabledThirdPartyApps) {
+		$disabledThirdPartyApps[]= $app;
 	});
 	$updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource) {
 		$eventSource->send('failure', $message);
@@ -73,6 +74,15 @@ if (OC::checkUpgrade(false)) {
 
 	$updater->upgrade();
 
+	if (!empty($incompatibleApps)) {
+		$eventSource->send('notice',
+			(string)$l->t('Following incompatible apps have been disabled: %s', implode(', ', $incompatibleApps)));
+	}
+	if (!empty($disabledThirdPartyApps)) {
+		$eventSource->send('notice',
+			(string)$l->t('Following 3rd party apps have been disabled: %s', implode(', ', $disabledThirdPartyApps)));
+	}
+
 	$eventSource->send('done', '');
 	$eventSource->close();
 }
diff --git a/core/command/upgrade.php b/core/command/upgrade.php
index 91e4c3c744a..8899bd50ba7 100644
--- a/core/command/upgrade.php
+++ b/core/command/upgrade.php
@@ -100,7 +100,8 @@ class Upgrade extends Command {
 
 		if(\OC::checkUpgrade(false)) {
 			$self = $this;
-			$updater = new Updater(\OC::$server->getHTTPHelper(), \OC::$server->getAppConfig());
+			$updater = new Updater(\OC::$server->getHTTPHelper(),
+				\OC::$server->getConfig());
 
 			$updater->setSimulateStepEnabled($simulateStepEnabled);
 			$updater->setUpdateStepEnabled($updateStepEnabled);
@@ -122,8 +123,11 @@ class Upgrade extends Command {
 			$updater->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($output) {
 				$output->writeln('<info>Checked database schema update</info>');
 			});
-			$updater->listen('\OC\Updater', 'disabledApps', function ($appList) use($output) {
-				$output->writeln('<info>Disabled incompatible apps: ' . implode(', ', $appList) . '</info>');
+			$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($output) {
+				$output->writeln('<info>Disabled incompatible app: ' . $app . '</info>');
+			});
+			$updater->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use($output) {
+				$output->writeln('<info>Disabled 3rd-party app: ' . $app . '</info>');
 			});
 
 			$updater->listen('\OC\Updater', 'failure', function ($message) use($output, $self) {
diff --git a/core/js/update.js b/core/js/update.js
index f63808f65be..60f04832935 100644
--- a/core/js/update.js
+++ b/core/js/update.js
@@ -38,6 +38,9 @@
 			updateEventSource.listen('success', function(message) {
 				$('<span>').append(message).append('<br />').appendTo($el);
 			});
+			updateEventSource.listen('notice', function(message) {
+				$('<span>').addClass('error').append(message).append('<br />').appendTo($el);
+			});
 			updateEventSource.listen('error', function(message) {
 				$('<span>').addClass('error').append(message).append('<br />').appendTo($el);
 				message = t('core', 'Please reload the page.');
diff --git a/lib/private/app.php b/lib/private/app.php
index 365b0d09065..2950ded078a 100644
--- a/lib/private/app.php
+++ b/lib/private/app.php
@@ -958,39 +958,6 @@ class OC_App {
 		return false;
 	}
 
-	/**
-	 * check if the current enabled apps are compatible with the current
-	 * ownCloud version. disable them if not.
-	 * This is important if you upgrade ownCloud and have non ported 3rd
-	 * party apps installed.
-	 *
-	 * @param array $apps optional app id list to check, uses all enabled apps
-	 * when not specified
-	 *
-	 * @return array containing the list of ids of the disabled apps
-	 */
-	public static function checkAppsRequirements($apps = array()) {
-		$disabledApps = array();
-		if (empty($apps)) {
-			$apps = OC_App::getEnabledApps();
-		}
-		$version = OC_Util::getVersion();
-		foreach ($apps as $app) {
-			// check if the app is compatible with this version of ownCloud
-			$info = OC_App::getAppInfo($app);
-			if (!self::isAppCompatible($version, $info)) {
-				OC_Log::write('core',
-					'App "' . $info['name'] . '" (' . $app . ') can\'t be used because it is'
-					. ' not compatible with this version of ownCloud',
-					OC_Log::ERROR);
-				OC_App::disable($app);
-				OC_Hook::emit('update', 'success', 'Disabled ' . $info['name'] . ' app because it is not compatible');
-				$disabledApps[] = $app;
-			}
-		}
-		return $disabledApps;
-	}
-
 	/**
 	 * Adjust the number of version parts of $version1 to match
 	 * the number of version parts of $version2.
diff --git a/lib/private/templatelayout.php b/lib/private/templatelayout.php
index c8be5631fec..9f06c7b45eb 100644
--- a/lib/private/templatelayout.php
+++ b/lib/private/templatelayout.php
@@ -77,7 +77,8 @@ class OC_TemplateLayout extends OC_Template {
 			// Update notification
 			if($this->config->getSystemValue('updatechecker', true) === true &&
 				OC_User::isAdminUser(OC_User::getUser())) {
-				$updater = new \OC\Updater(\OC::$server->getHTTPHelper(), \OC::$server->getAppConfig());
+				$updater = new \OC\Updater(\OC::$server->getHTTPHelper(),
+					\OC::$server->getConfig());
 				$data = $updater->check();
 
 				if(isset($data['version']) && $data['version'] != '' and $data['version'] !== Array()) {
diff --git a/lib/private/updater.php b/lib/private/updater.php
index f76630d411d..41ce779d7db 100644
--- a/lib/private/updater.php
+++ b/lib/private/updater.php
@@ -30,6 +30,9 @@
 namespace OC;
 
 use OC\Hooks\BasicEmitter;
+use OC_App;
+use OC_Util;
+use OCP\IConfig;
 
 /**
  * Class that handles autoupdating of ownCloud
@@ -42,29 +45,27 @@ use OC\Hooks\BasicEmitter;
  */
 class Updater extends BasicEmitter {
 
-	/**
-	 * @var \OC\Log $log
-	 */
+	/** @var \OC\Log $log */
 	private $log;
 	
-	/**
-	 * @var \OC\HTTPHelper $helper;
-	 */
+	/** @var \OC\HTTPHelper $helper */
 	private $httpHelper;
 	
-	/**
-	 * @var \OCP\IAppConfig;
-	 */
+	/** @var IConfig */
 	private $config;
 
+	/** @var bool */
 	private $simulateStepEnabled;
 
+	/** @var bool */
 	private $updateStepEnabled;
 
 	/**
+	 * @param HTTPHelper $httpHelper
+	 * @param IConfig $config
 	 * @param \OC\Log $log
 	 */
-	public function __construct($httpHelper, $config,  $log = null) {
+	public function __construct(HTTPHelper $httpHelper, IConfig $config, $log = null) {
 		$this->httpHelper = $httpHelper;
 		$this->log = $log;
 		$this->config = $config;
@@ -102,23 +103,23 @@ class Updater extends BasicEmitter {
 	public function check($updaterUrl = null) {
 
 		// Look up the cache - it is invalidated all 30 minutes
-		if (($this->config->getValue('core', 'lastupdatedat') + 1800) > time()) {
-			return json_decode($this->config->getValue('core', 'lastupdateResult'), true);
+		if (((int)$this->config->getAppValue('core', 'lastupdatedat') + 1800) > time()) {
+			return json_decode($this->config->getAppValue('core', 'lastupdateResult'), true);
 		}
 
 		if (is_null($updaterUrl)) {
 			$updaterUrl = 'https://apps.owncloud.com/updater.php';
 		}
 
-		$this->config->setValue('core', 'lastupdatedat', time());
+		$this->config->setAppValue('core', 'lastupdatedat', time());
 
-		if ($this->config->getValue('core', 'installedat', '') == '') {
-			$this->config->setValue('core', 'installedat', microtime(true));
+		if ($this->config->getAppValue('core', 'installedat', '') == '') {
+			$this->config->setAppValue('core', 'installedat', microtime(true));
 		}
 
 		$version = \OC_Util::getVersion();
-		$version['installed'] = $this->config->getValue('core', 'installedat');
-		$version['updated'] = $this->config->getValue('core', 'lastupdatedat');
+		$version['installed'] = $this->config->getAppValue('core', 'installedat');
+		$version['updated'] = $this->config->getAppValue('core', 'lastupdatedat');
 		$version['updatechannel'] = \OC_Util::getChannel();
 		$version['edition'] = \OC_Util::getEditionString();
 		$version['build'] = \OC_Util::getBuild();
@@ -146,7 +147,7 @@ class Updater extends BasicEmitter {
 		}
 
 		// Cache the result
-		$this->config->setValue('core', 'lastupdateResult', json_encode($data));
+		$this->config->setAppValue('core', 'lastupdateResult', json_encode($data));
 		return $tmp;
 	}
 
@@ -157,9 +158,9 @@ class Updater extends BasicEmitter {
 	 * @return bool true if the operation succeeded, false otherwise
 	 */
 	public function upgrade() {
-		\OC_Config::setValue('maintenance', true);
+		$this->config->setSystemValue('maintenance', true);
 
-		$installedVersion = \OC_Config::getValue('version', '0.0.0');
+		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
 		$currentVersion = implode('.', \OC_Util::getVersion());
 		if ($this->log) {
 			$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
@@ -172,7 +173,7 @@ class Updater extends BasicEmitter {
 			$this->emit('\OC\Updater', 'failure', array($exception->getMessage()));
 		}
 
-		\OC_Config::setValue('maintenance', false);
+		$this->config->setSystemValue('maintenance', false);
 		$this->emit('\OC\Updater', 'maintenanceEnd');
 	}
 
@@ -220,10 +221,10 @@ class Updater extends BasicEmitter {
 		// create empty file in data dir, so we can later find
 		// out that this is indeed an ownCloud data directory
 		// (in case it didn't exist before)
-		file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
+		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
 
 		// pre-upgrade repairs
-		$repair = new \OC\Repair(\OC\Repair::getBeforeUpgradeRepairSteps());
+		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps());
 		$repair->run();
 
 		// simulate DB upgrade
@@ -238,22 +239,18 @@ class Updater extends BasicEmitter {
 		if ($this->updateStepEnabled) {
 			$this->doCoreUpgrade();
 
-			$disabledApps = \OC_App::checkAppsRequirements();
-			if (!empty($disabledApps)) {
-				$this->emit('\OC\Updater', 'disabledApps', array($disabledApps));
-			}
-
+			$this->checkAppsRequirements();
 			$this->doAppUpgrade();
 
 			// post-upgrade repairs
-			$repair = new \OC\Repair(\OC\Repair::getRepairSteps());
+			$repair = new Repair(Repair::getRepairSteps());
 			$repair->run();
 
 			//Invalidate update feed
-			$this->config->setValue('core', 'lastupdatedat', 0);
+			$this->config->setAppValue('core', 'lastupdatedat', 0);
 
 			// only set the final version if everything went well
-			\OC_Config::setValue('version', implode('.', \OC_Util::getVersion()));
+			$this->config->setSystemValue('version', implode('.', \OC_Util::getVersion()));
 		}
 	}
 
@@ -278,14 +275,11 @@ class Updater extends BasicEmitter {
 		$apps = \OC_App::getEnabledApps();
 
 		foreach ($apps as $appId) {
-			if ($version) {
-				$info = \OC_App::getAppInfo($appId);
-				$compatible = \OC_App::isAppCompatible($version, $info);
-			} else {
-				$compatible = true;
-			}
+			$info = \OC_App::getAppInfo($appId);
+			$compatible = \OC_App::isAppCompatible($version, $info);
+			$isShipped = \OC_App::isShipped($appId);
 
-			if ($compatible && \OC_App::shouldUpgrade($appId)) {
+			if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
 				/**
 				 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
 				 * are not possible anymore within it. - Consider this when touching the code.
@@ -356,5 +350,28 @@ class Updater extends BasicEmitter {
 			}
 		}
 	}
+
+	/**
+	 * check if the current enabled apps are compatible with the current
+	 * ownCloud version. disable them if not.
+	 * This is important if you upgrade ownCloud and have non ported 3rd
+	 * party apps installed.
+	 */
+	private function checkAppsRequirements() {
+		$apps = OC_App::getEnabledApps();
+		$version = OC_Util::getVersion();
+		foreach ($apps as $app) {
+			// check if the app is compatible with this version of ownCloud
+			$info = OC_App::getAppInfo($app);
+			if(!OC_App::isAppCompatible($version, $info)) {
+				OC_App::disable($app);
+				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
+			}
+			if (!OC_App::isShipped($app)) {
+				\OC_App::disable($app);
+				$this->emit('\OC\Updater', 'thirdPartyAppDisabled', array($app));
+			}
+		}
+	}
 }
 
diff --git a/tests/lib/updater.php b/tests/lib/updater.php
index f847ffc91bf..7a1bc48e1a8 100644
--- a/tests/lib/updater.php
+++ b/tests/lib/updater.php
@@ -88,7 +88,7 @@ class UpdaterTest extends \Test\TestCase {
 
 	protected function getUpdaterMock($content){
 		// Invalidate cache
-		$mockedAppConfig = $this->getMockBuilder('\OC\AppConfig')
+		$mockedConfig = $this->getMockBuilder('\OCP\IConfig')
 				->disableOriginalConstructor()
 				->getMock()
 		;
@@ -101,7 +101,7 @@ class UpdaterTest extends \Test\TestCase {
 
 		$mockedHTTPHelper->expects($this->once())->method('getUrlContent')->will($this->returnValue($content));
 
-		return new Updater($mockedHTTPHelper, $mockedAppConfig);
+		return new Updater($mockedHTTPHelper, $mockedConfig);
 	}
 
 }
-- 
GitLab