diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php index 7affb0d5069c0..4d34b7678d74d 100644 --- a/apps/settings/lib/Controller/AppSettingsController.php +++ b/apps/settings/lib/Controller/AppSettingsController.php @@ -6,6 +6,7 @@ */ namespace OCA\Settings\Controller; +use OC\App\AppManager; use OC\App\AppStore\Bundles\BundleFetcher; use OC\App\AppStore\Fetcher\AppDiscoverFetcher; use OC\App\AppStore\Fetcher\AppFetcher; @@ -15,7 +16,6 @@ use OC\App\Platform; use OC\Installer; use OCP\App\AppPathNotFoundException; -use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; @@ -62,7 +62,7 @@ public function __construct( private IL10N $l10n, private IConfig $config, private INavigationManager $navigationManager, - private IAppManager $appManager, + private AppManager $appManager, private CategoryFetcher $categoryFetcher, private AppFetcher $appFetcher, private IFactory $l10nFactory, @@ -592,6 +592,8 @@ public function uninstallApp(string $appId): JSONResponse { $appId = $this->appManager->cleanAppId($appId); $result = $this->installer->removeApp($appId); if ($result !== false) { + // If this app was force enabled, remove the force-enabled-state + $this->appManager->removeOverwriteNextcloudRequirement($appId); $this->appManager->clearAppsCache(); return new JSONResponse(['data' => ['appid' => $appId]]); } @@ -631,7 +633,7 @@ private function sortApps($a, $b) { public function force(string $appId): JSONResponse { $appId = $this->appManager->cleanAppId($appId); - $this->appManager->ignoreNextcloudRequirementForApp($appId); + $this->appManager->overwriteNextcloudRequirement($appId); return new JSONResponse(); } } diff --git a/apps/settings/tests/Controller/AppSettingsControllerTest.php b/apps/settings/tests/Controller/AppSettingsControllerTest.php index c219ee2fc9fda..f72bd45a3d234 100644 --- a/apps/settings/tests/Controller/AppSettingsControllerTest.php +++ b/apps/settings/tests/Controller/AppSettingsControllerTest.php @@ -6,13 +6,13 @@ */ namespace OCA\Settings\Tests\Controller; +use OC\App\AppManager; use OC\App\AppStore\Bundles\BundleFetcher; use OC\App\AppStore\Fetcher\AppDiscoverFetcher; use OC\App\AppStore\Fetcher\AppFetcher; use OC\App\AppStore\Fetcher\CategoryFetcher; use OC\Installer; use OCA\Settings\Controller\AppSettingsController; -use OCP\App\IAppManager; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; @@ -47,8 +47,7 @@ class AppSettingsControllerTest extends TestCase { private $config; /** @var INavigationManager|MockObject */ private $navigationManager; - /** @var IAppManager|MockObject */ - private $appManager; + private AppManager&MockObject $appManager; /** @var CategoryFetcher|MockObject */ private $categoryFetcher; /** @var AppFetcher|MockObject */ @@ -83,7 +82,7 @@ protected function setUp(): void { ->willReturnArgument(0); $this->config = $this->createMock(IConfig::class); $this->navigationManager = $this->createMock(INavigationManager::class); - $this->appManager = $this->createMock(IAppManager::class); + $this->appManager = $this->createMock(AppManager::class); $this->categoryFetcher = $this->createMock(CategoryFetcher::class); $this->appFetcher = $this->createMock(AppFetcher::class); $this->l10nFactory = $this->createMock(IFactory::class); diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 73445aadd05bb..437be7441f8c9 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -1025,11 +1025,6 @@ - - - - - getEMailAddress() => $user->getDisplayName()]]]> @@ -1337,12 +1332,6 @@ - - - - - - diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 2b6d2a2700bc4..fe5d3e2faebfc 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -200,10 +200,6 @@ public function getEnabledAppsForUser(IUser $user) { return array_keys($appsForUser); } - /** - * @param IGroup $group - * @return array - */ public function getEnabledAppsForGroup(IGroup $group): array { $apps = $this->getInstalledAppsValues(); $appsForGroups = array_filter($apps, function ($enabled) use ($group) { @@ -304,10 +300,6 @@ public function getAutoDisabledApps(): array { return $this->autoDisabledApps; } - /** - * @param string $appId - * @return array - */ public function getAppRestriction(string $appId): array { $values = $this->getInstalledAppsValues(); @@ -321,7 +313,6 @@ public function getAppRestriction(string $appId): array { return json_decode($values[$appId], true); } - /** * Check if an app is enabled for user * @@ -410,12 +401,25 @@ public function isInstalled($appId) { return isset($installedApps[$appId]); } - public function ignoreNextcloudRequirementForApp(string $appId): void { + /** + * Overwrite the `max-version` requirement for this app. + */ + public function overwriteNextcloudRequirement(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); } + $this->config->setSystemValue('app_install_overwrite', $ignoreMaxApps); + } + + /** + * Remove the `max-version` overwrite for this app. + * This means this app now again can not be enabled if the `max-version` is smaller than the current Nextcloud version. + */ + public function removeOverwriteNextcloudRequirement(string $appId): void { + $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []); + $ignoreMaxApps = array_filter($ignoreMaxApps, fn (string $id) => $id !== $appId); + $this->config->setSystemValue('app_install_overwrite', $ignoreMaxApps); } public function loadApp(string $app): void { @@ -573,7 +577,7 @@ public function enableApp(string $appId, bool $forceEnable = false): void { $this->getAppPath($appId); if ($forceEnable) { - $this->ignoreNextcloudRequirementForApp($appId); + $this->overwriteNextcloudRequirement($appId); } $this->installedAppsCache[$appId] = 'yes'; @@ -619,7 +623,7 @@ public function enableAppForGroups(string $appId, array $groups, bool $forceEnab } if ($forceEnable) { - $this->ignoreNextcloudRequirementForApp($appId); + $this->overwriteNextcloudRequirement($appId); } /** @var string[] $groupIds */ @@ -646,7 +650,7 @@ public function enableAppForGroups(string $appId, array $groups, bool $forceEnab * @param bool $automaticDisabled * @throws \Exception if app can't be disabled */ - public function disableApp($appId, $automaticDisabled = false) { + public function disableApp($appId, $automaticDisabled = false): void { if ($this->isAlwaysEnabled($appId)) { throw new \Exception("$appId can't be disabled."); } @@ -706,7 +710,7 @@ public function getAppWebPath(string $appId): string { /** * Clear the cached list of apps when enabling/disabling an app */ - public function clearAppsCache() { + public function clearAppsCache(): void { $this->appInfos = []; } diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index 0af7cdfc49530..110bcacf396be 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -144,7 +144,7 @@ public function enableAppForGroups(string $appId, array $groups, bool $forceEnab * @param bool $automaticDisabled * @since 8.0.0 */ - public function disableApp($appId, $automaticDisabled = false); + public function disableApp($appId, $automaticDisabled = false): void; /** * Get the directory for the given app. @@ -185,7 +185,7 @@ public function getInstalledApps(); * Clear the cached list of apps when enabling/disabling an app * @since 8.1.0 */ - public function clearAppsCache(); + public function clearAppsCache(): void; /** * @param string $appId @@ -201,7 +201,7 @@ public function isShipped($appId); * @return bool * * This function walks through the Nextcloud directory and loads all apps - * it can find. A directory contains an app if the file /appinfo/info.xml + * it can find. A directory contains an app if the file `/appinfo/info.xml` * exists. * * if $types is set to non-empty array, only apps of those types will be loaded @@ -271,7 +271,7 @@ public function getDefaultApps(): array; /** * Set the global default apps with fallbacks * - * @param string[] $appId + * @param string[] $defaultApps * @throws \InvalidArgumentException If any of the apps is not installed * @since 28.0.0 * @deprecated 31.0.0