Commit 7755d437 authored by catch's avatar catch

Issue #2858434 by amateescu, vijaycs85, plach, timmillwood, catch: Menu...

Issue #2858434 by amateescu, vijaycs85, plach, timmillwood, catch: Menu changes from node form leak into live site when creating draft revision
parent 478ddd31
......@@ -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');
}
/**
......
<?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.';
}
<?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();
}
}
}
}
<?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');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment