summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2017-07-18 12:32:38 +0100
committerNathaniel Catchpole2017-07-18 12:32:38 +0100
commit7755d437e0c639a0fc92e3f06105211a2e5e1566 (patch)
tree80fc68cb6b0c0f4c6ec560df246be7e8f12a28d4
parent478ddd3118a6e580faacd074050e37b695acb912 (diff)
Issue #2858434 by amateescu, vijaycs85, plach, timmillwood, catch: Menu changes from node form leak into live site when creating draft revision
-rw-r--r--core/modules/menu_ui/menu_ui.module13
-rw-r--r--core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php19
-rw-r--r--core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraintValidator.php62
-rw-r--r--core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php131
4 files changed, 225 insertions, 0 deletions
diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index cffccde..ed33b14 100644
--- a/core/modules/menu_ui/menu_ui.module
+++ b/core/modules/menu_ui/menu_ui.module
@@ -71,6 +71,10 @@ function menu_ui_entity_type_build(array &$entity_types) {
->setLinkTemplate('edit-form', '/admin/structure/menu/manage/{menu}')
->setLinkTemplate('add-link-form', '/admin/structure/menu/manage/{menu}/add')
->setLinkTemplate('collection', '/admin/structure/menu');
+
+ if (isset($entity_types['node'])) {
+ $entity_types['node']->addConstraint('MenuSettings', []);
+ }
}
/**
@@ -357,6 +361,15 @@ function menu_ui_form_node_form_alter(&$form, FormStateInterface $form_state) {
$form['actions'][$action]['#submit'][] = 'menu_ui_form_node_form_submit';
}
}
+
+ $form['#entity_builders'][] = 'menu_ui_node_builder';
+}
+
+/**
+ * Entity form builder to add the menu information to the node.
+ */
+function menu_ui_node_builder($entity_type, NodeInterface $entity, &$form, FormStateInterface $form_state) {
+ $entity->menu = $form_state->getValue('menu');
}
/**
diff --git a/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php
new file mode 100644
index 0000000..2081ea3
--- /dev/null
+++ b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Drupal\menu_ui\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Validation constraint for changing the menu settings in forward revisions.
+ *
+ * @Constraint(
+ * id = "MenuSettings",
+ * label = @Translation("Menu settings.", context = "Validation"),
+ * )
+ */
+class MenuSettingsConstraint extends Constraint {
+
+ public $message = 'You can only change the menu settings for the <em>published</em> version of this content.';
+
+}
diff --git a/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraintValidator.php b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraintValidator.php
new file mode 100644
index 0000000..a27cbe9
--- /dev/null
+++ b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraintValidator.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\menu_ui\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+
+/**
+ * Constraint validator for changing the menu settings in forward revisions.
+ */
+class MenuSettingsConstraintValidator extends ConstraintValidator {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validate($entity, Constraint $constraint) {
+ if (isset($entity) && !$entity->isNew() && !$entity->isDefaultRevision()) {
+ $defaults = menu_ui_get_menu_link_defaults($entity);
+ $values = $entity->menu;
+ $violation_path = NULL;
+
+ if (trim($values['title']) && !empty($values['menu_parent'])) {
+ list($menu_name, $parent) = explode(':', $values['menu_parent'], 2);
+ $values['menu_name'] = $menu_name;
+ $values['parent'] = $parent;
+ }
+
+ // Handle the case when a menu link is added to a forward revision.
+ if ($defaults['entity_id'] != $values['entity_id']) {
+ $violation_path = 'menu';
+ }
+ // Handle the case when the menu link is deleted in a forward revision.
+ elseif (empty($values['enabled'] && $values['entity_id'])) {
+ $violation_path = 'menu';
+ }
+ // Handle all the other menu link changes in a forward revision.
+ elseif (($values['title'] != $defaults['title'])) {
+ $violation_path = 'menu.title';
+ }
+ elseif (($values['description'] != $defaults['description'])) {
+ $violation_path = 'menu.description';
+ }
+ elseif (($values['menu_name'] != $defaults['menu_name'])) {
+ $violation_path = 'menu.menu_parent';
+ }
+ elseif (($values['parent'] != $defaults['parent'])) {
+ $violation_path = 'menu.menu_parent';
+ }
+ elseif (($values['weight'] != $defaults['weight'])) {
+ $violation_path = 'menu.weight';
+ }
+
+ if ($violation_path) {
+ $this->context->buildViolation($constraint->message)
+ ->atPath($violation_path)
+ ->setInvalidValue($entity)
+ ->addViolation();
+ }
+ }
+ }
+
+}
diff --git a/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php
new file mode 100644
index 0000000..85eb6ad
--- /dev/null
+++ b/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php
@@ -0,0 +1,131 @@
+<?php
+
+namespace Drupal\Tests\menu_ui\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+use Drupal\workflows\Entity\Workflow;
+
+/**
+ * Tests Menu UI and Content Moderation integration.
+ *
+ * @group menu_ui
+ */
+class MenuUiContentModerationTest extends BrowserTestBase {
+
+ /**
+ * Modules to install.
+ *
+ * @var array
+ */
+ public static $modules = ['block', 'content_moderation', 'node', 'menu_ui', 'test_page_test'];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $this->drupalPlaceBlock('system_menu_block:main');
+
+ // Create a 'page' content type.
+ $this->drupalCreateContentType([
+ 'type' => 'page',
+ 'name' => 'Basic page',
+ 'display_submitted' => FALSE,
+ ]);
+
+ $workflow = Workflow::load('editorial');
+ $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
+ $workflow->save();
+ }
+
+ /**
+ * Tests that node drafts can not modify the menu settings.
+ */
+ public function testMenuUiWithForwardRevisions() {
+ $editor = $this->drupalCreateUser([
+ 'administer nodes',
+ 'administer menu',
+ 'create page content',
+ 'edit any page content',
+ 'use editorial transition create_new_draft',
+ 'use editorial transition publish',
+ 'view latest version',
+ 'view any unpublished content',
+ ]);
+ $this->drupalLogin($editor);
+
+ // Create a node.
+ $node = $this->drupalCreateNode();
+
+ // Add a menu link and save a new default (published) revision.
+ $edit = [
+ 'menu[enabled]' => 1,
+ 'menu[title]' => 'Test menu link',
+ ];
+ $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Publish'));
+
+ $this->assertSession()->linkExists('Test menu link');
+
+ // Try to change the menu link title and save a new non-default (draft)
+ // revision.
+ $edit = [
+ 'menu[title]' => 'Test menu link draft',
+ ];
+ $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft'));
+
+ // Check that the menu settings were not applied.
+ $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
+ $this->assertSession()->linkExists('Test menu link');
+ $this->assertSession()->linkNotExists('Test menu link draft');
+
+ // Try to change the menu link description and save a new non-default
+ // (draft) revision.
+ $edit = [
+ 'menu[description]' => 'Test menu link description',
+ ];
+ $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft'));
+
+ // Check that the menu settings were not applied.
+ $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
+
+ // Try to change the menu link weight and save a new non-default (draft)
+ // revision.
+ $edit = [
+ 'menu[weight]' => 1,
+ ];
+ $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft'));
+
+ // Check that the menu settings were not applied.
+ $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
+
+ // Try to change the menu link parent and save a new non-default (draft)
+ // revision.
+ $edit = [
+ 'menu[menu_parent]' => 'main:test_page_test.front_page',
+ ];
+ $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft'));
+
+ // Check that the menu settings were not applied.
+ $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
+
+ // Try to delete the menu link and save a new non-default (draft) revision.
+ $edit = [
+ 'menu[enabled]' => 0,
+ ];
+ $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft'));
+
+ // Check that the menu settings were not applied.
+ $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
+ $this->assertSession()->linkExists('Test menu link');
+
+ // Try to save a new non-default (draft) revision without any changes and
+ // check that the error message is not shown.
+ $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and Create New Draft'));
+
+ // Check that the menu settings were not applied.
+ $this->assertSession()->pageTextNotContains('You can only change the menu settings for the published version of this content.');
+ $this->assertSession()->linkExists('Test menu link');
+ }
+
+}