diff --git a/core/modules/content_moderation/src/EntityTypeInfo.php b/core/modules/content_moderation/src/EntityTypeInfo.php index 487cac057f..fcd37bbc96 100644 --- a/core/modules/content_moderation/src/EntityTypeInfo.php +++ b/core/modules/content_moderation/src/EntityTypeInfo.php @@ -320,6 +320,7 @@ public function formAlter(array &$form, FormStateInterface $form_state, $form_id $full_message = $this->t('Unable to save this @type_label. Publish or delete the latest draft revision to allow all workflow transitions.', $args); drupal_set_message($full_message, 'error'); + $form['moderation_state']['#access'] = FALSE; $form['actions']['#access'] = FALSE; $form['invalid_transitions'] = [ 'label' => [ diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php index d385a86791..a7d73308b2 100644 --- a/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php +++ b/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php @@ -250,7 +250,8 @@ public function testContentTranslationNodeForm() { $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'Some moderated content', 'body[0][value]' => 'First version of the content.', - ], t('Save and Create New Draft')); + 'moderation_state[0][state]' => 'draft', + ], t('Save')); $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]')); $node = $this->drupalGetNodeByTitle('Some moderated content'); @@ -266,12 +267,13 @@ public function testContentTranslationNodeForm() { // Add french translation (revision 2). $this->drupalGet($translate_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); $this->drupalPostForm(NULL, [ 'body[0][value]' => 'Second version of the content.', - ], t('Save and Publish (this translation)')); + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); $this->drupalGet($latest_version_path, ['language' => $french]); $this->assertSession()->statusCodeEquals('403'); @@ -279,21 +281,20 @@ public function testContentTranslationNodeForm() { // Add french forward revision (revision 3). $this->drupalGet($edit_path, ['language' => $french]); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); $this->drupalPostForm(NULL, [ 'body[0][value]' => 'Third version of the content.', - ], t('Save and Create New Draft (this translation)')); + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); $this->drupalGet($latest_version_path, ['language' => $french]); $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]')); // It should not be possible to add a new english revision. $this->drupalGet($edit_path); - $this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); $this->clickLink('Publish'); @@ -308,51 +309,52 @@ public function testContentTranslationNodeForm() { // Publish the french forward revision (revision 4). $this->drupalGet($edit_path, ['language' => $french]); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); $this->drupalPostForm(NULL, [ 'body[0][value]' => 'Fifth version of the content.', - ], t('Save and Publish (this translation)')); + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); $this->drupalGet($latest_version_path, ['language' => $french]); $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); // Now we can publish the english (revision 5). $this->drupalGet($edit_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); $this->drupalPostForm(NULL, [ 'body[0][value]' => 'Sixth version of the content.', - ], t('Save and Publish (this translation)')); + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); $this->drupalGet($latest_version_path); $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); // Make sure we're allowed to create a forward french revision. $this->drupalGet($edit_path, ['language' => $french]); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); // Add a english forward revision (revision 6). $this->drupalGet($edit_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); $this->drupalPostForm(NULL, [ 'body[0][value]' => 'Seventh version of the content.', - ], t('Save and Create New Draft (this translation)')); + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); $this->drupalGet($latest_version_path); $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]')); // Make sure we're not allowed to create a forward french revision. $this->drupalGet($edit_path, ['language' => $french]); - $this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); $this->drupalGet($latest_version_path, ['language' => $french]); @@ -360,33 +362,35 @@ public function testContentTranslationNodeForm() { // We should be able to publish the english forward revision (revision 7) $this->drupalGet($edit_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); $this->drupalPostForm(NULL, [ 'body[0][value]' => 'Eighth version of the content.', - ], t('Save and Publish (this translation)')); + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); $this->drupalGet($latest_version_path); $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); // Make sure we're allowed to create a forward french revision. $this->drupalGet($edit_path, ['language' => $french]); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); // Make sure we're allowed to create a forward english revision. $this->drupalGet($edit_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); // Create new moderated content. (revision 1). $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'Second moderated content', 'body[0][value]' => 'First version of the content.', - ], t('Save and Publish')); + 'moderation_state[0][state]' => 'published', + ], t('Save')); $node = $this->drupalGetNodeByTitle('Second moderated content'); $this->assertTrue($node->language(), 'en'); @@ -395,24 +399,24 @@ public function testContentTranslationNodeForm() { // Add a forward revision (revision 2). $this->drupalGet($edit_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); $this->drupalPostForm(NULL, [ 'body[0][value]' => 'Second version of the content.', - ], t('Save and Create New Draft (this translation)')); + 'moderation_state[0][state]' => 'draft', + ], t('Save')); // It shouldn't be possible to translate as we have a forward revision. $this->drupalGet($translate_path); - $this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); // Create new moderated content (revision 1). $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'Third moderated content', - ], t('Save and Publish')); + 'moderation_state[0][state]' => 'published', + ], t('Save')); $node = $this->drupalGetNodeByTitle('Third moderated content'); $this->assertTrue($node->language(), 'en'); @@ -421,38 +425,44 @@ public function testContentTranslationNodeForm() { // Translate it, without updating data (revision 2). $this->drupalGet($translate_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); - $this->drupalPostForm(NULL, [], t('Save and Create New Draft (this translation)')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); // Add another draft for the translation (revision 3). $this->drupalGet($edit_path, ['language' => $french]); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); - $this->drupalPostForm(NULL, [], t('Save and Create New Draft (this translation)')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); // Editing the original translation should not be possible. $this->drupalGet($edit_path); - $this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); // Updating and publishing the french translation is still possible. $this->drupalGet($edit_path, ['language' => $french]); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]')); - $this->drupalPostForm(NULL, [], t('Save and Publish (this translation)')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); // Now the french translation is published, an english draft can be added. $this->drupalGet($edit_path); - $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]')); - $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]')); - $this->drupalPostForm(NULL, [], t('Save and Create New Draft (this translation)')); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); } } diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php index 88ba3a2f9a..3104450fce 100644 --- a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php +++ b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php @@ -156,7 +156,9 @@ public function testTranslateModeratedContent() { $this->assertEqual($french_node->getTitle(), 'Translated node', 'The default revision of the published translation remains the same.'); // Publish the French article before testing the archive transition. - $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)')); + $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [ + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); $this->assertText(t('Article New draft of translated node has been updated.')); $english_node = $this->drupalGetNodeByTitle('Another node', TRUE); $french_node = $english_node->getTranslation('fr'); diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php index 3218241be9..82695bdf49 100644 --- a/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php +++ b/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php @@ -144,4 +144,45 @@ public function testPagers() { $this->assertEqual(0, $query['page']); } + /** + * Tests the workflow is a user has no Content Moderation permissions. + */ + public function testNoContentModerationPermissions() { + // Create a user with quite advanced node permissions but no content + // moderation permissions. + $limited_user = $this->createUser([ + 'administer nodes', + 'bypass node access', + ]); + $this->drupalLogin($limited_user); + + // Check the user can add content, but can't see the moderation state + // select. + $this->drupalGet('node/add/moderated_content'); + $this->assertSession()->statusCodeEquals(200); + $this->assertFalse($this->xpath('//select[@name="moderation_state[0][state]"]')); + $this->drupalPostForm(NULL, [ + 'title[0][value]' => 'moderated content', + ], t('Save')); + + // Manually move the content to archived because the user doesn't have + // permission to do this. + $node = $this->getNodeByTitle('moderated content'); + $node->moderation_state->value = 'archived'; + $node->save(); + + // Check the user can see the current state but not the select. + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Archived'); + $this->assertTrue($this->xpath('//label[@for="edit-moderation-state-0-current"]')); + $this->assertFalse($this->xpath('//select[@name="moderation_state[0][state]"]')); + $this->drupalPostForm(NULL, [], t('Save')); + + // When saving they should still be on the edit form, and see the validation + // error message. + $this->assertSession()->pageTextContains('Edit Moderated content moderated content'); + $this->assertSession()->pageTextContains('Invalid state transition from Archived to Archived'); + } + }