function devel_node_access_block

File

./devel_node_access.module, line 216

Code

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="@link">block</a>.', array(
                '@link' => 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(
                                '<a href="#node-' . $row->nid . '">' . _devel_node_access_get_node_title($row, TRUE) . '</a>',
                                $row->realm,
                                $row->gid,
                                $row->grant_view,
                                $row->grant_update,
                                $row->grant_delete,
                                implode('<br />', $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';
                        $variables = 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.', $variables),
                            ),
                            'ok' => array(
                                t('ok'),
                                'ok',
                                t('Highest priority grant, in !na.', $variables),
                            ),
                            'static' => array(
                                t('static'),
                                'ok',
                                t('Non-standard grant in !na.', $variables),
                            ),
                            '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.', $variables),
                            ),
                            'empty' => array(
                                t('empty'),
                                'warning',
                                t('Does not grant any access, but could block lower priority grants; not in !na.', $variables),
                            ),
                            'missing' => array(
                                t('missing'),
                                'error',
                                t("Should be in !na but isn't!", $variables),
                            ),
                            'illegitimate' => array(
                                t('illegitimate'),
                                'error',
                                t('Should NOT be in !na because of lower priority!', $variables),
                            ),
                            'alien' => array(
                                t('alien'),
                                'error',
                                t('Should NOT be in !na because of unknown origin!', $variables),
                            ),
                        );
                        $active_states = array(
                            'default',
                            'ok',
                            'static',
                            'unexpected',
                            'illegitimate',
                            'alien',
                        );
                        $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) {
                                    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()
                            if (isset($active_grants[$nid])) {
                                foreach ($active_grants[$nid] as $realm => $active_grants_realm) {
                                    foreach ($active_grants_realm as $gid => $active_grant) {
                                        $found = FALSE;
                                        $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']);
                                                }
                                            }
                                        }
                                        $fixed_grant = (array) $active_grant;
                                        if ($count_nonempty_grants == 0 && $realm == 'all' && $gid == 0) {
                                            $fixed_grant += array(
                                                'priority' => '&ndash;',
                                                'state' => 'default',
                                            );
                                        }
                                        elseif (!$found) {
                                            $acknowledged = _devel_node_access_module_invoke_all('node_access_acknowledge', $fixed_grant);
                                            if (empty($acknowledged)) {
                                                // no one acknowledged this record, mark it as alien:
                                                $fixed_grant += array(
                                                    'priority' => '?',
                                                    'state' => 'alien',
                                                );
                                            }
                                            else {
                                                // at least one module acknowledged the record, attribute it to the first one:
                                                $fixed_grant += array(
                                                    'priority' => '&ndash;',
                                                    'state' => 'static',
                                                    '#module' => reset(array_keys($acknowledged)),
                                                );
                                            }
                                        }
                                        else {
                                            continue;
                                        }
                                        $fixed_grant += array(
                                            'nid' => $nid,
                                            '#title' => _devel_node_access_get_node_title($node),
                                        );
                                        $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('<br />', module_invoke_all('node_access_explain', $row));
                            unset($row->title);
                            // possibly needed above
                            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']) && in_array($grant['state'], $active_states)) {
                                    $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'] ? 0 : $row["grant_{$op}"]['data']);
                                    $row["grant_{$op}"]['class'] = 'error';
                                }
                            }
                            $row['nid'] = '<a href="#node-' . $grant['nid'] . '">' . $row['nid'] . '</a>';
                            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) {
                            $variables['!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.", $variables) . '</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();
                        if (!isset($user->name)) {
                            $user->name = '';
                        }
                        $variables += array(
                            '!username' => theme('username', $user),
                            '%uid' => $user->uid,
                        );
                        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>';
                            $variables['%access'] = 'view';
                            $output .= "\n<div style='text-align: left' title='" . t('These are the grants returned by hook_node_grants() for this user.') . "'>" . t('!username (user %uid) can use these grants for %access access (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($nid = arg(1)) && arg(2) == null && ($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.uid, u.*, (u.uid <> 0) AS authorized FROM {users} u ORDER BY authorized ASC, u.access DESC', 0, 10);
                        while ($data = db_fetch_object($result)) {
                            $account = user_load($data->uid);
                            $username = theme('username', $data);
                            if ($account->uid == $user->uid) {
                                $username = '<strong>' . $username . '</strong>';
                            }
                            $rows[] = array(
                                $username,
                                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 for more details.)'),
                            ));
                            return array(
                                'subject' => t('Access permissions by user'),
                                'content' => $output,
                            );
                        }
                    }
                    break;
            }
            break;
    }
}