forum_access.module in Forum Access 5
Same filename and directory in other branches
This module uses form_alter to add permissions and moderator settings to forums.
File
forum_access.moduleView source
<?php
/**
* @file forum_access.module
*
* This module uses form_alter to add permissions and moderator settings to
* forums.
*
*/
/**
* This function supplies the forum access grants. forum_access simply uses
* roles as ACLs, so rids translate directly to gids.
*/
function forum_access_node_grants($user, $op) {
$grants['forum_access'] = array_keys($user->roles);
return $grants;
}
/**
* Implementation of hook_node_access_records().
*
* Returns a list of grant records for the passed in node object.
* Checks to see if maybe we're being disabled.
*/
function forum_access_node_access_records($node) {
if (!forum_access_enabled()) {
return;
}
static $grants = array();
if ($node->type == 'forum') {
if (!isset($grants[$node->tid])) {
$result = db_query('SELECT * FROM {forum_access} WHERE tid = %d', $node->tid);
while ($grant = db_fetch_object($result)) {
$grants[$node->tid][] = array(
'realm' => 'forum_access',
'gid' => $grant->rid,
'grant_view' => $grant->grant_view,
'grant_update' => $grant->grant_update,
'grant_delete' => $grant->grant_delete,
'priority' => 0,
);
}
//drupal_set_message("forum_access_node_access_records($node->nid) (tid=$node->tid) returns ". var_export($grants[$node->tid], TRUE), 'status');
}
return $grants[$node->tid];
}
}
/**
* Implementation of hook_form_alter().
*
* Remove inaccessible forums from the node form.
*/
function forum_access_form_alter($form_id, &$form) {
if (isset($form['type']) && $form['type']['#value'] . '_node_form' == $form_id) {
forum_access_node_form($form_id, $form);
}
else {
if ($form_id == 'forum_form_container') {
forum_access_forum_form($form_id, $form, TRUE);
}
else {
if ($form_id == 'forum_form_forum') {
forum_access_forum_form($form_id, $form, FALSE);
}
else {
if ($form_id == 'user_admin_role') {
forum_access_user_admin_role_form($form_id, $form);
}
else {
if ($form_id == 'content_access_admin_settings') {
if (arg(3) == 'forum' && empty($_POST)) {
drupal_set_message(t('Note: In Drupal, access can only be granted, not taken away. Whatever access you grant here will not be reflected on the !Forum_Access settings, but !Forum_Access can only allow <i>more</i> access, not less.', array(
'!Forum_Access' => 'Forum Access',
)), 'error');
}
}
}
}
}
}
}
/**
* Rewrite the taxonomy item on the node form.
*/
function forum_access_node_form($form_id, &$form) {
if (!is_array($form['taxonomy'][_forum_get_vid()]['#options'])) {
return;
}
// forum administrators do NOT get their forms rewritten here.
if (user_access('administer forums')) {
return;
}
global $user;
$roles = _forum_access_get_roles($user);
$result = db_query("SELECT tid FROM {forum_access} WHERE rid IN (%s) AND grant_create = 1", $roles);
while ($obj = db_fetch_object($result)) {
$tids[$obj->tid] = $obj->tid;
}
// Also get all forums they happen to be able to moderate.
$result = db_query("SELECT a.name AS tid FROM {acl} a INNER JOIN {acl_user} u ON a.acl_id = u.acl_id WHERE a.module = 'forum_access' AND u.uid = %d", $user->uid);
while ($obj = db_fetch_object($result)) {
$tids[$obj->tid] = $obj->tid;
}
// Ensure the forum they're trying to post to directly is allowed, otherwise
// there will be much confusion.
$forum_tid = arg(3);
if (is_numeric($forum_tid) && $forum_tid && !$tids[$forum_tid]) {
drupal_access_denied();
module_invoke_all('exit');
exit;
}
foreach ($form['taxonomy'][_forum_get_vid()]['#options'] as $tid => $name) {
if (!is_numeric($tid)) {
$options[$tid] = $name;
}
elseif (is_object($name)) {
foreach ($name->option as $sub_tid => $sub_name) {
if ($tids[$sub_tid]) {
$options[$tid]->option[$sub_tid] = $sub_name;
}
}
}
elseif ($tids[$tid]) {
$options[$tid] = $name;
}
}
if ($options) {
$form['taxonomy'][_forum_get_vid()]['#options'] = $options;
}
else {
unset($form['taxonomy'][_forum_get_vid()]);
}
}
/**
* Rewrite the forum administration page with our new access rules.
*/
function forum_access_forum_form($form_id, &$form, $container) {
$rids = array();
$result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
while ($obj = db_fetch_object($result)) {
$rids[$obj->rid] = $obj->name;
}
if (isset($form['tid']['#value'])) {
// edit
$result = db_query("SELECT * FROM {forum_access} where tid=%d", $form['tid']['#value']);
while ($forum_access = db_fetch_object($result)) {
$row_received = TRUE;
if ($forum_access->grant_view) {
$view[] = $forum_access->rid;
}
if ($forum_access->grant_update) {
$update[] = $forum_access->rid;
}
if ($forum_access->grant_delete) {
$delete[] = $forum_access->rid;
}
if ($forum_access->grant_create) {
$create[] = $forum_access->rid;
}
}
if (!isset($row_received) && empty($form['#post'])) {
drupal_set_message(t('If you have only just installed !Forum_Access, then the posts in this forum may still be accessible, but once your permissions get rebuilt (intentionally or behind-the-scenes by some other module), they will vanish — so, be sure to set the desired Access Control below and save!', array(
'!Forum_Access' => 'Forum Access',
)), 'error');
}
}
else {
// create
// Default to all users can read; all logged in users can post.
$view = array(
1,
2,
);
$create = array(
2,
);
$update = $delete = array();
}
$form['forum_access'] = array(
'#type' => 'fieldset',
'#title' => t('Access control'),
'#collapsible' => TRUE,
'#tree' => TRUE,
);
$form['forum_access']['view'] = array(
'#type' => 'checkboxes',
'#prefix' => '<div class="forum-access-div">',
'#suffix' => '</div>',
'#options' => $rids,
'#title' => t('View this forum'),
'#default_value' => $view,
);
$form['forum_access']['create'] = array(
'#type' => 'checkboxes',
'#prefix' => '<div class="forum-access-div">',
'#suffix' => '</div>',
'#options' => $rids,
'#title' => t('Post in this forum'),
'#default_value' => $create,
);
// Containers do not contain any nodes, so these fields become meaningless for them.
if (!$container) {
$form['forum_access']['update'] = array(
'#type' => 'checkboxes',
'#prefix' => '<div class="forum-access-div">',
'#suffix' => '</div>',
'#options' => $rids,
'#title' => t('Edit posts'),
'#default_value' => $update,
);
$form['forum_access']['delete'] = array(
'#type' => 'checkboxes',
'#prefix' => '<div class="forum-access-div">',
'#suffix' => '</div>',
'#options' => $rids,
'#title' => t('Delete posts'),
'#default_value' => $delete,
);
}
// Find our moderator ACL:
$form['forum_access']['clearer'] = array(
'#value' => '<div class="forum-access-clearer"></div>',
);
drupal_add_css(drupal_get_path('module', 'forum_access') . '/forum_access.css');
if (isset($form['tid']['#value'])) {
// edit, not new
$acl_id = db_result(db_query("SELECT acl_id from {acl} WHERE module = 'forum_access' AND name = '%d'", $form['tid']['#value']));
if (!$acl_id) {
// create one
$acl_id = acl_create_new_acl('forum_access', $form['tid']['#value']);
// update every existing node in this forum to use this acl.
$result = db_query("SELECT nid FROM {term_node} WHERE tid = %d", $form['tid']['#value']);
while ($node = db_fetch_object($result)) {
// all privs to this ACL.
acl_node_add_acl($node->nid, $acl_id, 1, 1, 1);
}
}
$form['forum_access']['acl'] = acl_edit_form($acl_id, t('Moderators'));
}
$form['forum_access']['interference'] = array(
'#type' => 'fieldset',
'#title' => t('Module interference'),
'#collapsible' => TRUE,
'#attributes' => $is_conflict ? array(
'class' => 'error',
) : array(),
);
$variables = array(
'%content_type' => node_get_types('name', 'forum'),
'!Forum_Access' => 'Forum Access',
'!Content_Access' => 'Content Access',
'!button' => t('Rebuild permissions'),
);
if (module_exists('content_access')) {
$ca_settings = variable_get('content_access_settings', array());
foreach (array(
'view',
'update',
'delete',
'per_node',
) as $type) {
$value = content_access_get_settings($type, 'forum');
if (!empty($value)) {
$ca_interferes = TRUE;
}
}
$ca_priority = content_access_get_settings('priority', 'forum');
$fa_priority = 0;
$is_conflict = $ca_priority >= $fa_priority && !empty($ca_interferes);
$form['forum_access']['interference']['#attributes'] = $is_conflict ? array(
'class' => 'error',
) : array();
$variables['!link'] = l(t('!Content_Access configuration for the %content_type type', $variables), 'admin/content/types/forum/access', array(), NULL, NULL, FALSE, TRUE);
$specifically = $ca_priority == $fa_priority ? t('Specifically, any grants given by !Content_Access cannot be taken back by !Forum_Access.', $variables) : '';
if ($is_conflict) {
$form['forum_access']['interference'][] = array(
'#value' => '<p>' . t('You have set the !Content_Access module to control access to content of type %content_type—this can interfere with proper operation of !Forum_Access!', $variables) . " {$specifically}</p>",
);
if ($ca_priority == $fa_priority) {
$form['forum_access']['interference'][] = array(
'#value' => '<p>' . t("Unless you really know what you're doing, we recommend that you go to the !link page and clear all checkboxes.", $variables) . '</p>',
);
}
else {
$form['forum_access']['interference'][] = array(
'#value' => '<div>' . t("The priority of !Content_Access ({$ca_priority}) is higher than the priority of !Forum_Access ({$fa_priority}), which means the latter is <b>completely disabled</b> for the %content_type type! Unless you really know what you're doing, we recommend that you go to the !link page and clear all checkboxes and/or change the priorities.", $variables) . '</div>',
);
}
}
else {
$form['forum_access']['interference'][] = array(
'#value' => '<p>' . t('Note: You have installed the !Content_Access module, which has the capability to grant access to content that would otherwise be protected by !Forum_Access. Be careful when configuring !Content_Access!', $variables) . '</p>',
);
}
}
$variables['!link'] = l('admin/content/node-settings', 'admin/content/node-settings');
$form['forum_access']['interference'][] = array(
// This doesn't apply to D6!
'#value' => '<p>' . t("Note: If you have any other node access module installed besides !Forum_Access, and you've set that other module to use a grant priority (or 'weight') > 0 and to also control access to %content_type nodes, then you need to go to !link and click the [!button] button, <strong>after</strong> submitting this form. This is a limitation of Drupal 5 core. <br /> Be aware, however, that this may cause the !Forum_Access settings to be ignored in favor of that other modules' settings!", $variables) . '</p>',
);
// Move some stuff down so our block goes in a nice place.
$form['submit']['#weight'] = 10;
$form['delete']['#weight'] = 10;
$form['#submit']['forum_access_form_submit'] = current($form['#submit']);
}
function forum_access_form_submit($form_id, $form_values) {
db_query("DELETE FROM {forum_access} WHERE tid = %d", $form_values['tid']);
$access = $form_values['forum_access'];
// shortcut
if (array_key_exists('acl', $access)) {
acl_save_form($access['acl']);
}
foreach ($access['view'] as $rid => $checked) {
$grants[] = array(
'realm' => 'forum_access',
'gid' => $rid,
'grant_view' => (bool) $checked,
'grant_update' => !empty($access['update'][$rid]),
'grant_delete' => !empty($access['delete'][$rid]),
);
db_query("INSERT INTO {forum_access} (tid, rid, grant_view, grant_update, grant_delete, grant_create) VALUES (%d, %d, %d, %d, %d, %d)", $form_values['tid'], $rid, (bool) $checked, !empty($access['update'][$rid]), !empty($access['delete'][$rid]), !empty($access['create'][$rid]));
}
// mass update
$result = db_query("SELECT n.nid FROM {node} n LEFT JOIN {term_node} tn ON tn.nid = n.nid WHERE tn.tid = %d", $form_values['tid']);
while ($node = db_fetch_object($result)) {
node_access_write_grants($node, $grants, 'forum_access');
}
}
/**
* We must know when a role is deleted.
*/
function forum_access_user_admin_role_form($form_id, &$form) {
$form['#submit']['forum_access_user_admin_role_submit'] = array();
}
/**
* If a role is deleted, we remove the grants it provided.
*/
function forum_access_user_admin_role_submit($form, &$form_state) {
if ($form_state['op'] == $form_state['delete']) {
db_query("DELETE FROM {forum_access} WHERE rid = %d", $form_state['rid']);
db_query("DELETE FROM {node_access} WHERE gid = %d AND realm = 'forum_access'", $form_state['rid']);
}
}
/**
* Implementation of hook_db_rewrite_sql().
*
* Because in order to restrict the visible forums, we have to rewrite
* the sql. This is because there isn't a node_access equivalent for
* taxonomy. There should be.
*/
function forum_access_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
if ($primary_field == 'tid' && !user_access('administer forums')) {
global $user;
$roles = _forum_access_get_roles($user);
$sql['join'] = "LEFT JOIN {forum_access} fa ON {$primary_table}.tid = fa.tid\n LEFT JOIN {acl} acl_fa ON acl_fa.name = " . ($GLOBALS['db_type'] == 'pgsql' ? 'CAST(' : '') . "{$primary_table}.tid" . ($GLOBALS['db_type'] == 'pgsql' ? ' AS VARCHAR)' : '') . " AND acl_fa.module = 'forum_access'\n LEFT JOIN {acl_user} aclu_fa ON aclu_fa.acl_id = acl_fa.acl_id AND aclu_fa.uid = {$user->uid}";
$sql['where'] = "(fa.grant_view >= 1 AND fa.rid IN ({$roles})) OR fa.tid IS NULL OR aclu_fa.uid = {$user->uid}";
$sql['distinct'] = 1;
return $sql;
}
}
/**
* Implementation of hook_nodeapi().
*
* Add ACL data to fresh forum posts.
*/
function forum_access_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
static $old_tid = NULL;
if ($node && $node->type == 'forum') {
switch ($op) {
case 'prepare':
$old_tid = $node->tid;
break;
case 'update':
if ($node->tid == $old_tid) {
break;
}
$acl_id = db_result(db_query("SELECT acl_id from {acl} WHERE module = 'forum_access' AND name = '%d'", $old_tid));
acl_node_remove_acl($node->nid, $acl_id);
// fall through to 'insert' to enter the new tid...
case 'insert':
$acl_id = db_result(db_query("SELECT acl_id from {acl} WHERE module = 'forum_access' AND name = '%d'", $node->tid));
acl_node_add_acl($node->nid, $acl_id, 1, 1, 1);
$old_tid = NULL;
break;
}
}
}
/**
* Get an array of moderator UIDs or NULL.
*/
function forum_access_get_moderator_uids($tid) {
if ($acl_id = acl_get_id_by_name('forum_access', $tid)) {
if ($uids = acl_get_uids($acl_id)) {
return $uids;
}
}
}
/**
* Return a themed list of moderators for a given forum.
*/
function forum_access_moderator_list($tid) {
return theme('forum_access_moderator_list', forum_access_get_moderator_uids($tid));
}
/**
* Theme function for list of moderators.
*/
function theme_forum_access_moderator_list($moderators) {
static $users;
if (!empty($moderators)) {
$moderators_links = array();
foreach ($moderators as $uid) {
if (!isset($users[$uid])) {
$users[$uid] = user_load(array(
'uid' => $uid,
));
}
$moderators_links[] = theme('username', $users[$uid]);
}
$output = '<span class="moderator-list-title">' . format_plural(count($moderators_links), 'Moderator:', 'Moderators:') . ' </span>';
$moderators = implode(', ', $moderators_links);
$output .= '<span class="moderator-list-usernames">' . $moderators . '</span>';
$output = '<div class="moderator-list">' . $output . '</div>';
return $output;
}
else {
return '';
}
}
/**
* This is also required by ACL module.
*/
function forum_access_enabled($set = NULL) {
static $enabled = true;
if ($set !== NULL) {
$enabled = $set;
}
return $enabled;
}
/**
* Implementation of hook_enable().
*/
function forum_access_enable() {
node_access_rebuild();
}
/**
* Implementation of hook_disable().
*/
function forum_access_disable() {
forum_access_enabled(FALSE);
node_access_rebuild();
}
/**
* Implementation of hook_init().
*
* Deny access to forum if the user does not have access to it.
*/
function forum_access_init() {
if (!function_exists('user_access')) {
// page is cached; bail.
return;
}
if (!user_access('administer forums') && arg(0) == 'forum' && is_numeric(arg(1))) {
global $user;
if (!forum_access_access(arg(1), 'view')) {
drupal_access_denied();
module_invoke_all('exit');
exit;
}
}
}
/**
* See if a given user has access to a forum.
*
* $tid -- the tid of the forum
* $type -- view, update, delete or create
* $account -- the account to test for. If NULL use current user.
*/
function forum_access_access($tid, $type, $account = NULL) {
static $cache = array();
if (!$account) {
global $user;
$account = $user;
}
if (user_access('administer forums', $account)) {
return TRUE;
}
if (!isset($cache[$account->uid][$tid][$type])) {
$roles = _forum_access_get_roles($account);
$result = db_result(db_query("SELECT tid FROM {forum_access} WHERE rid IN (%s) AND grant_{$type} = 1 AND tid = %d", $roles, $tid));
if ($result) {
$cache[$account->uid][$tid][$type] = TRUE;
}
else {
// check our moderators too
$acl_id = db_result(db_query("SELECT acl_id from {acl} WHERE module = 'forum_access' AND name = '%d'", $tid));
$result = db_result(db_query("SELECT uid FROM {acl_user} WHERE acl_id = %d AND uid = %d", $acl_id, $account->uid));
if ($result) {
$cache[$account->uid][$tid][$type] = TRUE;
}
else {
$cache[$account->uid][$tid][$type] = FALSE;
}
}
}
return $cache[$account->uid][$tid][$type];
}
/**
* Get the roles of a user.
*/
function _forum_access_get_roles($user) {
return implode(', ', array_keys($user->roles));
}
/**
* Implementation of hook_node_access_explain().
*/
function forum_access_node_access_explain($row) {
static $roles = NULL;
if ($row->realm == 'forum_access') {
if (!isset($roles)) {
$roles = user_roles();
}
if (isset($roles[$row->gid])) {
return array(
$roles[$row->gid],
);
}
return array(
'(unknown gid)',
);
}
}
Functions
Name | Description |
---|---|
forum_access_access | See if a given user has access to a forum. |
forum_access_db_rewrite_sql | Implementation of hook_db_rewrite_sql(). |
forum_access_disable | Implementation of hook_disable(). |
forum_access_enable | Implementation of hook_enable(). |
forum_access_enabled | This is also required by ACL module. |
forum_access_form_alter | Implementation of hook_form_alter(). |
forum_access_form_submit | |
forum_access_forum_form | Rewrite the forum administration page with our new access rules. |
forum_access_get_moderator_uids | Get an array of moderator UIDs or NULL. |
forum_access_init | Implementation of hook_init(). |
forum_access_moderator_list | Return a themed list of moderators for a given forum. |
forum_access_nodeapi | Implementation of hook_nodeapi(). |
forum_access_node_access_explain | Implementation of hook_node_access_explain(). |
forum_access_node_access_records | Implementation of hook_node_access_records(). |
forum_access_node_form | Rewrite the taxonomy item on the node form. |
forum_access_node_grants | This function supplies the forum access grants. forum_access simply uses roles as ACLs, so rids translate directly to gids. |
forum_access_user_admin_role_form | We must know when a role is deleted. |
forum_access_user_admin_role_submit | If a role is deleted, we remove the grants it provided. |
theme_forum_access_moderator_list | Theme function for list of moderators. |
_forum_access_get_roles | Get the roles of a user. |