diff --git a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php index e3563ae4402e822642954c91e70e0b02f47c74af..b2d85335aacd64964efcf6022ddd94f408bd78bc 100644 --- a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php +++ b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutPublishNode.php @@ -53,23 +53,14 @@ public static function create(ContainerInterface $container, array $configuratio /** * {@inheritdoc} */ - public function execute($entity = NULL) { + public function access($entity, AccountInterface $account = NULL, $return_as_object = FALSE) { + /** @var \Drupal\node\NodeInterface $entity */ if ($entity && $this->moderationInfo->isModeratedEntity($entity)) { - drupal_set_message($this->t('One or more entities were skipped as they are under moderation and may not be directly published or unpublished.')); - return; + drupal_set_message($this->t("@bundle @label were skipped as they are under moderation and may not be directly published.", ['@bundle' => node_get_type_label($entity), '@label' => $entity->getEntityType()->getPluralLabel()]), 'warning'); + $result = AccessResult::forbidden(); + return $return_as_object ? $result : $result->isAllowed(); } - - parent::execute($entity); - } - - /** - * {@inheritdoc} - */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { - $result = parent::access($object, $account, TRUE) - ->andif(AccessResult::forbiddenIf($this->moderationInfo->isModeratedEntity($object))->addCacheableDependency($object)); - - return $return_as_object ? $result : $result->isAllowed(); + return parent::access($entity, $account, $return_as_object); } } diff --git a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php index 28b968991a35d33e1ab4b76fd99c0c7718afc972..ee36169468d57e8baaeb86fb36a5a33f666811bb 100644 --- a/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php +++ b/core/modules/content_moderation/src/Plugin/Action/ModerationOptOutUnpublishNode.php @@ -53,23 +53,14 @@ public static function create(ContainerInterface $container, array $configuratio /** * {@inheritdoc} */ - public function execute($entity = NULL) { + public function access($entity, AccountInterface $account = NULL, $return_as_object = FALSE) { + /** @var \Drupal\node\NodeInterface $entity */ if ($entity && $this->moderationInfo->isModeratedEntity($entity)) { - drupal_set_message($this->t('One or more entities were skipped as they are under moderation and may not be directly published or unpublished.')); - return; + drupal_set_message($this->t("@bundle @label were skipped as they are under moderation and may not be directly unpublished.", ['@bundle' => node_get_type_label($entity), '@label' => $entity->getEntityType()->getPluralLabel()]), 'warning'); + $result = AccessResult::forbidden(); + return $return_as_object ? $result : $result->isAllowed(); } - - parent::execute($entity); - } - - /** - * {@inheritdoc} - */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { - $result = parent::access($object, $account, TRUE) - ->andif(AccessResult::forbiddenIf($this->moderationInfo->isModeratedEntity($object))->addCacheableDependency($object)); - - return $return_as_object ? $result : $result->isAllowed(); + return parent::access($entity, $account, $return_as_object); } } diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationActionsTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationActionsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..32d10fa045cba5cf0faa663b59d5ca30ae2d8962 --- /dev/null +++ b/core/modules/content_moderation/tests/src/Functional/ModerationActionsTest.php @@ -0,0 +1,137 @@ +<?php + +namespace Drupal\Tests\content_moderation\Functional; + +use Drupal\node\Entity\Node; +use Drupal\simpletest\ContentTypeCreationTrait; +use Drupal\Tests\BrowserTestBase; +use Drupal\workflows\Entity\Workflow; + +/** + * Test the content moderation actions. + * + * @group content_moderation + */ +class ModerationActionsTest extends BrowserTestBase { + + use ContentTypeCreationTrait; + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + 'content_moderation', + 'node', + 'views', + ]; + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + + $moderated_bundle = $this->createContentType(['type' => 'moderated_bundle']); + $moderated_bundle->save(); + $standard_bundle = $this->createContentType(['type' => 'standard_bundle']); + $standard_bundle->save(); + + $workflow = Workflow::load('editorial'); + $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated_bundle'); + $workflow->save(); + + $admin = $this->drupalCreateUser([ + 'access content overview', + 'administer nodes', + 'bypass node access', + ]); + $this->drupalLogin($admin); + } + + /** + * Test the node status actions report moderation status to users correctly. + * + * @dataProvider nodeStatusActionsTestCases + */ + public function testNodeStatusActions($action, $bundle, $warning_appears, $starting_status, $final_status) { + // Create and run an action on a node. + $node = Node::create([ + 'type' => $bundle, + 'title' => $this->randomString(), + 'status' => $starting_status, + ]); + if ($bundle == 'moderated_bundle') { + $node->moderation_state->value = $starting_status ? 'published' : 'draft'; + } + $node->save(); + + $this->drupalPostForm('admin/content', [ + 'node_bulk_form[0]' => TRUE, + 'action' => $action, + ], 'Apply to selected items'); + + if ($warning_appears) { + if ($action == 'node_publish_action') { + $this->assertSession() + ->elementContains('css', '.messages--warning', node_get_type_label($node) . ' content items were skipped as they are under moderation and may not be directly published.'); + } + else { + $this->assertSession() + ->elementContains('css', '.messages--warning', node_get_type_label($node) . ' content items were skipped as they are under moderation and may not be directly unpublished.'); + } + } + else { + $this->assertSession()->elementNotExists('css', '.messages--warning'); + } + + // Ensure after the action has run, the node matches the expected status. + $node = Node::load($node->id()); + $this->assertEquals($node->isPublished(), $final_status); + } + + /** + * Test cases for ::testNodeStatusActions. + * + * @return array + * An array of test cases. + */ + public function nodeStatusActionsTestCases() { + return [ + 'Moderated bundle shows warning (publish action)' => [ + 'node_publish_action', + 'moderated_bundle', + TRUE, + // If the node starts out unpublished, the action should not work. + FALSE, + FALSE, + ], + 'Moderated bundle shows warning (unpublish action)' => [ + 'node_unpublish_action', + 'moderated_bundle', + TRUE, + // If the node starts out published, the action should not work. + TRUE, + TRUE, + ], + 'Normal bundle works (publish action)' => [ + 'node_publish_action', + 'standard_bundle', + FALSE, + // If the node starts out unpublished, the action should work. + FALSE, + TRUE, + ], + 'Normal bundle works (unpublish action)' => [ + 'node_unpublish_action', + 'standard_bundle', + FALSE, + // If the node starts out published, the action should work. + TRUE, + FALSE, + ], + ]; + } + +}