Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions lib/Controller/ExAppsPageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use OC\App\AppStore\Version\VersionParser;
use OC\App\DependencyAnalyzer;
use OC\App\Platform;
use OC_App;
use OCA\AppAPI\AppInfo\Application;
use OCA\AppAPI\DeployActions\DockerActions;
use OCA\AppAPI\Fetcher\ExAppFetcher;
Expand Down Expand Up @@ -518,8 +517,20 @@ public function uninstallApp(string $appId, bool $removeContainer = true, bool $
*/
#[PasswordConfirmationRequired]
public function force(string $appId): JSONResponse {
$appId = OC_App::cleanAppId($appId);
$this->appManager->overwriteNextcloudRequirement($appId);
$appId = $this->appManager->cleanAppId($appId);

// Same effect as the non-public OC\App\AppManager::overwriteNextcloudRequirement(),
// except that a corrupt (non-array) value is repaired instead of raising a TypeError.
// The same system value is read back in getAppsForCategory().
$ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []);
if (!is_array($ignoreMaxApps)) {
$this->logger->warning('The value given for app_install_overwrite is not an array. Ignoring...');
$ignoreMaxApps = [];
}
if (!in_array($appId, $ignoreMaxApps, true)) {
$ignoreMaxApps[] = $appId;
$this->config->setSystemValue('app_install_overwrite', $ignoreMaxApps);
}
return new JSONResponse();
}

Expand Down
63 changes: 61 additions & 2 deletions tests/php/Controller/ExAppsPageControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class ExAppsPageControllerTest extends TestCase {
private ExAppService&MockObject $exAppService;
private DaemonConfigService&MockObject $daemonConfigService;
private IConfig&MockObject $config;
private IAppManager&MockObject $appManager;

protected function setUp(): void {
parent::setUp();
Expand All @@ -49,7 +50,7 @@ protected function setUp(): void {
$this->exAppFetcher = $this->createMock(ExAppFetcher::class);
$l10n = $this->createMock(IL10N::class);
$logger = $this->createMock(LoggerInterface::class);
$appManager = $this->createMock(IAppManager::class);
$this->appManager = $this->createMock(IAppManager::class);
$this->exAppService = $this->createMock(ExAppService::class);
$exAppDeployOptionsService = $this->createMock(ExAppDeployOptionsService::class);

Expand All @@ -64,7 +65,7 @@ protected function setUp(): void {
$this->exAppFetcher,
$l10n,
$logger,
$appManager,
$this->appManager,
$this->exAppService,
$exAppDeployOptionsService,
);
Expand Down Expand Up @@ -169,4 +170,62 @@ public function testListAppsPicksTranslationForInjectedLanguage(): void {
self::assertSame('Fake App (de)', $data['apps'][0]['name']);
self::assertSame('Eine Test-App', $data['apps'][0]['description']);
}

/**
* force() marks an ExApp as compatible by adding its id to the
* `app_install_overwrite` system value. This mirrors the non-public
* OC\App\AppManager::overwriteNextcloudRequirement(); the same key is read
* back in getAppsForCategory(), so both sides must stay in sync.
*
* The id must be the one returned by cleanAppId(), not the raw input.
*/
public function testForceAppendsCleanedAppIdToOverwriteList(): void {
$this->appManager->expects(self::once())
->method('cleanAppId')
->with('My_ExApp!')
->willReturn('my_exapp');

$this->config->method('getSystemValue')
->with('app_install_overwrite', self::anything())
->willReturn(['other_app']);

$this->config->expects(self::once())
->method('setSystemValue')
->with('app_install_overwrite', ['other_app', 'my_exapp']);

self::assertInstanceOf(JSONResponse::class, $this->controller->force('My_ExApp!'));
}

/**
* The duplicate check must compare the cleaned id against the stored list,
* so this passes a raw id that differs from the cleaned one.
*/
public function testForceDoesNotRewriteWhenAlreadyMarked(): void {
$this->appManager->expects(self::once())
->method('cleanAppId')
->with('My_ExApp!')
->willReturn('my_exapp');

$this->config->method('getSystemValue')
->with('app_install_overwrite', self::anything())
->willReturn(['my_exapp']);

$this->config->expects(self::never())->method('setSystemValue');

self::assertInstanceOf(JSONResponse::class, $this->controller->force('My_ExApp!'));
}

public function testForceRecoversFromNonArrayOverwriteValue(): void {
$this->appManager->method('cleanAppId')->willReturn('my_exapp');

$this->config->method('getSystemValue')
->with('app_install_overwrite', self::anything())
->willReturn('not-an-array');

$this->config->expects(self::once())
->method('setSystemValue')
->with('app_install_overwrite', ['my_exapp']);

self::assertInstanceOf(JSONResponse::class, $this->controller->force('my_exapp'));
}
}
1 change: 0 additions & 1 deletion tests/psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
<UndefinedClass>
<code><![CDATA[$this->categoryFetcher]]></code>
<code><![CDATA[DependencyAnalyzer]]></code>
<code><![CDATA[OC_App]]></code>
<code><![CDATA[Platform]]></code>
<code><![CDATA[VersionParser]]></code>
<code><![CDATA[private]]></code>
Expand Down
Loading