Update to Drupal 8.1.9. For more information, see https://www.drupal.org/project/drupal/releases/8.1.9
This commit is contained in:
parent
f9f23cdf38
commit
09b113657a
125 changed files with 2307 additions and 385 deletions
|
@ -1213,7 +1213,7 @@ function _node_access_rebuild_batch_operation(&$context) {
|
|||
// Initiate multistep processing.
|
||||
$context['sandbox']['progress'] = 0;
|
||||
$context['sandbox']['current_node'] = 0;
|
||||
$context['sandbox']['max'] = \Drupal::entityQuery('node')->count()->execute();
|
||||
$context['sandbox']['max'] = \Drupal::entityQuery('node')->accessCheck(FALSE)->count()->execute();
|
||||
}
|
||||
|
||||
// Process the next 20 nodes.
|
||||
|
|
|
@ -127,7 +127,7 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
|
|||
public function revisionShow($node_revision) {
|
||||
$node = $this->entityManager()->getStorage('node')->loadRevision($node_revision);
|
||||
$node = $this->entityManager()->getTranslationFromContext($node);
|
||||
$node_view_controller = new NodeViewController($this->entityManager, $this->renderer);
|
||||
$node_view_controller = new NodeViewController($this->entityManager, $this->renderer, $this->currentUser());
|
||||
$page = $node_view_controller->view($node);
|
||||
unset($page['nodes'][$node->id()]['#cache']);
|
||||
return $page;
|
||||
|
|
|
@ -4,12 +4,50 @@ namespace Drupal\node\Controller;
|
|||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\Controller\EntityViewController;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a controller to render a single node.
|
||||
*/
|
||||
class NodeViewController extends EntityViewController {
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Creates an NodeViewController object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer service.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user. For backwards compatibility this is optional, however
|
||||
* this will be removed before Drupal 9.0.0.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, RendererInterface $renderer, AccountInterface $current_user = NULL) {
|
||||
parent::__construct($entity_manager, $renderer);
|
||||
$this->currentUser = $current_user ?: \Drupal::currentUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('renderer'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -17,27 +55,44 @@ class NodeViewController extends EntityViewController {
|
|||
$build = parent::view($node, $view_mode, $langcode);
|
||||
|
||||
foreach ($node->uriRelationships() as $rel) {
|
||||
// Set the node path as the canonical URL to prevent duplicate content.
|
||||
$build['#attached']['html_head_link'][] = array(
|
||||
array(
|
||||
'rel' => $rel,
|
||||
'href' => $node->url($rel),
|
||||
),
|
||||
TRUE,
|
||||
);
|
||||
$url = $node->toUrl($rel);
|
||||
// Add link relationships if the user is authenticated or if the anonymous
|
||||
// user has access. Access checking must be done for anonymous users to
|
||||
// avoid traffic to inaccessible pages from web crawlers. For
|
||||
// authenticated users, showing the links in HTML head does not impact
|
||||
// user experience or security, since the routes are access checked when
|
||||
// visited and only visible via view source. This prevents doing
|
||||
// potentially expensive and hard to cache access checks on every request.
|
||||
// This means that the page will vary by user.permissions. We also rely on
|
||||
// the access checking fallback to ensure the correct cacheability
|
||||
// metadata if we have to check access.
|
||||
if ($this->currentUser->isAuthenticated() || $url->access($this->currentUser)) {
|
||||
// Set the node path as the canonical URL to prevent duplicate content.
|
||||
$build['#attached']['html_head_link'][] = array(
|
||||
array(
|
||||
'rel' => $rel,
|
||||
'href' => $url->toString(),
|
||||
),
|
||||
TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
if ($rel == 'canonical') {
|
||||
// Set the non-aliased canonical path as a default shortlink.
|
||||
$build['#attached']['html_head_link'][] = array(
|
||||
array(
|
||||
'rel' => 'shortlink',
|
||||
'href' => $node->url($rel, array('alias' => TRUE)),
|
||||
'href' => $url->setOption('alias', TRUE)->toString(),
|
||||
),
|
||||
TRUE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Given this varies by $this->currentUser->isAuthenticated(), add a cache
|
||||
// context based on the anonymous role.
|
||||
$build['#cache']['contexts'][] = 'user.roles:anonymous';
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
namespace Drupal\node\Plugin\migrate;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Database\DatabaseExceptionWrapper;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\migrate\Exception\RequirementsException;
|
||||
use Drupal\migrate\Plugin\MigrationDeriverTrait;
|
||||
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +34,7 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
/**
|
||||
* The CCK plugin manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerInterface
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
|
||||
*/
|
||||
protected $cckPluginManager;
|
||||
|
||||
|
@ -49,12 +50,12 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
*
|
||||
* @param string $base_plugin_id
|
||||
* The base plugin ID for the plugin ID.
|
||||
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_manager
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_manager
|
||||
* The CCK plugin manager.
|
||||
* @param bool $translations
|
||||
* Whether or not to include translations.
|
||||
*/
|
||||
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager, $translations) {
|
||||
public function __construct($base_plugin_id, MigrateCckFieldPluginManagerInterface $cck_manager, $translations) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->cckPluginManager = $cck_manager;
|
||||
$this->includeTranslations = $translations;
|
||||
|
@ -128,14 +129,15 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
if (isset($fields[$node_type])) {
|
||||
foreach ($fields[$node_type] as $field_name => $info) {
|
||||
$field_type = $info['type'];
|
||||
if ($this->cckPluginManager->hasDefinition($info['type'])) {
|
||||
try {
|
||||
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, ['core' => 6], $migration);
|
||||
if (!isset($this->cckPluginCache[$field_type])) {
|
||||
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, ['core' => 6], $migration);
|
||||
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($plugin_id, ['core' => 6], $migration);
|
||||
}
|
||||
$this->cckPluginCache[$field_type]
|
||||
->processCckFieldValues($migration, $field_name, $info);
|
||||
}
|
||||
else {
|
||||
catch (PluginNotFoundException $ex) {
|
||||
$migration->setProcessOfProperty($field_name, $field_name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
namespace Drupal\node\Plugin\migrate;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Database\DatabaseExceptionWrapper;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\migrate\Exception\RequirementsException;
|
||||
use Drupal\migrate\Plugin\MigrationDeriverTrait;
|
||||
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +34,7 @@ class D7NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
/**
|
||||
* The CCK plugin manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerInterface
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
|
||||
*/
|
||||
protected $cckPluginManager;
|
||||
|
||||
|
@ -42,10 +43,10 @@ class D7NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
*
|
||||
* @param string $base_plugin_id
|
||||
* The base plugin ID for the plugin ID.
|
||||
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_manager
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_manager
|
||||
* The CCK plugin manager.
|
||||
*/
|
||||
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager) {
|
||||
public function __construct($base_plugin_id, MigrateCckFieldPluginManagerInterface $cck_manager) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->cckPluginManager = $cck_manager;
|
||||
}
|
||||
|
@ -98,14 +99,15 @@ class D7NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
if (isset($fields[$node_type])) {
|
||||
foreach ($fields[$node_type] as $field_name => $info) {
|
||||
$field_type = $info['type'];
|
||||
if ($this->cckPluginManager->hasDefinition($field_type)) {
|
||||
try {
|
||||
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, ['core' => 7], $migration);
|
||||
if (!isset($this->cckPluginCache[$field_type])) {
|
||||
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, ['core' => 7], $migration);
|
||||
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($plugin_id, ['core' => 7], $migration);
|
||||
}
|
||||
$this->cckPluginCache[$field_type]
|
||||
->processCckFieldValues($migration, $field_name, $info);
|
||||
}
|
||||
else {
|
||||
catch (PluginNotFoundException $ex) {
|
||||
$migration->setProcessOfProperty($field_name, $field_name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\node\Tests;
|
||||
|
||||
use Drupal\node\Entity\NodeType;
|
||||
|
||||
/**
|
||||
* Ensures that node access rebuild functions work correctly even
|
||||
* when other modules implements hook_node_grants().
|
||||
|
@ -11,20 +13,27 @@ namespace Drupal\node\Tests;
|
|||
class NodeAccessRebuildNodeGrantsTest extends NodeTestBase {
|
||||
|
||||
/**
|
||||
* A user to test the rebuild nodes feature.
|
||||
* A user to create nodes that only it has access to.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $webUser;
|
||||
|
||||
/**
|
||||
* A user to test the rebuild nodes feature which can't access the nodes.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports', 'bypass node access'));
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->adminUser = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports'));
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->webUser = $this->drupalCreateUser();
|
||||
}
|
||||
|
@ -34,25 +43,54 @@ class NodeAccessRebuildNodeGrantsTest extends NodeTestBase {
|
|||
*/
|
||||
public function testNodeAccessRebuildNodeGrants() {
|
||||
\Drupal::service('module_installer')->install(['node_access_test']);
|
||||
\Drupal::state()->set('node_access_test.private', TRUE);
|
||||
node_access_test_add_field(NodeType::load('page'));
|
||||
$this->resetAll();
|
||||
|
||||
$node = $this->drupalCreateNode(array(
|
||||
'uid' => $this->webUser->id(),
|
||||
));
|
||||
// Create 30 nodes so that _node_access_rebuild_batch_operation() has to run
|
||||
// more than once.
|
||||
for ($i = 0; $i < 30; $i++) {
|
||||
$nodes[] = $this->drupalCreateNode(array(
|
||||
'uid' => $this->webUser->id(),
|
||||
'private' => [['value' => 1]]
|
||||
));
|
||||
}
|
||||
|
||||
/** @var \Drupal\node\NodeGrantDatabaseStorageInterface $grant_storage */
|
||||
$grant_storage = \Drupal::service('node.grant_storage');
|
||||
// Default realm access and node records are present.
|
||||
$this->assertTrue(\Drupal::service('node.grant_storage')->access($node, 'view', $this->webUser), 'The expected node access records are present');
|
||||
foreach ($nodes as $node) {
|
||||
$this->assertTrue($node->private->value);
|
||||
$this->assertTrue($grant_storage->access($node, 'view', $this->webUser)->isAllowed(), 'Prior to rebuilding node access the grant storage returns allowed for the node author.');
|
||||
$this->assertTrue($grant_storage->access($node, 'view', $this->adminUser)->isAllowed(), 'Prior to rebuilding node access the grant storage returns allowed for the admin user.');
|
||||
}
|
||||
|
||||
$this->assertEqual(1, \Drupal::service('node.grant_storage')->checkAll($this->webUser), 'There is an all realm access record');
|
||||
$this->assertTrue(\Drupal::state()->get('node.node_access_needs_rebuild'), 'Node access permissions need to be rebuilt');
|
||||
|
||||
// Rebuild permissions.
|
||||
$this->drupalGet('admin/reports/status/rebuild');
|
||||
$this->drupalGet('admin/reports/status');
|
||||
$this->clickLink(t('Rebuild permissions'));
|
||||
$this->drupalPostForm(NULL, array(), t('Rebuild permissions'));
|
||||
$this->assertText(t('The content access permissions have been rebuilt.'));
|
||||
|
||||
// Test if the rebuild has been successful.
|
||||
// Test if the rebuild by user that cannot bypass node access and does not
|
||||
// have access to the nodes has been successful.
|
||||
$this->assertFalse($this->adminUser->hasPermission('bypass node access'));
|
||||
$this->assertNull(\Drupal::state()->get('node.node_access_needs_rebuild'), 'Node access permissions have been rebuilt');
|
||||
$this->assertTrue(\Drupal::service('node.grant_storage')->access($node, 'view', $this->webUser), 'The expected node access records are present');
|
||||
foreach ($nodes as $node) {
|
||||
$this->assertTrue($grant_storage->access($node, 'view', $this->webUser)->isAllowed(), 'After rebuilding node access the grant storage returns allowed for the node author.');
|
||||
$this->assertFalse($grant_storage->access($node, 'view', $this->adminUser)->isForbidden(), 'After rebuilding node access the grant storage returns forbidden for the admin user.');
|
||||
}
|
||||
$this->assertFalse(\Drupal::service('node.grant_storage')->checkAll($this->webUser), 'There is no all realm access record');
|
||||
|
||||
// Test an anonymous node access rebuild from code.
|
||||
$this->drupalLogout();
|
||||
node_access_rebuild();
|
||||
foreach ($nodes as $node) {
|
||||
$this->assertTrue($grant_storage->access($node, 'view', $this->webUser)->isAllowed(), 'After rebuilding node access the grant storage returns allowed for the node author.');
|
||||
$this->assertFalse($grant_storage->access($node, 'view', $this->adminUser)->isForbidden(), 'After rebuilding node access the grant storage returns forbidden for the admin user.');
|
||||
}
|
||||
$this->assertFalse(\Drupal::service('node.grant_storage')->checkAll($this->webUser), 'There is no all realm access record');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\node\Tests;
|
||||
|
||||
/**
|
||||
* Ensures that node access rebuild functions work correctly.
|
||||
*
|
||||
* @group node
|
||||
*/
|
||||
class NodeAccessRebuildTest extends NodeTestBase {
|
||||
/**
|
||||
* A normal authenticated user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $webUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$web_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports'));
|
||||
$this->drupalLogin($web_user);
|
||||
$this->webUser = $web_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rebuilding the node access permissions table.
|
||||
*/
|
||||
function testNodeAccessRebuild() {
|
||||
$this->drupalGet('admin/reports/status');
|
||||
$this->clickLink(t('Rebuild permissions'));
|
||||
$this->drupalPostForm(NULL, array(), t('Rebuild permissions'));
|
||||
$this->assertText(t('Content permissions have been rebuilt.'));
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,16 @@ class NodeCacheTagsTest extends EntityWithUriCacheTagsTestBase {
|
|||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultCacheContexts() {
|
||||
$defaults = parent::getDefaultCacheContexts();
|
||||
// @see \Drupal\node\Controller\NodeViewController::view()
|
||||
$defaults[] = 'user.roles:anonymous';
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -18,14 +18,49 @@ class NodeViewTest extends NodeTestBase {
|
|||
|
||||
$this->drupalGet($node->urlInfo());
|
||||
|
||||
$result = $this->xpath('//link[@rel = "canonical"]');
|
||||
$this->assertEqual($result[0]['href'], $node->url());
|
||||
|
||||
// Link relations are checked for access for anonymous users.
|
||||
$result = $this->xpath('//link[@rel = "version-history"]');
|
||||
$this->assertFalse($result, 'Version history not present for anonymous users without access.');
|
||||
|
||||
$result = $this->xpath('//link[@rel = "edit-form"]');
|
||||
$this->assertFalse($result, 'Edit form not present for anonymous users without access.');
|
||||
|
||||
$this->drupalLogin($this->createUser(['access content']));
|
||||
$this->drupalGet($node->urlInfo());
|
||||
|
||||
$result = $this->xpath('//link[@rel = "canonical"]');
|
||||
$this->assertEqual($result[0]['href'], $node->url());
|
||||
|
||||
// Link relations are present regardless of access for authenticated users.
|
||||
$result = $this->xpath('//link[@rel = "version-history"]');
|
||||
$this->assertEqual($result[0]['href'], $node->url('version-history'));
|
||||
|
||||
$result = $this->xpath('//link[@rel = "edit-form"]');
|
||||
$this->assertEqual($result[0]['href'], $node->url('edit-form'));
|
||||
|
||||
// Give anonymous users access to edit the node. Do this through the UI to
|
||||
// ensure caches are handled properly.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$edit = [
|
||||
'anonymous[edit own ' . $node->bundle() . ' content]' => TRUE
|
||||
];
|
||||
$this->drupalPostForm('admin/people/permissions', $edit, 'Save permissions');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Anonymous user's should now see the edit-form link but not the
|
||||
// version-history link.
|
||||
$this->drupalGet($node->urlInfo());
|
||||
$result = $this->xpath('//link[@rel = "canonical"]');
|
||||
$this->assertEqual($result[0]['href'], $node->url());
|
||||
|
||||
$result = $this->xpath('//link[@rel = "version-history"]');
|
||||
$this->assertFalse($result, 'Version history not present for anonymous users without access.');
|
||||
|
||||
$result = $this->xpath('//link[@rel = "edit-form"]');
|
||||
$this->assertEqual($result[0]['href'], $node->url('edit-form'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,7 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
|
|||
'd7_taxonomy_vocabulary',
|
||||
'd7_field',
|
||||
'd7_field_instance',
|
||||
'd7_node:test_content_type',
|
||||
'd7_node',
|
||||
'd7_node:article',
|
||||
]);
|
||||
}
|
||||
|
|
Reference in a new issue