diff --git a/core/modules/content_moderation/config/optional/views.view.moderated_content.yml b/core/modules/content_moderation/config/optional/views.view.moderated_content.yml index a404a09..22b8eb8 100644 --- a/core/modules/content_moderation/config/optional/views.view.moderated_content.yml +++ b/core/modules/content_moderation/config/optional/views.view.moderated_content.yml @@ -23,7 +23,7 @@ display: access: type: perm options: - perm: 'access content overview' + perm: 'view any unpublished content' cache: type: tag options: { } diff --git a/core/modules/content_moderation/content_moderation.routing.yml b/core/modules/content_moderation/content_moderation.routing.yml index 98ed7a2..7b216d9 100644 --- a/core/modules/content_moderation/content_moderation.routing.yml +++ b/core/modules/content_moderation/content_moderation.routing.yml @@ -4,7 +4,7 @@ content_moderation.admin_moderated_content: _controller: '\Drupal\content_moderation\Controller\ModeratedContentController::listing' _title: 'Moderated content' requirements: - _permission: 'access content overview' + _permission: 'view any unpublished content' content_moderation.workflow_type_edit_form: path: '/admin/config/workflow/workflows/manage/{workflow}/type/{entity_type_id}' diff --git a/core/modules/content_moderation/tests/src/Functional/ModeratedContentViewTest.php b/core/modules/content_moderation/tests/src/Functional/ModeratedContentViewTest.php new file mode 100644 index 0000000..9582a0f --- /dev/null +++ b/core/modules/content_moderation/tests/src/Functional/ModeratedContentViewTest.php @@ -0,0 +1,129 @@ +drupalCreateContentType(['type' => 'page', 'name' => 'Basic page'])->save(); + $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article'])->save(); + $this->drupalCreateContentType(['type' => 'unmoderated_type', 'name' => 'Unmoderated type'])->save(); + + $workflow = Workflow::load('editorial'); + $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page'); + $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'article'); + $workflow->save(); + + $this->adminUser = $this->drupalCreateUser(['access administration pages', 'view any unpublished content', 'administer nodes', 'bypass node access']); + } + + /** + * Tests the moderated content page. + */ + public function testModeratedContentPage() { + $assert_sesison = $this->assertSession(); + $this->drupalLogin($this->adminUser); + + // Use an explicit changed time to ensure the expected order in the content + // admin listing. We want these to appear in the table in the same order as + // they appear in the following code, and the 'moderated_content' view has a + // table style configuration with a default sort on the 'changed' field + // descending. + $time = \Drupal::time()->getRequestTime(); + $excluded_nodes['published_page'] = $this->drupalCreateNode(['type' => 'page', 'changed' => $time--, 'moderation_state' => 'published']); + $excluded_nodes['published_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'published']); + + $excluded_nodes['unmoderated_type'] = $this->drupalCreateNode(['type' => 'unmoderated_type', 'changed' => $time--]); + $excluded_nodes['unmoderated_type']->setNewRevision(TRUE); + $excluded_nodes['unmoderated_type']->isDefaultRevision(FALSE); + $excluded_nodes['unmoderated_type']->changed->value = $time--; + $excluded_nodes['unmoderated_type']->save(); + + $nodes['published_then_draft_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'published', 'title' => 'first article - published']); + $nodes['published_then_draft_article']->setNewRevision(TRUE); + $nodes['published_then_draft_article']->setTitle('first article - draft'); + $nodes['published_then_draft_article']->moderation_state->value = 'draft'; + $nodes['published_then_draft_article']->changed->value = $time--; + $nodes['published_then_draft_article']->save(); + + $nodes['published_then_archived_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'published']); + $nodes['published_then_archived_article']->setNewRevision(TRUE); + $nodes['published_then_archived_article']->moderation_state->value = 'archived'; + $nodes['published_then_archived_article']->changed->value = $time--; + $nodes['published_then_archived_article']->save(); + + $nodes['draft_article'] = $this->drupalCreateNode(['type' => 'article', 'changed' => $time--, 'moderation_state' => 'draft']); + $nodes['draft_page_1'] = $this->drupalCreateNode(['type' => 'page', 'changed' => $time--, 'moderation_state' => 'draft']); + $nodes['draft_page_2'] = $this->drupalCreateNode(['type' => 'page', 'changed' => $time, 'moderation_state' => 'draft']); + + // Verify view, edit, and delete links for any content. + $this->drupalGet('admin/content/node/moderated'); + $assert_sesison->statusCodeEquals(200); + + // Check that nodes with pending revisions appear in the view. + $node_type_labels = $this->xpath('//td[contains(@class, "views-field-type")]'); + $delta = 0; + foreach ($nodes as $node) { + $assert_sesison->linkByHrefExists('node/' . $node->id()); + $assert_sesison->linkByHrefExists('node/' . $node->id() . '/edit'); + $assert_sesison->linkByHrefExists('node/' . $node->id() . '/delete'); + // Verify that we can see the content type label. + $this->assertEquals($node->type->entity->label(), trim($node_type_labels[$delta]->getText())); + $delta++; + } + + // Check that nodes that are not moderated or do not have a pending revision + // do not appear in the view. + foreach ($excluded_nodes as $node) { + $assert_sesison->linkByHrefNotExists('node/' . $node->id()); + } + + // Check that the latest revision is displayed. + $assert_sesison->pageTextContains('first article - draft'); + $assert_sesison->pageTextNotContains('first article - published'); + + // Verify filtering by moderation state. + $this->drupalGet('admin/content/node/moderated', ['query' => ['moderation_state' => 'draft']]); + + $assert_sesison->linkByHrefExists('node/' . $nodes['published_then_draft_article']->id() . '/edit'); + $assert_sesison->linkByHrefExists('node/' . $nodes['draft_article']->id() . '/edit'); + $assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_1']->id() . '/edit'); + $assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_1']->id() . '/edit'); + $assert_sesison->linkByHrefNotExists('node/' . $nodes['published_then_archived_article']->id() . '/edit'); + + // Verify filtering by moderation state and content type. + $this->drupalGet('admin/content/node/moderated', ['query' => ['moderation_state' => 'draft', 'type' => 'page']]); + + $assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_1']->id() . '/edit'); + $assert_sesison->linkByHrefExists('node/' . $nodes['draft_page_2']->id() . '/edit'); + $assert_sesison->linkByHrefNotExists('node/' . $nodes['published_then_draft_article']->id() . '/edit'); + $assert_sesison->linkByHrefNotExists('node/' . $nodes['published_then_archived_article']->id() . '/edit'); + $assert_sesison->linkByHrefNotExists('node/' . $nodes['draft_article']->id() . '/edit'); + } + +}