From 3eee359d7ffd6219f6a2ab8cca18a13118552842 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 5 Sep 2019 12:55:24 +0200 Subject: [PATCH] Allow to force enable apps via CLI Co-authored-by: Christoph Wurst Signed-off-by: Joas Schilling Signed-off-by: Christoph Wurst --- .../lib/Controller/AppSettingsController.php | 8 +-- core/Command/App/Enable.php | 18 ++++-- lib/private/App/AppManager.php | 29 +++++++++- lib/private/Installer.php | 5 +- lib/private/Server.php | 1 + lib/public/App/IAppManager.php | 6 +- tests/lib/App/AppManagerTest.php | 57 +++++++++++-------- tests/lib/AppTest.php | 1 + 8 files changed, 83 insertions(+), 42 deletions(-) diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php index e0b2524052..80ba23594a 100644 --- a/apps/settings/lib/Controller/AppSettingsController.php +++ b/apps/settings/lib/Controller/AppSettingsController.php @@ -549,13 +549,7 @@ class AppSettingsController extends Controller { public function force(string $appId): JSONResponse { $appId = OC_App::cleanAppId($appId); - - $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []); - if (!in_array($appId, $ignoreMaxApps, true)) { - $ignoreMaxApps[] = $appId; - $this->config->setSystemValue('app_install_overwrite', $ignoreMaxApps); - } - + $this->appManager->ignoreNextcloudRequirementForApp($appId); return new JSONResponse(); } diff --git a/core/Command/App/Enable.php b/core/Command/App/Enable.php index 6e91ae430a..c4e2363def 100644 --- a/core/Command/App/Enable.php +++ b/core/Command/App/Enable.php @@ -73,15 +73,22 @@ class Enable extends Command implements CompletionAwareInterface { 'g', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'enable the app only for a list of groups' + ) + ->addOption( + 'force', + 'f', + InputOption::VALUE_NONE, + 'enable the app regardless of the Nextcloud version requirement' ); } protected function execute(InputInterface $input, OutputInterface $output) { $appIds = $input->getArgument('app-id'); $groups = $this->resolveGroupIds($input->getOption('groups')); + $forceEnable = (bool) $input->getOption('force'); foreach ($appIds as $appId) { - $this->enableApp($appId, $groups, $output); + $this->enableApp($appId, $groups, $forceEnable, $output); } return $this->exitCode; @@ -90,9 +97,10 @@ class Enable extends Command implements CompletionAwareInterface { /** * @param string $appId * @param array $groupIds + * @param bool $forceEnable * @param OutputInterface $output */ - private function enableApp(string $appId, array $groupIds, OutputInterface $output): void { + private function enableApp(string $appId, array $groupIds, bool $forceEnable, OutputInterface $output): void { $groupNames = array_map(function (IGroup $group) { return $group->getDisplayName(); }, $groupIds); @@ -106,13 +114,13 @@ class Enable extends Command implements CompletionAwareInterface { $installer->downloadApp($appId); } - $installer->installApp($appId); + $installer->installApp($appId, $forceEnable); if ($groupIds === []) { - $this->appManager->enableApp($appId); + $this->appManager->enableApp($appId, $forceEnable); $output->writeln($appId . ' enabled'); } else { - $this->appManager->enableAppForGroups($appId, $groupIds); + $this->appManager->enableAppForGroups($appId, $groupIds, $forceEnable); $output->writeln($appId . ' enabled for groups: ' . implode(', ', $groupNames)); } } catch (AppPathNotFoundException $e) { diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 130ea1510c..937cc51198 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -42,6 +42,7 @@ use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; use OCP\App\ManagerEvent; use OCP\ICacheFactory; +use OCP\IConfig; use OCP\IGroup; use OCP\IGroupManager; use OCP\ILogger; @@ -66,6 +67,9 @@ class AppManager implements IAppManager { /** @var IUserSession */ private $userSession; + /** @var IConfig */ + private $config; + /** @var AppConfig */ private $appConfig; @@ -101,18 +105,21 @@ class AppManager implements IAppManager { /** * @param IUserSession $userSession + * @param IConfig $config * @param AppConfig $appConfig * @param IGroupManager $groupManager * @param ICacheFactory $memCacheFactory * @param EventDispatcherInterface $dispatcher */ public function __construct(IUserSession $userSession, + IConfig $config, AppConfig $appConfig, IGroupManager $groupManager, ICacheFactory $memCacheFactory, EventDispatcherInterface $dispatcher, ILogger $logger) { $this->userSession = $userSession; + $this->config = $config; $this->appConfig = $appConfig; $this->groupManager = $groupManager; $this->memCacheFactory = $memCacheFactory; @@ -296,16 +303,29 @@ class AppManager implements IAppManager { return isset($installedApps[$appId]); } + public function ignoreNextcloudRequirementForApp(string $appId): void { + $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []); + if (!in_array($appId, $ignoreMaxApps, true)) { + $ignoreMaxApps[] = $appId; + $this->config->setSystemValue('app_install_overwrite', $ignoreMaxApps); + } + } + /** * Enable an app for every user * * @param string $appId + * @param bool $forceEnable * @throws AppPathNotFoundException */ - public function enableApp($appId) { + public function enableApp(string $appId, bool $forceEnable = false): void { // Check if app exists $this->getAppPath($appId); + if ($forceEnable) { + $this->ignoreNextcloudRequirementForApp($appId); + } + $this->installedAppsCache[$appId] = 'yes'; $this->appConfig->setValue($appId, 'enabled', 'yes'); $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent( @@ -334,10 +354,11 @@ class AppManager implements IAppManager { * * @param string $appId * @param \OCP\IGroup[] $groups + * @param bool $forceEnable * @throws \InvalidArgumentException if app can't be enabled for groups * @throws AppPathNotFoundException */ - public function enableAppForGroups($appId, $groups) { + public function enableAppForGroups(string $appId, array $groups, bool $forceEnable = false): void { // Check if app exists $this->getAppPath($appId); @@ -346,6 +367,10 @@ class AppManager implements IAppManager { throw new \InvalidArgumentException("$appId can't be enabled for groups."); } + if ($forceEnable) { + $this->ignoreNextcloudRequirementForApp($appId); + } + $groupIds = array_map(function ($group) { /** @var \OCP\IGroup $group */ return ($group instanceof IGroup) diff --git a/lib/private/Installer.php b/lib/private/Installer.php index 2ad1fb36af..d583dd2076 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -94,10 +94,11 @@ class Installer { * Installs an app that is located in one of the app folders already * * @param string $appId App to install + * @param bool $forceEnable * @throws \Exception * @return string app ID */ - public function installApp($appId) { + public function installApp(string $appId, bool $forceEnable = false): string { $app = \OC_App::findAppInDirectories($appId); if($app === false) { throw new \Exception('App not found in any app directory'); @@ -117,7 +118,7 @@ class Installer { } $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []); - $ignoreMax = in_array($appId, $ignoreMaxApps); + $ignoreMax = $forceEnable || in_array($appId, $ignoreMaxApps, true); $version = implode('.', \OCP\Util::getVersion()); if (!\OC_App::isAppCompatible($version, $info, $ignoreMax)) { diff --git a/lib/private/Server.php b/lib/private/Server.php index b8765654c3..78304b6fcb 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -798,6 +798,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService(AppManager::class, function (Server $c) { return new \OC\App\AppManager( $c->getUserSession(), + $c->getConfig(), $c->query(\OC\AppConfig::class), $c->getGroupManager(), $c->getMemCacheFactory(), diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index 918c759744..4cf8da586e 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -86,10 +86,11 @@ interface IAppManager { * Enable an app for every user * * @param string $appId + * @param bool $forceEnable * @throws AppPathNotFoundException * @since 8.0.0 */ - public function enableApp($appId); + public function enableApp(string $appId, bool $forceEnable = false): void; /** * Whether a list of types contains a protected app type @@ -105,10 +106,11 @@ interface IAppManager { * * @param string $appId * @param \OCP\IGroup[] $groups + * @param bool $forceEnable * @throws \Exception * @since 8.0.0 */ - public function enableAppForGroups($appId, $groups); + public function enableAppForGroups(string $appId, array $groups, bool $forceEnable = false): void; /** * Disable an app for every user diff --git a/tests/lib/App/AppManagerTest.php b/tests/lib/App/AppManagerTest.php index 11450667fc..0e895b5f99 100644 --- a/tests/lib/App/AppManagerTest.php +++ b/tests/lib/App/AppManagerTest.php @@ -1,4 +1,4 @@ - @@ -11,20 +11,17 @@ namespace Test\App; use OC\App\AppManager; use OC\AppConfig; -use OC\Group\Group; -use OC\User\User; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; -use OCP\IAppConfig; use OCP\ICache; use OCP\ICacheFactory; use OCP\IConfig; use OCP\IGroup; use OCP\IGroupManager; use OCP\ILogger; -use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserSession; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Test\TestCase; @@ -35,7 +32,7 @@ use Test\TestCase; */ class AppManagerTest extends TestCase { /** - * @return AppConfig|\PHPUnit_Framework_MockObject_MockObject + * @return AppConfig|MockObject */ protected function getAppConfig() { $appConfig = array(); @@ -73,25 +70,28 @@ class AppManagerTest extends TestCase { return $config; } - /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ + /** @var IUserSession|MockObject */ protected $userSession; - /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ + /** @var IConfig|MockObject */ + private $config; + + /** @var IGroupManager|MockObject */ protected $groupManager; - /** @var AppConfig|\PHPUnit_Framework_MockObject_MockObject */ + /** @var AppConfig|MockObject */ protected $appConfig; - /** @var ICache|\PHPUnit_Framework_MockObject_MockObject */ + /** @var ICache|MockObject */ protected $cache; - /** @var ICacheFactory|\PHPUnit_Framework_MockObject_MockObject */ + /** @var ICacheFactory|MockObject */ protected $cacheFactory; - /** @var EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject */ + /** @var EventDispatcherInterface|MockObject */ protected $eventDispatcher; - /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */ + /** @var ILogger|MockObject */ protected $logger; /** @var IAppManager */ @@ -102,6 +102,7 @@ class AppManagerTest extends TestCase { $this->userSession = $this->createMock(IUserSession::class); $this->groupManager = $this->createMock(IGroupManager::class); + $this->config = $this->createMock(IConfig::class); $this->appConfig = $this->getAppConfig(); $this->cacheFactory = $this->createMock(ICacheFactory::class); $this->cache = $this->createMock(ICache::class); @@ -111,7 +112,15 @@ class AppManagerTest extends TestCase { ->method('createDistributed') ->with('settings') ->willReturn($this->cache); - $this->manager = new AppManager($this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger); + $this->manager = new AppManager( + $this->userSession, + $this->config, + $this->appConfig, + $this->groupManager, + $this->cacheFactory, + $this->eventDispatcher, + $this->logger + ); } protected function expectClearCache() { @@ -161,10 +170,10 @@ class AppManagerTest extends TestCase { $groups = [$group1, $group2]; $this->expectClearCache(); - /** @var AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */ + /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) ->setConstructorArgs([ - $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger + $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger ]) ->setMethods([ 'getAppPath', @@ -208,10 +217,10 @@ class AppManagerTest extends TestCase { $groups = [$group1, $group2]; $this->expectClearCache(); - /** @var AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */ + /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) ->setConstructorArgs([ - $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger + $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger ]) ->setMethods([ 'getAppPath', @@ -262,10 +271,10 @@ class AppManagerTest extends TestCase { $groups = [$group1, $group2]; - /** @var AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */ + /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) ->setConstructorArgs([ - $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger + $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger ]) ->setMethods([ 'getAppPath', @@ -426,9 +435,9 @@ class AppManagerTest extends TestCase { } public function testGetAppsNeedingUpgrade() { - /** @var AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */ + /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) - ->setConstructorArgs([$this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger]) + ->setConstructorArgs([$this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger]) ->setMethods(['getAppInfo']) ->getMock(); @@ -476,9 +485,9 @@ class AppManagerTest extends TestCase { } public function testGetIncompatibleApps() { - /** @var AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */ + /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) - ->setConstructorArgs([$this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger]) + ->setConstructorArgs([$this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger]) ->setMethods(['getAppInfo']) ->getMock(); diff --git a/tests/lib/AppTest.php b/tests/lib/AppTest.php index 4aac0d6831..4ef370cd34 100644 --- a/tests/lib/AppTest.php +++ b/tests/lib/AppTest.php @@ -549,6 +549,7 @@ class AppTest extends \Test\TestCase { $this->overwriteService('AppConfig', $appConfig); $this->overwriteService('AppManager', new \OC\App\AppManager( \OC::$server->getUserSession(), + \OC::$server->getConfig(), $appConfig, \OC::$server->getGroupManager(), \OC::$server->getMemCacheFactory(),