View source
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\Core\Database\Database;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\Component\Serialization\Json;
class NodeRevisionsTest extends NodeTestBase {
protected $defaultTheme = 'stark';
protected $nodes;
protected $revisionLogs;
protected static $modules = [
'node',
'contextual',
'datetime',
'language',
'content_translation',
];
protected function setUp() : void {
parent::setUp();
ConfigurableLanguage::createFromLangcode('de')
->save();
ConfigurableLanguage::createFromLangcode('it')
->save();
$field_storage_definition = [
'field_name' => 'untranslatable_string_field',
'entity_type' => 'node',
'type' => 'string',
'cardinality' => 1,
'translatable' => FALSE,
];
$field_storage = FieldStorageConfig::create($field_storage_definition);
$field_storage
->save();
$field_definition = [
'field_storage' => $field_storage,
'bundle' => 'page',
];
$field = FieldConfig::create($field_definition);
$field
->save();
\Drupal::service('content_translation.manager')
->setEnabled('node', 'page', TRUE);
$web_user = $this
->drupalCreateUser([
'view page revisions',
'revert page revisions',
'delete page revisions',
'edit any page content',
'delete any page content',
'access contextual links',
'translate any entity',
'administer content types',
]);
$this
->drupalLogin($web_user);
$node = $this
->drupalCreateNode();
$settings = get_object_vars($node);
$settings['revision'] = 1;
$settings['isDefaultRevision'] = TRUE;
$nodes = [];
$logs = [];
$nodes[] = clone $node;
$revision_count = 3;
for ($i = 0; $i < $revision_count; $i++) {
$logs[] = $node->revision_log = $this
->randomMachineName(32);
$node->title = $this
->randomMachineName();
$node->body = [
'value' => $this
->randomMachineName(32),
'format' => filter_default_format(),
];
$node->untranslatable_string_field->value = $this
->randomString();
$node
->setNewRevision();
if ($i < 2) {
$editor = $this
->drupalCreateUser();
$node
->setRevisionUserId($editor
->id());
}
else {
$node
->setRevisionUserId($web_user
->id());
}
$node
->save();
$node = Node::load($node
->id());
$nodes[] = clone $node;
}
$this->nodes = $nodes;
$this->revisionLogs = $logs;
}
public function testRevisions() {
$node = $this
->drupalCreateNode();
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $node
->getRevisionId() . "/view");
$this
->assertSession()
->statusCodeEquals(200);
$node_storage = $this->container
->get('entity_type.manager')
->getStorage('node');
$nodes = $this->nodes;
$logs = $this->revisionLogs;
$node = $nodes[3];
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $node
->getRevisionId() . "/view");
$this
->assertSession()
->pageTextContains($node->body->value);
$this
->drupalGet("node/" . $node
->id() . "/revisions");
foreach ($logs as $revision_log) {
$this
->assertSession()
->pageTextContains($revision_log);
}
$web_user = $nodes[0]->revision_uid->entity;
$this
->assertSession()
->pageTextContains('by ' . $web_user
->getAccountName());
$editor = $nodes[2]->revision_uid->entity;
$this
->assertSession()
->pageTextContains('by ' . $editor
->getAccountName());
$this
->assertTrue($node
->isDefaultRevision(), 'Third node revision is the default one.');
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $nodes[1]
->getRevisionid() . "/revert");
$this
->submitForm([], 'Revert');
$this
->assertSession()
->pageTextContains("Basic page {$nodes[1]->label()} has been reverted to the revision from {$this->container->get('date.formatter')->format($nodes[1]->getRevisionCreationTime())}.");
$node_storage
->resetCache([
$node
->id(),
]);
$reverted_node = $node_storage
->load($node
->id());
$this
->assertSame($nodes[1]->body->value, $reverted_node->body->value, 'Node reverted correctly.');
$this
->assertSame($this->loggedInUser
->id(), $reverted_node
->getRevisionUserId(), 'Node revision author is user performing revert.');
$this
->assertNotSame($nodes[1]
->getRevisionUserId(), $reverted_node
->getRevisionUserId(), 'Node revision author is not original revision author.');
$node = node_revision_load($node
->getRevisionId());
$this
->assertFalse($node
->isDefaultRevision(), 'Third node revision is not the default one.');
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $nodes[1]
->getRevisionId() . "/delete");
$this
->submitForm([], 'Delete');
$this
->assertSession()
->pageTextContains("Revision from {$this->container->get('date.formatter')->format($nodes[1]->getRevisionCreationTime())} of Basic page {$nodes[1]->label()} has been deleted.");
$connection = Database::getConnection();
$nids = \Drupal::entityQuery('node')
->accessCheck(FALSE)
->allRevisions()
->condition('nid', $node
->id())
->condition('vid', $nodes[1]
->getRevisionId())
->execute();
$this
->assertCount(0, $nids);
$old_revision_date = REQUEST_TIME - 86400;
$connection
->update('node_revision')
->condition('vid', $nodes[2]
->getRevisionId())
->fields([
'revision_timestamp' => $old_revision_date,
])
->execute();
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $nodes[2]
->getRevisionId() . "/revert");
$this
->submitForm([], 'Revert');
$this
->assertSession()
->pageTextContains("Basic page {$nodes[2]->label()} has been reverted to the revision from {$this->container->get('date.formatter')->format($old_revision_date)}.");
$new_node_revision = clone $node;
$new_body = $this
->randomMachineName();
$new_node_revision->body->value = $new_body;
$new_node_revision
->setNewRevision();
$new_node_revision->isDefaultRevision = FALSE;
$new_node_revision
->save();
$this
->drupalGet('node/' . $node
->id());
$this
->assertSession()
->pageTextNotContains($new_body);
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $new_node_revision
->getRevisionId() . "/view");
$this
->assertSession()
->pageTextContains($new_body);
$default_revision = $connection
->select('node', 'n')
->fields('n', [
'vid',
])
->condition('nid', $node
->id())
->execute()
->fetchCol();
$default_revision_vid = $default_revision[0];
$this
->assertGreaterThan($default_revision_vid, $new_node_revision
->getRevisionId());
$node = $this
->drupalCreateNode();
$node->title = 'Node title in EN';
$node->revision_log = 'Simple revision message (EN)';
$node
->save();
$this
->drupalGet("node/" . $node
->id() . "/revisions");
$this
->assertSession()
->statusCodeEquals(200);
$this
->assertSession()
->pageTextContains('Simple revision message (EN)');
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $node
->getRevisionId() . "/delete");
$this
->assertSession()
->statusCodeEquals(403);
$this
->drupalGet("node/" . $node
->id() . "/revisions/" . $node
->getRevisionId() . "/revert");
$this
->assertSession()
->statusCodeEquals(403);
$node = Node::load($node
->id());
$node->body->value = 'New text (EN)';
$node->revision_log = 'New revision message (EN)';
$node
->setNewRevision();
$node
->save();
$this
->drupalGet("node/" . $node
->id() . "/revisions");
$this
->assertSession()
->pageTextContains('Simple revision message (EN)');
$this
->assertSession()
->pageTextContains('New revision message (EN)');
$node = $this
->drupalCreateNode();
$node->langcode = 'en';
$node->title = 'Node title in EN';
$node->revision_log = 'Simple revision message (EN)';
$node
->save();
$this
->drupalGet("node/" . $node
->id() . "/revisions");
$this
->assertSession()
->statusCodeEquals(200);
$this
->assertSession()
->pageTextContains('Simple revision message (EN)');
$translation = $node
->addTranslation('de');
$translation->title->value = 'Node title in DE';
$translation->body->value = 'New text (DE)';
$translation->revision_log = 'New revision message (DE)';
$translation
->setNewRevision();
$translation
->save();
$this
->drupalGet("it/node/" . $node
->id() . "/revisions");
$this
->assertSession()
->pageTextContains('Simple revision message (EN)');
$this
->assertSession()
->pageTextNotContains('New revision message (DE)');
$this
->drupalGet("de/node/" . $node
->id() . "/revisions");
$this
->assertSession()
->pageTextNotContains('Simple revision message (EN)');
$this
->assertSession()
->pageTextContains('New revision message (DE)');
$this
->drupalGet("node/" . $node
->id() . "/revisions");
$this
->assertSession()
->pageTextContains('Simple revision message (EN)');
$this
->assertSession()
->pageTextNotContains('New revision message (DE)');
}
public function testNodeRevisionWithoutLogMessage() {
$node_storage = $this->container
->get('entity_type.manager')
->getStorage('node');
$revision_log = $this
->randomMachineName(10);
$node = $this
->drupalCreateNode([
'revision_log' => $revision_log,
]);
$new_title = $this
->randomMachineName(10) . 'testNodeRevisionWithoutLogMessage1';
$node = clone $node;
$node->title = $new_title;
$node->revision_log = '';
$node
->setNewRevision(FALSE);
$node
->save();
$this
->drupalGet('node/' . $node
->id());
$this
->assertSession()
->pageTextContains($new_title);
$node_storage
->resetCache([
$node
->id(),
]);
$node_revision = $node_storage
->load($node
->id());
$this
->assertEquals($revision_log, $node_revision->revision_log->value, 'After an existing node revision is re-saved without a log message, the original log message is preserved.');
$node = $this
->drupalCreateNode([
'revision_log' => $revision_log,
]);
$new_title = $this
->randomMachineName(10) . 'testNodeRevisionWithoutLogMessage2';
$node = clone $node;
$node->title = $new_title;
$node
->setNewRevision();
$node->revision_log = NULL;
$node
->save();
$this
->drupalGet('node/' . $node
->id());
$this
->assertSession()
->pageTextContains($new_title);
$node_storage
->resetCache([
$node
->id(),
]);
$node_revision = $node_storage
->load($node
->id());
$this
->assertEmpty($node_revision->revision_log->value, 'After a new node revision is saved with an empty log message, the log message for the node is empty.');
}
protected function renderContextualLinks(array $ids, $current_path) {
$post = [];
for ($i = 0; $i < count($ids); $i++) {
$post['ids[' . $i . ']'] = $ids[$i];
}
$response = $this
->drupalPost('contextual/render', 'application/json', $post, [
'query' => [
'destination' => $current_path,
],
]);
return Json::decode($response);
}
public function testRevisionTranslationRevert() {
$node = $this
->drupalCreateNode([
'langcode' => 'en',
]);
$initial_revision_id = $node
->getRevisionId();
$initial_title = $node
->label();
$this
->createRevisions($node, 2);
$translation = $node
->addTranslation('it');
$this
->createRevisions($translation, 3);
$revert_id = $node
->getRevisionId();
$translated_title = $translation
->label();
$untranslatable_string = $node->untranslatable_string_field->value;
$this
->createRevisions($node, 1);
$default_translation_title = $node
->label();
$this
->createRevisions($translation, 2);
$translation_revision_id = $translation
->getRevisionId();
$revert_translation_url = Url::fromRoute('node.revision_revert_translation_confirm', [
'node' => $node
->id(),
'node_revision' => $revert_id,
'langcode' => 'it',
]);
$this
->drupalGet($revert_translation_url);
$this
->submitForm([], 'Revert');
$node_storage = $this->container
->get('entity_type.manager')
->getStorage('node');
$node_storage
->resetCache();
$node = $node_storage
->load($node
->id());
$this
->assertGreaterThan($translation_revision_id, $node
->getRevisionId());
$this
->assertEquals($default_translation_title, $node
->label());
$this
->assertEquals($translated_title, $node
->getTranslation('it')
->label());
$this
->assertNotEquals($untranslatable_string, $node->untranslatable_string_field->value);
$latest_revision_id = $translation
->getRevisionId();
$this
->drupalGet($revert_translation_url);
$this
->submitForm([
'revert_untranslated_fields' => TRUE,
], 'Revert');
$node_storage
->resetCache();
$node = $node_storage
->load($node
->id());
$this
->assertGreaterThan($latest_revision_id, $node
->getRevisionId());
$this
->assertEquals($default_translation_title, $node
->label());
$this
->assertEquals($translated_title, $node
->getTranslation('it')
->label());
$this
->assertEquals($untranslatable_string, $node->untranslatable_string_field->value);
$latest_revision_id = $translation
->getRevisionId();
$revert_url = Url::fromRoute('node.revision_revert_confirm', [
'node' => $node
->id(),
'node_revision' => $initial_revision_id,
]);
$this
->drupalGet($revert_url);
$this
->submitForm([], 'Revert');
$node_storage
->resetCache();
$node = $node_storage
->load($node
->id());
$this
->assertGreaterThan($latest_revision_id, $node
->getRevisionId());
$this
->assertEquals($initial_title, $node
->label());
$this
->assertFalse($node
->hasTranslation('it'));
}
protected function createRevisions(NodeInterface $node, $count) {
for ($i = 0; $i < $count; $i++) {
$node->title = $this
->randomString();
$node->untranslatable_string_field->value = $this
->randomString();
$node
->setNewRevision(TRUE);
$node
->save();
}
}
}