View source
<?php
define('ABT_NO_CONTROL', 0);
define('ABT_CONTROL_DEFAULT_RESTRICT', 1);
define('ABT_CONTROL_DEFAULT_ALLOW', 2);
function abt_node_access($node, $op, $account) {
if (is_string($node)) {
return NODE_ACCESS_IGNORE;
}
if ($op == 'view' && $node->status == 0 && !user_access('view unpublished abt controlled nodes') && !(user_access('view own unpublished content') && $account->uid == $node->uid && $account->uid != 0)) {
return NODE_ACCESS_DENY;
}
if ($op == 'view' && $account->uid == $node->uid && $account->uid != 0 && user_access('view own abt controlled nodes')) {
return NODE_ACCESS_ALLOW;
}
return NODE_ACCESS_IGNORE;
}
function abt_node_grants($account, $op) {
$grants = array();
$usr = user_load($account->uid);
$access_map = field_read_fields(array(
'module' => 'taxonomy',
));
$cop = 'ctrl_' . $op . '_access';
foreach ($access_map as $field_name => $r) {
if (!(array_key_exists('abt_map', $r['settings']) && array_key_exists($cop, $r['settings']['abt_map']))) {
continue;
}
if (is_object($usr) && property_exists($usr, $field_name) === TRUE) {
$terms = field_get_items('user', $usr, $field_name);
$grants['abt_' . $field_name] = AbtUtils::taxonomyGetChildrenAll($terms);
}
if (module_exists('profile2')) {
$profile_names = db_select('field_config_instance', 'fci')
->fields('fci', array(
'bundle',
))
->condition('field_name', $r['field_name'])
->execute();
while ($pname = $profile_names
->fetchAssoc()) {
$pids = db_select('profile', 'p')
->fields('p', array(
'pid',
))
->condition('type', $pname['bundle'])
->condition('uid', $usr->uid)
->execute();
while ($pid = $pids
->fetchAssoc()) {
$profile = profile2_load($pid['pid']);
if (property_exists($profile, $r['field_name']) === TRUE) {
$terms = field_get_items('profile2', $profile, $r['field_name']);
$grants['abt_' . $r['field_name']] = AbtUtils::taxonomyGetChildrenAll($terms);
}
}
}
}
$grants['abt_' . $r['field_name']][] = 0;
}
return $grants;
}
function abt_node_access_records($node) {
$grants = array();
$access_map = field_read_fields(array(
'module' => 'taxonomy',
));
foreach ($access_map as $field_name => $realm) {
if (!property_exists($node, $field_name) || !array_key_exists('abt_map', $realm['settings'])) {
continue;
}
$abtmap = $realm['settings']['abt_map'];
$field_data = field_get_items('node', $node, $field_name);
if (empty($field_data)) {
$grants[] = AbtUtils::grantConstruct($node->nid, 'abt_' . $realm['field_name'], 0, $abtmap['ctrl_view_access'] == ABT_CONTROL_DEFAULT_ALLOW ? 1 : 0, $abtmap['ctrl_update_access'] == ABT_CONTROL_DEFAULT_ALLOW ? 1 : 0, $abtmap['ctrl_delete_access'] == ABT_CONTROL_DEFAULT_ALLOW ? 1 : 0);
}
else {
$used_tids = array();
for ($i = 0; $i < count($field_data); $i++) {
if (isset($field_data[$i]['tid'])) {
if (!in_array($field_data[$i]['tid'], $used_tids)) {
$used_tids[] = $field_data[$i]['tid'];
if (isset($realm['settings']['abt_map'])) {
$grants[] = AbtUtils::grantConstruct($node->nid, 'abt_' . $field_name, $field_data[$i]['tid'], $abtmap['ctrl_view_access'] == ABT_CONTROL_DEFAULT_RESTRICT || $abtmap['ctrl_view_access'] == ABT_CONTROL_DEFAULT_ALLOW ? 1 : 0, $abtmap['ctrl_update_access'] == ABT_CONTROL_DEFAULT_RESTRICT || $abtmap['ctrl_update_access'] == ABT_CONTROL_DEFAULT_ALLOW ? 1 : 0, $abtmap['ctrl_delete_access'] == ABT_CONTROL_DEFAULT_RESTRICT || $abtmap['ctrl_delete_access'] == ABT_CONTROL_DEFAULT_ALLOW ? 1 : 0);
}
}
}
}
}
}
return $grants;
}
function abt_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
if (!(isset($form['#field']['type']) && $form['#field']['type'] == 'taxonomy_term_reference')) {
return;
}
$no_perms = !user_access('assign view access control') & !user_access('assign update access control') & !user_access('assign delete access control');
$current = field_info_field($form['#field']['field_name']);
$form['abt'] = array(
'#type' => 'fieldset',
'#title' => t('Access by Term'),
'#weight' => -1,
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#description' => $no_perms ? '<p>' . t('Sorry but you have no permission to assign access control to fields. Talk to your administrator.') . '</p>' : '<p>' . t('<em>If you check one of below fields, the specified access for this content type will be controlled by ABT and unauthorized users will have no access to this content type. However, if none are checked, this remains a regular field. Let\'s say you check only "delete" flag. This would mean you want to control the "delete" access with the field. Other two unchecked boxes will result in default access settings.</em>') . '</p>' . '<p>' . t('<em>Note: by changing these settings, you will need to rebuild your content permissions.</em>') . '</p>',
);
foreach (array(
'view',
'update',
'delete',
) as $op) {
if (user_access('assign ' . $op . ' access control')) {
$form['abt']['abt_enable_' . $op . '_control'] = array(
'#type' => 'select',
'#title' => t('Control "@op" access with this field.', array(
'@op' => $op,
)),
'#options' => array(
ABT_NO_CONTROL => t('No'),
ABT_CONTROL_DEFAULT_RESTRICT => t('Yes, restrict access even if node is not tagged.'),
ABT_CONTROL_DEFAULT_ALLOW => t('Yes, but allow access if node is not tagged.'),
),
'#description' => t('Set this to control the "<strong>@op</strong>" access for the content type <strong>@ct</strong>.', array(
'@ct' => $form['#instance']['bundle'],
'@op' => $op,
)),
'#default_value' => isset($current['settings']['abt_map']['ctrl_' . $op . '_access']) ? $current['settings']['abt_map']['ctrl_' . $op . '_access'] : 0,
);
}
}
$form['#submit'][] = 'abt_form_field_ui_field_edit_form_submit';
}
function abt_form_field_ui_field_edit_form_submit($form_data) {
if (!isset($form_data['abt']['abt_enable_view_control']) && !isset($form_data['abt']['abt_enable_view_control']) && !isset($form_data['abt']['abt_enable_delete_control'])) {
return;
}
$field_name = $form_data['#field']['field_name'];
$ctrl_view_access = user_access('assign view access control') ? (int) $form_data['abt']['abt_enable_view_control']['#value'] : 0;
$ctrl_update_access = user_access('assign update access control') ? (int) $form_data['abt']['abt_enable_update_control']['#value'] : 0;
$ctrl_delete_access = user_access('assign delete access control') ? (int) $form_data['abt']['abt_enable_delete_control']['#value'] : 0;
$field = field_info_field($field_name);
$changes = 0;
if (isset($field['settings']['abt_map'])) {
if ($field['settings']['abt_map']['ctrl_view_access'] != $ctrl_view_access) {
$changes++;
}
if ($field['settings']['abt_map']['ctrl_update_access'] != $ctrl_update_access) {
$changes++;
}
if ($field['settings']['abt_map']['ctrl_delete_access'] != $ctrl_delete_access) {
$changes++;
}
}
else {
$changes++;
}
if ($changes > 0) {
$field_abt_map = array(
'ctrl_view_access' => $ctrl_view_access,
'ctrl_update_access' => $ctrl_update_access,
'ctrl_delete_access' => $ctrl_delete_access,
);
$field['settings']['abt_map'] = $field_abt_map;
field_update_field($field);
node_access_needs_rebuild(TRUE);
}
}
function abt_form_node_form_alter(&$form, &$form_state, $form_id) {
$access_map = field_read_fields(array(
'module' => 'taxonomy',
));
foreach ($access_map as $field_name => $realm) {
if (isset($realm['settings']['abt_map'])) {
$field =& $form[$field_name];
$view = $realm['settings']['abt_map']['ctrl_view_access'] >= ABT_CONTROL_DEFAULT_RESTRICT ? t('view') . ' ' : '';
$update = $realm['settings']['abt_map']['ctrl_update_access'] >= ABT_CONTROL_DEFAULT_RESTRICT ? t('update') . ' ' : '';
$delete = $realm['settings']['abt_map']['ctrl_delete_access'] >= ABT_CONTROL_DEFAULT_RESTRICT ? t('delete') . ' ' : '';
$msg = str_replace(' ', ', ', trim($view . $update . $delete));
$msg = !empty($msg) ? ' <em>' . t('(Access control enabled for: @msg)', array(
'@msg' => $msg,
)) . '</em>' : '';
$field[$field['#language']]['#title'] = $field[$field['#language']]['#title'] . $msg;
}
}
if (!user_access('allow edit abt field content in node')) {
$form = abt_remove_fields($form);
}
}
function abt_node_view($node, $view_mode, $langcode) {
if (!user_access('allow view abt field content in node')) {
$node->content = abt_remove_fields($node->content);
}
}
function abt_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
if (!user_access('allow edit abt field content in profile')) {
$form = abt_remove_fields($form);
}
}
function abt_user_view($account, $view_mode, $langcode) {
if (!user_access('allow view abt field content in profile')) {
$account->content = abt_remove_fields($account->content);
}
}
function abt_remove_fields($data) {
$abt_fields = field_read_fields(array(
'module' => 'taxonomy',
));
foreach ($abt_fields as $field_name => $field) {
if (array_key_exists('abt_map', $field['settings'])) {
if (is_array($data)) {
unset($data[$field_name]);
}
elseif (is_object($data) && property_exists($data, $field_name)) {
unset($data->{$field_name});
}
}
}
return $data;
}
function abt_permission() {
return array(
'assign view access control' => array(
'title' => t('Assign fields to control node <strong>view</strong> access'),
'restrict access' => TRUE,
),
'assign update access control' => array(
'title' => t('Assign fields to control node <strong>update</strong> access'),
'restrict access' => TRUE,
),
'assign delete access control' => array(
'title' => t('Assign fields to control node <strong>delete</strong> access'),
'restrict access' => TRUE,
),
'allow edit abt field content in profile' => array(
'title' => t('Allow users to <strong>edit</strong> ABT terms on profile page.'),
'restrict access' => TRUE,
),
'allow view abt field content in profile' => array(
'title' => t('Allow users to <strong>view</strong> ABT terms on profile page.'),
'restrict access' => TRUE,
),
'allow edit abt field content in node' => array(
'title' => t('Allow users to <strong>edit</strong> ABT terms on node page.'),
'restrict access' => TRUE,
),
'allow view abt field content in node' => array(
'title' => t('Allow users to <strong>view</strong> ABT terms on node page.'),
'restrict access' => TRUE,
),
'view unpublished abt controlled nodes' => array(
'title' => t('Allow users to <strong>view</strong> unpublished nodes, controlled with ABT.'),
'restrict access' => TRUE,
),
'view own abt controlled nodes' => array(
'title' => t('Allow users to <strong>view</strong> their own nodes, controlled with ABT.'),
'restrict access' => TRUE,
),
);
}
function abt_help($path, $arg) {
if ($path == 'admin/help#abt') {
$out = '';
$out .= '<h3>' . t('About ABT') . '</h3>';
$out .= '<p>' . t('ABT (Access by Term) is a module that controls node access based on relationship between node->term<-user where taxonomy terms allow for hierarchical content access control.') . '</p>';
$out .= '<h3>' . t('Installation') . '</h3>';
$out .= '<p>' . t('Install & enable.') . '</p>';
$out .= '<h3>' . t('Usage') . '</h3>';
$out .= '<ol>';
$out .= '<li>' . t('After enabling the module, make sure you set appropriate permissions for your roles.') . '</li>';
$out .= '<li>' . t('Add some taxonomy terms in the vocabularies you intent to use. Do not forget to think hierarchically. ABT handles access inheritance in such way that parent has equal or greater access then it\'s child.') . '</li>';
$out .= '<li>' . t('Create fields:');
$out .= '<ul>';
$out .= '<li>' . t('Add a "Term reference" field instance to the content type(s) you want to control.') . '</li>';
$out .= '<li>' . t('Add a "Term reference" field instance to the user.') . '</li>';
$out .= '</ul>';
$out .= '<p>' . t('ABT has support for multiple access flags, so you may set the field instances to "unlimited" values, if you need. When editing/adding settings for the field instance, pick the type of access to control by checking any or all of the flags view/update/delete. If you check any of these, access for this content type will be controlled by ABT. If none are checked, this remains a regular field. Let\'s say you check only "delete" flag. This would mean you want to control the "delete" access with the field. Other two unchecked boxes will result in "access denied".') . '</p>';
$out .= '<p>' . t('If your setup requires, you can create any number of different fields (with different vocabularies attached) and have each control one of the flags (view/update/delete). It\'s completely up to you how you set it up. If you ame to use more then one field per content type - It is your responsibility to make sure that there fields controlling are not overlapping (For example: field A and field B are both set to control view-access for content type Articles - this could have unexpected results).') . '</p>';
$out .= '</li>';
$out .= '<li>' . t('"Tag" nodes with appropriate access terms.') . '</li>';
$out .= '<li>' . t('"Tag" users with appropriate access terms.') . '</li>';
$out .= '</ol>';
return $out;
}
}