diff --git a/sites/all/modules/taxonomy_access_control/tac.admin.php b/sites/all/modules/taxonomy_access_control/tac.admin.php index a2c7c2fc0e8b18db8aab362a298e7a32b1961d4b..e997ca99b6e22fcc2d858b75edb66369d46b153a 100644 --- a/sites/all/modules/taxonomy_access_control/tac.admin.php +++ b/sites/all/modules/taxonomy_access_control/tac.admin.php @@ -47,10 +47,15 @@ function tac_admin($form, $form_state, $rid = NULL) { foreach (taxonomy_get_tree($vocabulary) as $term) { $subform['term_' . $term->tid] = array( '#title' => $term->name, - 'view' => array( - '#parents' => array('edit', $rid, $term->tid, 'view'), + 'list' => array( + '#parents' => array('edit', $rid, $term->tid, 'list'), '#type' => 'checkbox', - '#default_value' => (isset($currentValues[$rid][$term->tid]->grant_view) ? $currentValues[$rid][$term->tid]->grant_view : 0), + '#default_value' => (isset($currentValues[$rid][$term->tid]->grant_list) ? $currentValues[$rid][$term->tid]->grant_list : 0), + ), + 'create' => array( + '#parents' => array('edit', $rid, $term->tid, 'create'), + '#type' => 'checkbox', + '#default_value' => (isset($currentValues[$rid][$term->tid]->grant_create) ? $currentValues[$rid][$term->tid]->grant_create : 0), ), 'update' => array( '#parents' => array('edit', $rid, $term->tid, 'update'), @@ -79,13 +84,14 @@ function tac_admin($form, $form_state, $rid = NULL) { function theme_tac_term_list($variables) { $form = $variables['form']; - $headers = array('Term', 'View', 'Update', 'Delete'); + $headers = array('Term', 'List', 'Create', 'Update', 'Delete'); $rows = array(); foreach (element_children($form) as $key) { $rows[] = array( 'data' => array( $form[$key]['#title'], - drupal_render($form[$key]['view']), + drupal_render($form[$key]['list']), + drupal_render($form[$key]['create']), drupal_render($form[$key]['update']), drupal_render($form[$key]['delete']), ) @@ -115,12 +121,12 @@ function tac_admin_submit($form, &$form_state) { } - $insert = db_insert('tac_map')->fields(array('rid', 'tid', 'grant_view', 'grant_update', 'grant_delete')); + $insert = db_insert('tac_map')->fields(array('rid', 'tid', 'grant_list', 'grant_create', 'grant_update', 'grant_delete')); foreach ($form_state['values']['edit'] as $rid => $terms) { foreach ($terms as $tid => $grants) { $insert->values(array( - $rid, $tid, $grants['view'], $grants['update'], $grants['delete'], + $rid, $tid, $grants['list'], $grants['create'], $grants['update'], $grants['delete'], )); } } diff --git a/sites/all/modules/taxonomy_access_control/tac.install b/sites/all/modules/taxonomy_access_control/tac.install index 3aa690423cb24ee38f2e5bcda5916db89dcbb452..e9a503dbdb13bbad538da4448a7a443475228a92 100644 --- a/sites/all/modules/taxonomy_access_control/tac.install +++ b/sites/all/modules/taxonomy_access_control/tac.install @@ -45,6 +45,22 @@ function tac_schema() 'default' => 0, 'size' => 'tiny', ), + 'grant_create' => array( + 'description' => 'Boolean indicating whether a user with the realm/grant pair can create this term on a node.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + ), + 'grant_list' => array( + 'description' => 'Boolean indicating whether a user with the realm/grant pair can list this term.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + ), ), 'primary key' => array('rid', 'tid'), 'foreign keys' => array( @@ -122,6 +138,25 @@ function tac_update_7100() db_create_table('tac_map', $table); } +function tac_update_7101() { + db_add_field('tac_map', 'grant_create', array( + 'description' => 'Boolean indicating whether a user with the realm/grant pair can create this term on a node.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + )); + + db_add_field('tac_map', 'grant_list', array( + 'description' => 'Boolean indicating whether a user with the realm/grant pair can list this term.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + )); +} diff --git a/sites/all/modules/taxonomy_access_control/tac.module b/sites/all/modules/taxonomy_access_control/tac.module index a8f7405032342aba0a92e7d92fcfbb410c065170..a126751d89f529e30b57c0f161fd4048cbde347b 100644 --- a/sites/all/modules/taxonomy_access_control/tac.module +++ b/sites/all/modules/taxonomy_access_control/tac.module @@ -40,14 +40,7 @@ function tac_node_access_records($node) { $tac_vid = variable_get('tac_vocabulary', -1); $fields_to_check = array(); - $fields = field_info_instances('node', $node->type); - foreach ($fields as $field) { - $fieldInfo = field_info_field($field['field_name']); - if ($fieldInfo['type'] != 'taxonomy_term_reference') { - continue; - } - $fields_to_check[] = $field['field_name']; - } + $fields_to_check = _tac_get_taxonomy_fields_for_node($node); $selected_tids = array(); foreach ($fields_to_check as $field) { @@ -103,3 +96,185 @@ function tac_node_grants($account, $op) { return $grants; } + +function tac_form_alter(&$form, &$form_state, $form_id) { + if (substr($form_id, -10) == '_node_form') { + + // If the current user can bypass node access controls, we don't need to filter anything + if (user_access('bypass node access')) { + return; + } + + $taxonomy_fields = _tac_get_taxonomy_fields_for_node($form['#node']); + + $query = db_select('tac_map', 'm'); + $query->fields('m'); + $query->condition('m.rid', array_keys($GLOBALS['user']->roles), 'IN'); + $data = $query->execute()->fetchAll(); + + $grants = array(); + foreach ($data as $row) { + if ($row->grant_create) { + $grants[$row->tid]['create'] = TRUE; + } + if ($row->grant_list) { + $grants[$row->tid]['list'] = TRUE; + } + } + + array_unshift($form['#validate'], 'tac_node_form_validate'); + foreach ($taxonomy_fields as $field) { + + // If the terms are displayed as checkboxes, hide/disable them as necessary + if ($form[$field]['und']['#type'] == 'checkboxes' || $form[$field]['und']['#type'] == 'radios') { + $hidden_checkboxes = 0; + foreach ($form[$field]['und']['#options'] as $tid => $term) { + if ($tid == '_none') { + continue; + } + if (!isset($grants[$tid]['list']) || !$grants[$tid]['list']) { + $form[$field]['und'][$tid]['#type'] = 'hidden'; + $form_state['storage']['tac'][$field][$tid] = $tid; + $hidden_checkboxes++; + } + if (!isset($grants[$tid]['create']) || !$grants[$tid]['create']) { + $form[$field]['und'][$tid]['#disabled'] = 'TRUE'; + $form_state['storage']['tac'][$field][$tid] = $tid; + } + } + + // If all of the checkboxes are hidden, don't display the entire checkboxes elememnt + if ($hidden_checkboxes == count($form[$field]['und']['#options'])) { + $form[$field]['und']['#prefix'] = '<div style="display: none;">'; + $form[$field]['und']['#suffix'] = '</div>'; + } + } + + // If the terms are in a [multi-]select list, hide terms as necessary (since drupal doesn't support disabling) + if ($form[$field]['und']['#type'] == 'select') { + if ($form[$field]['und']['#multiple']) { + unset($form[$field]['und']['#options']['_none']); + } + foreach ($form[$field]['und']['#options'] as $tid => $term) { + if ($tid == '_none') { + continue; + } + if (!isset($grants[$tid]['create']) || !isset($grants[$tid]['list']) || !$grants[$tid]['create'] || !$grants[$tid]['list']) { + unset($form[$field]['und']['#options'][$tid]); + $form_state['storage']['tac'][$field][$tid] = $tid; + } + } + } + + if ($form[$field]['und']['#type'] == 'textfield') { + form_set_error('tac', "Autocomplete term widgets are not allowed when used with TAC."); + } + } + } +} + +function tac_node_form_validate($form, &$form_state) { + if (!isset($form_state['storage']['tac'])) { + return; + } + + foreach ($form_state['storage']['tac'] as $field => $locked_terms) { + $default_terms = $form[$field]['und']['#default_value']; + if ($form[$field]['und']['#type'] == 'select' && !$form[$field]['und']['#multiple']) { + $default_terms = $default_terms[0]; + } + + $set_terms = array(); + foreach ($form_state['values'][$field]['und'] as $key => $term_value) { + $set_terms[$key] = $term_value['tid']; + } + + // If multiple terms can be selected: + if (is_array($default_terms)) { + foreach ($locked_terms as $locked_term) { + if (in_array($locked_term, $default_terms) && !in_array($locked_term, $set_terms)) { + $form_state['values'][$field]['und'][] = array( + 'tid' => $locked_term, + ); + } + if (!in_array($locked_term, $default_terms) && in_array($locked_term, $set_terms)) { + form_set_error('tac', 'Attempt to add a denied term detected.'); + return; + } + } + } + // If only one term can be selected: + else { + if (in_array($default_terms, $locked_terms) && !in_array($default_terms, $set_terms)) { + drupal_set_message("A term you don't have access to was alerady selected.", 'warning'); + $form_state['values'][$field]['und'] = array(array('tid' => $default_terms)); + } + } + } +} + +function tac_query_alter(QueryAlterableInterface $query) { + if (!$query->hasTag('term_access')) { + return; + } + + // We need slightly more advanced filtering on the edit page. Handle it there. + if (arg(2) == 'edit') { + return; + } + + // If the current user can bypass node access controls, we don't need to filter anything + if (user_access('bypass node access') || user_access('administer taxonomy')) { + return; + } + + $alias = ''; + foreach ($query->getTables() as $table) { + if ($table['table'] == 'taxonomy_term_data') { + $alias = $table['alias']; + } + } + + $query->distinct(); + $query->addJoin( + 'LEFT', + '{tac_map}', + 'tm', + "$alias.tid = tm.tid AND tm.rid IN (:rids)", + array(':rids' => array_keys($GLOBALS['user']->roles)) + ); + $query->where('tm.grant_list = 1 OR tm.grant_list IS NULL'); +} + +function _tac_get_taxonomy_fields_for_node($node) { + $tac_vid = variable_get('tac_vocabulary', -1); + $vocabularies = taxonomy_get_vocabularies(); + if (!isset($vocabularies[$tac_vid])) { + return array(); + } + $vocabulary = $vocabularies[$tac_vid]; + + $taxonomy_fields = array(); + + $fields = field_info_instances('node', $node->type); + foreach ($fields as $field) { + $fieldInfo = field_info_field($field['field_name']); + if ($fieldInfo['type'] != 'taxonomy_term_reference') { + continue; + } + + $is_correct_vocabulary = FALSE; + foreach ($fieldInfo['settings']['allowed_values'] as $allowed_value) { + if ($allowed_value['vocabulary'] == $vocabulary->machine_name) { + $is_correct_vocabulary = TRUE; + } + } + if (!$is_correct_vocabulary) { + continue; + } + + $taxonomy_fields[] = $field['field_name']; + } + return $taxonomy_fields; +} +