--- nodeperm_role.module.4_6_3 2005-12-06 16:22:49.000000000 -0800 +++ nodeperm_role.module 2005-12-06 16:28:38.000000000 -0800 @@ -110,6 +110,10 @@ $help = t('
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'); + } +} + + ?>