3
votes

For all users I need to conditionally block access to nodes of type 'message'. The only way users should be able to view these message nodes is by successfully submitting a form.

I've started like this:

  function mymodule_node_access($node, $op, $account) {
    if ($op == 'view' && $node->type == 'message') {
      return NODE_ACCESS_DENY;
    }
  }

However, I want to allow view access to individual nodes of this type upon successful submission of form:

function form_submit($form, &$form_state) {
  // some logic here  
  $form_state['redirect'] = 'node/255';
}

so node 255 is of type 'message', and I want to 'lift' the NODE_ACCESS_DENY for this particular node and this user (+ in most cases this will be an anonymous user)

Any suggestions on different ways to accomplish this?

2

2 Answers

4
votes

The only way you can do that is to set a value in the form submission handler that is then checked by hook_node_access(); you could use a Drupal variable, or a value saved in a database table. You need to store the user ID of the user that accessed the form, and the node ID of every node for which such form has been submitted.

Supposing you use a Drupal variable, you could use code similar to the following one:

function mymodule_form_submit($form, &$form_state) {
  global $user;
  $message_nid = 255;
  $values = variable_get('access_nid', array());

  if (isset($values[$user->uid])) {
    if (!isset($values[$user->uid][$message_nid])) {
      $values[$user->uid][$message_nid] = $message_nid;
    }
  }
  else {
    $values[$user->uid] = array($message_nid => $message_nid);
  }

  variable_set('access_nid', $values);
  $form_state['redirect'] = 'node/' . $message_nid;
}

function mymodule_node_access($node, $op, $account) {
  $result = NODE_ACCESS_IGNORE;

  if ($op == 'view' && $node->type == 'message') {
    $values = variable_get('access_nid', array());
    if (!empty($values[$account->uid]) {
      if (isset($values[$account->uid][$node->nid])) {
        unset($values[$account->uid][$node->nid]);
        $result = NODE_ACCESS_ALLOW;
      }
      else {
        $result = NODE_ACCESS_DENY;
      }
    }
    else {
      $result = NODE_ACCESS_DENY;
    }
  }
  variable_set('access_nid', $values);

  return $result;
}

To notice that this code allows a user to access a node only once; if the user would try to access the same node the second time, the user would get an "access denied" error. If that is not desired, then the second function should be re-written as follows:

function mymodule_node_access($node, $op, $account) {
  if ($op == 'view' && $node->type == 'message') {
    $values = variable_get('access_nid', array());
    if (!empty($values[$account->uid]) {
      if (isset($values[$account->uid][$node->nid])) {
        return NODE_ACCESS_ALLOW;
      }

      return NODE_ACCESS_DENY;
      }
    }
    else {
      $result = NODE_ACCESS_DENY;
    }
  }

  return NODE_ACCESS_IGNORE;
}

I used a Drupal variable to write simple code; using a Drupal variable, in this case, should be done if the users that can create nodes of that content type are few; if there are many users who can create those nodes, then using a database table is better.
Also when using Drupal variables, Drupal is using a database table; the difference is that the content of that database table is always loaded in memory. If you need to store many data, you should not use Drupal variables.

2
votes

Modified solution to use $_SESSION as I'm working mostly with anonymous users:

function mymodule_form_submit($form, &$form_state) {
  $message_nid = 255;
  if (!isset($_SESSION['node_access'])) {
    $_SESSION['node_access'] = array();
  }
  if (!isset($_SESSION['node_access']['nid'])) {
    $_SESSION['node_access']['nid'] = $message_nid;
  }
  $form_state['redirect'] = 'node/' . $message_nid;
}

function mymodule_node_access($node, $op, $account) {
  $node_access = NODE_ACCESS_IGNORE;
  if ($op == 'view' && $node->type == 'message') {
    if (isset($_SESSION['node_access'] && !empty($_SESSION['node_access'])) {
      if ($node->nid == $_SESSION['node_access']['nid']) {
        unset($_SESSION['node_access']['nid']);
        $node_access = NODE_ACCESS_ALLOW ;
      } else {
        unset($_SESSION['node_access']['nid']);
        $node_access = NODE_ACCESS_DENY;
      }
    } else {
      $node_access = NODE_ACCESS_DENY;
    }
  }
  return $node_access;
}