Unverified Commit 54e0120b authored by Alex Pott's avatar Alex Pott
Browse files

Issue #214190 by jgoldberg, webchick, catch, jacobroufa, Mez, David_Rothstein,...

Issue #214190 by jgoldberg, webchick, catch, jacobroufa, Mez, David_Rothstein, theamoeba, acbramley, dww, smustgrave, gábor hojtsy, benjifisher, quietone, alexpott, ifrik, sidgrafix: Add administer node published status permission
parent d7a61c29
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -951,7 +951,7 @@ public function testWrite(): void {
    ]);
    $updated_response = $this->getDocumentFromResponse($response, FALSE);
    $this->assertEquals(403, $response->getStatusCode());
    $this->assertEquals("The current user is not allowed to PATCH the selected field (status). The 'administer nodes' permission is required.",
    $this->assertEquals("The current user is not allowed to PATCH the selected field (status). The following permissions are required: 'administer node published status' OR 'administer nodes'.",
      $updated_response['errors'][0]['detail']);

    $node = \Drupal::service('entity.repository')->loadEntityByUuid('node', $uuid);
+4 −0
Original line number Diff line number Diff line
@@ -27,6 +27,10 @@ rebuild node access permissions:
  title: 'Rebuild content access permissions'
  description: 'Trigger a content access permission rebuild. This can be a potentially long and disruptive process.'
  restrict access: true
administer node published status:
  title: 'Administer node published status'
  description: 'Edit the published status of a node across all content types.'
  restrict access: true

permission_callbacks:
  - \Drupal\node\NodePermissions::nodeTypePermissions
+8 −4
Original line number Diff line number Diff line
@@ -251,22 +251,26 @@ protected function checkCreateAccess(AccountInterface $account, array $context,
   * {@inheritdoc}
   */
  protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) {
    $fieldName = $field_definition->getName();
    if ($operation == 'edit' && $fieldName === 'status') {
      return AccessResult::allowedIfHasPermissions($account, ['administer node published status', 'administer nodes'], 'OR');
    }
    // Only users with the administer nodes permission can edit administrative
    // fields.
    $administrative_fields = ['uid', 'status', 'created', 'promote', 'sticky'];
    if ($operation == 'edit' && in_array($field_definition->getName(), $administrative_fields, TRUE)) {
    $administrative_fields = ['uid', 'created', 'promote', 'sticky'];
    if ($operation == 'edit' && in_array($fieldName, $administrative_fields, TRUE)) {
      return AccessResult::allowedIfHasPermission($account, 'administer nodes');
    }

    // No user can change read only fields.
    $read_only_fields = ['revision_timestamp', 'revision_uid'];
    if ($operation == 'edit' && in_array($field_definition->getName(), $read_only_fields, TRUE)) {
    if ($operation == 'edit' && in_array($fieldName, $read_only_fields, TRUE)) {
      return AccessResult::forbidden();
    }

    // Users have access to the revision_log field either if they have
    // administrative permissions or if the new revision option is enabled.
    if ($operation == 'edit' && $field_definition->getName() == 'revision_log') {
    if ($operation == 'edit' && $fieldName == 'revision_log') {
      if ($account->hasPermission('administer nodes')) {
        return AccessResult::allowed()->cachePerPermissions();
      }
+16 −4
Original line number Diff line number Diff line
@@ -115,7 +115,8 @@ public function testNodeEdit(): void {
    ]);
    $this->drupalLogin($second_web_user);
    // Edit the same node, creating a new revision.
    $this->drupalGet("node/" . $node->id() . "/edit");
    $node_edit_url = $node->toUrl('edit-form');
    $this->drupalGet($node_edit_url);
    $edit = [];
    $edit['title[0][value]'] = $this->randomMachineName(8);
    $edit[$body_key] = $this->randomMachineName(16);
@@ -136,12 +137,12 @@ public function testNodeEdit(): void {
    $this->assertNotSame($first_node_version->getRevisionUser()->id(), $second_node_version->getRevisionUser()->id(), 'Each revision has a distinct user.');

    // Check if the node revision checkbox is rendered on node edit form.
    $this->drupalGet('node/' . $node->id() . '/edit');
    $this->drupalGet($node_edit_url);
    $this->assertSession()->fieldExists('edit-revision', NULL);

    // Check that details form element opens when there are errors on child
    // elements.
    $this->drupalGet('node/' . $node->id() . '/edit');
    $this->drupalGet($node_edit_url);
    $edit = [];
    // This invalid date will trigger an error.
    $edit['created[0][value][date]'] = $this->randomMachineName(8);
@@ -156,11 +157,22 @@ public function testNodeEdit(): void {

    // Edit the same node, save it and verify it's unpublished after unchecking
    // the 'Published' boolean_checkbox and clicking 'Save'.
    $this->drupalGet("node/" . $node->id() . "/edit");
    $this->drupalGet($node_edit_url);
    $edit = ['status[value]' => FALSE];
    $this->submitForm($edit, 'Save');
    $node = $this->nodeStorage->load($node->id());
    $this->assertFalse($node->isPublished(), 'Node is unpublished');

    // Login as a user that can access the published checkbox.
    $this->drupalLogin($this->drupalCreateUser([
      'administer node published status',
      'edit any page content',
    ]));
    $this->drupalGet($node_edit_url);
    $this->assertSession()->fieldExists('status[value]');
    $this->submitForm(['status[value]' => TRUE], 'Save');
    $node = $this->nodeStorage->load($node->id());
    $this->assertTrue($node->isPublished());
  }

  /**
+13 −4
Original line number Diff line number Diff line
@@ -43,10 +43,9 @@ class NodeFieldAccessTest extends EntityKernelTestBase {
  protected $readOnlyFields = ['changed', 'revision_uid', 'revision_timestamp'];

  /**
   * Tests permissions on nodes status field.
   * Tests permissions on nodes administrative fields.
   */
  public function testAccessToAdministrativeFields(): void {

    // Create the page node type with revisions disabled.
    $page = NodeType::create([
      'type' => 'page',
@@ -80,6 +79,13 @@ public function testAccessToAdministrativeFields(): void {
      'delete any page content',
      'access content',
    ]);
    $page_publisher_user = $this->createUser([
      'create page content',
      'edit any page content',
      'delete any page content',
      'access content',
      'administer node published status',
    ]);

    // An unprivileged user.
    $page_unrelated_user = $this->createUser(['access content']);
@@ -116,7 +122,6 @@ public function testAccessToAdministrativeFields(): void {
    $node3->save();

    foreach ($this->administrativeFields as $field) {

      // Checks on view operations.
      foreach ($test_users as $account) {
        $may_view = $node1->{$field}->access('view', $account);
@@ -134,7 +139,7 @@ public function testAccessToAdministrativeFields(): void {
      $this->assertFalse($may_update, 'Users with permission "edit any page content" is not allowed to the field ' . $field . '.');
      $may_update = $node2->{$field}->access('edit', $page_unrelated_user);
      $this->assertFalse($may_update, 'Users not having permission "edit any page content" is not allowed to the field ' . $field . '.');
      $may_update = $node1->{$field}->access('edit', $content_admin_user) && $node3->status->access('edit', $content_admin_user);
      $may_update = $node1->{$field}->access('edit', $content_admin_user) && $node3->{$field}->access('edit', $content_admin_user);
      $this->assertTrue($may_update, 'Users with permission "administer nodes" may edit ' . $field . ' fields on all nodes.');
    }

@@ -152,6 +157,10 @@ public function testAccessToAdministrativeFields(): void {
      }
    }

    // Check the status field can be edited by users with the "administer node
    // status" permission.
    $this->assertTrue($node3->status->access('edit', $page_publisher_user));

    // Check the revision_log field on node 1 which has revisions disabled.
    $may_update = $node1->revision_log->access('edit', $content_admin_user);
    $this->assertTrue($may_update, 'A user with permission "administer nodes" can edit the revision_log field when revisions are disabled.');