Update to Drupal 8.1.8. For more information, see https://www.drupal.org/project/drupal/releases/8.1.8

This commit is contained in:
Pantheon Automation 2016-08-03 13:22:33 -07:00 committed by Greg Anderson
parent e9f047ccf8
commit f9f23cdf38
312 changed files with 6751 additions and 1546 deletions

View file

@ -6,7 +6,10 @@ deriver: Drupal\node\Plugin\migrate\D6NodeDeriver
source:
plugin: d6_node
process:
nid: nid
# In D6, nodes always have a tnid, but it's zero for untranslated nodes.
# We normalize it to equal the nid in that case.
# @see \Drupal\node\Plugin\migrate\source\d6\Node::prepareRow().
nid: tnid
vid: vid
langcode:
plugin: default_value

View file

@ -0,0 +1,52 @@
id: d6_node_translation
label: Node translations
migration_tags:
- Drupal 6
deriver: Drupal\node\Plugin\migrate\D6NodeDeriver
source:
plugin: d6_node
translations: true
process:
nid: tnid
type: type
langcode:
plugin: default_value
source: language
default_value: "und"
title: title
uid: node_uid
status: status
created: created
changed: changed
promote: promote
sticky: sticky
'body/format':
plugin: migration
migration: d6_filter_format
source: format
'body/value': body
'body/summary': teaser
revision_uid: revision_uid
revision_log: log
revision_timestamp: timestamp
# unmapped d6 fields.
# translate
# moderate
# comment
destination:
plugin: entity:node
translations: true
migration_dependencies:
required:
- d6_user
- d6_node_type
- d6_node_settings
- d6_filter_format
- language
optional:
- d6_field_instance_widget_settings
- d6_field_formatter_settings
- d6_upload_field_instance
provider: migrate_drupal

View file

@ -8,6 +8,7 @@ use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\node\NodeStorageInterface;
use Drupal\node\NodeTypeInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -125,6 +126,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);
$page = $node_view_controller->view($node);
unset($page['nodes'][$node->id()]['#cache']);
@ -170,12 +172,9 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
$delete_permission = (($account->hasPermission("delete $type revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes')) && $node->access('delete'));
$rows = array();
$vids = $node_storage->revisionIds($node);
$latest_revision = TRUE;
foreach (array_reverse($vids) as $vid) {
foreach ($this->_getRevisionIds($node, $node_storage) as $vid) {
/** @var \Drupal\node\NodeInterface $revision */
$revision = $node_storage->loadRevision($vid);
// Only show revisions that are affected by the language that is being
@ -263,6 +262,8 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
),
);
$build['pager'] = array('#type' => 'pager');
return $build;
}
@ -279,4 +280,25 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
return $this->t('Create @name', array('@name' => $node_type->label()));
}
/**
* Gets a list of node revision IDs for a specific node.
*
* @param \Drupal\node\NodeInterface
* The node entity.
* @param \Drupal\node\NodeStorageInterface $node_storage
* The node storage handler.
*
* @return int[]
* Node revision IDs (in descending order).
*/
protected function _getRevisionIds(NodeInterface $node, NodeStorageInterface $node_storage) {
$result = $node_storage->getQuery()
->allRevisions()
->condition($node->getEntityType()->getKey('id'), $node->id())
->sort($node->getEntityType()->getKey('revision'), 'DESC')
->pager(50)
->execute();
return array_keys($result);
}
}

View file

@ -146,10 +146,21 @@ class NodeViewBuilder extends EntityViewBuilder {
/** @var \Drupal\node\NodeInterface $entity */
parent::alterBuild($build, $entity, $display, $view_mode);
if ($entity->id()) {
$build['#contextual_links']['node'] = array(
'route_parameters' => array('node' => $entity->id()),
'metadata' => array('changed' => $entity->getChangedTime()),
);
if ($entity->isDefaultRevision()) {
$build['#contextual_links']['node'] = [
'route_parameters' => ['node' => $entity->id()],
'metadata' => ['changed' => $entity->getChangedTime()],
];
}
else {
$build['#contextual_links']['node_revision'] = [
'route_parameters' => [
'node' => $entity->id(),
'node_revision' => $entity->getRevisionId(),
],
'metadata' => ['changed' => $entity->getChangedTime()],
];
}
}
}

View file

@ -37,6 +37,13 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
*/
protected $cckPluginManager;
/**
* Whether or not to include translations.
*
* @var bool
*/
protected $includeTranslations;
/**
* D6NodeDeriver constructor.
*
@ -44,19 +51,24 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
* The base plugin ID for the plugin ID.
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_manager
* The CCK plugin manager.
* @param bool $translations
* Whether or not to include translations.
*/
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager) {
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager, $translations) {
$this->basePluginId = $base_plugin_id;
$this->cckPluginManager = $cck_manager;
$this->includeTranslations = $translations;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
// Translations don't make sense unless we have content_translation.
return new static(
$base_plugin_id,
$container->get('plugin.manager.migrate.cckfield')
$container->get('plugin.manager.migrate.cckfield'),
$container->get('module_handler')->moduleExists('content_translation')
);
}
@ -72,6 +84,11 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
* @see \Drupal\Component\Plugin\Derivative\DeriverBase::getDerivativeDefinition()
*/
public function getDerivativeDefinitions($base_plugin_definition) {
if ($base_plugin_definition['id'] == 'd6_node_translation' && !$this->includeTranslations) {
// Refuse to generate anything.
return $this->derivatives;
}
// Read all CCK field instance definitions in the source database.
$fields = array();
try {
@ -100,9 +117,10 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
$values['source']['node_type'] = $node_type;
$values['destination']['default_bundle'] = $node_type;
// If this migration is based on the d6_node_revision migration, it
// should explicitly depend on the corresponding d6_node variant.
if ($base_plugin_definition['id'] == 'd6_node_revision') {
// If this migration is based on the d6_node_revision migration or
// is for translations of nodes, it should explicitly depend on the
// corresponding d6_node variant.
if (in_array($base_plugin_definition['id'], ['d6_node_revision', 'd6_node_translation'])) {
$values['migration_dependencies']['required'][] = 'd6_node:' . $node_type;
}

View file

@ -2,6 +2,7 @@
namespace Drupal\node\Plugin\migrate\source\d6;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
@ -37,9 +38,11 @@ class Node extends DrupalSqlBase {
* {@inheritdoc}
*/
public function query() {
// Select node in its last revision.
$query = $this->select('node_revisions', 'nr')
->fields('n', array(
$query = $this->select('node_revisions', 'nr');
$query->innerJoin('node', 'n', static::JOIN);
$this->handleTranslations($query);
$query->fields('n', array(
'nid',
'type',
'language',
@ -54,17 +57,16 @@ class Node extends DrupalSqlBase {
'translate',
))
->fields('nr', array(
'vid',
'title',
'body',
'teaser',
'log',
'timestamp',
'format',
'vid',
));
$query->addField('n', 'uid', 'node_uid');
$query->addField('nr', 'uid', 'revision_uid');
$query->innerJoin('node', 'n', static::JOIN);
if (isset($this->configuration['node_type'])) {
$query->condition('n.type', $this->configuration['node_type']);
@ -123,6 +125,11 @@ class Node extends DrupalSqlBase {
}
}
// Make sure we always have a translation set.
if ($row->getSourceProperty('tnid') == 0) {
$row->setSourceProperty('tnid', $row->getSourceProperty('nid'));
}
return parent::prepareRow($row);
}
@ -251,4 +258,22 @@ class Node extends DrupalSqlBase {
return $ids;
}
/**
* Adapt our query for translations.
*
* @param \Drupal\Core\Database\Query\SelectInterface
* The generated query.
*/
protected function handleTranslations(SelectInterface $query) {
// Check whether or not we want translations.
if (empty($this->configuration['translations'])) {
// No translations: Yield untranslated nodes, or default translations.
$query->where('n.tnid = 0 OR n.tnid = n.nid');
}
else {
// Translations: Yield only non-default translations.
$query->where('n.tnid <> 0 AND n.tnid <> n.nid');
}
}
}

View file

@ -1,6 +1,7 @@
<?php
namespace Drupal\node\Plugin\migrate\source\d6;
use Drupal\Core\Database\Query\SelectInterface;
/**
* Drupal 6 node revision source from database.
@ -37,4 +38,11 @@ class NodeRevision extends Node {
return $ids;
}
/**
* {@inheritdoc}
*/
protected function handleTranslations(SelectInterface $query) {
// @todo in https://www.drupal.org/node/2746541
}
}

View file

@ -63,7 +63,9 @@ class Path extends FieldPluginBase {
*/
public function render(ResultRow $values) {
$nid = $this->getValue($values, 'nid');
return \Drupal::url('entity.node.canonical', ['node' => $nid], ['absolute' => $this->options['absolute']]);
return array(
'#markup' => \Drupal::url('entity.node.canonical', ['node' => $nid], ['absolute' => $this->options['absolute']]),
);
}
}

View file

@ -10,6 +10,11 @@ use Drupal\Tests\node\Kernel\Migrate\d6\MigrateNodeTestBase;
*/
class MigrateNodeRevisionTest extends MigrateNodeTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['language', 'content_translation'];
/**
* {@inheritdoc}
*/

View file

@ -2,6 +2,8 @@
namespace Drupal\node\Tests;
use Drupal\filter\Entity\FilterFormat;
/**
* Ensures that data added to nodes by other modules appears in RSS feeds.
*
@ -60,4 +62,47 @@ class NodeRSSContentTest extends NodeTestBase {
$this->assertNoText($rss_only_content, 'Node content designed for RSS does not appear when viewing node.');
}
/**
* Tests relative, root-relative, protocol-relative and absolute URLs.
*/
public function testUrlHandling() {
// Only the plain_text text format is available by default, which escapes
// all HTML.
FilterFormat::create([
'format' => 'full_html',
'name' => 'Full HTML',
'filters' => [],
])->save();
$defaults = [
'type' => 'article',
'promote' => 1,
];
$this->drupalCreateNode($defaults + [
'body' => [
'value' => '<p><a href="' . file_url_transform_relative(file_create_url('public://root-relative')) . '">Root-relative URL</a></p>',
'format' => 'full_html',
],
]);
$protocol_relative_url = substr(file_create_url('public://protocol-relative'), strlen(\Drupal::request()->getScheme() . ':'));
$this->drupalCreateNode($defaults + [
'body' => [
'value' => '<p><a href="' . $protocol_relative_url . '">Protocol-relative URL</a></p>',
'format' => 'full_html',
],
]);
$absolute_url = file_create_url('public://absolute');
$this->drupalCreateNode($defaults + [
'body' => [
'value' => '<p><a href="' . $absolute_url . '">Absolute URL</a></p>',
'format' => 'full_html',
],
]);
$this->drupalGet('rss.xml');
$this->assertRaw(file_create_url('public://root-relative'), 'Root-relative URL is transformed to absolute.');
$this->assertRaw($protocol_relative_url, 'Protocol-relative URL is left untouched.');
$this->assertRaw($absolute_url, 'Absolute URL is left untouched.');
}
}

View file

@ -2,6 +2,8 @@
namespace Drupal\node\Tests;
use Drupal\node\NodeInterface;
/**
* Create a node with revisions and test viewing, saving, reverting, and
* deleting revisions for user with access to all.
@ -15,7 +17,7 @@ class NodeRevisionsAllTest extends NodeTestBase {
protected function setUp() {
parent::setUp();
$node_storage = $this->container->get('entity.manager')->getStorage('node');
// Create and log in user.
$web_user = $this->drupalCreateUser(
array(
@ -45,17 +47,7 @@ class NodeRevisionsAllTest extends NodeTestBase {
for ($i = 0; $i < $revision_count; $i++) {
$logs[] = $node->revision_log = $this->randomMachineName(32);
// Create revision with a random title and body and update variables.
$node->title = $this->randomMachineName();
$node->body = array(
'value' => $this->randomMachineName(32),
'format' => filter_default_format(),
);
$node->setNewRevision();
$node->save();
$node_storage->resetCache(array($node->id()));
$node = $node_storage->load($node->id()); // Make sure we get revision information.
$node = $this->createNodeRevision($node);
$nodes[] = clone $node;
}
@ -63,6 +55,28 @@ class NodeRevisionsAllTest extends NodeTestBase {
$this->revisionLogs = $logs;
}
/**
* Creates a new revision for a given node.
*
* @param \Drupal\node\NodeInterface $node
* A node object.
*
* @return \Drupal\node\NodeInterface
* A node object with up to date revision information.
*/
protected function createNodeRevision(NodeInterface $node) {
// Create revision with a random title and body and update variables.
$node->title = $this->randomMachineName();
$node->body = array(
'value' => $this->randomMachineName(32),
'format' => filter_default_format(),
);
$node->setNewRevision();
$node->save();
return $node;
}
/**
* Checks node revision operations.
*/
@ -145,6 +159,29 @@ class NodeRevisionsAllTest extends NodeTestBase {
'%title' => $nodes[2]->getTitle(),
'%revision-date' => format_date($old_revision_date),
)));
// Create 50 more revisions in order to trigger paging on the revisions
// overview screen.
$node = $nodes[0];
for ($i = 0; $i < 50; $i++) {
$logs[] = $node->revision_log = $this->randomMachineName(32);
$node = $this->createNodeRevision($node);
$nodes[] = clone $node;
}
$this->drupalGet('node/' . $node->id() . '/revisions');
// Check that the pager exists.
$this->assertRaw('page=1');
// Check that the last revision is displayed on the first page.
$this->assertText(end($logs));
// Go to the second page and check that one of the initial three revisions
// is displayed.
$this->clickLink(t('Page 2'));
$this->assertText($logs[2]);
}
}

View file

@ -8,6 +8,7 @@ use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\Component\Serialization\Json;
/**
* Create a node with revisions and test viewing, saving, reverting, and
@ -34,7 +35,7 @@ class NodeRevisionsTest extends NodeTestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('node', 'datetime', 'language', 'content_translation');
public static $modules = ['node', 'contextual', 'datetime', 'language', 'content_translation'];
/**
* {@inheritdoc}
@ -71,6 +72,7 @@ class NodeRevisionsTest extends NodeTestBase {
'delete page revisions',
'edit any page content',
'delete any page content',
'access contextual links',
'translate any entity',
'administer content types',
)
@ -152,6 +154,18 @@ class NodeRevisionsTest extends NodeTestBase {
// Confirm that this is the default revision.
$this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.');
// Confirm that the "Edit" and "Delete" contextual links appear for the
// default revision.
$ids = ['node:node=' . $node->id() . ':changed=' . $node->getChangedTime()];
$json = $this->renderContextualLinks($ids, 'node/' . $node->id());
$this->verbose($json[$ids[0]]);
$expected = '<li class="entitynodeedit-form"><a href="' . base_path() . 'node/' . $node->id() . '/edit">Edit</a></li>';
$this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Edit" contextual link is shown for the default revision.');
$expected = '<li class="entitynodedelete-form"><a href="' . base_path() . 'node/' . $node->id() . '/delete">Delete</a></li>';
$this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Delete" contextual link is shown for the default revision.');
// Confirm that revisions revert properly.
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionid() . "/revert", array(), t('Revert'));
$this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.',
@ -165,6 +179,16 @@ class NodeRevisionsTest extends NodeTestBase {
$node = node_revision_load($node->getRevisionId());
$this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.');
// Confirm that "Edit" and "Delete" contextual links don't appear for
// non-default revision.
$ids = ['node_revision::node=' . $node->id() . '&node_revision=' . $node->getRevisionId() . ':'];
$json = $this->renderContextualLinks($ids, 'node/' . $node->id() . '/revisions/' . $node->getRevisionId() . '/view');
$this->verbose($json[$ids[0]]);
$this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodeedit-form">'), 'The "Edit" contextual link is not shown for a non-default revision.');
$this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodedelete-form">'), 'The "Delete" contextual link is not shown for a non-default revision.');
// Confirm revisions delete properly.
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", array(), t('Delete'));
$this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.',
@ -317,6 +341,27 @@ class NodeRevisionsTest extends NodeTestBase {
$this->assertTrue(empty($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.');
}
/**
* Gets server-rendered contextual links for the given contextual links IDs.
*
* @param string[] $ids
* An array of contextual link IDs.
* @param string $current_path
* The Drupal path for the page for which the contextual links are rendered.
*
* @return string
* The decoded JSON response body.
*/
protected function renderContextualLinks(array $ids, $current_path) {
$post = array();
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);
}
/**
* Tests the revision translations are correctly reverted.
*/

View file

@ -445,4 +445,53 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
}
}
/**
* Tests that revision translations are rendered properly.
*/
public function testRevisionTranslationRendering() {
$storage = \Drupal::entityTypeManager()->getStorage('node');
// Create a node.
$nid = $this->createEntity(['title' => 'First rev en title'], 'en');
$node = $storage->load($nid);
$original_revision_id = $node->getRevisionId();
// Add a French translation.
$translation = $node->addTranslation('fr');
$translation->title = 'First rev fr title';
$translation->setNewRevision(FALSE);
$translation->save();
// Create a new revision.
$node->title = 'Second rev en title';
$node->setNewRevision(TRUE);
$node->save();
// Get an English view of this revision.
$original_revision = $storage->loadRevision($original_revision_id);
$original_revision_url = $original_revision->toUrl('revision')->toString();
// Should be different from regular node URL.
$this->assertNotIdentical($original_revision_url, $original_revision->toUrl()->toString());
$this->drupalGet($original_revision_url);
$this->assertResponse(200);
// Contents should be in English, of correct revision.
$this->assertText('First rev en title');
$this->assertNoText('First rev fr title');
// Get a French view.
$url_fr = $original_revision->getTranslation('fr')->toUrl('revision')->toString();
// Should have different URL from English.
$this->assertNotIdentical($url_fr, $original_revision->toUrl()->toString());
$this->assertNotIdentical($url_fr, $original_revision_url);
$this->drupalGet($url_fr);
$this->assertResponse(200);
// Contents should be in French, of correct revision.
$this->assertText('First rev fr title');
$this->assertNoText('First rev en title');
}
}

View file

@ -23,7 +23,9 @@ class NodeTypeTranslationTest extends WebTestBase {
* @var array
*/
public static $modules = array(
'block',
'config_translation',
'field_ui',
'node',
);
@ -53,6 +55,8 @@ class NodeTypeTranslationTest extends WebTestBase {
$admin_permissions = array(
'administer content types',
'administer node fields',
'administer languages',
'administer site configuration',
'administer themes',
'translate configuration',
@ -144,6 +148,29 @@ class NodeTypeTranslationTest extends WebTestBase {
$this->assertText('Edited title');
$this->drupalGet("$langcode/node/add/$type");
$this->assertText('Translated title');
// Add an e-mail field.
$this->drupalPostForm("admin/structure/types/manage/$type/fields/add-field", array('new_storage_type' => 'email', 'label' => 'Email', 'field_name' => 'email'), 'Save and continue');
$this->drupalPostForm(NULL, array(), 'Save field settings');
$this->drupalPostForm(NULL, array(), 'Save settings');
$type = Unicode::strtolower($this->randomMachineName(16));
$name = $this->randomString();
$this->drupalCreateContentType(array('type' => $type, 'name' => $name));
// Set tabs.
$this->drupalPlaceBlock('local_tasks_block', array('primary' => TRUE));
// Change default language.
$this->drupalPostForm('admin/config/regional/language', array('site_default_language' => 'es'), 'Save configuration');
// Try re-using the email field.
$this->drupalGet("es/admin/structure/types/manage/$type/fields/add-field");
$this->drupalPostForm(NULL, array('existing_storage_name' => 'field_email', 'existing_storage_label' => 'Email'), 'Save and continue');
$this->assertResponse(200);
$this->drupalGet("es/admin/structure/types/manage/$type/fields/node.$type.field_email/translate");
$this->assertResponse(200);
$this->assertText("The configuration objects have different language codes so they cannot be translated");
}
}

View file

@ -0,0 +1,77 @@
<?php
namespace Drupal\node\Tests\Views;
use Drupal\views\Views;
/**
* Tests the node row plugin.
*
* @group node
*/
class PathPluginTest extends NodeTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_node_path_plugin');
/**
* Contains all nodes used by this test.
*
* @var Node[]
*/
protected $nodes;
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(array('type' => 'article'));
// Create two nodes.
for ($i = 0; $i < 2; $i++) {
$this->nodes[] = $this->drupalCreateNode(
array(
'type' => 'article',
'body' => array(
array(
'value' => $this->randomMachineName(42),
'format' => filter_default_format(),
'summary' => $this->randomMachineName(),
),
),
)
);
}
}
/**
* Tests the node path plugin.
*/
public function testPathPlugin() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_node_path_plugin');
$view->initDisplay();
$view->setDisplay('page_1');
$view->initStyle();
$view->rowPlugin->options['view_mode'] = 'full';
// Test with view_mode full.
$output = $view->preview();
$output = $renderer->renderRoot($output);
foreach ($this->nodes as $node) {
$this->assertTrue(strpos($output, 'This is <strong>not escaped</strong> and this is ' . $node->link('the link')) !== FALSE, 'Make sure path field rewriting is not escaped.');
}
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Drupal\node\Tests\Views;
/**
* Tests the different revision link handlers.
*
* @group node
*
* @see \Drupal\node\Plugin\views\field\RevisionLink
* @see \Drupal\node\Plugin\views\field\RevisionLinkDelete
* @see \Drupal\node\Plugin\views\field\RevisionLinkRevert
*/
class RevisionLinkTest extends NodeTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_node_revision_links'];
/**
* Tests revision links.
*/
public function testRevisionLinks() {
// Create one user which can view/revert and delete and one which can only
// do one of them.
$this->drupalCreateContentType(['name' => 'page', 'type' => 'page']);
$account = $this->drupalCreateUser(['revert all revisions', 'view all revisions', 'delete all revisions', 'edit any page content', 'delete any page content']);
$this->drupalLogin($account);
// Create two nodes, one without an additional revision and one with a
// revision.
$nodes = [
$this->drupalCreateNode(),
$this->drupalCreateNode(),
];
$first_revision = $nodes[1]->getRevisionId();
// Create revision of the node.
$nodes[1]->setNewRevision();
$nodes[1]->save();
$second_revision = $nodes[1]->getRevisionId();
$this->drupalGet('test-node-revision-links');
$this->assertResponse(200, 'Test view can be accessed in the path expected');
// The first node revision should link to the node directly as you get an
// access denied if you link to the revision.
$url = $nodes[0]->urlInfo()->toString();
$this->assertLinkByHref($url);
$this->assertNoLinkByHref($url . '/revisions/' . $nodes[0]->getRevisionId() . '/view');
$this->assertNoLinkByHref($url . '/revisions/' . $nodes[0]->getRevisionId() . '/delete');
$this->assertNoLinkByHref($url . '/revisions/' . $nodes[0]->getRevisionId() . '/revert');
// For the second node the current revision got set to the last revision, so
// the first one should also link to the node page itself.
$url = $nodes[1]->urlInfo()->toString();
$this->assertLinkByHref($url);
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/view');
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/delete');
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/revert');
$this->assertNoLinkByHref($url . '/revisions/' . $second_revision . '/view');
$this->assertNoLinkByHref($url . '/revisions/' . $second_revision . '/delete');
$this->assertNoLinkByHref($url . '/revisions/' . $second_revision . '/revert');
$accounts = [
'view' => $this->drupalCreateUser(['view all revisions']),
'revert' => $this->drupalCreateUser(['revert all revisions', 'edit any page content']),
'delete' => $this->drupalCreateUser(['delete all revisions', 'delete any page content']),
];
$url = $nodes[1]->urlInfo()->toString();
// Render the view with users which can only delete/revert revisions.
foreach ($accounts as $allowed_operation => $account) {
$this->drupalLogin($account);
$this->drupalGet('test-node-revision-links');
// Check expected links.
foreach (['revert', 'delete'] as $operation) {
if ($operation == $allowed_operation) {
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/' . $operation);
}
else {
$this->assertNoLinkByHref($url . '/revisions/' . $first_revision . '/' . $operation);
}
}
}
}
}

View file

@ -0,0 +1,182 @@
langcode: en
status: true
dependencies:
module:
- node
- user
id: test_node_path_plugin
label: test_node_path_plugin
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
quantity: 9
style:
type: default
row:
type: fields
fields:
path:
id: path
table: node
field: path
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: true
text: 'This is <strong>not escaped</strong> and this is <a href="{{ path }}" hreflang="en">the link</a>.'
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
absolute: false
entity_type: node
plugin_id: node_path
filters:
status:
value: true
table: node_field_data
field: status
plugin_id: boolean
entity_type: node
entity_field: status
id: status
expose:
operator: ''
group: 1
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
entity_type: node
entity_field: created
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
granularity: second
title: test_node_path_plugin
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_interface'
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
display_extenders: { }
path: test-node-path-plugin
cache_metadata:
max-age: -1
contexts:
- 'languages:language_interface'
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }

View file

@ -0,0 +1,224 @@
langcode: en
status: true
dependencies:
module:
- node
id: test_node_revision_links
label: test_node_revision_links
module: views
description: ''
tag: ''
base_table: node_field_revision
base_field: vid
core: '8'
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: none
options: { }
cache:
type: none
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: none
options:
items_per_page: 0
offset: 0
style:
type: default
row:
type: fields
fields:
link_to_revision:
id: link_to_revision
table: node_field_revision
field: link_to_revision
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
text: 'Link to revision'
entity_type: node
plugin_id: node_revision_link
delete_revision:
id: delete_revision
table: node_field_revision
field: delete_revision
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
text: 'Link to delete revision'
entity_type: node
plugin_id: node_revision_link_delete
revert_revision:
id: revert_revision
table: node_field_revision
field: revert_revision
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
text: 'Link to delete revision'
entity_type: node
plugin_id: node_revision_link_revert
filters: { }
sorts: { }
title: test_node_revision_links
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
display_extenders: { }
path: test-node-revision-links

View file

@ -0,0 +1,50 @@
<?php
namespace Drupal\Tests\node\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Test D6NodeDeriver.
*
* @group migrate_drupal_6
*/
class MigrateNodeDeriverTest extends MigrateDrupal6TestBase {
/**
* The migration plugin manager.
*
* @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
*/
protected $pluginManager;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->pluginManager = $this->container->get('plugin.manager.migration');
}
/**
* Test node translation migrations with translation disabled.
*/
public function testNoTranslations() {
// Without content_translation, there should be no translation migrations.
$migrations = $this->pluginManager->createInstances('d6_node_translation');
$this->assertSame([], $migrations,
"No node translation migrations without content_translation");
}
/**
* Test node translation migrations with translation enabled.
*/
public function testTranslations() {
// With content_translation, there should be translation migrations for
// each content type.
$this->enableModules(['language', 'content_translation']);
$migrations = $this->pluginManager->createInstances('d6_node_translation');
$this->assertArrayHasKey('d6_node_translation:story', $migrations,
"Node translation migrations exist after content_translation installed");
}
}

View file

@ -16,6 +16,11 @@ class MigrateNodeTest extends MigrateNodeTestBase {
use FileMigrationTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['language', 'content_translation'];
/**
* {@inheritdoc}
*/
@ -23,7 +28,7 @@ class MigrateNodeTest extends MigrateNodeTestBase {
parent::setUp();
$this->setUpMigratedFiles();
$this->installSchema('file', ['file_usage']);
$this->executeMigrations(['d6_node']);
$this->executeMigrations(['language', 'd6_node', 'd6_node_translation']);
}
/**
@ -85,6 +90,15 @@ class MigrateNodeTest extends MigrateNodeTestBase {
$this->assertSame('Buy it now', $node->field_test_link->title);
$this->assertSame(['attributes' => ['target' => '_blank']], $node->field_test_link->options);
// Test that translations are working.
$node = Node::load(10);
$this->assertIdentical('en', $node->langcode->value);
$this->assertIdentical('The Real McCoy', $node->title->value);
$this->assertTrue($node->hasTranslation('fr'), "Node 10 has french translation");
// Node 11 is a translation of node 10, and should not be imported separately.
$this->assertNull(Node::load(11), "Node 11 doesn't exist in D8, it was a translation");
// Rerun migration with two source database changes.
// 1. Add an invalid link attributes and a different URL and
// title. If only the attributes are changed the error does not occur.

View file

@ -44,6 +44,7 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
'd7_user',
'd7_node_type',
'd7_comment_type',
'd7_taxonomy_vocabulary',
'd7_field',
'd7_field_instance',
'd7_node:test_content_type',
@ -139,9 +140,13 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
$this->assertIdentical('title text', $node->field_images->title);
$this->assertIdentical('93', $node->field_images->width);
$this->assertIdentical('93', $node->field_images->height);
$this->assertIdentical('http://google.com', $node->field_link->uri);
$this->assertIdentical('Click Here', $node->field_link->title);
$node = Node::load(2);
$this->assertIdentical("...is that it's the absolute best show ever. Trust me, I would know.", $node->body->value);
$this->assertIdentical('internal:/', $node->field_link->uri);
$this->assertIdentical('Home', $node->field_link->title);
}
}

View file

@ -40,7 +40,7 @@ class NodeByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 1,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 1',
@ -64,7 +64,7 @@ class NodeByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 2,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 2',

View file

@ -134,7 +134,7 @@ class NodeRevisionByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 1,
'translate' => 0,
'vid' => 1,
'node_uid' => 1,
@ -156,7 +156,7 @@ class NodeRevisionByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 1,
'translate' => 0,
'vid' => 3,
'node_uid' => 1,

View file

@ -133,7 +133,7 @@ class NodeRevisionTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 1,
'translate' => 0,
// Node revision fields.
'vid' => 1,
@ -157,7 +157,7 @@ class NodeRevisionTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 1,
'translate' => 0,
// Node revision fields.
'vid' => 3,

View file

@ -2,16 +2,12 @@
namespace Drupal\Tests\node\Unit\Plugin\migrate\source\d6;
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
/**
* Tests D6 node source plugin.
*
* @group node
*/
class NodeTest extends MigrateSqlSourceTestCase {
const PLUGIN_CLASS = 'Drupal\node\Plugin\migrate\source\d6\Node';
class NodeTest extends NodeTestBase {
protected $migrationConfiguration = array(
'id' => 'test',
@ -36,7 +32,7 @@ class NodeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 1,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 1',
@ -60,7 +56,7 @@ class NodeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 2,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 2',
@ -83,7 +79,7 @@ class NodeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 0,
'tnid' => 5,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 5',
@ -98,79 +94,29 @@ class NodeTest extends MigrateSqlSourceTestCase {
),
),
),
array(
'nid' => 6,
'vid' => 6,
'type' => 'story',
'language' => 'en',
'title' => 'node title 6',
'uid' => 1,
'status' => 1,
'created' => 1279290909,
'changed' => 1279308994,
'comment' => 0,
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 6,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 6',
'teaser' => 'body for node 6',
'log' => '',
'timestamp' => 1279308994,
'format' => 1,
),
);
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->databaseContents['content_node_field'] = array(
array(
'field_name' => 'field_test_four',
'type' => 'number_float',
'global_settings' => 'a:0:{}',
'required' => '0',
'multiple' => '0',
'db_storage' => '1',
'module' => 'number',
'db_columns' => 'a:1:{s:5:"value";a:3:{s:4:"type";s:5:"float";s:8:"not null";b:0;s:8:"sortable";b:1;}}',
'active' => '1',
'locked' => '0',
),
);
$this->databaseContents['content_node_field_instance'] = array(
array(
'field_name' => 'field_test_four',
'type_name' => 'story',
'weight' => '3',
'label' => 'Float Field',
'widget_type' => 'number',
'widget_settings' => 'a:0:{}',
'display_settings' => 'a:0:{}',
'description' => 'An example float field.',
'widget_module' => 'number',
'widget_active' => '1',
),
);
$this->databaseContents['content_type_story'] = array(
array(
'nid' => 5,
'vid' => 5,
'uid' => 5,
'field_test_four_value' => '3.14159',
),
);
$this->databaseContents['system'] = array(
array(
'type' => 'module',
'name' => 'content',
'schema_version' => 6001,
'status' => TRUE,
),
);
foreach ($this->expectedResults as $k => $row) {
foreach (array('nid', 'vid', 'title', 'uid', 'body', 'teaser', 'format', 'timestamp', 'log') as $field) {
$this->databaseContents['node_revisions'][$k][$field] = $row[$field];
switch ($field) {
case 'nid': case 'vid':
break;
case 'uid':
$this->databaseContents['node_revisions'][$k]['uid']++;
break;
default:
unset($row[$field]);
break;
}
}
$this->databaseContents['node'][$k] = $row;
}
array_walk($this->expectedResults, function (&$row) {
$row['node_uid'] = $row['uid'];
$row['revision_uid'] = $row['uid'] + 1;
unset($row['uid']);
});
parent::setUp();
}
}

View file

@ -0,0 +1,179 @@
<?php
namespace Drupal\Tests\node\Unit\Plugin\migrate\source\d6;
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
/**
* Base for D6 node migration tests.
*/
abstract class NodeTestBase extends MigrateSqlSourceTestCase {
const PLUGIN_CLASS = 'Drupal\node\Plugin\migrate\source\d6\Node';
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->databaseContents['content_node_field'] = array(
array(
'field_name' => 'field_test_four',
'type' => 'number_float',
'global_settings' => 'a:0:{}',
'required' => '0',
'multiple' => '0',
'db_storage' => '1',
'module' => 'number',
'db_columns' => 'a:1:{s:5:"value";a:3:{s:4:"type";s:5:"float";s:8:"not null";b:0;s:8:"sortable";b:1;}}',
'active' => '1',
'locked' => '0',
),
);
$this->databaseContents['content_node_field_instance'] = array(
array(
'field_name' => 'field_test_four',
'type_name' => 'story',
'weight' => '3',
'label' => 'Float Field',
'widget_type' => 'number',
'widget_settings' => 'a:0:{}',
'display_settings' => 'a:0:{}',
'description' => 'An example float field.',
'widget_module' => 'number',
'widget_active' => '1',
),
);
$this->databaseContents['content_type_story'] = array(
array(
'nid' => 5,
'vid' => 5,
'uid' => 5,
'field_test_four_value' => '3.14159',
),
);
$this->databaseContents['system'] = array(
array(
'type' => 'module',
'name' => 'content',
'schema_version' => 6001,
'status' => TRUE,
),
);
$this->databaseContents['node'] = [
[
'nid' => 1,
'vid' => 1,
'type' => 'page',
'language' => 'en',
'title' => 'node title 1',
'uid' => 1,
'status' => 1,
'created' => 1279051598,
'changed' => 1279051598,
'comment' => 2,
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'translate' => 0,
'tnid' => 0,
],
[
'nid' => 2,
'vid' => 2,
'type' => 'page',
'language' => 'en',
'title' => 'node title 2',
'uid' => 1,
'status' => 1,
'created' => 1279290908,
'changed' => 1279308993,
'comment' => 0,
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'translate' => 0,
'tnid' => 0,
],
[
'nid' => 5,
'vid' => 5,
'type' => 'story',
'language' => 'en',
'title' => 'node title 5',
'uid' => 1,
'status' => 1,
'created' => 1279290908,
'changed' => 1279308993,
'comment' => 0,
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'translate' => 0,
'tnid' => 0,
],
[
'nid' => 6,
'vid' => 6,
'type' => 'story',
'language' => 'en',
'title' => 'node title 6',
'uid' => 1,
'status' => 1,
'created' => 1279290909,
'changed' => 1279308994,
'comment' => 0,
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'translate' => 0,
'tnid' => 6,
],
[
'nid' => 7,
'vid' => 7,
'type' => 'story',
'language' => 'fr',
'title' => 'node title 7',
'uid' => 1,
'status' => 1,
'created' => 1279290910,
'changed' => 1279308995,
'comment' => 0,
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'translate' => 0,
'tnid' => 6,
],
];
foreach ($this->databaseContents['node'] as $k => $row) {
// Find the equivalent row from expected results.
$result_row = NULL;
foreach ($this->expectedResults as $result) {
if (in_array($result['nid'], [$row['nid'], $row['tnid']]) && $result['language'] == $row['language']) {
$result_row = $result;
break;
}
}
// Populate node_revisions.
foreach (array('nid', 'vid', 'title', 'uid', 'body', 'teaser', 'format', 'timestamp', 'log') as $field) {
$value = isset($row[$field]) ? $row[$field] : $result_row[$field];
$this->databaseContents['node_revisions'][$k][$field] = $value;
if ($field == 'uid') {
$this->databaseContents['node_revisions'][$k]['uid']++;
}
}
}
array_walk($this->expectedResults, function (&$row) {
$row['node_uid'] = $row['uid'];
$row['revision_uid'] = $row['uid'] + 1;
unset($row['uid']);
});
parent::setUp();
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace Drupal\Tests\node\Unit\Plugin\migrate\source\d6;
/**
* Tests D6 node translation source plugin.
*
* @group node
*/
class NodeTranslationTest extends NodeTestBase {
protected $migrationConfiguration = array(
'id' => 'test',
'source' => array(
'plugin' => 'd6_node',
'translations' => TRUE,
),
);
protected $expectedResults = array(
array(
'nid' => 7,
'vid' => 7,
'type' => 'story',
'language' => 'fr',
'title' => 'node title 7',
'uid' => 1,
'status' => 1,
'created' => 1279290910,
'changed' => 1279308995,
'comment' => 0,
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
'tnid' => 6,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 7',
'teaser' => 'body for node 7',
'log' => '',
'timestamp' => 1279308995,
'format' => 1,
),
);
}