You are here

nodeaccess.module in Nodeaccess 8

Control access to site content based on the users and roles.

File

nodeaccess.module
View source
<?php

/**
 * @file
 * Control access to site content based on the users and roles.
 */
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\user\RoleInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\node\NodeTypeInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\node\NodeInterface;

/**
 * Implements hook_help().
 */
function nodeaccess_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'entity.node.grants':
      return t("You can set grants for individual users. Enter a name or a partial name in the box and click Search or press return. You must check the 'Keep?' checkbox if you want to keep the user for granting. Note that user grants are in addition to those coming from roles.");
  }
}

/**
 * Implements hook_node_access_records().
 */
function nodeaccess_node_access_records($node) {
  $settings = \Drupal::configFactory()
    ->get('nodeaccess.settings');
  $ntype = $node
    ->getType();

  // Need to find out if node has own grants or whether to use defaults.
  $default = $settings
    ->get($ntype);
  $roles_gids = $settings
    ->get('role_map');
  $nid = $node
    ->id();
  $grants = [];

  // Setup default keys that are required by node_access_write_grants().
  $grant_defaults = [
    'gid' => 0,
    'realm' => 'nodeaccess_rid',
    'grant_view' => 0,
    'grant_update' => 0,
    'grant_delete' => 0,
    'priority' => $settings
      ->get('priority'),
  ];
  $db = \Drupal::database();
  $entries = $db
    ->select('nodeaccess', 'n')
    ->fields('n')
    ->condition('nid', $nid, '=')
    ->execute()
    ->fetchAll();
  $node_count = count($entries);
  if ($node_count < 1) {

    // Node has no own grants, use defaults if published.
    if ($node
      ->isPublished()) {
      $i = 0;
      foreach ($default as $key => $val) {
        if ($key != 'author') {
          $rid = $roles_gids[$key];
          $grants[$i] = $default[$key];
          $grants[$i]['gid'] = $rid;
          $i++;
        }
      }
    }
    else {

      // Otherwise, check access to unpublished content for authenticated and
      // anonymous users.
      $role_perms = user_role_permissions([
        DRUPAL_ANONYMOUS_RID,
        DRUPAL_AUTHENTICATED_RID,
      ]);

      // Anonymous user setting.
      $grants[] = [
        'gid' => DRUPAL_ANONYMOUS_RID,
        'grant_view' => in_array('bypass node access', $role_perms[DRUPAL_ANONYMOUS_RID]),
      ];

      // Authenticated user setting.
      $grants[] = [
        'gid' => DRUPAL_AUTHENTICATED_RID,
        'grant_view' => in_array('bypass node access', $role_perms[DRUPAL_AUTHENTICATED_RID]),
      ];
    }
  }
  else {

    // Node has own grants, use them.
    $db = \Drupal::database();
    $entries = $db
      ->select('nodeaccess', 'n')
      ->fields('n')
      ->condition('nid', $nid, '=')
      ->execute()
      ->fetchAll();
    $grants = [];
    foreach ($entries as $row) {
      $grants[] = [
        'gid' => $row->gid,
        'realm' => $row->realm,
        'grant_view' => $row->grant_view,
        'grant_update' => $row->grant_update,
        'grant_delete' => $row->grant_delete,
      ];
    }
  }

  // Apply author grants.
  $grant = $default['author'];
  $grant['gid'] = $node
    ->getOwnerId();
  $grant['realm'] = 'nodeaccess_author';

  // Include author grant even with all values FALSE, it may be
  // needed to overwrite an older value.
  $grants[] = $grant;
  $updated_grants = [];
  foreach ($grants as $id => $grant) {

    // Merge missing default grant keys.
    $updated_grants[] = $grants[$id] + $grant_defaults;
  }
  return $updated_grants;
}

/**
 * Implements hook_node_grants().
 */
function nodeaccess_node_grants(AccountInterface $account, $op) {
  $config = \Drupal::configFactory()
    ->get('nodeaccess.settings');
  $role_map = $config
    ->get('role_map');
  $roles = $account
    ->getRoles();
  $rids = [];
  foreach ($roles as $role) {
    $rids[] = $role_map[$role];
  }
  return [
    'nodeaccess_rid' => $rids,
    'nodeaccess_uid' => [
      $account
        ->id(),
    ],
    'nodeaccess_author' => [
      $account
        ->id(),
    ],
  ];
}

/**
 * Implements hook_entity_update().
 */
function nodeaccess_entity_update(EntityInterface $entity) {
  $config = \Drupal::configFactory()
    ->getEditable('nodeaccess.settings');
  if ($entity instanceof RoleInterface) {
    $role_alias = $config
      ->get('role_alias');
    if ($role_alias[$entity
      ->id()]) {
      $role_alias[$entity
        ->id()]['alias'] = $entity
        ->label();
      $role_alias[$entity
        ->id()]['name'] = $entity
        ->label();
    }
    else {
      $role_alias[$entity
        ->id()] = [
        'alias' => $entity
          ->label(),
        'name' => $entity
          ->label(),
        'weight' => 0,
        'allow' => 0,
      ];
    }
    $config
      ->set('role_alias', $role_alias);
    $config
      ->save();
  }
}

/**
 * Implements hook_entity_insert().
 */
function nodeaccess_entity_insert(EntityInterface $entity) {
  $config = \Drupal::configFactory()
    ->getEditable('nodeaccess.settings');
  if ($entity instanceof RoleInterface) {
    $roles_gids = array_flip($config
      ->get('role_map'));
    $roles_gids[] = $entity
      ->id();
    $config
      ->set('role_map', array_flip($roles_gids));
    $role_alias = $config
      ->get('role_alias');
    $role_alias[$entity
      ->id()] = [
      'alias' => $entity
        ->label(),
      'name' => $entity
        ->label(),
      'weight' => 0,
      'allow' => 0,
    ];
    $config
      ->set('role_alias', $role_alias);
    $config
      ->save();
  }
}

/**
 * Implements hook_entity_delete().
 */
function nodeaccess_entity_delete(EntityInterface $entity) {
  $config = \Drupal::configFactory()
    ->getEditable('nodeaccess.settings');
  if ($entity instanceof RoleInterface) {
    $roles_gids = $config
      ->get('role_map');
    unset($roles_gids[$entity
      ->id()]);
    $config
      ->set('role_map', $roles_gids);
    $role_alias = $config
      ->get('role_alias');
    unset($role_alias[$entity
      ->id()]);
    $config
      ->set('role_alias', $role_alias);
    $config
      ->save();
  }
}

/**
 * Implements hook_node_delete().
 */
function nodeaccess_node_delete(EntityInterface $node) {

  // Deleting node, delete related permissions.
  \Drupal::database()
    ->delete('nodeaccess')
    ->condition('nid', $node
    ->id())
    ->execute();
}

/**
 * Implements hook_ENTITY_TYPE_delete().
 */
function nodeaccess_node_type_delete(NodeTypeInterface $type) {
  $config = \Drupal::configFactory()
    ->getEditable('nodeaccess.settings');
  $allowed_types = $config
    ->get('allowed_types');
  unset($allowed_types[$type
    ->id()]);
  $config
    ->clear($type
    ->id())
    ->set('allowed_types', $allowed_types)
    ->save();
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function nodeaccess_node_type_insert(NodeTypeInterface $type) {
  $config = \Drupal::configFactory()
    ->getEditable('nodeaccess.settings');

  // New node type, default to whatever is set for access content permission.
  $role_perms = user_role_permissions([
    DRUPAL_ANONYMOUS_RID,
    DRUPAL_AUTHENTICATED_RID,
  ]);
  $anonymous_access = (int) in_array('access content', $role_perms[DRUPAL_ANONYMOUS_RID]);
  $authenticated_access = (int) in_array('access content', $role_perms[DRUPAL_AUTHENTICATED_RID]);
  $grants[DRUPAL_ANONYMOUS_RID] = [
    'grant_view' => $anonymous_access,
    'grant_update' => 0,
    'grant_delete' => 0,
  ];
  $grants[DRUPAL_AUTHENTICATED_RID] = [
    'grant_view' => $authenticated_access,
    'grant_update' => 0,
    'grant_delete' => 0,
  ];
  $grants['author'] = [
    'grant_view' => 0,
    'grant_update' => 0,
    'grant_delete' => 0,
  ];
  $allowed_types = $config
    ->get('allowed_types');
  $allowed_types[$type
    ->id()] = 0;
  $config
    ->set($type
    ->id(), $grants)
    ->set('allowed_types', $allowed_types)
    ->save();
  node_access_needs_rebuild(TRUE);
}

/**
 * Implements hook_node_access().
 */
function nodeaccess_node_access(NodeInterface $node, $op, $account) {
  $settings = \Drupal::configFactory()
    ->get('nodeaccess.settings');
  $role_map = $settings
    ->get('role_map');
  switch ($op) {
    case 'update':
    case 'delete':

      // If the node belongs to a deleted user.
      if ($account
        ->id() == 0 && $node
        ->getOwnerId() == 0) {

        // We check if the role has particular access to this node.
        $grants = _nodeaccess_get_grants($node);
        $anonymous_rid = $role_map[DRUPAL_ANONYMOUS_RID];

        // If anonymous has rights to this node, we allow them.
        if ($grants['rid'][$anonymous_rid]['grant_update'] && $op == 'update' || $grants['rid'][$anonymous_rid]['grant_delete'] && $op == 'delete') {
          return AccessResult::Allowed();
        }
        return AccessResult::forbidden();
      }
      break;
  }
}

/**
 * Return the grants applied to a node object used for Grant form.
 *
 * @return array
 *   An array of grants with keys 'rid' for roles and 'uid' for users.
 */
function _nodeaccess_get_grants($node) {
  $grants = [];

  // Load all roles.
  $db = \Drupal::database();
  $result = $db
    ->select('nodeaccess', 'na')
    ->fields('na', [
    'gid',
    'grant_view',
    'grant_update',
    'grant_delete',
  ])
    ->condition('nid', $node->id, '=')
    ->condition('realm', 'nodeaccess_rid', '=')
    ->execute()
    ->fetchAll();
  foreach ($result as $grant) {
    $grants['rid'][$grant->gid] = [
      'grant_view' => $grant->grant_view,
      'grant_update' => $grant->grant_update,
      'grant_delete' => $grant->grant_delete,
    ];
  }

  // Load users from node_access.
  $db = \Drupal::database();
  $entries = $db
    ->select('nodeaccess', 'n');
  $entries
    ->join('users_field_data', 'ufd', 'ufd.uid = n.gid');
  $entries
    ->fields('n', [
    'grant_view',
    'grant_update',
    'grant_delete',
  ])
    ->condition('n.nid', $node->id, '=')
    ->condition('n.realm', 'nodeaccess_uid', '=')
    ->orderBy('ufd.name', 'ASC');
  $result = $entries
    ->execute();
  $results = [];
  while ($data = $result
    ->fetchObject()) {
    $results[] = $data;
  }
  foreach ($result as $account) {
    $grants['uid'][$account->uid] = [
      'name' => $account->name,
      'keep' => 1,
      'grant_view' => $account->grant_view,
      'grant_update' => $account->grant_update,
      'grant_delete' => $account->grant_delete,
    ];
  }
  return $grants;
}