devel_node_access_block

Versions
5 – 7
devel_node_access_block($op = 'list', $delta = 0)

Code

contrib/devel/devel_node_access.module, line 206

<?php
function devel_node_access_block($op = 'list', $delta = 0) {
  global $user;
  global $theme_key;
  static $block1_visible, $hint = '';
  if (!isset($block1_visible)) {
    $block1_visible = db_result(db_query("SELECT status FROM {blocks} WHERE module = 'devel_node_access' AND delta = 1 AND theme = '%s'", $theme_key));
    if (!$block1_visible) {
      $hint = t('For per-user access permissions enable the second DNA <a href="@block">block</a>.', array('@block' => url('admin/build/block')));
    }
  }

  switch ($op) {
    case 'list':
      $blocks[0]['info'] = t('Devel Node Access');
      $blocks[0]['status'] = 1;
      $blocks[0]['region'] = 'footer';
      $blocks[1]['info'] = t('Devel Node Access by User');
      $blocks[1]['status'] = 0;
      $blocks[1]['region'] = 'footer';
      return $blocks;

    case 'view':
      if (!user_access(DNA_ACCESS_VIEW)) {
        return;
      }
      switch ($delta) {
        case 0:
          if (!count(dna_visible_nodes())) {
            return;
          }

          // include rows where nid == 0
          $nids = array_merge(array(0 => 0), dna_visible_nodes());
          $result = db_query('SELECT na.*, n.title FROM {node_access} na LEFT JOIN {node} n ON n.nid = na.nid WHERE na.nid IN ('. db_placeholders($nids) .') ORDER BY na.nid, na.realm, na.gid', $nids);

          if (!variable_get('devel_node_access_debug_mode', FALSE)) {
            $headers = array(t('node'), t('realm'), t('gid'), t('view'), t('update'), t('delete'), t('explained'));
            $rows = array();
            while ($row = db_fetch_object($result)) {
              $explained = module_invoke_all('node_access_explain', $row);
              $rows[] = array(_devel_node_access_get_node_title($row),
                              $row->realm,
                              $row->gid,
                              $row->grant_view,
                              $row->grant_update,
                              $row->grant_delete,
                              implode('; ', $explained));
            }
            $output = theme('table', $headers, $rows, array('style' => 'text-align: left'));
            $hint = t('To see more details enable <a href="@debug_mode">debug mode</a>.', array('@debug_mode' => url('admin/settings/devel', array('fragment' => 'edit-devel-node-access-debug-mode')))) .' '. $hint;
          }
          else {
            $tr = 't';
            $tokens = array('!na' => '{node_access}');
            $states = array(
              'default'      => array(t('default'),      'ok',      t('Default grant supplied by core in the absence of any other non-empty grants, in !na.', $tokens)),
              'ok'           => array(t('ok'),           'ok',      t('Highest priority grant, in !na.', $tokens)),
              'unexpected'   => array(t('unexpected'),   'warning', t('The 0/0/all/... grant applies to all nodes and all users -- usually it should not be present if any node access module is active!')),
              'ignored'      => array(t('ignored'),      'warning', t('Lower priority grant, not in !na and thus ignored.', $tokens)),
              'empty'        => array(t('empty'),        'warning', t('Does not grant any access, but could block lower priority grants; not in !na.', $tokens)),
              'missing'      => array(t('missing'),      'error',   t("Should be in !na but isn't!", $tokens)),
              'illegitimate' => array(t('illegitimate'), 'error',   t('Should NOT be in !na because of lower priority!', $tokens)),
              'alien'        => array(t('alien'),        'error',   t('Should NOT be in !na because of unknown origin!', $tokens)),
            );
            $headers = array(t('node'), t('prio'), t('status'), t('realm'), t('gid'), t('view'), t('update'), t('delete'), t('explained'));
            $active_grants = array();
            while ($active_grant = db_fetch_object($result)) {
              $active_grants[$active_grant->nid][$active_grant->realm][$active_grant->gid] = $active_grant;
            }
            $all_grants = $checked_grants = $checked_status = array();
            foreach ($nids as $nid) {
              $acquired_grants_nid = array();
              if ($node = node_load($nid)) {
                // check node_access_acquire_grants()
                $grants = _devel_node_access_module_invoke_all('node_access_records', $node);
                if (!empty($grants)) {
                  $top_priority = NULL;
                  foreach ($grants as $grant) {
                    $priority = intval($grant['priority']);
                    $top_priority = (isset($top_priority) ? max($top_priority, $priority) : $priority);
                    $grant['priority'] = (isset($grant['priority']) ? $priority : '&ndash;&nbsp;');
                    $acquired_grants_nid[$priority][$grant['realm']][$grant['gid']] = $grant + array(
                      '#title' => _devel_node_access_get_node_title($node),
                      '#module' => (isset($grant['#module']) ? $grant['#module'] : ''),
                    );
                  }
                  krsort($acquired_grants_nid);
                }
                // check node_access_grants()
                $checked_status[$nid] = $node->status;
                if ($node->nid && $node->status) {
                  foreach (array('view', 'update', 'delete') as $op) {
                    $checked_grants[$nid][$op] = array_merge(
                      array('all' => array(0)),
                      _devel_node_access_module_invoke_all('node_grants', $user, $op)
                    );
                  }
                }
              }
              // check for grants in the node_access table that aren't returned by node_access_acquire_grants()
              $found = FALSE;
              if (isset($active_grants[$nid])) {
                foreach ($active_grants[$nid] as $realm => $active_grants_realm) {
                  foreach ($active_grants_realm as $gid => $active_grant) {
                    $count_nonempty_grants = 0;
                    foreach ($acquired_grants_nid as $priority => $acquired_grants_nid_priority) {
                      if (isset($acquired_grants_nid_priority[$realm][$gid])) {
                        $found = TRUE;
                      }
                    }
                    if ($acquired_grants_nid_priority = reset($acquired_grants_nid)) { // highest priority only
                      foreach ($acquired_grants_nid_priority as $acquired_grants_nid_priority_realm) {
                        foreach ($acquired_grants_nid_priority_realm as $acquired_grants_nid_priority_realm_gid) {
                          $count_nonempty_grants += (!empty($acquired_grants_nid_priority_realm_gid['grant_view']) || !empty($acquired_grants_nid_priority_realm_gid['grant_update']) || !empty($acquired_grants_nid_priority_realm_gid['grant_delete']));
                        }
                      }
                    }
                    if ($count_nonempty_grants == 0 && $realm == 'all' && $gid == 0 ) {
                      $fixed_grant = ((array) $active_grant) + array(
                        'priority' => '&ndash;',
                        'state'    => 'default',
                      );
                    }
                    elseif (!$found) {
                      $fixed_grant = ((array) $active_grant) + array(
                        'priority' => '?',
                        'state'    => 'alien',
                      );
                    }
                    else {
                      continue;
                    }
                    $fixed_grant += array(
                      'nid'    => $nid,
                      '#title' => _devel_node_access_get_node_title($node, FALSE),
                    );
                    $all_grants[] = $fixed_grant;
                  }
                }
              }
              // order grants and evaluate their status
              foreach ($acquired_grants_nid as $priority => $acquired_grants_priority) {
                ksort($acquired_grants_priority);
                foreach ($acquired_grants_priority as $realm => $acquired_grants_realm) {
                  ksort($acquired_grants_realm);
                  foreach ($acquired_grants_realm as $gid => $acquired_grant) {
                    if ($priority == $top_priority) {
                      if (empty($acquired_grant['grant_view']) && empty($acquired_grant['grant_update']) && empty($acquired_grant['grant_delete'])) {
                        $acquired_grant['state'] = 'empty';
                      }
                      else {
                        $acquired_grant['state'] = (isset($active_grants[$nid][$realm][$gid]) ? 'ok' : 'missing');
                        if ($acquired_grant['state'] == 'ok') {
                          foreach (array('view', 'update', 'delete') as $op) {
                            $active_grant = (array) $active_grants[$nid][$realm][$gid];
                            if (empty($acquired_grant["grant_$op"]) != empty($active_grant["grant_$op"]) ) {
                              $acquired_grant["grant_$op!"] = $active_grant["grant_$op"];
                            }
                          }
                        }
                      }
                    }
                    else {
                      $acquired_grant['state'] = (isset($active_grants[$nid][$realm][$gid]) ? 'illegitimate' : 'ignored');
                    }
                    $all_grants[] = $acquired_grant + array('nid' => $nid);
                  }
                }
              }
            }
            // fill in the table rows
            $rows = array();
            $error_count = 0;
            foreach ($all_grants as $grant) {
              $row = new stdClass();
              $row->nid = $grant['nid'];
              $row->title = $grant['#title'];
              $row->priority = $grant['priority'];
              $row->state = array('data' => $states[$grant['state']][0], 'title' => $states[$grant['state']][2]);
              $row->realm = $grant['realm'];
              $row->gid = $grant['gid'];
              $row->grant_view = $grant['grant_view'];
              $row->grant_update = $grant['grant_update'];
              $row->grant_delete = $grant['grant_delete'];
              $row->explained = implode('; ', module_invoke_all('node_access_explain', $row));
              unset($row->title);
              if ($row->nid == 0 && $row->gid == 0 && $row->realm == 'all' && count($all_grants) > 1) {
                $row->state = array('data' => $states['unexpected'][0], 'title' => $states['unexpected'][2]);
                $class = $states['unexpected'][1];
              }
              else {
                $class = $states[$grant['state']][1];
              }
              $error_count += ($class == 'error');
              $row = (array) $row;
              foreach (array('view', 'update', 'delete') as $op) {
                $row["grant_$op"] = array('data' => $row["grant_$op"]);
                if ((isset($checked_grants[$grant['nid']][$op][$grant['realm']]) && in_array($grant['gid'], $checked_grants[$grant['nid']][$op][$grant['realm']]) || ($row['nid'] == 0 && $row['gid'] == 0 && $row['realm'] == 'all')) && !empty($row["grant_$op"]['data'])) {
                  $row["grant_$op"]['data'] .= '&prime;';
                  $row["grant_$op"]['title'] = t('This entry grants access to this node to this user.');
                }
                if (isset($grant["grant_$op!"])) {
                  $row["grant_$op"]['data'] = $grant["grant_$op!"] .'&gt;'. $row["grant_$op"]['data'];
                  $row["grant_$op"]['class'] = 'error';
                }
              }
              foreach (array('nid', 'priority', 'gid') as $key) {
                $row[$key] = array('data' => $row[$key], 'style' => 'text-align: right');
              }
              $row['nid']['title'] = $grant['#title'];
              $row['realm'] = (empty($grant['#module']) || strpos($grant['realm'], $grant['#module']) === 0 ? '' : $grant['#module'] .':<br />') . $grant['realm'];
              $rows[] = array('data' => array_values($row), 'class' => 'even '. $class);
            }
            $output = theme('table', $headers, $rows, array('class' => 'system-status-report', 'style' => 'text-align: left'));

            $output .= theme_item(array('#value' => '', '#description' => '(Some of the table elements provide additional information if you hover your mouse over them.)'));

            if ($error_count > 0) {
              $tokens['!Rebuild_permissions'] = '<a href="'. url('admin/content/node-settings/rebuild') .'">'. $tr('Rebuild permissions') .'</a>';
              $output .= theme_item(array('#value' => '<div class="error">'. t("You have errors in your !na table! You may be able to fix these for now by running !Rebuild_permissions, but this is likely to destroy the evidence and make it impossible to identify the underlying issues. If you don't fix those, the errors will probably come back again. <br /> DON'T do this just yet if you intend to ask for help with this situation.", $tokens) .'</div>'));
            }

            // Explain whether access is granted or denied, and why (using code from node_access()).
            $tr = 't';
            array_shift($nids);  // remove the 0
            $accounts = array();
            $variables['!username'] = theme('username', $user);

            if (user_access('administer nodes')) {
              $variables['%administer_nodes'] = $tr('administer nodes');
              $output .= t('!username has the %administer_nodes permission and thus full access to all nodes.', $variables) .'<br />&nbsp;';
            }
            else {
              $variables['!list'] = '<div style="margin-left: 2em">'. _devel_node_access_get_grant_list($nid, $checked_status, $checked_grants) .'</div>';
              $output .= "\n<div style='text-align: left' title='". t('These are the grants returned by hook_node_grants() for this user.') ."'>". t('!username can use these grants (if they are present above): !list', $variables) ."</div>\n";
              $accounts[] = $user;
            }
            if (arg(0) == 'node' && is_numeric(arg(1)) && !$block1_visible) {  // only for single nodes
              if (user_is_logged_in()) {
                $accounts[] = user_load(0);  // Anonymous, too
              }
              foreach ($accounts as $account) {
                $variables['!username'] = theme('username', $account);
                $output .= "\n<div style='text-align: left'>". t("!username has the following access", $variables) .' ';
                $nid_items = array();
                foreach ($nids as $nid) {
                  $op_items = array();
                  foreach (array('create', 'view', 'update', 'delete') as $op) {
                    $explain = _devel_node_access_explain_access($op, $nid, $account);
                    $op_items[] = "<div style='width: 5em; display: inline-block'>". t('%op:', array('%op' => $op)) .' </div>'. $explain[2];
                  }
                  $nid_items[] = t('to node !nid:', array('!nid' => l($nid, 'node/'. $nid)))
                    ."\n<div style='margin-left: 2em'>". theme('item_list', $op_items, NULL, 'ul') .'</div>';
                }
                if (count($nid_items) == 1) {
                  $output .= $nid_items[0];
                }
                else {
                  $output .= "\n<div style='margin-left: 2em'>". theme('item_list', $nid_items, NULL, 'ul') .'</div>';
                }
                $output .= "\n</div>\n";
              }
            }
          }

          if (!empty($hint)) {
            $output .= theme_item(array('#value' => '', '#description' => '('. $hint .')'));
          }
          $subject = t('node_access entries for nodes shown on this page');
          return array('subject' => $subject, 'content' => $output .'<br /><br />');

        case 1:
          // show which users can access this node
          if (arg(0) == 'node' && is_numeric(arg(1))) {
            $nid = arg(1);
            $node = node_load($nid);
            $headers = array(t('username'), '<span title="'. t("Create nodes of the '@Node_type' type.", array('@Node_type' => node_get_types('name', $node))) .'">'. t('create') .'</span>', t('view'), t('update'), t('delete'));
            $rows = array();
            // Find all users. The following operations are very inefficient, so we
            // limit the number of users returned.  It would be better to make a
            // pager query, or at least make the number of users configurable.  If
            // anyone is up for that please submit a patch.
            $result = db_query_range('SELECT DISTINCT u.* FROM {users} u ORDER BY u.access DESC', 0, 10);
            while ($data = db_fetch_object($result)) {
              $account = user_load($data->uid);
              $rows[] = array(theme('username', $data),
                              theme('dna_permission', _devel_node_access_explain_access('create', $nid, $account)),
                              theme('dna_permission', _devel_node_access_explain_access('view', $nid, $account)),
                              theme('dna_permission', _devel_node_access_explain_access('update', $nid, $account)),
                              theme('dna_permission', _devel_node_access_explain_access('delete', $nid, $account)),
              );
            }
            if (count($rows)) {
              $output = theme('table', $headers, $rows, array('style' => 'text-align: left'));
              $output .= theme_item(array('#value' => '', '#description' => t('(This table lists the most-recently active users. Hover your mouse over each result to see the reason for allowing or denying access.)')));
              return array('subject' => t('Access permissions by user'),
                           'content' => $output);
            }
          }
          break;
      }
      break;
  }
}
?>