jsonapi-8.x-2.x-dev/tests/src/Traits/CommonCollectionFilterAccessTestPatternsTrait.php
tests/src/Traits/CommonCollectionFilterAccessTestPatternsTrait.php
<?php namespace Drupal\Tests\jsonapi\Traits; use Drupal\Component\Serialization\Json; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Url; use Drupal\entity_test\Entity\EntityTest; use Drupal\jsonapi\BackwardCompatibility\tests\Traits\EntityReferenceTestTrait; use Drupal\Tests\jsonapi\Functional\ResourceTestBase; use GuzzleHttp\RequestOptions; /** * Provides common filter access control tests. */ trait CommonCollectionFilterAccessTestPatternsTrait { use EntityReferenceTestTrait; /** * Implements ::testCollectionFilterAccess() for pure permission-based access. * * @param string $label_field_name * The entity type's label field name. * @param string $view_permission * The entity type's permission that grants 'view' access. * * @return \Drupal\Core\Entity\EntityInterface * The referencing entity. */ public function doTestCollectionFilterAccessBasedOnPermissions($label_field_name, $view_permission) { assert($this instanceof ResourceTestBase); // Set up data model. $this->assertTrue($this->container->get('module_installer')->install(['entity_test'], TRUE), 'Installed modules.'); entity_test_create_bundle('bar', NULL, 'entity_test'); $this->createEntityReferenceField( 'entity_test', 'bar', 'spotlight', NULL, static::$entityTypeId, 'default', [ 'target_bundles' => [ $this->entity->bundle() => $this->entity->bundle(), ], ] ); $this->rebuildAll(); $this->grantPermissionsToTestedRole(['view test entity']); // Create data. $referencing_entity = EntityTest::create([ 'name' => 'Camelids', 'type' => 'bar', 'spotlight' => [ 'target_id' => $this->entity->id(), ], ]); $referencing_entity->save(); // Test. $collection_url = Url::fromRoute('jsonapi.entity_test--bar.collection'); // Specifying a delta exercises TemporaryQueryGaurd more thoroughly. $filter_path = "spotlight.0.$label_field_name"; $collection_filter_url = $collection_url->setOption('query', ["filter[$filter_path]" => $this->entity->label()]); $request_options = []; $request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json'; $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions()); if ($view_permission !== NULL) { // ?filter[spotlight.LABEL]: 0 results. $response = $this->request('GET', $collection_filter_url, $request_options); $doc = Json::decode((string) $response->getBody()); $this->assertCount(0, $doc['data']); // Grant "view" permission. $this->grantPermissionsToTestedRole([$view_permission]); } // ?filter[spotlight.LABEL]: 1 result. $response = $this->request('GET', $collection_filter_url, $request_options); $doc = Json::decode((string) $response->getBody()); $this->assertCount(1, $doc['data']); $this->assertSame($referencing_entity->uuid(), $doc['data'][0]['id']); // ?filter[spotlight.LABEL]: 1 result. $response = $this->request('GET', $collection_filter_url, $request_options); $doc = Json::decode((string) $response->getBody()); $this->assertCount(1, $doc['data']); $this->assertSame($referencing_entity->uuid(), $doc['data'][0]['id']); // Install the jsonapi_test_field_filter_access module, which contains a // hook_jsonapi_entity_field_filter_access() implementation that forbids // access to the spotlight field if the 'filter by spotlight field' // permission is not granted. $this->assertTrue($this->container->get('module_installer')->install(['jsonapi_test_field_filter_access'], TRUE), 'Installed modules.'); $this->rebuildAll(); // Ensure that a 403 response is generated for attempting to filter by a // field that is forbidden by an implementation of // hook_jsonapi_entity_field_filter_access() . $response = $this->request('GET', $collection_filter_url, $request_options); $message = "The current user is not authorized to filter by the `spotlight` field, given in the path `spotlight`."; $expected_cache_tags = ['4xx-response', 'http_response']; $expected_cache_contexts = [ 'url.query_args:filter', 'url.query_args:sort', 'url.site', 'user.permissions', ]; $this->assertResourceErrorResponse(403, $message, $collection_filter_url, $response, FALSE, $expected_cache_tags, $expected_cache_contexts, FALSE, 'MISS'); // And ensure the it is allowed when the proper permission is granted. $this->grantPermissionsToTestedRole(['filter by spotlight field']); $response = $this->request('GET', $collection_filter_url, $request_options); $doc = Json::decode((string) $response->getBody()); $this->assertCount(1, $doc['data']); $this->assertSame($referencing_entity->uuid(), $doc['data'][0]['id']); $this->revokePermissionsFromTestedRole(['filter by spotlight field']); $this->assertTrue($this->container->get('module_installer')->uninstall(['jsonapi_test_field_filter_access'], TRUE), 'Uninstalled modules.'); return $referencing_entity; } /** * Implements ::testCollectionFilterAccess() for permission + status access. * * @param string $label_field_name * The entity type's label field name. * @param string $view_permission * The entity type's permission that grants 'view' access (for published * entities of this type). * @param string $admin_permission * The entity type's permission that grants 'view' access (for unpublished * entities of this type). * * @return \Drupal\Core\Entity\EntityInterface * The referencing entity. */ public function doTestCollectionFilterAccessForPublishableEntities($label_field_name, $view_permission, $admin_permission) { assert($this->entity instanceof EntityPublishedInterface); $this->assertTrue($this->entity->isPublished()); $referencing_entity = $this->doTestCollectionFilterAccessBasedOnPermissions($label_field_name, $view_permission); $collection_url = Url::fromRoute('jsonapi.entity_test--bar.collection'); $collection_filter_url = $collection_url->setOption('query', ["filter[spotlight.$label_field_name]" => $this->entity->label()]); $request_options = []; $request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json'; $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions()); // Unpublish. $this->entity->setUnpublished()->save(); // ?filter[spotlight.LABEL]: no result because the test entity is // unpublished. This proves that appropriate cache tags are bubbled. $response = $this->request('GET', $collection_filter_url, $request_options); $doc = Json::decode((string) $response->getBody()); $this->assertCount(0, $doc['data']); // Grant admin permission. $this->grantPermissionsToTestedRole([$admin_permission]); // ?filter[spotlight.LABEL]: 1 result despite the test entity being // unpublished, thanks to the admin permission. This proves that the // appropriate cache contexts are bubbled. $response = $this->request('GET', $collection_filter_url, $request_options); $doc = Json::decode((string) $response->getBody()); $this->assertCount(1, $doc['data']); $this->assertSame($referencing_entity->uuid(), $doc['data'][0]['id']); return $referencing_entity; } }