diff --git a/apps/provisioning_api/lib/Controller/AppsController.php b/apps/provisioning_api/lib/Controller/AppsController.php index 4d32584591b15..3f6cff7442a6d 100644 --- a/apps/provisioning_api/lib/Controller/AppsController.php +++ b/apps/provisioning_api/lib/Controller/AppsController.php @@ -8,6 +8,8 @@ */ 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\DataResponse; use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCSController; +use OCP\IAppConfig; use OCP\IRequest; class AppsController extends OCSController { @@ -23,6 +26,8 @@ public function __construct( string $appName, IRequest $request, private IAppManager $appManager, + private Installer $installer, + private IAppConfig $appConfig, ) { parent::__construct($appName, $request); } @@ -108,10 +113,19 @@ public function getAppInfo(string $app): DataResponse { 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 f56be7c4c366f..f95daeae7d381 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 @@ */ 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 @@ protected function setUp(): void { $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 cbd3cceb3d163..30dd0646b1081 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 41bf5d54a330f..36f64d970c3ab 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1049,6 +1049,7 @@ '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 6fbcd9b9cfaf5..327366ca889a0 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 413dc6ccd46e4..18f29114d0e1f 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -545,11 +545,16 @@ public function isAppLoaded(string $app): bool { * @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 @@ public function enableAppForGroups(string $appId, array $groups, bool $forceEnab 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 0000000000000..79ceebb44233f --- /dev/null +++ b/lib/private/App/AppStore/AppNotFoundException.php @@ -0,0 +1,13 @@ +