diff --git a/apps/provisioning_api/lib/Controller/AppsController.php b/apps/provisioning_api/lib/Controller/AppsController.php index 4d32584591b..3f6cff7442a 100644 --- a/apps/provisioning_api/lib/Controller/AppsController.php +++ b/apps/provisioning_api/lib/Controller/AppsController.php @@ -8,6 +8,8 @@ declare(strict_types=1); */ namespace OCA\Provisioning_API\Controller; +use OC\App\AppStore\AppNotFoundException; +use OC\Installer; use OC_App; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; @@ -16,6 +18,7 @@ use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCSController; +use OCP\IAppConfig; use OCP\IRequest; class AppsController extends OCSController { @@ -23,6 +26,8 @@ class AppsController extends OCSController { string $appName, IRequest $request, private IAppManager $appManager, + private Installer $installer, + private IAppConfig $appConfig, ) { parent::__construct($appName, $request); } @@ -108,10 +113,19 @@ class AppsController extends OCSController { public function enable(string $app): DataResponse { try { $app = $this->verifyAppId($app); + + if (!$this->installer->isDownloaded($app)) { + $this->installer->downloadApp($app); + } + + if ($this->appConfig->getValueString($app, 'installed_version', '') === '') { + $this->installer->installApp($app); + } + $this->appManager->enableApp($app); } catch (\InvalidArgumentException $e) { throw new OCSException($e->getMessage(), OCSController::RESPOND_UNAUTHORISED); - } catch (AppPathNotFoundException $e) { + } catch (AppPathNotFoundException|AppNotFoundException $e) { throw new OCSException('The request app was not found', OCSController::RESPOND_NOT_FOUND); } return new DataResponse(); diff --git a/apps/provisioning_api/tests/Controller/AppsControllerTest.php b/apps/provisioning_api/tests/Controller/AppsControllerTest.php index f56be7c4c36..f95daeae7d3 100644 --- a/apps/provisioning_api/tests/Controller/AppsControllerTest.php +++ b/apps/provisioning_api/tests/Controller/AppsControllerTest.php @@ -7,14 +7,17 @@ */ namespace OCA\Provisioning_API\Tests\Controller; +use OC\Installer; use OCA\Provisioning_API\Controller\AppsController; use OCA\Provisioning_API\Tests\TestCase; use OCP\App\IAppManager; use OCP\AppFramework\OCS\OCSException; +use OCP\IAppConfig; use OCP\IGroupManager; use OCP\IRequest; use OCP\IUserSession; use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; /** * Class AppsTest @@ -25,6 +28,8 @@ use OCP\Server; */ class AppsControllerTest extends TestCase { private IAppManager $appManager; + private IAppConfig&MockObject $appConfig; + private Installer&MockObject $installer; private AppsController $api; private IUserSession $userSession; @@ -34,13 +39,17 @@ class AppsControllerTest extends TestCase { $this->appManager = Server::get(IAppManager::class); $this->groupManager = Server::get(IGroupManager::class); $this->userSession = Server::get(IUserSession::class); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->installer = $this->createMock(Installer::class); $request = $this->createMock(IRequest::class); $this->api = new AppsController( 'provisioning_api', $request, - $this->appManager + $this->appManager, + $this->installer, + $this->appConfig, ); } diff --git a/build/integration/run.sh b/build/integration/run.sh index cbd3cceb3d1..30dd0646b10 100755 --- a/build/integration/run.sh +++ b/build/integration/run.sh @@ -18,6 +18,8 @@ HIDE_OC_LOGS=$2 INSTALLED=$($OCC status | grep installed: | cut -d " " -f 5) if [ "$INSTALLED" == "true" ]; then + # Disable appstore to avoid spamming from CI + $OCC config:system:set appstoreenabled --value=false --type=boolean # Disable bruteforce protection because the integration tests do trigger them $OCC config:system:set auth.bruteforce.protection.enabled --value false --type bool # Disable rate limit protection because the integration tests do trigger them diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 41bf5d54a33..36f64d970c3 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1049,6 +1049,7 @@ return array( 'OC\\AppScriptDependency' => $baseDir . '/lib/private/AppScriptDependency.php', 'OC\\AppScriptSort' => $baseDir . '/lib/private/AppScriptSort.php', 'OC\\App\\AppManager' => $baseDir . '/lib/private/App/AppManager.php', + 'OC\\App\\AppStore\\AppNotFoundException' => $baseDir . '/lib/private/App/AppStore/AppNotFoundException.php', 'OC\\App\\AppStore\\Bundles\\Bundle' => $baseDir . '/lib/private/App/AppStore/Bundles/Bundle.php', 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => $baseDir . '/lib/private/App/AppStore/Bundles/BundleFetcher.php', 'OC\\App\\AppStore\\Bundles\\EducationBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/EducationBundle.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 6fbcd9b9cfa..327366ca889 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1090,6 +1090,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\AppScriptDependency' => __DIR__ . '/../../..' . '/lib/private/AppScriptDependency.php', 'OC\\AppScriptSort' => __DIR__ . '/../../..' . '/lib/private/AppScriptSort.php', 'OC\\App\\AppManager' => __DIR__ . '/../../..' . '/lib/private/App/AppManager.php', + 'OC\\App\\AppStore\\AppNotFoundException' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/AppNotFoundException.php', 'OC\\App\\AppStore\\Bundles\\Bundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/Bundle.php', 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/BundleFetcher.php', 'OC\\App\\AppStore\\Bundles\\EducationBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/EducationBundle.php', diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 413dc6ccd46..18f29114d0e 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -545,11 +545,16 @@ class AppManager implements IAppManager { * @param string $appId * @param bool $forceEnable * @throws AppPathNotFoundException + * @throws \InvalidArgumentException if the application is not installed yet */ public function enableApp(string $appId, bool $forceEnable = false): void { // Check if app exists $this->getAppPath($appId); + if ($this->config->getAppValue($appId, 'installed_version', '') === '') { + throw new \InvalidArgumentException("$appId is not installed, cannot be enabled."); + } + if ($forceEnable) { $this->overwriteNextcloudRequirement($appId); } @@ -596,6 +601,10 @@ class AppManager implements IAppManager { throw new \InvalidArgumentException("$appId can't be enabled for groups."); } + if ($this->config->getAppValue($appId, 'installed_version', '') === '') { + throw new \InvalidArgumentException("$appId is not installed, cannot be enabled."); + } + if ($forceEnable) { $this->overwriteNextcloudRequirement($appId); } diff --git a/lib/private/App/AppStore/AppNotFoundException.php b/lib/private/App/AppStore/AppNotFoundException.php new file mode 100644 index 00000000000..79ceebb4423 --- /dev/null +++ b/lib/private/App/AppStore/AppNotFoundException.php @@ -0,0 +1,13 @@ +