View source
<?php
namespace Drupal\Tests\jsonapi\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Url;
use Drupal\jsonapi\Normalizer\HttpExceptionNormalizer;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\jsonapi\Traits\CommonCollectionFilterAccessTestPatternsTrait;
use Drupal\user\Entity\User;
use GuzzleHttp\RequestOptions;
class NodeTest extends ResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
use CommonCollectionFilterAccessTestPatternsTrait;
public static $modules = [
'node',
'path',
];
protected static $entityTypeId = 'node';
protected static $resourceTypeName = 'node--camelids';
protected $entity;
protected static $patchProtectedFieldNames = [
'revision_timestamp' => NULL,
'created' => "The 'administer nodes' permission is required.",
'changed' => NULL,
'promote' => "The 'administer nodes' permission is required.",
'sticky' => "The 'administer nodes' permission is required.",
'path' => "The following permissions are required: 'create url aliases' OR 'administer url aliases'.",
];
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this
->grantPermissionsToTestedRole([
'access content',
]);
break;
case 'POST':
$this
->grantPermissionsToTestedRole([
'access content',
'create camelids content',
]);
break;
case 'PATCH':
$this
->grantPermissionsToTestedRole([
'access content',
'edit any camelids content',
]);
break;
case 'DELETE':
$this
->grantPermissionsToTestedRole([
'access content',
'delete any camelids content',
]);
break;
}
}
protected function createEntity() {
if (!NodeType::load('camelids')) {
NodeType::create([
'name' => 'Camelids',
'type' => 'camelids',
])
->save();
}
$node = Node::create([
'type' => 'camelids',
]);
$node
->setTitle('Llama')
->setOwnerId($this->account
->id())
->setPublished(TRUE)
->setCreatedTime(123456789)
->setChangedTime(123456789)
->setRevisionCreationTime(123456789)
->set('path', '/llama')
->save();
return $node;
}
protected function getExpectedDocument() {
$author = User::load($this->entity
->getOwnerId());
$self_url = Url::fromUri('base:/jsonapi/node/camelids/' . $this->entity
->uuid())
->setAbsolute()
->toString(TRUE)
->getGeneratedUrl();
$normalization = [
'jsonapi' => [
'meta' => [
'links' => [
'self' => 'http://jsonapi.org/format/1.0/',
],
],
'version' => '1.0',
],
'links' => [
'self' => $self_url,
],
'data' => [
'id' => $this->entity
->uuid(),
'type' => 'node--camelids',
'links' => [
'self' => $self_url,
],
'attributes' => [
'created' => 123456789,
'changed' => $this->entity
->getChangedTime(),
'default_langcode' => TRUE,
'langcode' => 'en',
'nid' => 1,
'path' => [
'alias' => '/llama',
'pid' => 1,
'langcode' => 'en',
],
'promote' => TRUE,
'revision_log' => NULL,
'revision_timestamp' => 123456789,
'revision_translation_affected' => TRUE,
'status' => TRUE,
'sticky' => FALSE,
'title' => 'Llama',
'uuid' => $this->entity
->uuid(),
'vid' => 1,
],
'relationships' => [
'type' => [
'data' => [
'id' => NodeType::load('camelids')
->uuid(),
'type' => 'node_type--node_type',
],
'links' => [
'related' => $self_url . '/type',
'self' => $self_url . '/relationships/type',
],
],
'uid' => [
'data' => [
'id' => $author
->uuid(),
'type' => 'user--user',
],
'links' => [
'related' => $self_url . '/uid',
'self' => $self_url . '/relationships/uid',
],
],
'revision_uid' => [
'data' => [
'id' => $author
->uuid(),
'type' => 'user--user',
],
'links' => [
'related' => $self_url . '/revision_uid',
'self' => $self_url . '/relationships/revision_uid',
],
],
],
],
];
if (floatval(\Drupal::VERSION) < 8.5) {
unset($normalization['data']['attributes']['revision_default']);
}
return $normalization;
}
protected function getPostDocument() {
return [
'data' => [
'type' => 'node--camelids',
'attributes' => [
'title' => 'Dramallama',
],
],
];
}
protected function getExpectedUnauthorizedAccessMessage($method) {
switch ($method) {
case 'GET':
case 'POST':
case 'PATCH':
case 'DELETE':
return "The 'access content' permission is required.";
}
}
public function testPatchPath() {
$this
->setUpAuthorization('GET');
$this
->setUpAuthorization('PATCH');
$url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), [
static::$entityTypeId => $this->entity
->uuid(),
]);
$response = $this
->request('GET', $url, $this
->getAuthenticationRequestOptions());
$normalization = Json::decode((string) $response
->getBody());
$normalization['data']['attributes']['path']['alias'] .= 's-rule-the-world';
$request_options = $this
->getAuthenticationRequestOptions();
$request_options[RequestOptions::BODY] = Json::encode($normalization);
$response = $this
->request('PATCH', $url, $request_options);
$expected_document = [
'errors' => [
[
'title' => 'Forbidden',
'status' => 403,
'detail' => "The current user is not allowed to PATCH the selected field (path). The following permissions are required: 'create url aliases' OR 'administer url aliases'.",
'links' => [
'info' => HttpExceptionNormalizer::getInfoUrl(403),
],
'code' => 0,
'id' => '/node--camelids/' . $this->entity
->uuid(),
'source' => [
'pointer' => '/data/attributes/path',
],
],
],
];
$this
->assertResourceResponse(403, $expected_document, $response);
$this
->grantPermissionsToTestedRole([
'create url aliases',
]);
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceResponse(200, FALSE, $response);
$updated_normalization = Json::decode((string) $response
->getBody());
$this
->assertSame($normalization['data']['attributes']['path']['alias'], $updated_normalization['data']['attributes']['path']['alias']);
}
public function testGetIndividual() {
parent::testGetIndividual();
$this->entity
->setUnpublished()
->save();
$url = Url::fromRoute(sprintf('jsonapi.%s.individual', static::$resourceTypeName), [
static::$entityTypeId => $this->entity
->uuid(),
]);
$request_options = $this
->getAuthenticationRequestOptions();
$response = $this
->request('GET', $url, $request_options);
$expected_document = [
'errors' => [
[
'title' => 'Forbidden',
'status' => 403,
'detail' => 'The current user is not allowed to GET the selected resource.',
'links' => [
'info' => HttpExceptionNormalizer::getInfoUrl(403),
],
'code' => 0,
'id' => '/node--camelids/' . $this->entity
->uuid(),
'source' => [
'pointer' => '/data',
],
],
],
];
$this
->assertResourceResponse(403, $expected_document, $response);
$this
->grantPermissionsToTestedRole([
'view own unpublished content',
]);
$response = $this
->request('GET', $url, $request_options);
$expected_cache_contexts = Cache::mergeContexts($this
->getExpectedCacheContexts(), [
'user',
]);
$expected_cache_contexts = array_diff($expected_cache_contexts, [
'user.permissions',
]);
$this
->assertResourceResponse(200, FALSE, $response, $this
->getExpectedCacheTags(), $expected_cache_contexts, FALSE, 'UNCACHEABLE');
}
protected static function getIncludePermissions() {
return [
'uid.type' => [
'administer users',
],
'uid.roles' => [
'administer permissions',
],
];
}
public function testCollectionFilterAccess() {
$label_field_name = 'title';
$this
->doTestCollectionFilterAccessForPublishableEntities($label_field_name, 'access content', 'bypass node access');
$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());
$this
->revokePermissionsFromTestedRole([
'bypass node access',
]);
$response = $this
->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response
->getBody());
$this
->assertCount(0, $doc['data']);
$this
->grantPermissionsToTestedRole([
'view own unpublished content',
]);
$response = $this
->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response
->getBody());
$this
->assertCount(1, $doc['data']);
$this->entity
->setOwnerId(0)
->save();
$response = $this
->request('GET', $collection_filter_url, $request_options);
$doc = Json::decode((string) $response
->getBody());
$this
->assertCount(0, $doc['data']);
$this
->assertTrue($this->container
->get('module_installer')
->install([
'node_access_test',
], TRUE), 'Installed modules.');
node_access_rebuild();
$this
->rebuildAll();
$response = $this
->request('GET', $collection_filter_url, $request_options);
$this
->assertTrue(in_array('user.node_grants:view', explode(' ', $response
->getHeader('X-Drupal-Cache-Contexts')[0]), TRUE));
}
}