Drupal\'s default behavior is to reset options to their defaults when a node is edited. Change this behavior by indicating, below, which options will be preserved when a user edits a node they don\'t own. Users with "administer nodes" permission may override these settings within the node form.
', array('%default-options-link' => url('admin/node/configure/types')));
$output .= form_group(t('Editing options'), $help. $group);
+ // CRG : Add an advanced option that will allow for incremental changes to access instead of replacement changes
+ $html = form_checkbox(t("Allow incremental per-role settings"), 'nodeperm_role_inherit', 1, variable_get('nodeperm_role_inherit',0), 'Allows actions to inherit, remove or set permissions for roles. Inheriting means any existing permissions for this role are retained by this action.');
+ $output .= form_group(t('Advanced options'), $html, 'Changes to individual actions will not occur until the actions are edited and saved again');
+
return $output;
}
@@ -169,12 +173,17 @@
* Save node permissions by writing them to the database.
*/
function nodeperm_save($node) {
- if ($node->nodeperm_role_view || $node->nodeperm_role_edit) {
+ // If either of the special array are set then update node_access. Original code used just || which
+ // failed when all permissions were being taken away.
+ if (is_array($node->nodeperm_role_view) || is_array($node->nodeperm_role_edit)) {
$roles = nodeperm_get_roles();
db_query("DELETE FROM {node_access} WHERE nid = %d AND realm = 'nodeperm_role'", $node->nid);
$grants = array();
+
+ // Get current node permissions
$node->nodeperm_role_view = isset($node->nodeperm_role_view) ? $node->nodeperm_role_view : array();
$node->nodeperm_role_edit = isset($node->nodeperm_role_edit) ? $node->nodeperm_role_edit : array();
+
/* A rid of -1 means that the user doesn't want anybody else to edit their entry. */
foreach ($node->nodeperm_role_view as $rid) {
if ($rid != -1) {
@@ -189,12 +198,18 @@
}
foreach ($grants as $rid => $grant) {
- db_query('INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, \'nodeperm_role\', %d, %d, %d)', $node->nid, $rid, $grant['view'], $grant['edit'], $grant['edit']);
- if ($grant['view']) {
- $rnames_view[] = $roles[$rid];
- }
- if ($grant['edit']) {
- $rnames_edit[] = $roles[$rid];
+ // Optimize the node access table. If all permissions are FALSE then do not bother adding it (deny is the default)
+ // - In theory reducing node access rows will improve performance
+ // - Note that edit permission is also used for delete permission
+ if ($grant['view'] || $grant['edit']) {
+ // %d format control will auto-convert undefined values to 0 which is what is desired
+ db_query('INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, \'nodeperm_role\', %d, %d, %d)', $node->nid, $rid, $grant['view'], $grant['edit'], $grant['edit']);
+ if ($grant['view']) {
+ $rnames_view[] = $roles[$rid];
+ }
+ if ($grant['edit']) {
+ $rnames_edit[] = $roles[$rid];
+ }
}
}
if ($rnames_view) {
@@ -248,7 +263,7 @@
return $nodeperm_role_edit;
}
-function nodeperm_get_roles() {
+function nodeperm_get_roles($none = False) {
static $roles;
if (!$roles) {
@@ -265,8 +280,21 @@
* Implementation of a Drupal action.
* Alters node level role permissions for a node.
*
+ * If advanced inheritence flag is set then this action supports set/remove/inherit logic. This is the only
+ * place such code exists. Inheritence does not make any sense when a node is being edited as there is nothing
+ * to inherit from!
*/
function action_node_assign_role_perms($op, &$edit, &$node) {
+ // Set some common values, used by many operations
+
+ // *** From module settings
+ $advanced_form_name = 'nodeperm_role_inherit';
+ $is_advanced_form = variable_get($advanced_form_name, 0);
+ // True if view permission is being maintained
+ $is_view = variable_get('nodeperm_role_mode', 0) == 0;
+
+
+ // Handle operation
switch($op) {
case 'metadata':
return array(
@@ -278,10 +306,67 @@
break;
case 'do':
+ // If node contains nodeperm settings use them, otherwise fetch them
+ // - In most cases the data will not exist, but allow for it in case others have done some modifications
+ // - Only bother getting values if advanced flag is set
+ // - Make sure defaults are initialized to arrays
+ // - When done each element contains the role IDs currently granted the specific permission
+ $default['view'] = array();
+ $default['edit'] = array();
+
+ if ($is_advanced_form) {
+ // Avoid grabbing view permissions if this has been deactivated
+ if ($is_view) {
+ if (is_array($node->nodeperm_role_view)) {
+ $default['view'] = $node->nodeperm_role_view;
+ }
+ else {
+ $default['view'] = nodeperm_role_load_view($node->nid);
+ }
+ }
+ // edit (aka update) (also used for delete) is always grabbed
+ if (is_array($node->nodeperm_role_edit)) {
+ $default['edit'] = $node->nodeperm_role_edit;
+ }
+ else {
+ $default['edit'] = nodeperm_role_load_view($node->nid);
+ }
+ } // End of inheritence support check
+
+ // Loop through parameters passed via edit[]
+ // Handle new style inheritance settings in a way that is compatible with the old
+ // - A teeny bit slower then original code but of little consequence for actions as they fire rarely (as compared to reads) in all but VERY extreme cases
+ $grants = array('view' => array(), 'edit' => array()); // Initialize final result set
+
+ foreach (nodeperm_get_roles() as $rid => $role_name) {
+ // Loop through each permission
+ foreach (nodeperm_role_perms() as $p) {
+ $set_name = 'nodeperm_role_'. $p; // Name of element holding rids that have explicit permissions
+ $inherit_name = 'nodeperm_role_'. $p . '_inherit'; // Name of element holding rids that inherit
+
+ if (in_array($rid, $edit[$set_name])) {
+ // permissions was explicitly specified for this role
+ $grants[$p][] = $rid;
+ }
+ elseif(in_array($rid, $edit[$inherit_name])) {
+ // permissions is inherited. If this rid is in default set then add it to result set
+ if (in_array($rid, $default[$p])) {
+ $grants[$p][] = $rid;
+ }
+ }
+ // else denial is assumed (does not appear in an array)
+ }
+ }
+
+ // Add back into node and save nodeperm data
if (variable_get('nodeperm_role_mode', 0) == 0) {
- $node->nodeperm_role_view = $edit['nodeperm_role_view'];
+ $node->nodeperm_role_view = $grants['view'];
}
- $node->nodeperm_role_edit = $edit['nodeperm_role_edit'];
+ $node->nodeperm_role_edit = $grants['edit'];
+
+ // Data is now in normal nodeperm format:
+ // nodeperm_role_view = array of rids granted view
+ // nodeperm_role_edit = array of rids granted edit
nodeperm_save($node);
break;
@@ -291,10 +376,77 @@
$roles[-1] = t('none');
ksort($roles);
$output = '';
- if (variable_get('nodeperm_role_mode', 0) == 0) {
- $output .= form_select(t('Roles that may view the node'), 'nodeperm_role_view', $edit['nodeperm_role_view'], $roles, t('Select the roles that will be able to view the node.'), NULL, TRUE, FALSE);
+
+ // Get available permisisons, often used as a suffix for array keys
+ $perms = nodeperm_role_perms();
+
+
+ // Make sure elements are initialized
+ foreach (array('', '_inherit') as $type) {
+ foreach ($perms as $p) {
+ $name = 'nodeperm_role_' . $p . $type;
+ if (! $edit[$name]) {
+ $edit[$name] = array();
+ }
+ }
+ }
+
+ // Remember the type of form being generated
+ // - Use a different name so detection between re-display and initial display is possible
+ $output .= form_hidden($advanced_form_name, $is_advanced_form);
+
+ if ($is_advanced_form) {
+ // CRG: Support the advanced permission handling
+
+ // If this is the first display of this form
+ // - There is no preview so this check is probably not needed but do it anyway for completeness
+ if (! array_key_exists('nodeperm_role_form_type', $edit)) {
+ // Convert an array or roles to applicable options
+ // actions saves paramater data in $edit[] (same as CGI which normally makes it easy to transition between the two but doesn't help much now)
+ // - This is NOT blazing fast but for the very few times it will be triggered (defining an action) it is fine
+ // - This handles old style or new style
+ foreach ( nodeperm_get_roles() as $rid => $role_name) {
+ // Loop through each permission
+ foreach ($perms as $p) {
+ $cgi_name = 'nodeperm_role_'. $p .'_' . $rid;
+ if (in_array($rid, $edit['nodeperm_role_' . $p])) {
+ $edit[$cgi_name] = '1';
+ }
+ elseif($edit['nodeperm_role_' . $p . '_inherit'] && in_array($rid, $edit['nodeperm_role_' . $p . '_inherit'])) {
+ $edit[$cgi_name] = '-';
+ } else {
+ // Assume denial
+ $edit[$cgi_name] = '0';
+ }
+ }
+ }
+ }
+
+ $rows = array();
+ $columns = array();
+ $html .= '';
+ foreach ( nodeperm_get_roles() as $rid => $role_name) {
+ $columns = array($role_name); // Role name
+
+ foreach ($perms as $p) {
+ $cgi_name = 'nodeperm_role_'. $p .'_' . $rid;
+ $control = "\n";
+ $columns[] = $control;
+ }
+ $rows[] = $columns;
+ }
+ $output .= form_group(t('Advanced role permissions'), theme('table', array_merge(array('role'), $perms), $rows), t("For each role select '-' to retain exsiting permission (no change) or 'Y' to grant permission or 'N' to deny permission"));
+ } else {
+ // Original code
+ if (variable_get('nodeperm_role_mode', 0) == 0) {
+ $output .= form_select(t('Roles that may view the node'), 'nodeperm_role_view', $edit['nodeperm_role_view'], $roles, t('Select the roles that will be able to view the node.'), NULL, TRUE, FALSE);
+ }
+ $output .= form_select(t('Roles that may edit the node'), 'nodeperm_role_edit', $edit['nodeperm_role_edit'], $roles, t('Select the roles that will be able to edit the node.'), NULL, TRUE, FALSE);
}
- $output .= form_select(t('Roles that may edit the node'), 'nodeperm_role_edit', $edit['nodeperm_role_edit'], $roles, t('Select the roles that will be able to edit the node.'), NULL, TRUE, FALSE);
return $output;
break;
@@ -302,16 +454,20 @@
case 'validate':
$errors = array();
- if (!$edit['nodeperm_role_edit'] && $edit['nodeperm_role_view']) {
- $errors['nodeperm_role_edit'] = t('Please choose the role(s) to transition to.');
- }
+ // Validation only applies to simple interface
+ if (! $edit[$advanced_form_name]) {
+ if (!$edit['nodeperm_role_edit'] && $edit['nodeperm_role_view']) {
+ $errors['nodeperm_role_edit'] = t('Please choose the role(s) to transition to.');
+ }
- foreach ((array) $edit['nodeperm_role_view'] as $key => $rid) {
- $edit['nodeperm_role_view'][$key] = $rid;
- }
- foreach ((array) $edit['nodeperm_role_edit'] as $key => $rid) {
- $edit['nodeperm_role_view'][$key] = $rid;
- $edit['nodeperm_role_edit'][$key] = $rid;
+ foreach ((array) $edit['nodeperm_role_view'] as $key => $rid) {
+ $edit['nodeperm_role_view'][$key] = $rid;
+ }
+ foreach ((array) $edit['nodeperm_role_edit'] as $key => $rid) {
+ // CRG: view and edit can be different, allow this since other node access modules will be working with this one
+ // $edit['nodeperm_role_view'][$key] = $rid;
+ $edit['nodeperm_role_edit'][$key] = $rid;
+ }
}
foreach ($errors as $name => $message) {
@@ -323,9 +479,72 @@
// process the HTML form to store configuration
case 'submit':
- $params = array('nodeperm_role_edit' => $edit['nodeperm_role_edit'], 'nodeperm_role_view' => $edit['nodeperm_role_view']);
+ if ($edit[$advanced_form_name]) {
+ // If the new interface then translate the advanced settings into the old style
+ // nodeperm_role_view_inherit - List of roles that inherit the view permission
+ // nodeperm_role_edit_inherit - List of roles that inherit the edit permission
+ $params = array(
+ 'nodeperm_role_edit' => array(),
+ 'nodeperm_role_view' => array(),
+ 'nodeperm_role_edit_inherit' => array(),
+ 'nodeperm_role_view_inherit' => array());
+
+ foreach ( nodeperm_get_roles() as $rid => $role_name) {
+ // Loop through each permission - simular code as in 'form' but different enough to make factor hardly worth the effort
+ $perms = nodeperm_role_perms();
+ foreach ($perms as $p) {
+ $cgi_name = 'nodeperm_role_'. $p .'_' . $rid; // Name of CGI form data
+ $param_name = 'nodeperm_role_' . $p; // Paramater name to save rid in
+ if ($edit[$cgi_name]) {
+ switch ($edit[$cgi_name]) {
+ case '1':
+ $params[$param_name][] = $rid;
+ break;
+
+ case '-':
+ $params[$param_name . '_inherit'][] = $rid;
+ break;
+
+ // N is assumed if not in either array
+ }
+ }
+
+ } // end of loop through permissions
+ } // End of loop through roles
+ }
+ else {
+ // Old (simple) non-inheritance form data
+ // Inherit arrays are cleared just in case this is a transition from advanced to simple
+ $params = array(
+ 'nodeperm_role_edit' => $edit['nodeperm_role_edit'],
+ 'nodeperm_role_view' => $edit['nodeperm_role_view'],
+ 'nodeperm_role_edit_inherit' => array(),
+ 'nodeperm_role_view_inherit' => array());
+ }
+
return $params;
break;
}
}
+
+/*
+ * Returns an array of permissions that are being used.
+ *
+ * Note that internall the code reers to the update grant as 'edit'.
+ * This was retained during addition of inheritence code.
+ *
+ */
+
+function nodeperm_role_perms() {
+ if (variable_get('nodeperm_role_mode', 0) == 0) {
+ // Some think permissions slow things down but I have my doubts (CRG) since permissions are all on a single row in node_access
+ // XXX If TRUE then always return view/edit
+ return array('view', 'edit');
+ }
+ else {
+ return array('edit');
+ }
+}
+
+
?>