diff --git a/core/ajax/update.php b/core/ajax/update.php index baa01b4f20..656fe2736a 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 91e4c3c744..87e83afde2 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,17 @@ class Upgrade extends Command { $updater->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($output) { $output->writeln('Checked database schema update'); }); - $updater->listen('\OC\Updater', 'disabledApps', function ($appList) use($output) { - $output->writeln('Disabled incompatible apps: ' . implode(', ', $appList) . ''); + $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($output) { + $output->writeln('Disabled incompatible app: ' . $app . ''); + }); + $updater->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use($output) { + $output->writeln('Disabled 3rd-party app: ' . $app . ''); + }); + $updater->listen('\OC\Updater', 'appUpgradeCheck', function () use ($output) { + $output->writeln('Checked database schema update for apps'); + }); + $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($output) { + $output->writeln("Updated <$app> to $version"); }); $updater->listen('\OC\Updater', 'failure', function ($message) use($output, $self) { diff --git a/core/js/update.js b/core/js/update.js index f63808f65b..60f0483293 100644 --- a/core/js/update.js +++ b/core/js/update.js @@ -38,6 +38,9 @@ updateEventSource.listen('success', function(message) { $('').append(message).append('
').appendTo($el); }); + updateEventSource.listen('notice', function(message) { + $('').addClass('error').append(message).append('
').appendTo($el); + }); updateEventSource.listen('error', function(message) { $('').addClass('error').append(message).append('
').appendTo($el); message = t('core', 'Please reload the page.'); diff --git a/lib/private/app.php b/lib/private/app.php index 365b0d0906..2950ded078 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 c8be5631fe..9f06c7b45e 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 f76630d411..5b505d7ded 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,50 @@ 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() { + $isCoreUpgrade = $this->isCodeUpgrade(); + $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)); + } + // no need to disable any app in case this is a non-core upgrade + if (!$isCoreUpgrade) { + continue; + } + // shipped apps will remain enabled + if (OC_App::isShipped($app)) { + continue; + } + // authentication and session apps will remain enabled as well + if (OC_App::isType($app, ['session', 'authentication'])) { + continue; + } + + // disable any other 3rd party apps + \OC_App::disable($app); + $this->emit('\OC\Updater', 'thirdPartyAppDisabled', array($app)); + } + } + + private function isCodeUpgrade() { + $installedVersion = $this->config->getSystemValue('version', '0.0.0'); + $currentVersion = implode('.', OC_Util::getVersion()); + if (version_compare($currentVersion, $installedVersion, '>')) { + return true; + } + return false; + } } diff --git a/tests/lib/updater.php b/tests/lib/updater.php index f847ffc91b..7a1bc48e1a 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); } }