You are here

function module_grants_node_access in Module Grants 6.4

Same name and namespace in other branches
  1. 6 module_grants.module \module_grants_node_access()
  2. 6.3 module_grants.module \module_grants_node_access()
  3. 7 module_grants.module \module_grants_node_access()

Similar to node_access() in node.module but ANDs rather than ORs grants together on a per module base to create more natural behaviour. Also makes sure that published and unpublished content are treated in the same way, i.e. that grants are checked in either case.

Parameters

$node_op: One of 'view', 'update' or 'delete'. We don't need to deal with 'create'.

$node: The node for which the supplied operation is checked

$account: user object, use NULL or omit for current user

Return value

FALSE if the supplied operation isn't permitted on the node

2 calls to module_grants_node_access()
module_grants_node_revision_access in ./module_grants.module
Menu options dealing with revisions have their revision-specific permissions checked via user_access(), before being tested for the associated node-specific operation. Return a boolean indicating whether the current user has access to the requested…
node_tools_get_nodes in node_tools/node_tools.module
Retrieve a list of nodes or revisions accessible to the logged-in user via the supplied operation.
1 string reference to 'module_grants_node_access'
module_grants_menu_alter in ./module_grants.module
Implementation of hook_menu_alter().

File

./module_grants.module, line 154
Module to apply access grants to pre-published content just as they are to published content and to make multiple content access modules work together in the expected way.

Code

function module_grants_node_access($node_op, $node, $account = NULL) {
  static $access = array();
  global $user;
  if (!$node) {
    return FALSE;
  }
  $nid = $node->nid;
  if (isset($access["{$nid}:{$node_op}"])) {
    return $access["{$nid}:{$node_op}"];
  }

  // If the node is in a restricted format, disallow editing.
  if ($node_op == 'update' && !filter_access($node->format)) {
    return $access["{$nid}:{$node_op}"] = FALSE;
  }

  // If no account object is supplied, the access check is for the current user.
  if (empty($account)) {
    $account = $user;
  }
  if (user_access('administer nodes', $account)) {
    return $access["{$nid}:{$node_op}"] = TRUE;
  }
  if (!user_access('access content', $account)) {
    return $access["{$nid}:{$node_op}"] = FALSE;
  }
  $module = node_get_types('module', $node);
  if ($module == 'node') {
    $module = 'node_content';
  }
  $result = module_invoke($module, 'access', $node_op, $node, $account);
  if (!is_null($result)) {

    //drupal_set_message("'$node_op' access=$result by module $module: '$node->title'", 'warning', FALSE);
    return $access["{$nid}:{$node_op}"] = $result;
  }

  // Having arrived here, node access has still neither been granted nor denied.
  // We're about to hand over to enabled content access modules, that is those
  // that implement hook_node_grants() and consult the node_access table.
  // By default the node_access table allows 'view' access to all and does not
  // take the node's publication status into account. This would mean that
  // anonymous users would be able to view content that isn't published,
  // assuming they have the 'access content' permission, which is normal.
  // Therefore, to differentiate view access for unpublished content between
  // anonymous and authorised users, we only allow view access to unpublished
  // content to roles that have the 'view revisions' or 'view revisions of
  // any|own <type> content" permissions (from Revisioning).
  // So, do NOT give any of these view revisions permissions to the anonymous
  // user role.
  // The exception are authors viewing their own content. It would be silly to
  // disallow authors viewing the (unpublished) content they just saved!
  //
  if ($node_op == 'view' && !$node->status) {
    $may_view = module_invoke('revisioning', 'user_node_access', 'view revisions', $node) || user_access('view revisions');
    if (!$may_view) {
      if ($account->uid != $node->uid) {

        // Not the author: no permission to view this unpublished content.
        return $access["{$nid}:{$node_op}"] = FALSE;
      }
    }
  }
  $base_sql = "SELECT COUNT(*) FROM {node_access} WHERE (nid=0 OR nid=%d) AND ((gid=0 AND realm='all')";

  // If module_grants_lenient is set, then a content access module that has
  // nothing to say about the node in question will be deemed to be ok with
  // $account having access to $node.
  // If module_grants_lenient isn't set and a content access module has nothing
  // to say about the node in question this will be taken as a 'deny access'.
  $nid1 = variable_get('module_grants_lenient', TRUE) ? $nid : NULL;
  $all_grants = _module_grants_by_module($node_op, $account, $nid1);
  if (count($all_grants) == 0) {

    // no module implements hook_node_grants()
    // Note that in the absence of any content access modules the node_access
    // table by default contains a single row that grants the 'all' realm
    // 'view' access to all nodes via nid=0.
    $sql = "{$base_sql}) AND grant_{$node_op} >=1";
    $result = db_result(db_query($sql, $nid));

    //drupal_set_message("'$node_op' access=$result by node_access table: '$node->title'", 'warning', FALSE);
    return $access["{$nid}:{$node_op}"] = $result;
  }
  $or_modules = variable_get('module_grants_OR_modules', FALSE);
  foreach ($all_grants as $module => $module_grants) {
    $sql = $base_sql . (empty($module_grants) ? "" : " OR ({$module_grants})") . ") AND grant_{$node_op} >=1";

    // Effectively AND module_grants together by breaking loop as soon as one fails
    // A single SQL statement may be slightly quicker but won't tells us
    // which of the modules denied access. This is useful debug feedback.
    $result = db_result(db_query($sql, $nid));

    //drupal_set_message("'$node_op' access=$result by $module-grants: '$node->title'", 'warning', FALSE);
    if ($or_modules) {
      if ($result > 0) {

        // OR module grants together: break as soon as one succeeds
        break;
      }
    }
    elseif ($result == 0) {

      // AND module grants together: break as soon as one fails
      break;
    }
  }
  return $access["{$nid}:{$node_op}"] = $result;
}