grantPermissionsToTestedRole(['access content']); break; case 'POST': $this->grantPermissionsToTestedRole(['access content', 'create camelids content']); break; case 'PATCH': // Do not grant the 'create url aliases' permission to test the case // when the path field is protected/not accessible, see // \Drupal\Tests\rest\Functional\EntityResource\Term\TermResourceTestBase // for a positive test. $this->grantPermissionsToTestedRole(['access content', 'edit any camelids content']); break; case 'DELETE': $this->grantPermissionsToTestedRole(['access content', 'delete any camelids content']); break; } } /** * {@inheritdoc} */ protected function createEntity() { if (!NodeType::load('camelids')) { // Create a "Camelids" node type. NodeType::create([ 'name' => 'Camelids', 'type' => 'camelids', ])->save(); } // Create a "Llama" node. $node = Node::create(['type' => 'camelids']); $node->setTitle('Llama') ->setOwnerId(static::$auth ? $this->account->id() : 0) ->setPublished(TRUE) ->setCreatedTime(123456789) ->setChangedTime(123456789) ->setRevisionCreationTime(123456789) ->set('path', '/llama') ->save(); return $node; } /** * {@inheritdoc} */ protected function getExpectedNormalizedEntity() { $author = User::load($this->entity->getOwnerId()); return [ 'nid' => [ ['value' => 1], ], 'uuid' => [ ['value' => $this->entity->uuid()], ], 'vid' => [ ['value' => 1], ], 'langcode' => [ [ 'value' => 'en', ], ], 'type' => [ [ 'target_id' => 'camelids', 'target_type' => 'node_type', 'target_uuid' => NodeType::load('camelids')->uuid(), ], ], 'title' => [ [ 'value' => 'Llama', ], ], 'status' => [ [ 'value' => TRUE, ], ], 'created' => [ $this->formatExpectedTimestampItemValues(123456789), ], 'changed' => [ $this->formatExpectedTimestampItemValues($this->entity->getChangedTime()), ], 'promote' => [ [ 'value' => TRUE, ], ], 'sticky' => [ [ 'value' => FALSE, ], ], 'revision_timestamp' => [ $this->formatExpectedTimestampItemValues(123456789), ], 'revision_translation_affected' => [ [ 'value' => TRUE, ], ], 'default_langcode' => [ [ 'value' => TRUE, ], ], 'uid' => [ [ 'target_id' => (int) $author->id(), 'target_type' => 'user', 'target_uuid' => $author->uuid(), 'url' => base_path() . 'user/' . $author->id(), ], ], 'revision_uid' => [ [ 'target_id' => (int) $author->id(), 'target_type' => 'user', 'target_uuid' => $author->uuid(), 'url' => base_path() . 'user/' . $author->id(), ], ], 'revision_log' => [], 'path' => [ [ 'alias' => '/llama', 'pid' => 1, 'langcode' => 'en', ], ], ]; } /** * {@inheritdoc} */ protected function getNormalizedPostEntity() { return [ 'type' => [ [ 'target_id' => 'camelids', ], ], 'title' => [ [ 'value' => 'Dramallama', ], ], ]; } /** * {@inheritdoc} */ protected function getExpectedUnauthorizedAccessMessage($method) { if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) { return parent::getExpectedUnauthorizedAccessMessage($method); } if ($method === 'GET' || $method == 'PATCH' || $method == 'DELETE') { return "The 'access content' permission is required."; } return parent::getExpectedUnauthorizedAccessMessage($method); } /** * Tests PATCHing a node's path with and without 'create url aliases'. * * For a positive test, see the similar test coverage for Term. * * @see \Drupal\Tests\rest\Functional\EntityResource\Term\TermResourceTestBase::testPatchPath() */ public function testPatchPath() { $this->initAuthentication(); $this->provisionEntityResource(); $this->setUpAuthorization('GET'); $this->setUpAuthorization('PATCH'); $url = $this->getEntityResourceUrl()->setOption('query', ['_format' => static::$format]); // GET node's current normalization. $response = $this->request('GET', $url, $this->getAuthenticationRequestOptions('GET')); $normalization = $this->serializer->decode((string) $response->getBody(), static::$format); // @todo In https://www.drupal.org/node/2824851, we will be able to stop // unsetting these fields from the normalization, because // EntityResource::patch() will ignore any fields that are sent that // match the current value (and obviously we're sending the current // value). $normalization = $this->removeFieldsFromNormalization($normalization, [ 'revision_timestamp', 'revision_uid', 'created', 'changed', 'promote', 'sticky', ]); // Change node's path alias. $normalization['path'][0]['alias'] .= 's-rule-the-world'; // Create node PATCH request. $request_options = []; $request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType; $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH')); $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format); // PATCH request: 403 when creating URL aliases unauthorized. $response = $this->request('PATCH', $url, $request_options); $this->assertResourceErrorResponse(403, "Access denied on updating field 'path'.", $response); // Grant permission to create URL aliases. $this->grantPermissionsToTestedRole(['create url aliases']); // Repeat PATCH request: 200. $response = $this->request('PATCH', $url, $request_options); $this->assertResourceResponse(200, FALSE, $response); $updated_normalization = $this->serializer->decode((string) $response->getBody(), static::$format); $this->assertSame($normalization['path'], $updated_normalization['path']); } }