node_privacy_byrole.module in node privacy byrole 6
Same filename and directory in other branches
Set node access permissions by role.
File
node_privacy_byrole.moduleView source
<?php
/**
* @file
* Set node access permissions by role.
*/
/**
* Implementation of hook_help().
*/
function node_privacy_byrole_help($path, $arg) {
switch ($path) {
case 'admin/help#node_privacy_byrole':
$output = '<p>' . t('The node privacy by role module allows users, when creating or editing a post, to select which roles of users on a site will have <em>view</em> permissions for the node and which users on a site will have <em>edit</em> permissions. Community leaders frequently want to give permissions to roles to create and manage content for a site. The ability to publish information, that would traditionally be hoarded, allows communities to educate each other while still preserving the value of knowledge.') . '</p>';
$output .= '<p>' . t('The node privacy by-role permissions are set by users for their nodes. If the node privacy by role module is disabled, the default permissions scheme will be in effect again, in which all users have view permissions for all nodes. However, if the module is re-enabled, the node-by-node permissions that were in place during the previous period in which the module was enabled will take effect again. Roles given edit permissions are automatically given view permissions even if the user tries to give <em>edit</em> permissions to a particular role, but not view permissions.') . '</p>';
$output .= t('<p>You can:</p>
<ul>
<li>set default permissions for each content type in the default workflow settings at <a href="@admin-node-configure-types">Administer >> Content management >> Content types</a> for each content type.</li>
<li>decide who can ignore the default permissions for each content type in the default workflow settings at <a href="@admin-node-configure-types">Administer >> Content management >> Content types</a> for each content type.</li>
</ul>', array(
'@admin-node-configure-types' => url('admin/content/types'),
));
$output .= '<p>' . t('For more information please read the configuration and customization handbook <a href="@node_privacy_byrole">Node privacy by role page</a>.', array(
'@node_privacy_byrole' => 'http://www.drupal.org/handbook/modules/node_privacy_byrole/',
)) . '</p>';
return $output;
}
}
/**
* Implementation of hook_views_api().
*/
function node_privacy_byrole_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'node_privacy_byrole') . '/views',
);
}
/**
* Simple function to identify when module is being disabled
* so that as the node_access table is rebuilt, it doesn't set
* any permissions for this module
*/
function node_privacy_byrole_disabling($set = NULL) {
static $disabling = FALSE;
if ($set != NULL) {
$disabling = $set;
}
return $disabling;
}
/**
* Implementation of hook_node_grants().
*/
function node_privacy_byrole_node_grants($account, $op) {
return array(
'node_privacy_byrole_role' => array_keys($account->roles),
'node_privacy_byrole_user' => array(
$account->uid,
),
);
}
/**
* Implementation of hook_node_access_records().
*/
function node_privacy_byrole_node_access_records($node) {
if (node_privacy_byrole_disabling()) {
return;
}
node_privacy_byrole_nodeapi_prepare($node);
$grants = array();
$user_edit_perm = empty($node->node_privacy_byrole['author']['edit']) ? 0 : 1;
$user_delete_perm = empty($node->node_privacy_byrole['author']['delete']) ? 0 : 1;
$user_view_perm = $user_edit_perm || $user_delete_perm ? 1 : (empty($node->node_privacy_byrole['author']['view']) ? 0 : 1);
// permission for node owner
if ($node->uid > 0) {
$grants[] = array(
'realm' => 'node_privacy_byrole_user',
'gid' => $node->uid,
'grant_view' => $user_view_perm,
'grant_update' => $user_edit_perm,
'grant_delete' => $user_delete_perm,
'priority' => 0,
);
}
// permission for node roles
foreach (array_keys(user_roles()) as $rid) {
$edit_perm = $node->node_privacy_byrole['roles'][$rid]['edit'] ? 1 : 0;
$delete_perm = $node->node_privacy_byrole['roles'][$rid]['delete'] ? 1 : 0;
$view_perm = $edit_perm || $delete_perm ? 1 : $node->node_privacy_byrole['roles'][$rid]['view'];
$grants[] = array(
'realm' => 'node_privacy_byrole_role',
'gid' => $rid,
'grant_view' => $view_perm,
'grant_update' => $edit_perm,
'grant_delete' => $delete_perm,
'priority' => 0,
);
}
return $grants;
}
/**
* Implementation of hook_nodeapi().
*/
function node_privacy_byrole_nodeapi(&$node, $op, $arg = 0) {
$roles = array_keys(user_roles());
switch ($op) {
case 'load':
case 'prepare':
node_privacy_byrole_nodeapi_prepare($node);
break;
case 'delete':
db_query('DELETE FROM {node_privacy_byrole} WHERE nid = %d', $node->nid);
break;
case 'insert':
node_privacy_byrole_nodeapi_prepare($node);
// http://drupal.org/node/256396
foreach ($roles as $rid) {
db_query("INSERT INTO {node_privacy_byrole} (nid, gid, realm, grant_view, grant_update, grant_delete)\n VALUES (%d, %d, '%s', %d, %d, %d)", $node->nid, $rid, 'node_privacy_byrole_role', $node->node_privacy_byrole['roles'][$rid]['view'], $node->node_privacy_byrole['roles'][$rid]['edit'], $node->node_privacy_byrole['roles'][$rid]['delete']);
}
db_query("INSERT INTO {node_privacy_byrole} (nid, gid, realm, grant_view, grant_update, grant_delete)\n VALUES (%d, %d, '%s', %d, %d, %d)", $node->nid, $node->uid, 'node_privacy_byrole_user', 1, 1, 1);
break;
case 'update':
node_privacy_byrole_nodeapi_prepare($node);
// http://drupal.org/node/153588
// As a new role might have been added since creation of the node, we cannot simply "update" and so delete and reinsert
db_query("DELETE FROM {node_privacy_byrole} WHERE nid = %d AND realm = 'node_privacy_byrole_role'", $node->nid);
foreach ($roles as $rid) {
db_query("INSERT INTO {node_privacy_byrole} (nid, gid, realm, grant_view, grant_update, grant_delete)\n VALUES (%d, %d, '%s', %d, %d, %d)", $node->nid, $rid, 'node_privacy_byrole_role', $node->node_privacy_byrole['roles'][$rid]['view'], $node->node_privacy_byrole['roles'][$rid]['edit'], $node->node_privacy_byrole['roles'][$rid]['delete']);
}
// Record for owner exists for sure, so we can simply update it
db_query("UPDATE {node_privacy_byrole} SET grant_view = %d, grant_update = %d, grant_delete = %d\n WHERE nid = %d AND gid = %d AND realm = 'node_privacy_byrole_user'", 1, 0, 0, $node->nid, $node->uid);
break;
}
}
function node_privacy_byrole_nodeapi_prepare(&$node) {
if (!isset($node->node_privacy_byrole)) {
$roles = array_keys(user_roles());
$perms = array(
'view',
'edit',
'delete',
);
if (isset($node->nid) && empty($node->is_new)) {
// this is an existing node, get current permissions
$result = db_query("SELECT gid, grant_view, grant_update, grant_delete FROM {node_privacy_byrole} " . "WHERE nid = %d AND realm = 'node_privacy_byrole_role'", $node->nid);
$current_perms = array();
while ($role = db_fetch_object($result)) {
$current_perms[$role->gid]['view'] = $role->grant_view;
$current_perms[$role->gid]['edit'] = $role->grant_update;
$current_perms[$role->gid]['delete'] = $role->grant_delete;
}
while (list(, $rid) = each($roles)) {
// if the role exists in node_privacy_byrole table, fill its perm with the database ones
if (isset($current_perms[$rid])) {
while (list(, $perm) = each($perms)) {
$node->node_privacy_byrole['roles'][$rid][$perm] = $current_perms[$rid][$perm] ? 1 : 0;
}
}
else {
// else : the role doesn't exist in node_privacy_byrole table (it has been recently added).
// In this case, fill perms with default ones
while (list(, $perm) = each($perms)) {
$default_roles = _node_privacy_byrole_get_default_roles($node->type, $perm);
$node->node_privacy_byrole['roles'][$rid][$perm] = in_array($rid, $default_roles) ? 1 : 0;
}
}
reset($perms);
}
}
else {
// case where node is being created
while (list(, $rid) = each($roles)) {
while (list(, $perm) = each($perms)) {
$default_roles = _node_privacy_byrole_get_default_roles($node->type, $perm);
$node->node_privacy_byrole['roles'][$rid][$perm] = in_array($rid, $default_roles) ? 1 : 0;
}
reset($perms);
}
}
}
}
/**
* Implementation of hook_form_alter().
*/
function node_privacy_byrole_form_alter(&$form, $form_state, $form_id) {
if ('node_type_form' == $form_id) {
node_privacy_byrole_node_type_form($form);
}
elseif ('node_configure' == $form_id) {
$form['npbr_default_permissions'] = array(
'#type' => 'checkbox',
'#title' => 'When rebuilding permissions, reset the node privacy by role permissions on all nodes to the content type defaults.',
'#weight' => 0,
'#default_value' => variable_get('npbr_default_permissions', 0),
);
$form['access']['#weight'] = -1;
}
elseif ('node_configure_rebuild_confirm' == $form_id) {
if (variable_get('npbr_default_permissions', 0)) {
// Make sure the npbr handler runs first.
$form['#submit'] = array_merge(array(
'node_privacy_byrole_rebuild_submit',
), $form['#submit']);
}
}
elseif ($form['#id'] == 'node-form') {
if (node_privacy_byrole_user_has_meta_perm($form['#node'])) {
node_privacy_byrole_node_form($form);
}
}
}
function node_privacy_byrole_rebuild_submit($form, &$form_state) {
db_query('TRUNCATE TABLE {node_privacy_byrole}');
}
/**
* Checks that the active user has access to set permissions on nodes.
*/
function node_privacy_byrole_user_has_meta_perm($node) {
global $user;
if ($user->uid == 1) {
return TRUE;
}
$permitted_roles = _node_privacy_byrole_get_default_roles($node->type, 'grant');
$user_roles = array_keys($user->roles);
return count(array_intersect($permitted_roles, $user_roles)) ? TRUE : FALSE;
}
/**
* Returns those role id's that are permitted to do $action on a $type node
*/
function _node_privacy_byrole_get_default_roles($type, $action) {
return variable_get('npbr_default_' . $action . '_perms_' . $type, array());
}
/**
* Form elements that extends node type form
* Used for set the default permission settings per node type
*/
function node_privacy_byrole_node_type_form(&$form) {
$type = $form['#node_type']->type;
$roles = user_roles();
$perms = array(
'view' => array(
'title' => t('Default View Permissions'),
'description' => t('Select roles to be given view permisions by default.'),
),
'edit' => array(
'title' => t('Default Edit Permissions'),
'description' => t('Select roles to be given edit permissions by default.'),
),
'delete' => array(
'title' => t('Default Delete Permissions'),
'description' => t('Select roles to be given delete permissions by default.'),
),
'grant' => array(
'title' => t('Roles with rights to update permissions'),
'description' => t('Select which roles will have rights to alter permissions on nodes.'),
),
);
$form['npbr_workflow_settings'] = array(
'#type' => 'fieldset',
'#title' => t('Node privacy by role'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
while (list($perm, $permdata) = each($perms)) {
$permname = 'npbr_default_' . $perm . '_perms';
$form['npbr_workflow_settings'][$permname] = array(
'#tree' => TRUE,
'#type' => 'fieldset',
'#title' => $permdata['title'],
'#collapsible' => FALSE,
'#collapsed' => FALSE,
'#description' => $permdata['description'],
'#weight' => 0,
);
$default_perms = _node_privacy_byrole_get_default_roles($type, $perm);
foreach (array_keys($roles) as $rid) {
$form['npbr_workflow_settings'][$permname][$rid] = array(
'#type' => 'checkbox',
'#title' => $roles[$rid],
'#return_value' => 1,
'#default_value' => in_array($rid, $default_perms),
);
}
}
}
/**
* Form elements that extends node edit form
*/
function node_privacy_byrole_node_form(&$form) {
$roles = array_keys(user_roles());
$perms = array(
'view',
'edit',
'delete',
);
// create checkboxes for every role and every permission
// later depending on the $op variable only the default values will be updated
$form['node_privacy_byrole'] = array(
'#tree' => TRUE,
'#theme' => 'node_privacy_byrole_node_form',
'#type' => 'fieldset',
'#title' => t('View/Edit Permissions'),
'#collapsible' => TRUE,
// collapse depends on bug when viewing tables included in collapsed fielsets in IE7:
// http://drupal.org/node/237565
'#collapsed' => strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 7.0') > 0 ? FALSE : TRUE,
'#weight' => 9,
);
while (list(, $rid) = each($roles)) {
$form['node_privacy_byrole']['roles'][$rid] = array(
'#type' => 'fieldset',
'#collapsible' => FALSE,
'#collapsed' => FALSE,
'#weight' => 0,
);
while (list(, $perm) = each($perms)) {
$form['node_privacy_byrole']['roles'][$rid][$perm] = array(
'#type' => 'checkbox',
'#title' => NULL,
'#return_value' => 1,
'#default_value' => $form['#node']->node_privacy_byrole['roles'][$rid][$perm],
);
}
reset($perms);
}
}
function node_privacy_byrole_theme() {
return array(
'node_privacy_byrole_node_form' => array(
'arguments' => array(
'form' => NULL,
),
),
);
}
/**
* Theming permission settings form elements on node edit form.
*/
function theme_node_privacy_byrole_node_form($form) {
$roles = user_roles();
$header = array(
t('Role'),
t('View'),
t('Edit'),
t('Delete'),
);
$rows = array();
// every row is a role
foreach (element_children($form['roles']) as $rid) {
$row = array();
$row[] = $roles[$rid];
// every column is a permission
foreach (element_children($form['roles'][$rid]) as $i) {
$row[] = drupal_render($form['roles'][$rid][$i]);
}
$rows[] = $row;
}
return theme('form_element', array(
'#description' => t('Select which users can view/edit your post based on their role.'),
), theme('table', $header, $rows));
}
/**
* Implementation of hook_node_operations().
*
* @return array
*/
function node_privacy_byrole_node_operations() {
$operations = array();
foreach (user_roles() as $rid => $role) {
$grants = array();
$revokes = array();
foreach (array(
'view',
'edit',
'delete',
) as $priv) {
$operations["grant-{$rid}-{$priv}"]['label'] = t('Grant !priv for !role', array(
'!priv' => $priv,
'!role' => $role,
));
$operations["grant-{$rid}-{$priv}"]['callback'] = 'node_privacy_byrole_node_operations_update';
$operations["grant-{$rid}-{$priv}"]['callback arguments'] = array(
1,
$rid,
$priv,
);
$operations["revoke-{$rid}-{$priv}"]['label'] = t('Revoke !priv for !role', array(
'!priv' => $priv,
'!role' => $role,
));
$operations["revoke-{$rid}-{$priv}"]['callback'] = 'node_privacy_byrole_node_operations_update';
$operations["revoke-{$rid}-{$priv}"]['callback arguments'] = array(
0,
$rid,
$priv,
);
}
}
return $operations;
}
function node_privacy_byrole_node_operations_update($nodes, $perm, $rid, $priv) {
foreach ($nodes as $node_to_update) {
$node = node_load($node_to_update);
$node->node_privacy_byrole['roles'][$rid][$priv] = $perm;
node_save($node);
}
}
/**
* Implementation of hook_action_info().
*/
function node_privacy_byrole_action_info() {
return array(
'node_privacy_byrole_change_role_action' => array(
'description' => t('Change role permissions'),
'configurable' => TRUE,
'type' => 'node',
'hooks' => array(
'nodeapi' => array(
'insert',
'update',
),
),
),
'node_privacy_byrole_rolereference_action' => array(
'description' => t('Change permissions based on rolereference field'),
'type' => 'node',
'configurable' => TRUE,
'hooks' => array(
'nodeapi' => array(
'insert',
'update',
),
),
),
);
}
function node_privacy_byrole_change_role_action($node, $context) {
/*
Mod $node here to have new permissions. It expects:
$node->node_privacy_byrole['roles'][$rid]['view']
$node->node_privacy_byrole['roles'][$rid]['edit']
$node->node_privacy_byrole['roles'][$rid]['delete']
Otherwise it will use defaults setup for the content type.
*/
if (isset($context['node_privacy_byrole']['roles'])) {
$node->node_privacy_byrole['roles'] = $context['node_privacy_byrole']['roles'];
}
module_invoke('node_privacy_byrole', 'nodeapi', $node, 'update');
}
function node_privacy_byrole_change_role_action_form($context) {
$form = array();
$form['#node']->node_privacy_byrole = isset($context['node_privacy_byrole']) ? $context['node_privacy_byrole'] : NULL;
// Avoiding a notice since menu_form_alter assumes if $form['#node'] is set, $form['#node']->type will be also.
$form['#node']->type = NULL;
node_privacy_byrole_node_form($form);
$form['node_privacy_byrole']['#weight'] = 0;
$form['node_privacy_byrole']['#collapsed'] = FALSE;
return $form;
}
function node_privacy_byrole_change_role_action_validate($form, &$form_state) {
$errors = array();
if (empty($form_state['values']['node_privacy_byrole'])) {
$errors['node_privacy_byrole'] = t('Please use the supplied form to submit access permissions.');
}
foreach ($errors as $name => $message) {
form_set_error($name, $message);
}
return count($errors) == 0;
}
function node_privacy_byrole_change_role_action_submit($form, &$form_state) {
return array(
'node_privacy_byrole' => $form_state['values']['node_privacy_byrole'],
);
}
function node_privacy_byrole_rolereference_action($node, $context) {
/*
Mod $node here to have new permissions. It expects:
$node->node_privacy_byrole['roles'][$rid]['view']
$node->node_privacy_byrole['roles'][$rid]['edit']
$node->node_privacy_byrole['roles'][$rid]['delete']
Otherwise it will use defaults setup for the content type.
*/
if (isset($context['node_privacy_byrole']['roles'])) {
$node->node_privacy_byrole['roles'] = $context['node_privacy_byrole']['roles'];
}
foreach ($context['permissions'] as $key => $value) {
// The true $values are normally literally 'view', 'edit', 'delete' or 0 for false
// which is required for the #default_values when loading the configuration
// page for an existing action, but the node access table actually works on
// 0 or 1 in the access tables, so convert them here because that's easier
// than converting 1 to 'edit' for the #default_value on the form case.
$context['permissions'][$key] = empty($context['permissions'][$key]) ? 0 : 1;
}
foreach ($context['node_author'] as $key => $value) {
// Do for author what was just done for other permissions.
$context['node_author'][$key] = empty($context['node_author'][$key]) ? 0 : 1;
}
$node->node_privacy_byrole['author'] = $context['node_author'];
foreach (_node_privacy_byrole_walk_role_fields($node->{$context}['field']) as $rid) {
$node->node_privacy_byrole['roles'][$rid] = $context['permissions'];
}
module_invoke('node_privacy_byrole', 'nodeapi', $node, 'update');
}
function node_privacy_byrole_rolereference_action_form($context) {
$form = array();
$form['#node']->node_privacy_byrole = isset($context['node_privacy_byrole']) ? $context['node_privacy_byrole'] : NULL;
// Avoiding a notice since menu_form_alter assumes if $form['#node'] is set, $form['#node']->type will be also.
$form['#node']->type = NULL;
node_privacy_byrole_node_form($form);
$form['node_privacy_byrole']['#collapsed'] = FALSE;
unset($form['node_privacy_byrole']['#weight']);
$form['node_privacy_byrole']['#title'] = t('Default permissions');
$form['new'] = array(
'#type' => 'fieldset',
'#title' => t('New permission'),
'#description' => t('The new permissions to set that will override the defaults. The value of the field is expected to match a numerical role id.'),
'#collapsed' => FALSE,
'#collapsible' => TRUE,
);
$fields = content_fields();
$options = array();
foreach ($fields as $field) {
if ($field['type'] == 'rolereference') {
$options[$field['field_name']] = t($field['widget']['label']) . ' (' . $field['field_name'] . ')';
}
}
if (!count($options)) {
drupal_set_message(t('This action cannot be applied because there are no rolereference fields currently available.'));
drupal_goto(referer_uri());
}
asort($options, SORT_LOCALE_STRING);
$form['new']['field'] = array(
'#title' => t('Field'),
'#type' => 'select',
'#options' => $options,
'#default_value' => isset($context['field']) ? $context['field'] : '',
);
unset($fields, $field, $options);
$form['new']['permissions'] = array(
'#title' => t('Permissions'),
'#type' => 'checkboxes',
'#options' => array(
'view' => t('view'),
'edit' => t('edit'),
'delete' => t('delete'),
),
'#default_value' => isset($context['permissions']) ? $context['permissions'] : array(),
'#description' => t('Edit permission implies view. Delete permission implies edit.'),
);
$form['author'] = array(
'#type' => 'fieldset',
'#title' => t('Node Author'),
'#collapsed' => FALSE,
'#collapsible' => TRUE,
);
$form['author']['node_author'] = array(
'#type' => 'checkboxes',
'#options' => array(
'view' => t('view'),
'edit' => t('edit'),
'delete' => t('delete'),
),
'#default_value' => isset($context['node_author']) ? $context['node_author'] : array(),
'#description' => t('Edit permission implies view. Delete permission implies edit.'),
);
return $form;
}
function node_privacy_byrole_rolereference_action_validate($form, &$form_state) {
$errors = array();
if (empty($form_state['values']['node_privacy_byrole']) && empty($form_state['values']['field']) && empty($form_state['values']['permissions']) && empty($form_state['values']['node_author'])) {
// this isn't a great validation check because it doesn't allow for setting errors on each form item
// but what is there really to validate here?
$errors['node_privacy_byrole'] = t('Please use the supplied form to submit access permissions.');
}
foreach ($errors as $name => $message) {
form_set_error($name, $message);
}
return count($errors) == 0;
}
function node_privacy_byrole_rolereference_action_submit($form, &$form_state) {
$params = array(
'node_privacy_byrole' => $form_state['values']['node_privacy_byrole'],
'field' => $form_state['values']['field'],
'permissions' => $form_state['values']['permissions'],
'node_author' => $form_state['values']['node_author'],
);
return $params;
}
/**
* Loop recursively through form submissions to find values of rids since we
* can't be sure if the field returns a string or a nested array like in a multiple select.
*/
function _node_privacy_byrole_walk_role_fields($form) {
if (!is_array($form)) {
return array(
$form,
);
}
else {
$rids = array();
foreach (array_keys($form) as $getvar) {
if (element_child($getvar) && is_array($form) && !is_null($form[$getvar])) {
$returned = _node_privacy_byrole_walk_role_fields($form[$getvar]);
$rids = array_merge($rids, $returned);
}
else {
$rids[] = $getvar;
}
}
}
return $rids;
}