From fd3c93931a72e44cbfef062b591829a81523ed28 Mon Sep 17 00:00:00 2001 From: bhdnb <172895427+bhdnb@users.noreply.github.com> Date: Thu, 16 Jan 2025 09:44:31 +0200 Subject: [PATCH] fix: If-None-Match header reset in Translation API (#204) --- src/CrowdinApiClient/Api/AbstractApi.php | 2 +- src/CrowdinApiClient/Api/TranslationApi.php | 17 +++- .../CrowdinApiClient/Api/AbstractTestApi.php | 6 +- .../Api/Enterprise/AbstractTestApi.php | 6 +- .../Api/Enterprise/TranslationApiTest.php | 4 - tests/CrowdinApiClient/Api/StorageApiTest.php | 21 ++--- .../Api/TranslationApiTest.php | 88 ++++++++++++------- 7 files changed, 89 insertions(+), 55 deletions(-) diff --git a/src/CrowdinApiClient/Api/AbstractApi.php b/src/CrowdinApiClient/Api/AbstractApi.php index 9909b006..62c80853 100644 --- a/src/CrowdinApiClient/Api/AbstractApi.php +++ b/src/CrowdinApiClient/Api/AbstractApi.php @@ -77,7 +77,7 @@ public function setHeaders(array $headers) return $this; } - public function hasHeader($header) + public function hasHeader($header): bool { return isset($this->headers[strtolower($header)]); } diff --git a/src/CrowdinApiClient/Api/TranslationApi.php b/src/CrowdinApiClient/Api/TranslationApi.php index d77a4385..38cf553c 100644 --- a/src/CrowdinApiClient/Api/TranslationApi.php +++ b/src/CrowdinApiClient/Api/TranslationApi.php @@ -73,8 +73,11 @@ public function getPreTranslation(int $projectId, string $preTranslationId): ?Pr * boolean $params[preserveFolderHierarchy] Default: false
* @return TranslationProjectDirectory|null */ - public function buildProjectDirectoryTranslation(int $projectId, int $directoryId, array $params = []): ?TranslationProjectDirectory - { + public function buildProjectDirectoryTranslation( + int $projectId, + int $directoryId, + array $params = [] + ): ?TranslationProjectDirectory { $path = sprintf('projects/%d/translations/builds/directories/%d', $projectId, $directoryId); return $this->_post($path, TranslationProjectDirectory::class, $params); @@ -96,12 +99,18 @@ public function buildProjectDirectoryTranslation(int $projectId, int $directoryI * boolean $params[skipUntranslatedFiles] true value can't be used with skipUntranslatedStrings=true in same request
* boolean $params[exportApprovedOnly] */ - public function buildProjectFileTranslation(int $projectId, int $fileId, array $params = [], string $ifNoneMatch = null): ?DownloadFile - { + public function buildProjectFileTranslation( + int $projectId, + int $fileId, + array $params = [], + ?string $ifNoneMatch = null + ): ?DownloadFile { $path = sprintf('projects/%d/translations/builds/files/%d', $projectId, $fileId); if ($ifNoneMatch) { $this->setHeader('If-None-Match', $ifNoneMatch); + } else { + $this->removeHeader('If-None-Match'); } return $this->_post($path, DownloadFileTranslation::class, $params); diff --git a/tests/CrowdinApiClient/Api/AbstractTestApi.php b/tests/CrowdinApiClient/Api/AbstractTestApi.php index 4ef0b906..e51640b3 100644 --- a/tests/CrowdinApiClient/Api/AbstractTestApi.php +++ b/tests/CrowdinApiClient/Api/AbstractTestApi.php @@ -46,9 +46,11 @@ public function mockRequest(array $params) if (isset($params['body'])) { $this->assertEquals($params['body'], $options['body']); } - if (isset($params['header'])) { - $this->assertEquals($params['header'], $options['header']); + + if (isset($params['headers'])) { + $this->assertEquals($params['headers'], $options['headers']); } + return $params['response'] ?? ''; })); } diff --git a/tests/CrowdinApiClient/Api/Enterprise/AbstractTestApi.php b/tests/CrowdinApiClient/Api/Enterprise/AbstractTestApi.php index 82dad661..c652ff52 100644 --- a/tests/CrowdinApiClient/Api/Enterprise/AbstractTestApi.php +++ b/tests/CrowdinApiClient/Api/Enterprise/AbstractTestApi.php @@ -47,9 +47,11 @@ public function mockRequest(array $params) if (isset($params['body'])) { $this->assertEquals($params['body'], $options['body']); } - if (isset($params['header'])) { - $this->assertEquals($params['header'], $options['header']); + + if (isset($params['headers'])) { + $this->assertEquals($params['headers'], $options['headers']); } + return $params['response'] ?? ''; })); } diff --git a/tests/CrowdinApiClient/Api/Enterprise/TranslationApiTest.php b/tests/CrowdinApiClient/Api/Enterprise/TranslationApiTest.php index c0b201a7..e9870a9b 100644 --- a/tests/CrowdinApiClient/Api/Enterprise/TranslationApiTest.php +++ b/tests/CrowdinApiClient/Api/Enterprise/TranslationApiTest.php @@ -8,10 +8,6 @@ use CrowdinApiClient\Model\TranslationProjectDirectory; use CrowdinApiClient\ModelCollection; -/** - * Class TranslationApiTest - * @package Crowdin\Tests\Api - */ class TranslationApiTest extends AbstractTestApi { public function testApplyPreTranslation() diff --git a/tests/CrowdinApiClient/Api/StorageApiTest.php b/tests/CrowdinApiClient/Api/StorageApiTest.php index dea3d7ad..be944ce9 100644 --- a/tests/CrowdinApiClient/Api/StorageApiTest.php +++ b/tests/CrowdinApiClient/Api/StorageApiTest.php @@ -4,7 +4,7 @@ use CrowdinApiClient\Model\Storage; use CrowdinApiClient\ModelCollection; -use CrowdinApiClient\Utility\Mimetypes; +use SplFileInfo; class StorageApiTest extends AbstractTestApi { @@ -68,21 +68,22 @@ public function testDelete() $this->crowdin->storage->delete(1); } - public function testCreate() + public function testCreate(): void { - $fileObject = new \SplFileInfo(__FILE__); + $fileObject = new SplFileInfo(__FILE__); $this->mockRequest([ 'method' => 'post', 'uri' => 'https://api.crowdin.com/api/v2/storages', - 'response' => '{ - "data": { - "id": 1 - } - }', + 'response' => json_encode([ + 'data' => [ + 'id' => 1 + ] + ]), 'headers' => [ - 'Content-Type' => Mimetypes::getInstance()->fromFilename($fileObject->getFilename()), - 'Crowdin-API-FileName' => $fileObject->getFilename(), + 'Content-Type' => 'application/octet-stream', + 'Crowdin-API-FileName' => 'StorageApiTest.php', + 'Authorization' => 'Bearer access_token', ], ]); diff --git a/tests/CrowdinApiClient/Api/TranslationApiTest.php b/tests/CrowdinApiClient/Api/TranslationApiTest.php index e625889b..6f316595 100644 --- a/tests/CrowdinApiClient/Api/TranslationApiTest.php +++ b/tests/CrowdinApiClient/Api/TranslationApiTest.php @@ -7,17 +7,13 @@ use CrowdinApiClient\Model\TranslationProjectBuild; use CrowdinApiClient\ModelCollection; -/** - * Class TranslationApiTest - * @package Crowdin\Tests\Api - */ class TranslationApiTest extends AbstractTestApi { public function testApplyPreTranslation() { $params = [ 'languageIds' => ['uk'], - 'fileIds' => [0] + 'fileIds' => [0], ]; $this->mockRequest([ @@ -50,7 +46,7 @@ public function testApplyPreTranslation() "startedAt": "2019-11-13T08:17:22Z", "finishedAt": "2019-11-13T08:17:22Z" } - }' + }', ]); $preTranslation = $this->crowdin->translation->applyPreTranslation(2, $params); @@ -60,7 +56,9 @@ public function testApplyPreTranslation() public function testGetPreTranslation() { - $this->mockRequestGet('/projects/2/pre-translations/9e7de270-4f83-41cb-b606-2f90631f26e2', '{ + $this->mockRequestGet( + '/projects/2/pre-translations/9e7de270-4f83-41cb-b606-2f90631f26e2', + '{ "data": { "identifier": "9e7de270-4f83-41cb-b606-2f90631f26e2", "status": "created", @@ -86,7 +84,8 @@ public function testGetPreTranslation() "startedAt": "2019-11-13T08:17:22Z", "finishedAt": "2019-11-13T08:17:22Z" } - }'); + }' + ); $preTranslation = $this->crowdin->translation->getPreTranslation(2, '9e7de270-4f83-41cb-b606-2f90631f26e2'); @@ -94,20 +93,30 @@ public function testGetPreTranslation() $this->assertEquals('9e7de270-4f83-41cb-b606-2f90631f26e2', $preTranslation->getIdentifier()); } - public function testBuildProjectFileTranslation() + public function testBuildProjectFileTranslation(): void { $this->mockRequest([ 'uri' => 'https://api.crowdin.com/api/v2/projects/1/translations/builds/files/2', 'method' => 'post', - 'response' => '{ - "data": { - "url": "https://foo.com/file", - "expireIn": "2019-09-20T10:31:21+00:00" - } - }' + 'headers' => [ + 'content-type' => 'application/json', + 'if-none-match' => 'bfc13a64729c4290ef5b2c2730249c88ca92d82d', + 'Authorization' => 'Bearer access_token', + ], + 'response' => json_encode([ + 'data' => [ + 'url' => 'https://foo.com/file', + 'expireIn' => '2019-09-20T10:31:21+00:00', + ], + ]), ]); - $file = $this->crowdin->translation->buildProjectFileTranslation(1, 2, ['targetLanguageId' => 'uk']); + $file = $this->crowdin->translation->buildProjectFileTranslation( + 1, + 2, + ['targetLanguageId' => 'uk'], + 'bfc13a64729c4290ef5b2c2730249c88ca92d82d' + ); $this->assertInstanceOf(DownloadFile::class, $file); $this->assertEquals('https://foo.com/file', $file->getUrl()); @@ -115,7 +124,9 @@ public function testBuildProjectFileTranslation() public function testListProjectBuilds() { - $this->mockRequestGet('/projects/2/translations/builds', '{ + $this->mockRequestGet( + '/projects/2/translations/builds', + '{ "data": [ { "data": { @@ -140,7 +151,8 @@ public function testListProjectBuilds() "limit": 0 } ] - }'); + }' + ); $translationProjectBuilds = $this->crowdin->translation->getProjectBuilds(2); $this->assertInstanceOf(ModelCollection::class, $translationProjectBuilds); @@ -173,9 +185,9 @@ public function testBuildProject() 'options' => [ 'body' => [ 'branchId' => 2, - 'targetLanguageIds' => ['uk'] - ] - ] + 'targetLanguageIds' => ['uk'], + ], + ], ]); $params = [ @@ -197,7 +209,9 @@ public function testBuildProject() public function testGetProjectBuildStatus() { - $this->mockRequestGet('/projects/2/translations/builds/2', '{ + $this->mockRequestGet( + '/projects/2/translations/builds/2', + '{ "data": { "id": 2, "projectId": 2, @@ -212,7 +226,8 @@ public function testGetProjectBuildStatus() "currentFileId": 1 } } - }'); + }' + ); $projectBuild = $this->crowdin->translation->getProjectBuildStatus(2, 2); @@ -222,16 +237,22 @@ public function testGetProjectBuildStatus() public function testDownloadProjectBuild() { - $this->mockRequestGet('/projects/2/translations/builds/2/download', '{ + $this->mockRequestGet( + '/projects/2/translations/builds/2/download', + '{ "data": { "url": "https://production-enterprise-importer.downloads.crowdin.com/992000002/2/14.xliff?response-content-disposition=attachment%3B%20filename%3D%22APP.xliff%22&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIGJKLQV66ZXPMMEA%2F20190920%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190920T093121Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=439ebd69a1b7e4c23e6d17891a491c94f832e0c82e4692dedb35a6cd1e624b62", "expireIn": "2019-09-20T10:31:21+00:00" } - }'); + }' + ); $file = $this->crowdin->translation->downloadProjectBuild(2, 2); $this->assertInstanceOf(DownloadFile::class, $file); - $this->assertEquals('https://production-enterprise-importer.downloads.crowdin.com/992000002/2/14.xliff?response-content-disposition=attachment%3B%20filename%3D%22APP.xliff%22&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIGJKLQV66ZXPMMEA%2F20190920%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190920T093121Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=439ebd69a1b7e4c23e6d17891a491c94f832e0c82e4692dedb35a6cd1e624b62', $file->getUrl()); + $this->assertEquals( + 'https://production-enterprise-importer.downloads.crowdin.com/992000002/2/14.xliff?response-content-disposition=attachment%3B%20filename%3D%22APP.xliff%22&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIGJKLQV66ZXPMMEA%2F20190920%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190920T093121Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=439ebd69a1b7e4c23e6d17891a491c94f832e0c82e4692dedb35a6cd1e624b62', + $file->getUrl() + ); } public function testDeleteProjectBuild() @@ -266,8 +287,8 @@ public function testUploadTranslations() 'body' => [ 'storageId' => 13, 'fileId' => 2, - ] - ] + ], + ], ]); $data = $this->crowdin->translation->uploadTranslations(8, 'uk', $params); @@ -278,7 +299,7 @@ public function testUploadTranslations() 'projectId' => 8, 'storageId' => 34, 'languageId' => 'uk', - 'fileId' => 56 + 'fileId' => 56, ], $data); } @@ -286,7 +307,7 @@ public function testExportProjectTranslation() { $params = [ 'targetLanguageId' => 'en', - 'fileIds' => [7, 14, 15] + 'fileIds' => [7, 14, 15], ]; $this->mockRequest( @@ -298,12 +319,15 @@ public function testExportProjectTranslation() "url": "https://production-enterprise-importer.downloads.crowdin.com/992000002/2/14.xliff?response-content-disposition=attachment%3B%20filename%3D%22APP.xliff%22&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIGJKLQV66ZXPMMEA%2F20190920%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190920T093121Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=439ebd69a1b7e4c23e6d17891a491c94f832e0c82e4692dedb35a6cd1e624b62", "expireIn": "2019-09-20T10:31:21+00:00" } - }' + }', ] ); $file = $this->crowdin->translation->exportProjectTranslation(2, $params); $this->assertInstanceOf(DownloadFile::class, $file); - $this->assertEquals('https://production-enterprise-importer.downloads.crowdin.com/992000002/2/14.xliff?response-content-disposition=attachment%3B%20filename%3D%22APP.xliff%22&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIGJKLQV66ZXPMMEA%2F20190920%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190920T093121Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=439ebd69a1b7e4c23e6d17891a491c94f832e0c82e4692dedb35a6cd1e624b62', $file->getUrl()); + $this->assertEquals( + 'https://production-enterprise-importer.downloads.crowdin.com/992000002/2/14.xliff?response-content-disposition=attachment%3B%20filename%3D%22APP.xliff%22&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIGJKLQV66ZXPMMEA%2F20190920%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190920T093121Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=439ebd69a1b7e4c23e6d17891a491c94f832e0c82e4692dedb35a6cd1e624b62', + $file->getUrl() + ); } }