Skip to content
Snippets Groups Projects
Verified Commit 4c8c814c authored by Dave Long's avatar Dave Long
Browse files

Issue #3336994 by mxr576, kksandr, dpi, smustgrave, xjm, alexpott, hchonov,...

Issue #3336994 by mxr576, kksandr, dpi, smustgrave, xjm, alexpott, hchonov, quietone: StringFormatter always displays links to entity even if the user in context does not have access
parent 43e738a6
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\Attribute\FieldFormatter;
......@@ -122,27 +123,33 @@ public function settingsSummary() {
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
$url = NULL;
$entity = $items->getEntity();
$entity_type = $entity->getEntityType();
$render_as_link = FALSE;
if ($this->getSetting('link_to_entity') && !$entity->isNew() && $entity_type->hasLinkTemplate('canonical')) {
$url = $this->getEntityUrl($entity);
$access = $url->access(return_as_object: TRUE);
(new CacheableMetadata())
->addCacheableDependency($access)
->applyTo($elements);
$render_as_link = $access->isAllowed();
}
foreach ($items as $delta => $item) {
$view_value = $this->viewValue($item);
if ($url) {
if ($render_as_link) {
assert(isset($url));
$elements[$delta] = [
'#type' => 'link',
'#title' => $view_value,
'#title' => $this->viewValue($item),
'#url' => $url,
];
}
else {
$elements[$delta] = $view_value;
$elements[$delta] = $this->viewValue($item);
}
}
return $elements;
}
......
......@@ -181,7 +181,7 @@ public function testListing(): void {
$this->drupalGet('admin/content/block');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->linkNotExists($link_text);
$matches = $this->xpath('//td/a');
$matches = $this->xpath('//td[1]');
$actual = $matches[0]->getText();
$this->assertEquals($label, $actual, 'Label found for test block.');
$this->assertSession()->linkNotExists('Edit');
......
......@@ -56,7 +56,11 @@ protected function setUp($import_test_views = TRUE): void {
$admin_role = Role::create([
'id' => 'admin',
'permissions' => ['administer comments', 'access user profiles'],
'permissions' => [
'administer comments',
'access user profiles',
'access comments',
],
'label' => 'Admin',
]);
$admin_role->save();
......@@ -177,8 +181,11 @@ public function testUsername(): void {
$this->assertNoLink($this->adminUser->label());
// Note: External users aren't pointing to drupal user profiles.
$this->assertLink('barry (not verified)');
$this->assertLink('My comment title');
$this->assertLink('Anonymous comment title');
// Anonymous user does not have access to this link but can still see title.
$this->assertText('My comment title');
$this->assertNoLink('My comment title');
$this->assertText('Anonymous comment title');
$this->assertNoLink('Anonymous comment title');
}
}
......@@ -12,6 +12,7 @@
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\user\Traits\UserCreationTrait;
/**
* Tests the creation of text fields.
......@@ -20,6 +21,8 @@
*/
class StringFormatterTest extends KernelTestBase {
use UserCreationTrait;
/**
* {@inheritdoc}
*/
......@@ -68,7 +71,10 @@ protected function setUp(): void {
// Configure the theme system.
$this->installConfig(['system', 'field']);
$this->installEntitySchema('entity_test_rev');
$this->installEntitySchema('entity_test_label');
$this->setUpCurrentUser(permissions: [
'view test entity',
'administer entity_test content',
]);
$this->entityType = 'entity_test_rev';
$this->bundle = $this->entityType;
......@@ -124,7 +130,7 @@ public function testStringFormatter(): void {
$value .= "\n\n<strong>" . $this->randomString() . '</strong>';
$value .= "\n\n" . $this->randomString();
$entity = EntityTestRev::create([]);
$entity = EntityTestRev::create(['name' => 'view revision']);
$entity->{$this->fieldName}->value = $value;
// Verify that all HTML is escaped and newlines are retained.
......@@ -194,6 +200,7 @@ public function testStringFormatter(): void {
*/
public function testLinkToContentForEntitiesWithNoCanonicalPath(): void {
$this->enableModules(['entity_test']);
$this->installEntitySchema('entity_test_label');
$field_name = 'test_field_name';
$entity_type = $bundle = 'entity_test_label';
......
......@@ -6,6 +6,7 @@
use Drupal\entity_test\Entity\EntityTest;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\user\Traits\UserCreationTrait;
/**
* Tests the output of a UUID field.
......@@ -14,6 +15,7 @@
*/
class UuidFormatterTest extends KernelTestBase {
use UserCreationTrait;
/**
* {@inheritdoc}
......@@ -28,6 +30,10 @@ protected function setUp(): void {
$this->installConfig(['system', 'field']);
$this->installEntitySchema('entity_test');
$this->installEntitySchema('user');
$this->setUpCurrentUser(permissions: [
'view test entity',
]);
}
/**
......
<?php
declare(strict_types=1);
namespace Drupal\Tests\field\Unit\Plugin\Field\FieldFormatter;
use Drupal\Core\Access\AccessResultAllowed;
use Drupal\Core\Access\AccessResultForbidden;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldFormatter\StringFormatter;
use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
use Drupal\Core\Url;
use Drupal\Tests\UnitTestCase;
/**
* Tests the string field formatter.
*
* @group field
*
* @coversDefaultClass \Drupal\Core\Field\Plugin\Field\FieldFormatter\StringFormatter
*/
final class StringFormatterTest extends UnitTestCase {
/**
* Checks link visibility depending on link templates and access.
*
* @param bool $hasUrl
* Whether the entity type has a canonical link template.
* @param string|null $accessClass
* The access result for the current user.
* @param bool $expectIsLinkElement
* Whether to expect the text to be wrapped in a link element.
*
* @phpstan-param class-string<\Drupal\Core\Access\AccessResultInterface>|null $accessClass
*
* @dataProvider providerAccessLinkToEntity
*/
public function testLinkToEntity(bool $hasUrl, ?string $accessClass, bool $expectIsLinkElement): void {
$fieldDefinition = $this->prophesize(FieldDefinitionInterface::class);
$entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
$fieldFormatter = new StringFormatter('foobar', [], $fieldDefinition->reveal(), [], 'TestLabel', 'default', [], $entityTypeManager->reveal());
$fieldFormatter->setSetting('link_to_entity', TRUE);
$entityType = $this->prophesize(EntityTypeInterface::class);
$entityType->hasLinkTemplate('canonical')->willReturn($hasUrl)->shouldBeCalledTimes(1);
$entityType->hasLinkTemplate('revision')->willReturn(FALSE)->shouldBeCalledTimes($hasUrl ? 1 : 0);
$entity = $this->prophesize(EntityInterface::class);
$entity->isNew()->willReturn(FALSE);
$entity->getEntityType()->willReturn($entityType->reveal());
if ($hasUrl) {
$url = $this->prophesize(Url::class);
$url->access(NULL, TRUE)->willReturn(new $accessClass());
$entity->toUrl('canonical')->willReturn($url);
}
$item = $this->getMockBuilder(StringItem::class)
->disableOriginalConstructor()
->onlyMethods([])
->getMock();
$item->setValue(['value' => 'FooText']);
$items = $this->prophesize(FieldItemListInterface::class);
$items->getEntity()->willReturn($entity->reveal());
$items->valid()->willReturn(TRUE, FALSE);
$items->next();
$items->rewind();
$items->current()->willReturn($item);
$items->key()->willReturn(0);
$elements = $fieldFormatter->viewElements($items->reveal(), 'en');
if ($expectIsLinkElement) {
$this->assertEquals('link', $elements[0]['#type']);
$this->assertEquals('FooText', $elements[0]['#title']['#context']['value']);
}
else {
$this->assertEquals('inline_template', $elements[0]['#type']);
$this->assertEquals('FooText', $elements[0]['#context']['value']);
}
}
/**
* Data provider.
*
* @return \Generator
* Test scenarios.
*/
public static function providerAccessLinkToEntity(): \Generator {
yield 'entity with no URL' => [
FALSE,
NULL,
FALSE,
];
yield 'entity with url, with access' => [
TRUE,
AccessResultAllowed::class,
TRUE,
];
yield 'entity with url, no access' => [
TRUE,
AccessResultForbidden::class,
FALSE,
];
}
}
......@@ -7,6 +7,7 @@
use Drupal\Core\Link;
use Drupal\Core\Render\RenderContext;
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\views\Views;
......@@ -19,6 +20,7 @@
class TaxonomyFieldTidTest extends ViewsKernelTestBase {
use TaxonomyTestTrait;
use UserCreationTrait;
/**
* {@inheritdoc}
......@@ -49,7 +51,11 @@ protected function setUp($import_test_views = TRUE): void {
parent::setUp($import_test_views);
$this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('user');
$this->installConfig(['filter']);
$this->setUpCurrentUser(permissions: [
'access content',
]);
/** @var \Drupal\taxonomy\Entity\Vocabulary $vocabulary */
$vocabulary = $this->createVocabulary();
......
......@@ -333,6 +333,9 @@ public function testFieldAlias(): void {
* different delta limit / offset.
*/
public function testFieldAliasRender(): void {
$this->setUpCurrentUser(permissions: [
'view test entity',
]);
$executable = Views::getView('test_field_alias_test');
$executable->execute();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment