Skip to content
Snippets Groups Projects
Commit 8e0689a7 authored by jurgenhaas's avatar jurgenhaas
Browse files

Add patch to book

parent be15720c
No related branches found
No related tags found
1 merge request!326Merging develop into main
Pipeline #1328119 passed
......@@ -11,6 +11,9 @@
"#3173340 Exception": "https://www.drupal.org/files/issues/2020-09-26/3173340-2.background_image.Error-Call-to-a-member-function-hasEntityToken-on-bool-in-DrupalbackgroundimageCacheContextBackgroundImageSettingsTextCacheContextgetContext.patch",
"#3128542 FileScan": "https://www.drupal.org/files/issues/2020-09-11/background_image-missing_folder-3128542-8.patch"
},
"drupal/book": {
"Validation": "https://gitlab.lakedrops.com/composer/plugin/drupal-environment/-/raw/main/patches/d10/book-validation.patch"
},
"drupal/bootstrap_clean_blog": {
"#3146287 Drupal 9": "https://www.drupal.org/files/issues/2021-10-23/3146287_3.patch"
},
......
From f81c6ebf721254f081a7d4f8ee520953a649960d Mon Sep 17 00:00:00 2001
From: Wilbur Ince <45246-wylbur@users.noreply.drupalcode.org>
Date: Wed, 2 Oct 2024 18:37:48 +0000
Subject: [PATCH] Merging the existing patch into the latest release Book
contrib module 1.0
---
book.module | 10 ++
book.permissions.yml | 1 +
.../BookOutlineConstraintValidator.php | 7 +-
.../Functional/BookContentModerationTest.php | 138 ++++++++++++++++++
tests/src/Functional/BookTest.php | 1 +
5 files changed, 156 insertions(+), 1 deletion(-)
diff --git a/book.module b/book.module
index d6973c9..b2e8cb1 100644
--- a/book.module
+++ b/book.module
@@ -155,6 +155,9 @@ function book_node_links_alter(array &$links, NodeInterface $node, array $contex
*/
function book_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id): void {
$node = $form_state->getFormObject()->getEntity();
+ if (!book_type_is_allowed($node->getType())) {
+ return;
+ }
$account = \Drupal::currentUser();
$access_check = new BookNodeOutlineAccessCheck($account);
$access_return = $access_check->access($node);
@@ -321,6 +324,10 @@ function book_node_predelete(EntityInterface $node): void {
* Implements hook_ENTITY_TYPE_prepare_form() for node entities.
*/
function book_node_prepare_form(NodeInterface $node, $operation, FormStateInterface $form_state): void {
+ if (!book_type_is_allowed($node->getType())) {
+ return;
+ }
+
/** @var \Drupal\book\BookManagerInterface $book_manager */
$book_manager = \Drupal::service('book.manager');
@@ -553,6 +560,9 @@ function template_preprocess_book_node_export_html(array &$variables): void {
* A Boolean TRUE if the node type can be included in books; otherwise, FALSE.
*/
function book_type_is_allowed(string $type): bool {
+ if (\Drupal::currentUser()->hasPermission('add any content to books')) {
+ return TRUE;
+ }
return in_array($type, \Drupal::config('book.settings')->get('allowed_types'));
}
diff --git a/book.permissions.yml b/book.permissions.yml
index 184385e..e585bd2 100644
--- a/book.permissions.yml
+++ b/book.permissions.yml
@@ -7,6 +7,7 @@ add content to books:
add any content to books:
title: 'Add non-book content to outlines'
description: 'This permission is only considered if a role is already granted the <em>Add content and child pages to books and manage their hierarchies</em> permission.'
+ restrict access: true
access printer-friendly version:
title: 'View printer-friendly books'
description: 'View a book page and all of its sub-pages as a single document for ease of printing. Can be performance heavy.'
diff --git a/src/Plugin/Validation/Constraint/BookOutlineConstraintValidator.php b/src/Plugin/Validation/Constraint/BookOutlineConstraintValidator.php
index d716040..e1232a9 100644
--- a/src/Plugin/Validation/Constraint/BookOutlineConstraintValidator.php
+++ b/src/Plugin/Validation/Constraint/BookOutlineConstraintValidator.php
@@ -35,7 +35,12 @@ class BookOutlineConstraintValidator extends ConstraintValidator implements Cont
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint): void {
- if (isset($value) && !$value->isNew() && !$value->isDefaultRevision()) {
+ // Validate the book structure when the user has access to manage book
+ // outlines. When the user can manage book outlines, the book variable will
+ // be populated even if the node is not part of the book. If the user cannot
+ // manage book outlines, the book variable will be empty, and we can safely
+ // ignore the constraints as the outline cannot be changed by this user.
+ if (isset($value) && !empty($value->book) && !$value->isNew() && !$value->isDefaultRevision()) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $original */
$original = $this->bookManager->loadBookLink($value->id(), FALSE) ?: [
'bid' => 0,
diff --git a/tests/src/Functional/BookContentModerationTest.php b/tests/src/Functional/BookContentModerationTest.php
index 69ab643..f602e4d 100644
--- a/tests/src/Functional/BookContentModerationTest.php
+++ b/tests/src/Functional/BookContentModerationTest.php
@@ -6,6 +6,8 @@ namespace Drupal\Tests\book\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
+use Drupal\user\Entity\Role;
+use Drupal\user\UserInterface;
/**
* Tests Book and Content Moderation integration.
@@ -17,6 +19,13 @@ class BookContentModerationTest extends BrowserTestBase {
use BookTestTrait;
use ContentModerationTestTrait;
+ /**
+ * A user with permission to make workflow transitions but not manage books.
+ *
+ * @var \Drupal\user\UserInterface
+ */
+ protected UserInterface $nonBookAdminUser;
+
/**
* Modules to install.
*
@@ -60,6 +69,19 @@ class BookContentModerationTest extends BrowserTestBase {
'use editorial transition create_new_draft',
'use editorial transition publish',
]);
+
+ // Another user without manage book permissions to test updates to nodes
+ // that are
+ // 1. Not part of a book outline.
+ // 2. Part of a book outline.
+ $this->nonBookAdminUser = $this->drupalCreateUser([
+ 'create book content',
+ 'edit own book content',
+ 'use editorial transition create_new_draft',
+ 'use editorial transition publish',
+ 'access printer-friendly version',
+ 'view any unpublished content',
+ ]);
}
/**
@@ -166,4 +188,120 @@ class BookContentModerationTest extends BrowserTestBase {
$this->assertSession()->pageTextNotContains('You can only change the book outline for the published version of this content.');
}
+ /**
+ * Tests that users who cannot manage books can still make node updates.
+ *
+ * @throws \Behat\Mink\Exception\ExpectationException
+ * @throws \Drupal\Core\Entity\EntityStorageException
+ */
+ public function testNonBookAdminNodeUpdates(): void {
+ // 1. First test that users who cannot manage books can make updates to
+ // nodes that are not part of a book outline.
+ $this->drupalLogin($this->nonBookAdminUser);
+ // Create a new book page without actually attaching it to a book and create
+ // a draft.
+ $this->drupalGet('node/add/book');
+ $this->assertSession()->statusCodeEquals(200);
+ $edit = [
+ 'title[0][value]' => 'Some moderated content',
+ 'moderation_state[0][state]' => 'draft',
+ ];
+ $this->submitForm($edit, 'Save');
+ $this->assertSession()->pageTextContains('Some moderated content has been created.');
+ $node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
+ $this->assertNotEmpty($node);
+
+ $this->drupalGet('node/' . $node->id() . '/edit');
+ $this->assertSession()->statusCodeEquals(200);
+ // Publish the content.
+ $edit = [
+ 'body[0][value]' => 'Second change non book admin user',
+ 'moderation_state[0][state]' => 'published',
+ ];
+ $this->submitForm($edit, 'Save');
+ $this->assertSession()->pageTextNotContains('You can only change the book outline for the published version of this content.');
+ $this->assertSession()->pageTextContains('Some moderated content has been updated');
+
+ // Now update content again, it should be successfully updated and not throw
+ // any errors.
+ $this->drupalGet('node/' . $node->id() . '/edit');
+ $this->assertSession()->statusCodeEquals(200);
+ $edit = [
+ 'moderation_state[0][state]' => 'draft',
+ ];
+ $this->submitForm($edit, 'Save');
+ $this->assertSession()->pageTextNotContains('You can only change the book outline for the published version of this content.');
+ $this->assertSession()->pageTextContains('Some moderated content has been updated');
+
+ // 2. Now test that users who cannot manage books can make updates to nodes
+ // that are part of a book outline. As the non admin book user, publish the
+ // content created above in order to be added to a book.
+ $this->drupalGet('node/' . $node->id() . '/edit');
+ $this->assertSession()->statusCodeEquals(200);
+ $edit = [
+ 'moderation_state[0][state]' => 'published',
+ ];
+ $this->submitForm($edit, 'Save');
+
+ // Create a book (as a book admin user).
+ $book_1_nodes = $this->createBook(['moderation_state[0][state]' => 'published']);
+ $book_1 = $this->book;
+
+ // Now add the node created previously by the non book admin user to the
+ // book created above. We need to grant additional permission for bookAuthor
+ // to be able to edit the node owned by nonBookAdminUser.
+ $role_ids = $this->bookAuthor->getRoles(TRUE);
+ $role_id = reset($role_ids);
+ $role = Role::load($role_id);
+ $role->grantPermission('edit any book content');
+ $role->save();
+ $this->drupalLogin($this->bookAuthor);
+ $this->drupalGet('node/' . $node->id() . '/edit');
+ $this->assertSession()->statusCodeEquals(200);
+ $edit = [
+ 'book[bid]' => $this->book->id(),
+ 'moderation_state[0][state]' => 'published',
+ ];
+ $this->submitForm($edit, 'Save');
+
+ // Assert that the node has been added to the book.
+ $this->assertSession()->pageTextNotContains('You can only change the book outline for the published version of this content.');
+ $this->assertSession()->pageTextContains('Some moderated content has been updated');
+ $this->checkBookNode($book_1, [
+ $book_1_nodes[0],
+ $book_1_nodes[3],
+ $book_1_nodes[4],
+ $node,
+ ], FALSE, FALSE, $book_1_nodes[0], []);
+
+ // Try to update the non book admin's node in the book as the user
+ // that cannot manage books, it should be successfully updated and not
+ // throw any errors.
+ $this->drupalLogin($this->nonBookAdminUser);
+ $this->drupalGet('node/' . $node->id() . '/edit');
+ $this->assertSession()->statusCodeEquals(200);
+ $edit = [
+ 'body[0][value]' => 'Change by non book admin user again',
+ 'moderation_state[0][state]' => 'draft',
+ ];
+ $this->submitForm($edit, 'Save');
+ $this->assertSession()->pageTextNotContains('You can only change the book outline for the published version of this content.');
+ $this->assertSession()->pageTextContains('Some moderated content has been updated');
+
+ $this->drupalLogout();
+ $this->drupalLogin($this->bookAuthor);
+ // Check that the book outline did not change.
+ $this->book = $book_1;
+ $this->checkBookNode($book_1, [
+ $book_1_nodes[0],
+ $book_1_nodes[3],
+ $book_1_nodes[4],
+ $node,
+ ], FALSE, FALSE, $book_1_nodes[0], []);
+ $this->checkBookNode($book_1_nodes[0], [
+ $book_1_nodes[1],
+ $book_1_nodes[2],
+ ], FALSE, $book_1, $book_1_nodes[1], [$book_1]);
+ }
+
}
diff --git a/tests/src/Functional/BookTest.php b/tests/src/Functional/BookTest.php
index f39ac94..4989d1a 100644
--- a/tests/src/Functional/BookTest.php
+++ b/tests/src/Functional/BookTest.php
@@ -707,6 +707,7 @@ class BookTest extends BrowserTestBase {
'create book content',
'edit own book content',
'add content to books',
+ 'add any content to books',
'node test view',
'edit any page content',
]);
--
GitLab
......@@ -11,6 +11,9 @@
"#3173340 Exception": "https://www.drupal.org/files/issues/2020-09-26/3173340-2.background_image.Error-Call-to-a-member-function-hasEntityToken-on-bool-in-DrupalbackgroundimageCacheContextBackgroundImageSettingsTextCacheContextgetContext.patch",
"#3128542 FileScan": "https://www.drupal.org/files/issues/2020-09-11/background_image-missing_folder-3128542-8.patch"
},
"drupal/book": {
"Validation": "https://gitlab.lakedrops.com/composer/plugin/drupal-environment/-/raw/main/patches/d10/book-validation.patch"
},
"drupal/bootstrap_clean_blog": {
"#3146287 Drupal 9": "https://www.drupal.org/files/issues/2021-10-23/3146287_3.patch"
},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment