' . t('This module allows you to restrict access to site content. It uses a simple scheme based on Taxonomy, Users and Roles. It uses the node_access table and other features built into Drupal to hide content from unauthorized users.') . '
'; $output .= '' . t('While this module has been designed to be as simple as possible to use, there are several steps required to set it up.') . '
'; $output .= '' . t('Currently, this module works with view grants only (no update or delete grants).') . '
'; return $output; break; } } /** * Implementation of hook_perm(). */ function tac_lite_perm() { return array('administer tac_lite'); } /** * Implementation of hook_menu(). */ function tac_lite_menu() { global $user; $items = array(); $items['admin/user/access/tac_lite'] = array( 'title' => 'Access by Taxonomy', 'description' => "taxonomy-based permissions by tac_lite", 'page callback' => 'drupal_get_form', 'page arguments' => array('tac_lite_admin_settings'), 'type' => MENU_NORMAL_ITEM, 'weight' => 1, // after 'roles' tab 'access arguments' => array('administer tac_lite'), ); $items['admin/user/access/tac_lite/settings'] = array( 'title' => 'Settings', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -1, 'access arguments' => array('administer tac_lite'), ); $schemes = variable_get('tac_lite_schemes', 1); for ($i = 1; $i <= $schemes; $i++) { $scheme = variable_get('tac_lite_config_scheme_'. $i, FALSE); if ($scheme) { $title = $scheme['name']; } else { $title = "Scheme $i"; } $items['admin/user/access/tac_lite/scheme_' . $i] = array( 'title' => $title, 'page callback' => 'tac_lite_admin_settings_scheme', 'page arguments' => array((string)$i), 'type' => MENU_LOCAL_TASK, 'weight' => $i, 'access arguments' => array('administer tac_lite'), ); } $items['tac_lite/autocomplete'] = array( 'title' => 'TAC lite autocomplete', 'page callback' => 'tac_lite_autocomplete', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK ); return $items; } function get_terms_from_tids($vid, $tids){ //print_r($tids); echo '---', '#suffix' => '
', ); $form['helptext2'] = array( '#type' => 'markup', '#value' => t('To grant by role, select the terms below.'), '#prefix' => '', '#suffix' => '
', ); $vocabularies = taxonomy_get_vocabularies(); $all_defaults = variable_get('tac_lite_grants_scheme_' . $i, array()); $form['tac_lite_grants_scheme_' . $i] = array('#tree' => TRUE); foreach ($roles as $rid => $role_name) { $form['tac_lite_grants_scheme_' . $i][$rid] = array( '#type' => 'fieldset', //'textfield', // '#tree' => TRUE, '#title' => check_plain(t('Grant permission by role: !role', array('!role' => $role_name))), '#description' => t(''), '#collapsible' => TRUE, '#autocomplete_path' => 'tac_lite/autocomplete/'.$form['#vocabulary']['vid'] ); $defaults = isset($all_defaults[$rid]) ? $all_defaults[$rid] : NULL; foreach ($vids as $vid) { $v = $vocabularies[$vid]; $form['tac_lite_grants_scheme_' . $i][$rid][$vid] = array( '#type' => 'textfield', //'#maxlength' => 10000, '#title' => $v->name, '#default_value' => get_terms_from_tids($vid, $defaults[$vid]), '#autocomplete_path' => 'tac_lite/autocomplete/'.$vid); } } $form['#submit'][] = 'tac_lite_admin_scheme_form_submit'; return system_settings_form($form); } else { return (array('body' => array('#type' => 'markup', '#value' => t('First select vocabularies on the settings page.', array('!url' => url('admin/user/access/tac_lite')))))); } } function tac_lite_split_field($string, $vid){ // Add slashes first $string = addslashes($string); $regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x'; preg_match_all($regexp, $string, $matches); $string_array = $matches[1]; //echo 's: '; print_r($string_array); return get_tids_from_terms($vid, $string_array); } /** * Submit function for admin settings form to rebuild the menu. */ function tac_lite_admin_scheme_form_submit($form, &$form_state) { //die('xxx'); $vids = variable_get('tac_lite_categories', NULL); $vocabularies = taxonomy_get_vocabularies(); $schemes = variable_get('tac_lite_schemes', 1); $roles = user_roles(); for ($i = 1; $i <= $schemes; $i++) { foreach ($form_state['values']['tac_lite_grants_scheme_'.$i] as &$rid) { //print_r($rid); die(); foreach ($vids as $vid) { $rid[$vid] = tac_lite_split_field($rid[$vid], $vid); } } } variable_set('menu_rebuild_needed', TRUE); } function tac_lite_user_form_submit($form, &$form_state) { //print_r($form_state['values']);die('xxx'); $x=array(); $x['tac_lite']=array(); $x['form_build_id']=$form_state['values']['_account']->form_build_id; $vids = variable_get('tac_lite_categories', NULL); foreach ($vids as $vid) { $x['tac_lite'][$vid]=tac_lite_split_field($form_state['values'][$vid], $vid); } //print_r(serialize($x)); //die(); db_query("UPDATE {users} SET data='%s' WHERE uid=".$form_state['values']['_account']->uid, serialize($x)); } /** * Implementation of hook_user(). */ function tac_lite_user($op, $edit, $account, $category = NULL) { if (!user_access('administer tac_lite')) { // Only for tac_lite administrators. return; } switch ($op) { case 'categories': return array(array('name' => 'tac_lite', 'title' => t('Access by taxonomy'), 'weight' => 5, 'access callback' => 'user_access', 'access arguments' => array('administer users'), ), ); break; case 'form': $vocabularies = taxonomy_get_vocabularies(); if ($category == 'tac_lite') { $vids = variable_get('tac_lite_categories', NULL); if (count($vids)) { for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) { $config = _tac_lite_config($i); //print_r($account); $terms = isset($account->$config['realm']) ? $account->$config['realm'] : array(); if ($config['name']) { $perms = $config['perms']; if ($config['term_visibility']) { $perms[] = t('term visibility'); } $form['tac_lite'][$config['realm']] = array( '#type' => 'fieldset', '#title' => $config['name'], '#description' => t('This scheme controls %perms.', array('%perms' => implode(' and ', $perms))), '#tree' => TRUE, ); foreach ($vids as $vid) { $v = $vocabularies[$vid]; $form['tac_lite_grants_scheme_' . $i][$rid][$vid] = array( '#type' => 'textfield', //'#maxlength' => 10000, '#title' => $v->name, //'#description' => $form['taxonomy'][$vid]['#description'], '#default_value' => get_terms_from_tids($vid, $terms[$vid]), '#autocomplete_path' => 'tac_lite/autocomplete/'.$vid); $form['tac_lite'][$config['realm']][$vid]['#description'] = t('Grant permission to this user by selecting terms. Note that permissions are in addition to those granted based on user roles.'); } } } $form['tac_lite'][0] = array( '#type' => 'markup', '#value' => '' . t('You may grant this user access based on the schemes and terms below. These permissions are in addition to role based grants on scheme settings pages.', array('!url' => url('admin/user/access/tac_lite/scheme_1'))) . "
\n", '#weight' => -1, ); $form['#submit'][] = 'tac_lite_user_form_submit'; return $form; } } break; } } /** * Implements hook_node_access_records(). * * We are given a node and we return records for the node_access table. In * our case, we inpect the node's taxonomy and grant permissions based on the * terms. */ function tac_lite_node_access_records($node) { // all terms from all vocabs $all_tids = _tac_lite_get_terms($node); // just the vocabs we're interested in $vids = variable_get('tac_lite_categories', NULL); // now find just the terms we're interested in. $tids = array(); if (count($all_tids) && count($vids)) { $result = db_query("SELECT DISTINCT td.tid FROM {term_data} td WHERE td.vid IN (%s) AND td.tid IN (%s)", implode(',', $vids), implode(',', $all_tids)); while ($term = db_fetch_object($result)) { $tids[] = $term->tid; } } if (!count($tids)) { // no relevant terms found. // in drupal 4-7 we had to write a row into the database. In drupal 5 and later, it should be safe to do nothing. } else { // if we're here, the node has terms associated with it which restrict // access to the node. $grants = array(); for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) { $config = _tac_lite_config($i); foreach ($tids as $tid) { $grant = array( 'realm' => $config['realm'], 'gid' => $tid, // use term id as grant id ); foreach ($config['perms'] as $perm) { $grant[$perm] = TRUE; } $grants[] = $grant; } } return $grants; } } /** * Get terms from a newly udpated node. * Terms are placed in $node->taxonomy by the form. */ function _tac_lite_get_terms(&$node) { $tids = array(); // emulating code from taxonomy_node_save here. // note that free tagging vocabs not currently supported if (count($node->taxonomy)) { foreach ($node->taxonomy as $term) { if (is_array($term)) { foreach ($term as $tid) { if (is_numeric($tid)) { $tids[$tid] = $tid; } else { // non-numeric means free-tagging vocabulary. // we do not support. Do nothing. } } } elseif (is_object($term)) { // in drupal 5 term is an object. Is this right? $tids[$term->tid] = $term->tid; } elseif (is_numeric($term)) { // $term is a tid. $tids[$term] = $term; } elseif ($term) { drupal_set_message(t('Unexpected term value "%term" in tac_lite.', array('%term' => $term)), 'error'); } } } return $tids; } function _tac_lite_get_terms_by_nid($nid) { $tids = array(); $terms = taxonomy_node_get_terms($nid); // terms is now an array of objects. We convert to a simple array of tids foreach ($terms as $term) { $tids[$term->tid] = $term->tid; } return $tids; } /** * Return the term ids of terms this user is allowed to access. * * Users are granted access to terms either because of who they are, * or because of the roles they have. */ function _tac_lite_user_tids($account, $scheme) { // grant id 0 is reserved for nodes which were not given a grant id when they were created. By adding 0 to the grant id, we let the user view those nodes. $grants = array(0); $config = _tac_lite_config($scheme); $realm = $config['realm']; if (isset($account->$realm) && count($account->$realm)) { // $account->$realm is array. Keys are vids, values are array of tids within that vocabulary, to which the user has access foreach ($account->$realm as $tids) { if (count($tids)) { $grants = array_merge($grants, $tids); } } } // add per-role grants in addition to per-user grants $defaults = variable_get('tac_lite_grants_scheme_' . $scheme, array()); foreach ($account->roles as $rid => $role_name) { if (isset($defaults[$rid]) && count($defaults[$rid])) { foreach ($defaults[$rid] as $tids) { if (count($tids)) { $grants = array_merge($grants, $tids); } } } } // Because of some flakyness in the form API and the form we insert under // user settings, we may have a bogus entry with vid set // to ''. Here we make sure not to return that. unset($grants['']); return $grants; } /** * Implementation of hook_node_grants(). * * Returns any grants which may give the user permission to perform the * requested op. */ function tac_lite_node_grants($account, $op) { $grants = array(); for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) { $config = _tac_lite_config($i); if (in_array('grant_' . $op, $config['perms'])) { $grants[$config['realm']] = _tac_lite_user_tids($account, $i); } } if (count($grants)) { return $grants; } } function tac_lite_db_rewrite_sql($query, $primary_table, $primary_field, $args) { global $user; if ($primary_field != 'tid') { // Only changes things in link with 'tid' return; } if (user_access('administer tac_lite')) { // Only for tac_lite administrators. return; } // the vocabularies containing protected info. $vids = variable_get('tac_lite_categories', NULL); $schemes = variable_get('tac_lite_schemes', 1); if (!$vids || !count($vids) || !$schemes) { return; } $term_visibility = FALSE; // the terms this user is allowed to see $tids = array(); for ($i = 1; $i <= $schemes; $i++) { $config = _tac_lite_config($i); if ($config['term_visibility']) { $tids = array_merge($tids, _tac_lite_user_tids($user, $i)); $term_visibility = TRUE; } } if ($term_visibility) { // Prevent query from finding terms the current user does not have permission to see. $join = "LEFT JOIN {term_data} tac_td ON $primary_table.tid = tac_td.tid"; $where = "$primary_table.tid IN (" . implode(', ', $tids) . ") OR tac_td.vid NOT IN (" . implode(',', $vids) .")"; return array('join' => $join, 'where' => $where); } }