From e212f337a2ea8371f20dbdae56beb3394ed62619 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Fri, 17 Jan 2025 15:24:32 +0100 Subject: [PATCH] fix(updatenotification): Parse pre-release version of apps The notitication is correctly created, but the changelog is not show. We need to make sure the version passed to the manager is in the allowed format (major.minor.patch). Signed-off-by: Ferdinand Thiessen --- .../lib/Controller/APIController.php | 13 +- apps/updatenotification/openapi.json | 30 ++++ .../tests/Controller/APIControllerTest.php | 162 ++++++++++++++++++ 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 apps/updatenotification/tests/Controller/APIControllerTest.php diff --git a/apps/updatenotification/lib/Controller/APIController.php b/apps/updatenotification/lib/Controller/APIController.php index 6b4f559f650..5b14297ae24 100644 --- a/apps/updatenotification/lib/Controller/APIController.php +++ b/apps/updatenotification/lib/Controller/APIController.php @@ -153,14 +153,23 @@ class APIController extends OCSController { * @param string $appId App to search changelog entry for * @param string|null $version The version to search the changelog entry for (defaults to the latest installed) * - * @return DataResponse|DataResponse + * @return DataResponse|DataResponse|DataResponse * * 200: Changelog entry returned + * 400: The `version` parameter is not a valid version format * 404: No changelog found */ public function getAppChangelogEntry(string $appId, ?string $version = null): DataResponse { $version = $version ?? $this->appManager->getAppVersion($appId); - $changes = $this->manager->getChangelog($appId, $version); + // handle pre-release versions + $matches = []; + $result = preg_match('/^(\d+\.\d+(\.\d+)?)/', $version, $matches); + if ($result === false || $result === 0) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + $shortVersion = $matches[0]; + + $changes = $this->manager->getChangelog($appId, $shortVersion); if ($changes === null) { return new DataResponse([], Http::STATUS_NOT_FOUND); diff --git a/apps/updatenotification/openapi.json b/apps/updatenotification/openapi.json index fb6c3c84cf5..969dfc7cfaa 100644 --- a/apps/updatenotification/openapi.json +++ b/apps/updatenotification/openapi.json @@ -338,6 +338,36 @@ } } } + }, + "400": { + "description": "The `version` parameter is not a valid version format", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object" + } + } + } + } + } + } + } } } } diff --git a/apps/updatenotification/tests/Controller/APIControllerTest.php b/apps/updatenotification/tests/Controller/APIControllerTest.php new file mode 100644 index 00000000000..3c3764248ef --- /dev/null +++ b/apps/updatenotification/tests/Controller/APIControllerTest.php @@ -0,0 +1,162 @@ +request = $this->createMock(IRequest::class); + $this->config = $this->createMock(IConfig::class); + $this->appManager = $this->createMock(IAppManager::class); + $this->appFetcher = $this->createMock(AppFetcher::class); + $this->l10nFactory = $this->createMock(IFactory::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->manager = $this->createMock(Manager::class); + + $this->apiController = new APIController( + Application::APP_NAME, + $this->request, + $this->config, + $this->appManager, + $this->appFetcher, + $this->l10nFactory, + $this->userSession, + $this->manager, + ); + } + + /** + * @dataProvider dataGetAppChangelog + */ + public function testGetAppChangelogEntry( + array $params, + bool $hasChanges, + array $appInfo, + array $expected, + ): void { + $this->appManager->method('getAppInfo') + ->with('the-app') + ->willReturn($appInfo); + $this->appManager->method('getAppVersion') + ->with('the-app') + ->willReturn($appInfo['version']); + $this->manager->method('getChangelog') + ->with('the-app', self::anything()) + ->willReturnCallback(fn ($app, $version) => $hasChanges ? "$app v$version" : null); + + $result = $this->apiController->getAppChangelogEntry(...$params); + $this->assertEquals($result->getStatus(), $expected['status']); + $this->assertEquals($result->getData(), $expected['data']); + } + + public static function dataGetAppChangelog(): array { + return [ + 'no changes found' => [ + ['the-app', null], + false, + [ + 'name' => 'Localized name', + 'version' => '1.0.0', + ], + [ + 'status' => Http::STATUS_NOT_FOUND, + 'data' => [], + ] + ], + 'changes with version parameter' => [ + ['the-app', '1.0.0'], + true, + [ + 'name' => 'Localized name', + 'version' => '1.2.0', // installed version + ], + [ + 'status' => Http::STATUS_OK, + 'data' => [ + 'appName' => 'Localized name', + 'content' => 'the-app v1.0.0', + 'version' => '1.0.0', + ], + ] + ], + 'changes without version parameter' => [ + ['the-app', null], + true, + [ + 'name' => 'Localized name', + 'version' => '1.2.0', + ], + [ + 'status' => Http::STATUS_OK, + 'data' => [ + 'appName' => 'Localized name', + 'content' => 'the-app v1.2.0', + 'version' => '1.2.0', + ], + ] + ], + 'changes of pre-release version' => [ + ['the-app', null], + true, + [ + 'name' => 'Localized name', + 'version' => '1.2.0-alpha.1', + ], + [ + 'status' => Http::STATUS_OK, + 'data' => [ + 'appName' => 'Localized name', + 'content' => 'the-app v1.2.0', + 'version' => '1.2.0-alpha.1', + ], + ] + ], + 'changes of pre-release version as parameter' => [ + ['the-app', '1.2.0-alpha.2'], + true, + [ + 'name' => 'Localized name', + 'version' => '1.2.0-beta.3', + ], + [ + 'status' => Http::STATUS_OK, + 'data' => [ + 'appName' => 'Localized name', + 'content' => 'the-app v1.2.0', + 'version' => '1.2.0-alpha.2', + ], + ] + ], + ]; + } +}