aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCôme Chilliet <91878298+come-nc@users.noreply.github.com>2025-06-05 17:55:08 +0200
committerGitHub <noreply@github.com>2025-06-05 17:55:08 +0200
commit5488f7e8b1e2676352edfcd0cf445144b8134db2 (patch)
treecce766251620203c8a5063e85ef0e5acafcd6688
parent4b50105fb4fe0175454ce01309075f7de71be96d (diff)
parentc85f7eacb88727c8e550fa38ff52d5ad992d1a77 (diff)
downloadnextcloud-server-5488f7e8b1e2676352edfcd0cf445144b8134db2.tar.gz
nextcloud-server-5488f7e8b1e2676352edfcd0cf445144b8134db2.zip
Merge pull request #53352 from nextcloud/fix/install-app-before-enable
fix: Do not enable applications which are not installed yet
-rw-r--r--apps/provisioning_api/lib/Controller/AppsController.php16
-rw-r--r--apps/provisioning_api/tests/Controller/AppsControllerTest.php11
-rwxr-xr-xbuild/integration/run.sh2
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/App/AppManager.php9
-rw-r--r--lib/private/App/AppStore/AppNotFoundException.php13
-rw-r--r--lib/private/Installer.php6
8 files changed, 55 insertions, 4 deletions
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 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\App\AppStore;
+
+class AppNotFoundException extends \Exception {
+}
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index 60896ec429d..3bbef3252f4 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace OC;
use Doctrine\DBAL\Exception\TableExistsException;
+use OC\App\AppStore\AppNotFoundException;
use OC\App\AppStore\Bundles\Bundle;
use OC\App\AppStore\Fetcher\AppFetcher;
use OC\AppFramework\Bootstrap\Coordinator;
@@ -174,6 +175,7 @@ class Installer {
* @param string $appId
* @param bool [$allowUnstable]
*
+ * @throws AppNotFoundException If the app is not found on the appstore
* @throws \Exception If the installation was not successful
*/
public function downloadApp(string $appId, bool $allowUnstable = false): void {
@@ -356,9 +358,9 @@ class Installer {
}
}
- throw new \Exception(
+ throw new AppNotFoundException(
sprintf(
- 'Could not download app %s',
+ 'Could not download app %s, it was not found on the appstore',
$appId
)
);