View source
<?php
define('TAXONOMY_ACCESS_MAX_UPDATE', 500);
define('TAXONOMY_ACCESS_CONFIG', 'admin/config/people/taxonomy_access');
define('TAXONOMY_ACCESS_GLOBAL_DEFAULT', 0);
define('TAXONOMY_ACCESS_VOCABULARY_DEFAULT', 0);
define('TAXONOMY_ACCESS_NODE_ALLOW', 1);
define('TAXONOMY_ACCESS_NODE_IGNORE', 0);
define('TAXONOMY_ACCESS_NODE_DENY', 2);
define('TAXONOMY_ACCESS_TERM_ALLOW', 1);
define('TAXONOMY_ACCESS_TERM_DENY', 0);
function _taxonomy_access_user_roles($permission = NULL) {
$roles =& drupal_static(__FUNCTION__, array());
if (!isset($roles[$permission])) {
$roles[$permission] = user_roles(FALSE, $permission);
}
return $roles[$permission];
}
function taxonomy_access_init() {
$path = drupal_get_path('module', 'taxonomy_access');
drupal_add_css($path . '/taxonomy_access.css');
drupal_register_shutdown_function('taxonomy_access_shutdown');
}
function taxonomy_access_theme() {
return array(
'taxonomy_access_admin_form' => array(
'render element' => 'form',
'file' => 'taxonomy_access.admin.inc',
),
'taxonomy_access_grant_table' => array(
'render element' => 'elements',
'file' => 'taxonomy_access.admin.inc',
),
);
}
function taxonomy_access_element_info() {
return array(
'taxonomy_access_grant_table' => array(
'#theme' => 'taxonomy_access_grant_table',
'#regions' => array(
'' => array(),
),
),
);
}
function taxonomy_access_menu() {
$items = array();
$items[TAXONOMY_ACCESS_CONFIG] = array(
'title' => 'Taxonomy access control',
'description' => 'Taxonomy-based access control for content',
'page callback' => 'taxonomy_access_admin',
'access arguments' => array(
'administer permissions',
),
'file' => 'taxonomy_access.admin.inc',
);
$items[TAXONOMY_ACCESS_CONFIG . '/role'] = array(
'title' => 'Configure role access rules',
'description' => 'Configure taxonomy access control',
'page callback' => 'taxonomy_access_admin',
'access arguments' => array(
'administer permissions',
),
'file' => 'taxonomy_access.admin.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items[TAXONOMY_ACCESS_CONFIG . '/role/%/edit'] = array(
'title callback' => 'taxonomy_access_role_edit_title',
'title arguments' => array(
5,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'taxonomy_access_admin_role',
5,
),
'access callback' => 'taxonomy_access_role_edit_access',
'access arguments' => array(
5,
),
'file' => 'taxonomy_access.admin.inc',
);
$items[TAXONOMY_ACCESS_CONFIG . '/role/%/enable'] = array(
'page callback' => 'taxonomy_access_enable_role_validate',
'page arguments' => array(
5,
),
'access arguments' => array(
'administer permissions',
),
'file' => 'taxonomy_access.admin.inc',
);
$items[TAXONOMY_ACCESS_CONFIG . '/role/%/delete'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array(
'taxonomy_access_role_delete_confirm',
5,
),
'access callback' => 'taxonomy_access_role_delete_access',
'access arguments' => array(
5,
),
'file' => 'taxonomy_access.admin.inc',
'type' => MENU_CALLBACK,
);
$items[TAXONOMY_ACCESS_CONFIG . '/role/%/disable/%taxonomy_vocabulary'] = array(
'page callback' => 'taxonomy_access_disable_vocab_confirm_page',
'page arguments' => array(
5,
7,
),
'access arguments' => array(
'administer permissions',
),
'file' => 'taxonomy_access.admin.inc',
'type' => MENU_CALLBACK,
);
$items['taxonomy_access/autocomplete'] = array(
'title' => 'Autocomplete taxonomy',
'page callback' => 'taxonomy_access_autocomplete',
'access arguments' => array(
'access content',
),
'type' => MENU_CALLBACK,
'file' => 'taxonomy_access.create.inc',
);
return $items;
}
function taxonomy_access_role_edit_title($rid) {
$roles = _taxonomy_access_user_roles();
return t('Access rules for @role', array(
'@role' => $roles[$rid],
));
}
function taxonomy_access_role_edit_access($rid) {
if (!user_access('administer permissions')) {
return FALSE;
}
$roles = _taxonomy_access_user_roles();
if (empty($roles[$rid])) {
return FALSE;
}
return TRUE;
}
function taxonomy_access_role_delete_access($rid) {
if (!user_access('administer permissions')) {
return FALSE;
}
if ($rid == DRUPAL_ANONYMOUS_RID || $rid == DRUPAL_AUTHENTICATED_RID) {
return FALSE;
}
$roles = _taxonomy_access_user_roles();
if (empty($roles[$rid])) {
return FALSE;
}
return TRUE;
}
function taxonomy_access_user_role_delete($role) {
taxonomy_access_delete_role_grants($role->rid, FALSE);
}
function taxonomy_access_taxonomy_vocabulary_delete($vocab) {
taxonomy_access_delete_default_grants($vocab->vid);
}
function taxonomy_access_taxonomy_term_delete($term) {
taxonomy_access_delete_term_grants($term->tid);
}
function taxonomy_access_node_grants($user, $op) {
$roles = is_array($user->roles) ? array_keys($user->roles) : -1;
return array(
'taxonomy_access_role' => $roles,
);
}
function taxonomy_access_node_access_records($node) {
if ($node->status) {
return _taxonomy_access_node_access_records($node->nid, TRUE);
}
}
function taxonomy_access_field_info_alter(&$info) {
if (empty($info['taxonomy_term_reference'])) {
return;
}
$info['taxonomy_term_reference']['settings']['options_list_callback'] = '_taxonomy_access_term_options';
}
function taxonomy_access_field_attach_validate($entity_type, $entity, &$errors) {
module_load_include('inc', 'taxonomy_access', 'taxonomy_access.create');
_taxonomy_access_field_validate($entity_type, $entity, $errors);
}
function taxonomy_access_query_term_access_alter($query) {
if (!taxonomy_access_list_enabled()) {
return;
}
$alias = '';
$tables =& $query
->getTables();
foreach ($tables as $i => $table) {
if (strpos($table['table'], 'taxonomy_term_') === 0) {
$alias = $table['alias'];
}
}
if (empty($alias)) {
return;
}
$tids =& drupal_static(__FUNCTION__, taxonomy_access_user_list_terms());
if ($tids === TRUE) {
return;
}
if (empty($tids)) {
$query
->isNull($alias . ".tid");
}
else {
$query
->condition($alias . ".tid", $tids, "IN");
}
}
function taxonomy_access_field_widget_taxonomy_autocomplete_form_alter(&$element, &$form_state, $context) {
taxonomy_access_disable_list();
module_load_include('inc', 'taxonomy_access', 'taxonomy_access.create');
_taxonomy_access_autocomplete_alter($element, $form_state, $context);
taxonomy_access_enable_list();
}
function taxonomy_access_field_widget_form_alter(&$element, &$form_state, $context) {
if ($context['field']['type'] != 'taxonomy_term_reference') {
return;
}
$widget = $context['instance']['widget']['type'];
if (!in_array($widget, array(
'options_buttons',
'options_select',
))) {
return;
}
taxonomy_access_disable_list();
module_load_include('inc', 'taxonomy_access', 'taxonomy_access.create');
_taxonomy_access_options_alter($element, $form_state, $context);
taxonomy_access_enable_list();
}
function taxonomy_access_enable_role($rid) {
$rid = intval($rid);
if (!$rid || taxonomy_access_role_enabled($rid)) {
return FALSE;
}
$row = new stdClass();
$row->vid = TAXONOMY_ACCESS_GLOBAL_DEFAULT;
$row->rid = $rid;
return drupal_write_record('taxonomy_access_default', $row);
}
function taxonomy_access_role_enabled($rid) {
$role_status =& drupal_static(__FUNCTION__, array());
if (!isset($role_status[$rid])) {
$role_status[$rid] = db_query('SELECT 1
FROM {taxonomy_access_default}
WHERE rid = :rid AND vid = :vid', array(
':rid' => $rid,
':vid' => TAXONOMY_ACCESS_GLOBAL_DEFAULT,
))
->fetchField();
}
return (bool) $role_status[$rid];
}
function taxonomy_access_enable_vocab($vid, $rid) {
$rid = intval($rid);
$vid = intval($vid);
if (!$rid || !$vid) {
return FALSE;
}
$vocab_status = db_query('SELECT 1
FROM {taxonomy_access_default}
WHERE rid = :rid AND vid = :vid', array(
':rid' => $rid,
':vid' => $vid,
))
->fetchField();
if ($vocab_status) {
return FALSE;
}
$global_default = db_query('SELECT grant_view, grant_update, grant_delete, grant_create, grant_list
FROM {taxonomy_access_default}
WHERE vid = :vid AND rid = :rid', array(
':rid' => $rid,
':vid' => TAXONOMY_ACCESS_GLOBAL_DEFAULT,
))
->fetchAssoc();
$record = _taxonomy_access_format_grant_record($vid, $rid, $global_default, TRUE);
return taxonomy_access_set_default_grants(array(
$vid => $record,
));
}
function taxonomy_access_disable_vocab($vid, $rid) {
$rid = intval($rid);
$vid = intval($vid);
if (!$vid || !$rid) {
return FALSE;
}
taxonomy_access_delete_default_grants($vid, $rid);
$tids = db_query("SELECT ta.tid\n FROM {taxonomy_access_term} ta\n INNER JOIN {taxonomy_term_data} td ON ta.tid = td.tid\n WHERE td.vid = :vid AND ta.rid = :rid", array(
':vid' => $vid,
':rid' => $rid,
))
->fetchCol();
taxonomy_access_delete_term_grants($tids, $rid);
return TRUE;
}
function taxonomy_access_shutdown() {
$affected_nodes = taxonomy_access_affected_nodes();
if (!empty($affected_nodes)) {
taxonomy_access_affected_nodes(NULL, TRUE);
_taxonomy_access_node_access_update($affected_nodes);
}
}
function _taxonomy_access_flag_rebuild() {
drupal_set_message(t("Taxonomy Access Control is updating node access... If you see a message that content access permissions need to be rebuilt, you may wait until after you have completed your configuration changes."), 'status');
node_access_needs_rebuild(TRUE);
}
function _taxonomy_access_node_access_update(array $nids) {
if (!node_access_needs_rebuild()) {
_taxonomy_access_flag_rebuild();
$nids = array_unique($nids);
if (sizeof($nids) < TAXONOMY_ACCESS_MAX_UPDATE) {
foreach ($nids as $node) {
$loaded_node = node_load($node, NULL, TRUE);
if (!empty($loaded_node)) {
node_access_acquire_grants($loaded_node);
}
}
node_access_needs_rebuild(FALSE);
}
}
return TRUE;
}
function taxonomy_access_affected_nodes(array $affected_nodes = NULL, $reset = FALSE) {
static $nodes = array();
if (!empty($nodes)) {
if (node_access_needs_rebuild() || $reset) {
$nodes = array();
return;
}
}
if (isset($affected_nodes)) {
$nodes = array_unique(array_merge($nodes, $affected_nodes));
if (sizeof($nodes) >= TAXONOMY_ACCESS_MAX_UPDATE) {
_taxonomy_access_flag_rebuild();
unset($nodes);
}
}
else {
return $nodes;
}
}
function _taxonomy_access_get_controlled_nodes_for_role($rid) {
$query = db_select('taxonomy_index', 'ti')
->fields('ti', array(
'nid',
))
->addTag('taxonomy_access_node');
$query
->leftJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid');
$query
->leftJoin('taxonomy_access_term', 'ta', 'ti.tid = ta.tid');
$query
->leftJoin('taxonomy_access_default', 'tad', 'tad.vid = td.vid');
$query
->condition(db_or()
->condition('ta.rid', $rid)
->condition('tad.rid', $rid));
$nids = $query
->execute()
->fetchCol();
return $nids;
}
function _taxonomy_access_get_nodes_for_global_default($rid) {
$tids = _taxonomy_access_global_controlled_terms($rid);
$query = db_select('node', 'n')
->fields('n', array(
'nid',
))
->addTag('taxonomy_access_node');
if (!empty($tids)) {
$query
->leftJoin('taxonomy_index', 'ti', 'ti.nid = n.nid');
$query
->condition(db_or()
->condition('ti.tid', $tids, 'NOT IN')
->isNull('ti.tid'));
}
$nids = $query
->execute()
->fetchCol();
return $nids;
}
function _taxonomy_access_get_nodes_for_defaults($vocab_ids, $rid = NULL) {
if (is_numeric($vocab_ids)) {
$vocab_ids = array(
$vocab_ids,
);
}
if (empty($vocab_ids)) {
return FALSE;
}
if (!empty($rid)) {
$tids = _taxonomy_access_vocab_controlled_terms($vocab_ids, $rid);
}
$query = db_select('taxonomy_index', 'ti')
->condition('td.vid', $vocab_ids)
->fields('ti', array(
'nid',
))
->addTag('taxonomy_access_node');
$query
->join('taxonomy_term_data', 'td', 'td.tid = ti.tid');
if (!empty($tids)) {
$query
->condition('ti.tid', $tids, 'NOT IN');
}
$nids = $query
->execute()
->fetchCol();
unset($tids);
unset($query);
if (in_array(TAXONOMY_ACCESS_GLOBAL_DEFAULT, $vocab_ids)) {
$nids = array_merge($nids, _taxonomy_access_get_nodes_for_global_default($rid));
}
return $nids;
}
function _taxonomy_access_global_controlled_terms($rid) {
$tids = db_query("SELECT td.tid\n FROM {taxonomy_term_data} td\n LEFT JOIN {taxonomy_access_term} ta ON td.tid = ta.tid\n LEFT JOIN {taxonomy_access_default} tad ON td.vid = tad.vid\n WHERE ta.rid = :rid OR tad.rid = :rid", array(
':rid' => $rid,
))
->fetchCol();
return $tids;
}
function _taxonomy_access_vocab_controlled_terms($vids, $rid) {
if (is_numeric($vids)) {
$vids = array(
$vids,
);
}
$tids = db_query("SELECT td.tid\n FROM {taxonomy_term_data} td\n INNER JOIN {taxonomy_access_term} ta ON td.tid = ta.tid\n WHERE ta.rid = :rid\n AND td.vid IN (:vids)", array(
':rid' => $rid,
':vids' => $vids,
))
->fetchCol();
return $tids;
}
function _taxonomy_access_get_nodes_for_terms($term_ids) {
if (empty($term_ids)) {
return FALSE;
}
$nids = db_select('taxonomy_index', 'ti')
->condition('ti.tid', $term_ids)
->fields('ti', array(
'nid',
))
->addTag('taxonomy_access_node')
->execute()
->fetchCol();
unset($term_ids);
return $nids;
}
function _taxonomy_access_get_descendants($tid) {
$descendants =& drupal_static(__FUNCTION__, array());
if (!isset($descendants[$tid])) {
$flag_state = taxonomy_access_list_enabled();
taxonomy_access_disable_list();
$descendants[$tid] = array();
$term = taxonomy_term_load($tid);
$tree = taxonomy_get_tree($term->vid, $tid);
foreach ($tree as $term) {
$descendants[$tid][] = $term->tid;
}
if ($flag_state) {
taxonomy_access_enable_list();
}
unset($term);
unset($tree);
}
return $descendants[$tid];
}
function _taxonomy_access_get_vocabulary_terms($vocab_id) {
static $descendants = array();
if (!isset($descendants[$vocab_id])) {
$flag_state = taxonomy_access_list_enabled();
taxonomy_access_disable_list();
$descendants[$vocab_id] = array();
$tree = taxonomy_get_tree($vocab_id);
foreach ($tree as $term) {
$descendants[$vocab_id][] = $term->tid;
}
if ($flag_state) {
taxonomy_access_enable_list();
}
unset($term);
unset($tree);
}
return $descendants[$vocab_id];
}
function taxonomy_access_delete_role_grants($rid, $update_nodes = TRUE) {
if (empty($rid)) {
return FALSE;
}
if ($rid == DRUPAL_ANONYMOUS_RID || $rid == DRUPAL_AUTHENTICATED_RID) {
return FALSE;
}
if ($update_nodes) {
$global_defaults = taxonomy_access_global_defaults();
$gd_records = array();
foreach ($global_defaults as $row) {
$gd_records[] = _taxonomy_access_format_node_access_record($row);
}
foreach ($gd_records as $gd) {
if ($gd['gid'] == DRUPAL_AUTHENTICATED_RID) {
$auth_gd = $gd;
}
elseif ($gd['gid'] == $rid) {
$role_gd = $gd;
}
}
$all_nodes = FALSE;
foreach (array(
'grant_view',
'grant_update',
'grant_delete',
) as $op) {
switch ($auth_gd[$op]) {
case TAXONOMY_ACCESS_NODE_DENY:
if ($role_gd[$op] == TAXONOMY_ACCESS_NODE_IGNORE || $role_gd[$op] == TAXONOMY_ACCESS_NODE_ALLOW) {
$all_nodes = TRUE;
}
break 2;
case TAXONOMY_ACCESS_NODE_IGNORE:
if ($role_gd[$op] == TAXONOMY_ACCESS_NODE_ALLOW) {
$all_nodes = TRUE;
}
break 2;
}
}
if ($all_nodes) {
$affected_nodes = db_query('SELECT nid FROM {node}')
->fetchCol();
}
else {
$affected_nodes = _taxonomy_access_get_controlled_nodes_for_role($rid);
}
taxonomy_access_affected_nodes($affected_nodes);
unset($affected_nodes);
}
db_delete('taxonomy_access_term')
->condition('rid', $rid)
->execute();
db_delete('taxonomy_access_default')
->condition('rid', $rid)
->execute();
return TRUE;
}
function taxonomy_access_delete_default_grants($vocab_ids, $rid = NULL, $update_nodes = TRUE) {
if ($vocab_ids !== TAXONOMY_ACCESS_GLOBAL_DEFAULT && empty($vocab_ids)) {
return FALSE;
}
if ($update_nodes) {
$affected_nodes = _taxonomy_access_get_nodes_for_defaults($vocab_ids, $rid);
taxonomy_access_affected_nodes($affected_nodes);
unset($affected_nodes);
}
$query = db_delete('taxonomy_access_default')
->condition('vid', $vocab_ids);
if (!empty($rid)) {
$query
->condition('rid', $rid);
}
$query
->execute();
unset($query);
return TRUE;
}
function taxonomy_access_delete_term_grants($term_ids, $rid = NULL, $update_nodes = TRUE) {
if (is_numeric($term_ids)) {
$term_ids = array(
$term_ids,
);
}
if (empty($term_ids)) {
return FALSE;
}
if ($update_nodes) {
$affected_nodes = _taxonomy_access_get_nodes_for_terms($term_ids);
taxonomy_access_affected_nodes($affected_nodes);
unset($affected_nodes);
}
$query = db_delete('taxonomy_access_term')
->condition('tid', $term_ids);
if (!empty($rid)) {
$query
->condition('rid', $rid);
}
$query
->execute();
unset($term_ids);
unset($query);
return TRUE;
}
function _taxonomy_access_format_grant_record($id, $rid, array $grants, $default = FALSE) {
$row = new stdClass();
if ($default) {
$row->vid = $id;
}
else {
$row->tid = $id;
}
$row->rid = $rid;
foreach ($grants as $op => $value) {
if (is_numeric($value)) {
$grant_name = strpos($op, 'grant_') ? $op : "grant_{$op}";
$row->{$grant_name} = $value;
}
}
return $row;
}
function taxonomy_access_set_term_grants(array $grant_rows, $update_nodes = TRUE) {
$terms_for_roles = array();
foreach ($grant_rows as $grant_row) {
$terms_for_roles[$grant_row->rid][] = $grant_row->tid;
}
foreach ($terms_for_roles as $rid => $tids) {
taxonomy_access_delete_term_grants($tids, $rid, $update_nodes);
}
foreach ($grant_rows as $row) {
drupal_write_record('taxonomy_access_term', $row);
}
return TRUE;
}
function taxonomy_access_set_default_grants(array $grant_rows, $update_nodes = TRUE) {
$vocabs_for_roles = array();
foreach ($grant_rows as $grant_row) {
$vocabs_for_roles[$grant_row->rid][] = $grant_row->vid;
}
foreach ($vocabs_for_roles as $rid => $vids) {
taxonomy_access_delete_default_grants($vids, $rid, $update_nodes);
}
foreach ($grant_rows as $row) {
drupal_write_record('taxonomy_access_default', $row);
}
return TRUE;
}
function _taxonomy_access_grant_query(array $grants, $default = FALSE) {
$table = $default ? 'taxonomy_vocabulary' : 'taxonomy_term_data';
$query = db_select($table, 'td')
->addTag('taxonomy_access')
->addTag('taxonomy_access_grants');
$query
->join('taxonomy_access_default', 'tadg', 'tadg.vid = :vid', array(
':vid' => TAXONOMY_ACCESS_GLOBAL_DEFAULT,
));
$query
->leftJoin('taxonomy_access_default', 'tad', 'tad.vid = td.vid AND tad.rid = tadg.rid');
if (!$default) {
$query
->leftJoin('taxonomy_access_term', 'ta', 'ta.tid = td.tid AND ta.rid = tadg.rid');
}
$grant_fields = array(
'view' => 'grant_view',
'update' => 'grant_update',
'delete' => 'grant_delete',
'create' => 'grant_create',
'list' => 'grant_list',
);
foreach ($grant_fields as $name => $grant) {
if (in_array($name, $grants)) {
if ($default) {
$query
->addExpression('BIT_OR(COALESCE(' . 'tad.' . db_escape_table($grant) . ', ' . 'tadg.' . db_escape_table($grant) . '))', $grant);
}
else {
$query
->addExpression('BIT_OR(COALESCE(' . 'ta.' . db_escape_table($grant) . ', ' . 'tad.' . db_escape_table($grant) . ', ' . 'tadg.' . db_escape_table($grant) . '))', $grant);
}
}
}
return $query;
}
function _taxonomy_access_node_access_records($node_nid, $reset = FALSE) {
$query = _taxonomy_access_grant_query(array(
'view',
'update',
'delete',
));
$query
->join('taxonomy_index', 'ti', 'td.tid = ti.tid');
$query
->fields('tadg', array(
'rid',
))
->condition('ti.nid', $node_nid)
->groupBy('tadg.rid')
->addTag('taxonomy_access_node_access')
->addTag('taxonomy_access_node');
$grants = array();
$records = $query
->execute()
->fetchAll();
if (sizeof($records) == 0) {
$records = taxonomy_access_global_defaults($reset);
}
foreach ($records as $record) {
$grants[] = _taxonomy_access_format_node_access_record($record);
}
return $grants;
}
function taxonomy_access_global_defaults($reset = FALSE) {
$global_grants =& drupal_static(__FUNCTION__, array());
if (empty($global_grants) || $reset) {
$global_grants = db_query('SELECT rid, grant_view, grant_update, grant_delete, grant_create,
grant_list
FROM {taxonomy_access_default}
WHERE vid = :vid', array(
':vid' => TAXONOMY_ACCESS_GLOBAL_DEFAULT,
))
->fetchAllAssoc('rid');
}
return $global_grants;
}
function _taxonomy_access_format_node_access_record(stdClass $record) {
return array(
'realm' => 'taxonomy_access_role',
'gid' => $record->rid,
'grant_view' => $record->grant_view == 1 ? 1 : 0,
'grant_update' => $record->grant_update == 1 ? 1 : 0,
'grant_delete' => $record->grant_delete == 1 ? 1 : 0,
'priority' => 0,
);
}
function _taxonomy_access_list_state($set_flag = NULL) {
static $flag = TRUE;
if (is_null($set_flag)) {
return $flag;
}
$flag = $set_flag ? TRUE : FALSE;
}
function taxonomy_access_enable_list() {
_taxonomy_access_list_state(TRUE);
}
function taxonomy_access_disable_list() {
_taxonomy_access_list_state(FALSE);
}
function taxonomy_access_list_enabled() {
return _taxonomy_access_list_state();
}
function taxonomy_access_user_list_terms() {
static $terms = NULL;
if (is_null($terms)) {
$terms = _taxonomy_access_user_term_grants(FALSE);
}
return $terms;
}
function _taxonomy_access_user_term_grants($create = FALSE, array $vids = array(), $account = NULL) {
$grant_type = $create ? 'create' : 'list';
$grant_field_name = 'grant_' . $grant_type;
if (is_null($account)) {
global $user;
$account = $user;
}
if (user_access('administer taxonomy', $account)) {
return TRUE;
}
$query = _taxonomy_access_grant_query(array(
$grant_type,
));
$query
->fields('td', array(
'tid',
))
->groupBy('td.tid')
->condition('tadg.rid', array_keys($account->roles), 'IN');
if (!empty($vids)) {
$query
->fields('td', array(
'vid',
))
->condition('td.vid', $vids, 'IN');
}
$r = $query
->execute()
->fetchAll();
$tids = array();
$grants_for_all_terms = empty($r) ? FALSE : TRUE;
foreach ($r as $record) {
if ($record->{$grant_field_name}) {
$tids[] = $record->tid;
}
else {
$grants_for_all_terms = FALSE;
}
}
if ($grants_for_all_terms) {
return TRUE;
}
return $tids;
}
function _taxonomy_access_term_options($field) {
$flag_state = taxonomy_access_list_enabled();
taxonomy_access_disable_list();
$options = taxonomy_allowed_values($field);
if ($flag_state) {
taxonomy_access_enable_list();
}
return $options;
}
function taxonomy_access_autocomplete_validate($element, &$form_state) {
taxonomy_access_disable_list();
module_load_include('inc', 'taxonomy_access', 'taxonomy_access.create');
_taxonomy_access_autocomplete_validate($element, $form_state);
}
function taxonomy_access_options_validate($element, &$form_state) {
taxonomy_access_disable_list();
module_load_include('inc', 'taxonomy_access', 'taxonomy_access.create');
_taxonomy_access_options_validate($element, $form_state);
}
function taxonomy_access_help($path, $arg) {
switch ($path) {
case 'admin/help#taxonomy_access':
$message = '';
$message .= '' . '<p>' . t('The Taxonomy Access Control module allows users to specify how each category can be used by various roles.') . '</p>' . '<p>' . t('Permissions can be set differently for each user role. Be aware that setting Taxonomy Access permissions works <em>only within one user role</em>.') . '</p>' . '<p>' . t('(For users with multiple user roles, see section <a href="#good-to-know">Good to know</a> below.)') . '</p><hr /><br />' . "<h3>" . t("On this page") . "</h3>" . "<ol>" . '<li><a href="#grant">' . t("Grant types") . '</a></li>' . '<li><a href="#perm">' . t("Permission options") . '</a></li>' . '<li><a href="#defaults">' . t("Global and vocabulary defaults") . '</a></li>' . '<li><a href="#good-to-know">' . t("Good to know") . '</a></li>' . "</ol><hr /><br />" . '<h3 id="grant">' . t("Grant types") . '</h3>' . '<p>' . t('On the category permissions page for each role, administrators can configure five types of permission for each term: <em>View, Update, Delete, Add Tag</em> (formerly <em>Create</em>), and <em>View Tag</em>: (formerly <em>List</em>') . '</p>' . _taxonomy_access_grant_help_table() . '<p>' . t('<em>View</em>, <em>Update</em>, and <em>Delete</em> control the node access system. <em>View Tag</em> and <em>Add Tag</em> control the terms themselves. (Note: In previous versions of Taxonomy Access Control, there was no <em>View Tag</em> permission its functionality was controlled by the <em>View</em> permission.)') . '</p><hr /><br />' . '<h3 id="perm">' . t("Permission options") . "</h3>" . '<p>' . t('<strong><em>View</em>, <em>Update</em>, and <em>Delete</em> have three options for each term:</strong> <em>Allow</em> (<acronym title="Allow">A</acronym>), <em>Ignore</em> (<acronym title="Ignore">I</acronym>), and <em>Deny</em> (<acronym title="Deny">D</acronym>). Indicate which rights each role should have for each term. If a node is tagged with multiple terms:') . '</p>' . "<ul>\n" . "<li>" . t('<em>Deny</em> (<acronym title="Deny">D</acronym>) overrides <em>Allow</em> (<acronym title="Allow">A</acronym>) within a role.') . "</li>" . "<li>" . t('Both <em>Allow</em> (<acronym title="Allow">A</acronym>) and <em>Deny</em> (<acronym title="Deny">D</acronym>) override <em>Ignore</em> (<acronym title="Ignore">I</acronym>) within a role.') . "</li>" . "<li>" . t('If a user has <strong>multiple roles</strong>, an <em>Allow</em> (<acronym title="Allow">A</acronym>) from one role <strong>will</strong> override a <em>Deny</em> (<acronym title="Deny">D</acronym>) in another. (For more information, see section <a href="#good-to-know">Good to know</a> below.)') . "</li>" . "</ul>\n\n" . '<p>' . t('<strong><em>Add Tag</em> and <em>View Tag</em> have only two options for each term:</strong> <em>Yes</em> (selected) or <em>No</em> (deselected). Indicate what each role should be allowed to do with each term.') . '</p>' . "<h4>" . t("Important notes") . "</h4>" . "<ol>" . "<li>" . t('Custom roles <strong>will</strong> inherit permissions from the <em>authenticated user</em> role. Be sure to <a href="@url">configure
the authenticated user</a> properly.', array(
"@url" => url(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_AUTHENTICATED_RID . 'edit'),
)) . "</li>\n" . '<li>' . "<p>" . t('The <em>Deny</em> directives are processed after the <em>Allow</em> directives. (<strong><em>Deny</em> overrides <em>Allow</em></strong>.)</em> So, if a multicategory node is in Categories "A" and "B" and a user has <em>Allow</em> permissions for <em>View</em> in Category "A" and <em>Deny</em> permissions for <em>View</em> in Category "B", then the user will NOT be permitted to <em>View</em> the node.') . '</p>' . '<p>' . t('<em>Access is denied by default.</em> So, if a multicategory node is in Categories "C" and "D" and a user has <em>Ignore</em> permissions for <em>View</em> in both Category "C" and "D", then the user will <strong>not</strong> be permitted to view the node.') . '</p>' . '<p>' . t('(If you are familiar with Apache mod_access, this permission system works similar to directive: <em>ORDER ALLOW, DENY</em>)') . '</p>' . "</li>" . "</ol>" . "<hr /><br />" . '<h3 id="defaults">' . t("Global and vocabulary defaults") . "</h3>" . '<p>' . t('This option, just underneath the vocabulary title, <em>sets the permission that will automatically be given</em> to the role, <em>for any new terms</em> that are added within the vocabulary. This includes terms that are added via free tagging.') . '</p><hr /><br />' . '<h3 id="good-to-know">' . t('Good to know') . '</h3>' . '<ol>' . '<li>' . '<p>' . t('<strong>Users with multiple user roles:</strong> Allow/Ignore/Deny options are interpreted <em>only within one user role</em>. When a user belongs to multiple user roles, then <strong>the user gets access if <em>any</em> of his/her user roles have the access granted.</strong>') . '</p>' . '<p>' . t('In this case, permissions for the given user are calculated so that the <em>permissions of ALL of his user roles are "OR-ed" together</em>, which means that <em>Allow</em> in one role will take precedence over <em>Deny</em> in the other. This is different from how node access permissions (for multi-category nodes) are handled <em>within one user role</em>, as noted above.') . '</p>' . '</li>' . '<li>' . '<p>' . t('<strong>Input formats:</strong> <em>Node editing/deleting is blocked</em>, even when the user has <em>Update</em> or <em>Delete</em> permission to the node, <em>when the user is not allowed to use a filter format</em> that the node was saved at.') . '</p>' . '</li>' . '</ol>' . '<hr /><br />';
return $message;
break;
}
}
function _taxonomy_access_grant_help_table() {
$header = array();
$rows = array();
$rows[] = array(
array(
'header' => TRUE,
'data' => t("View"),
),
"<p>" . t('Grants this role the ability to view nodes with the term. (Users must also have this permission to see <em class="perm">nodes</em> with the term listed in Views.)') . "</p>" . "<p>" . t('The role must <strong>have</strong> <em class="perm">access content</em> permission on the <a href="@path">permissions administration form</a>.', array(
'@path' => url('admin/people/permissions', array(
'fragment' => 'module-node',
)),
)),
);
$rows[] = array(
array(
'header' => TRUE,
'data' => t("Update") . ", " . t("Delete"),
),
"<p>" . t("Grants this role the ability to edit or delete nodes with the term, respectively.") . "</p>" . "<p>" . t('The role must <strong>not</strong> have <em class="perm">edit any [type] content</em> or <em class="perm">delete any [type] content</em> permission on the <a href="@path">permissions administration form</a> if you wish to control them here.', array(
'@path' => url('admin/people/permissions', array(
'fragment' => 'module-node',
)),
)) . "</p>",
);
$rows[] = array(
array(
'header' => TRUE,
'data' => t("Add Tag"),
),
"<p>" . t("Grants this role the ability to add the term to a node when creating or updating it.") . "</p>" . "<p>" . t('(Formerly <em>Create</em>). This does <strong>not</strong> give the role the ability to create nodes by itself; the role must <strong>have</strong> <em class="perm">create [type] content</em> permission on the <a href="@path">permissions administration form</a> in order to create new nodes.', array(
'@path' => url('admin/people/permissions', array(
'fragment' => 'module-node',
)),
)) . "</p>",
);
$rows[] = array(
array(
'header' => TRUE,
'data' => t("View Tag"),
),
"<p>" . t("(Formerly <em>List</em>.) Whether this role can see the term listed on node pages and in lists, and whether the user can view the %taxonomy-term-page page for the term.", array(
'%taxonomy-term-page' => "taxonomy/term/x",
)) . "</p>" . "<p>" . t("This does <strong>not</strong> control whether the role can see the <em>nodes</em> listed in Views, only the <em>term</em>.") . "</p>",
);
return theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'class' => array(
'grant_help',
),
),
));
}
function taxonomy_access_disable() {
foreach (field_read_fields() as $field_name => $field) {
if ($field['type'] == 'taxonomy_term_reference') {
if (!empty($field['settings']['options_list_callback']) && $field['settings']['options_list_callback'] == '_taxonomy_access_term_options') {
$field['settings']['options_list_callback'] = '';
field_update_field($field);
}
}
}
}