diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d7639f10b..83fc34367 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,23 +11,26 @@ jobs: cs-fix: name: Run code style check runs-on: "ubuntu-24.04" - steps: - - uses: actions/checkout@v4 - - name: Setup PHP Action - uses: shivammathur/setup-php@v2 - with: - php-version: '8.1' - coverage: none - extensions: 'pdo_sqlite, gd' - tools: cs2pr + strategy: + fail-fast: false + matrix: + php: + - '7.4' + - '8.1' + + steps: + - uses: actions/checkout@v4 - - uses: ramsey/composer-install@v3 - with: - dependency-versions: highest + - uses: ibexa/gh-workflows/actions/composer-install@main + with: + gh-client-id: ${{ secrets.AUTOMATION_CLIENT_ID }} + gh-client-secret: ${{ secrets.AUTOMATION_CLIENT_SECRET }} + satis-network-key: ${{ secrets.SATIS_NETWORK_KEY }} + satis-network-token: ${{ secrets.SATIS_NETWORK_TOKEN }} - - name: Run code style check - run: composer run-script check-cs -- --format=checkstyle | cs2pr + - name: Run code style check + run: composer run-script check-cs -- --format=checkstyle | cs2pr tests: name: Unit & integration tests @@ -39,34 +42,28 @@ jobs: matrix: php: - '7.4' - - '8.0' - - '8.2' + - '8.1' steps: - - uses: actions/checkout@v4 - - - name: Setup PHP Action - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - extensions: pdo_sqlite, gd - tools: cs2pr + - uses: actions/checkout@v4 - - uses: ramsey/composer-install@v3 - with: - dependency-versions: highest + - uses: ibexa/gh-workflows/actions/composer-install@main + with: + gh-client-id: ${{ secrets.AUTOMATION_CLIENT_ID }} + gh-client-secret: ${{ secrets.AUTOMATION_CLIENT_SECRET }} + satis-network-key: ${{ secrets.SATIS_NETWORK_KEY }} + satis-network-token: ${{ secrets.SATIS_NETWORK_TOKEN }} - - name: Run PHPStan analysis - run: composer run-script phpstan + - name: Run PHPStan analysis + run: composer run-script phpstan - - name: Setup problem matchers for PHPUnit - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Run unit test suite - run: composer test - - name: Run integration test suite - run: composer test-integration + - name: Run unit test suite + run: composer test + - name: Run integration test suite + run: composer test-integration functional-tests: name: "REST functional tests" diff --git a/composer.json b/composer.json index 4b9e8699e..41ab6c1ff 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "ext-libxml": "*", "ext-simplexml": "*", "ext-xmlwriter": "*", - "ibexa/core": "~4.6.0@dev", + "ibexa/core": "~4.6.x-dev", "symfony/http-kernel": "^5.3", "symfony/dependency-injection": "^5.3", "symfony/routing": "^5.3", diff --git a/dependencies.json b/dependencies.json new file mode 100644 index 000000000..fc4a24d50 --- /dev/null +++ b/dependencies.json @@ -0,0 +1,11 @@ +{ + "recipesEndpoint": "", + "packages": [ + { + "requirement": "dev-ct-group-is-system as 4.6.x-dev", + "repositoryUrl": "https://github.com/ibexa/core", + "package": "ibexa/core", + "shouldBeAddedAsVCS": false + } + ] +} \ No newline at end of file diff --git a/src/lib/Server/Controller/ContentType.php b/src/lib/Server/Controller/ContentType.php index ae98ede9d..603c6a286 100644 --- a/src/lib/Server/Controller/ContentType.php +++ b/src/lib/Server/Controller/ContentType.php @@ -168,8 +168,10 @@ public function loadContentTypeGroupList(Request $request) ); } + $includeSystem = $request->query->getBoolean('includeSystem', false); + return new Values\ContentTypeGroupList( - $this->contentTypeService->loadContentTypeGroups(Language::ALL) + $this->contentTypeService->loadContentTypeGroups(Language::ALL, $includeSystem) ); } diff --git a/src/lib/Server/Input/Parser/ContentTypeGroupInput.php b/src/lib/Server/Input/Parser/ContentTypeGroupInput.php index 1860e2b16..854bbadf5 100644 --- a/src/lib/Server/Input/Parser/ContentTypeGroupInput.php +++ b/src/lib/Server/Input/Parser/ContentTypeGroupInput.php @@ -68,6 +68,10 @@ public function parse(array $data, ParsingDispatcher $parsingDispatcher) $contentTypeGroupCreateStruct->creationDate = new DateTime($data['modificationDate']); } + if (array_key_exists('isSystem', $data)) { + $contentTypeGroupCreateStruct->isSystem = $this->parserTools->parseBooleanValue($data['isSystem']); + } + // @todo mainLanguageCode, names, descriptions? if (array_key_exists('User', $data) && is_array($data['User'])) { diff --git a/src/lib/Server/Input/Parser/Criterion/LogicalNot.php b/src/lib/Server/Input/Parser/Criterion/LogicalNot.php index 5bf03b787..8891b4485 100644 --- a/src/lib/Server/Input/Parser/Criterion/LogicalNot.php +++ b/src/lib/Server/Input/Parser/Criterion/LogicalNot.php @@ -28,7 +28,7 @@ class LogicalNot extends CriterionParser */ public function parse(array $data, ParsingDispatcher $parsingDispatcher) { - if (!array_key_exists('NOT', $data) && !is_array($data['NOT'])) { + if (!array_key_exists('NOT', $data) || !is_array($data['NOT'])) { throw new Exceptions\Parser('Invalid format'); } @@ -37,6 +37,11 @@ public function parse(array $data, ParsingDispatcher $parsingDispatcher) } $criterionName = key($data['NOT']); $criterionData = current($data['NOT']); + + if (!is_string($criterionName)) { + throw new Exceptions\Parser('Invalid format'); + } + $criteria = $this->dispatchCriterion($criterionName, $criterionData, $parsingDispatcher); return new LogicalNotCriterion($criteria); diff --git a/tests/bundle/Functional/ContentTypeTest.php b/tests/bundle/Functional/ContentTypeTest.php index b41027a28..dd0903694 100644 --- a/tests/bundle/Functional/ContentTypeTest.php +++ b/tests/bundle/Functional/ContentTypeTest.php @@ -7,6 +7,7 @@ namespace Ibexa\Tests\Bundle\Rest\Functional; use Ibexa\Tests\Bundle\Rest\Functional\TestCase as RESTFunctionalTestCase; +use Psr\Http\Message\ResponseInterface; class ContentTypeTest extends RESTFunctionalTestCase { @@ -159,6 +160,50 @@ public function testLoadContentTypeGroupList() // @todo test data } + /** + * Covers GET /content/typegroups without includeSystem param (defaults to false). + */ + public function testLoadContentTypeGroupListExcludesSystemByDefault(): void + { + $systemIdentifier = $this->createSystemContentTypeGroup(); + + $response = $this->sendHttpRequest( + $this->createHttpRequest( + 'GET', + '/api/ibexa/v2/content/typegroups', + '', + 'ContentTypeGroupList+json' + ) + ); + self::assertHttpResponseCodeEquals($response, 200); + + $identifiers = $this->getContentTypeGroupIdentifiers($response); + + self::assertNotContains($systemIdentifier, $identifiers); + } + + /** + * Covers GET /content/typegroups?includeSystem=true. + */ + public function testLoadContentTypeGroupListIncludesSystemGroups(): void + { + $systemIdentifier = $this->createSystemContentTypeGroup(); + + $response = $this->sendHttpRequest( + $this->createHttpRequest( + 'GET', + '/api/ibexa/v2/content/typegroups?includeSystem=true', + '', + 'ContentTypeGroupList+json' + ) + ); + self::assertHttpResponseCodeEquals($response, 200); + + $identifiers = $this->getContentTypeGroupIdentifiers($response); + + self::assertContains($systemIdentifier, $identifiers); + } + /** * @depends testUpdateContentTypeGroup * Covers GET /content/typegroups?identifier= @@ -172,6 +217,25 @@ public function testLoadContentTypeGroupListWithIdentifier() self::assertHttpResponseCodeEquals($response, 307); } + public function testCreateSystemContentTypeGroup(): void + { + $identifier = $this->createSystemContentTypeGroup(); + + $response = $this->sendHttpRequest( + $this->createHttpRequest( + 'GET', + '/api/ibexa/v2/content/typegroups?includeSystem=true', + '', + 'ContentTypeGroupList+json' + ) + ); + self::assertHttpResponseCodeEquals($response, 200); + + $identifiers = $this->getContentTypeGroupIdentifiers($response); + + self::assertContains($identifier, $identifiers); + } + /** * @depends testUpdateContentTypeGroup * Covers GET /content/typegroups/ @@ -672,6 +736,55 @@ public function testCreateViewWithContentTypeGroupName(): void self::assertArrayHasKey('ContentTypeList', $responseData); self::assertSame('image', $responseData['ContentTypeList']['ContentType'][0]['identifier']); } + + /** + * @return string[] + */ + private function getContentTypeGroupIdentifiers(ResponseInterface $response): array + { + $responseData = json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR); + self::assertArrayHasKey('ContentTypeGroupList', $responseData); + + $groupList = $responseData['ContentTypeGroupList']['ContentTypeGroup'] ?? []; + if (isset($groupList['_href'])) { + $groupList = [$groupList]; + } + + return array_map( + static function (array $group): string { + return strtolower($group['identifier'] ?? ''); + }, + $groupList + ); + } + + private function createSystemContentTypeGroup(): string + { + $identifier = $this->addTestSuffix('system_group_' . uniqid()); + $body = <<< XML + + + {$identifier} + true + +XML; + + $request = $this->createHttpRequest( + 'POST', + '/api/ibexa/v2/content/typegroups', + 'ContentTypeGroupInput+xml', + 'ContentTypeGroup+json', + $body + ); + + $response = $this->sendHttpRequest($request); + self::assertHttpResponseCodeEquals($response, 201); + self::assertHttpResponseHasHeader($response, 'Location'); + + $this->addCreatedElement($response->getHeader('Location')[0]); + + return $identifier; + } } class_alias(ContentTypeTest::class, 'EzSystems\EzPlatformRestBundle\Tests\Functional\ContentTypeTest'); diff --git a/tests/lib/Server/Input/Parser/ContentTypeGroupInputTest.php b/tests/lib/Server/Input/Parser/ContentTypeGroupInputTest.php index 1f2bac970..44c767433 100644 --- a/tests/lib/Server/Input/Parser/ContentTypeGroupInputTest.php +++ b/tests/lib/Server/Input/Parser/ContentTypeGroupInputTest.php @@ -24,6 +24,7 @@ public function testParse() '_href' => '/user/users/14', ], 'modificationDate' => '2012-12-31T12:00:00', + 'isSystem' => true, ]; $contentTypeGroupInput = $this->getParser(); @@ -52,6 +53,11 @@ public function testParse() $result->creationDate, 'ContentTypeGroupCreateStruct creationDate property not created correctly.' ); + + $this->assertTrue( + $result->isSystem, + 'ContentTypeGroupCreateStruct isSystem property not created correctly.' + ); } /**