I would like to propose a modification to the core Drupal system: A new hook titled
hook_roles.
hook_roles would add role IDs to the array of roles returned by the existing Drupal operation:
$user->roles
Module developers would create a function in their module titled "my_module_name_roles" and this function would return the IDs of additional roles that the module has determined the user should have at the time $user->roles is called.
So, the process would be:
1. $user->roles is called in some function somewhere.
2. Drupal checks hooks. Sample:
function mymodule_roles($user) {
array added_roles();
// Do whatever to determine what roles should be added to this user at this point.
return added_roles();
3. Whatever roles are returned by the hook_roles hooks are added to the results of $user->roles.
4. Drupal processes the results of $user->roles as normal.
I have a module I developed call og_user_roles http://drupal.org/node/87679. What this module does is assign roles to OG Group Members that are specific to the group the member is in at the time the requested function is called. Right now, for this to work, I have to hack the user_access function in the user.module like this:
function user_access($string, $account = NULL) {
global $user;
static $perm = array();
if (is_null($account)) {
$account = $user;
}
// User #1 has all privileges:
if ($account->uid == 1) {
return TRUE;
}
// To reduce the number of SQL queries, we cache the user's permissions
// in a static variable.
//
// Modifications
//
// We don't cache, so we don't need to check if $perm[$account->uid] is set
// We now use "user_all_roles" to bring back additional roles by group, instead of just $account->roles
//
// if (!isset($perm[$account->uid])) {
// $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', array_keys($account->roles))); // orig code
$result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', user_all_roles($account))); // my modification
$perm[$account->uid] = '';
while ($row = db_fetch_object($result)) {
$perm[$account->uid] .= "$row->perm, ";
}
// }
//
// Modification
// Remove duplicates from $perm[$account->uid];
//
static $tempArray = array();
static $tempArray0 = array();
$tempString = "";
//
// First covert $perm[$account->uid] to string;
//
$tempString = $perm[$account->uid];
//
// Next, convert this to an array;
//
$tempArray = split(',', $tempString);
//
// Now, make the array unique
//
$tempArray0 = array_unique($tempArray);
//
// Now copy back to $perm[$account->uid];
//
$perm[$account->uid] = implode(",", $tempArray0);
if (isset($perm[$account->uid])) {
return strpos($perm[$account->uid], "$string, ") !== FALSE;
}
return FALSE;
}
This proposed hook would eliminate the need for me, or anyone else with a similar need, to hack the core module for this purpose.
Comments
Comment #1
webchickFeatures only go into the dev release, not the stable version...
But I'm wondering if you couldn't alter the $user->roles property on hook_user op load?
Comment #2
somebodysysop commentedSorry. Learning this as I go.
It depends upon when the "load" op is executed in hook_user.
For example, $user->roles is called by user_access function. user_access function is called by the node_access function. Both of these functions are used to determine access privileges on content view/create/update/delete. So, I need to modify $user->roles when it is called on these types of operations.
Also, if the "load" op in hook_user could work, how would I alter the $user->roles property for JUST the operation being performed (I don't want the new roles permanently added to the $user object because they could change depending upon the group context)?
Comment #3
somebodysysop commentedI followed the suggestion and re-coded my module to use the hook_user "load" operation to add the additional roles to $user->roles.
I wrote a debug function that records the results every time hook_user "load" is called. Theoretically, it is going to be called every time $user->roles is called because it will be user object will be loaded on "global $user".
On the group navigation menu, I see all the "create" content type links associated with roles that the user has in the group.
Howerver, on node creation, what I found is that, for example:
http://www.mysite.com/node/add/link?gids[]=29
returns an "Access denied" message EVEN THOUGH my debug results show that my hook_user "load" operation has returned the correct roles.
What this says to me is that either the node or the og module is using something other than user_access and/or node_access to determine whether the user has permission to create this content type.
Can someone please help me with this? What I need to know is what, other then user_access/node_access would be called for permissions check on a group node creation operation?
p.s. One strange thing which might help: When I loaded the devel.module and gave the user in question access to it, the "Access denied" error goes away and he is able to create nodes as he should.
Comment #4
somebodysysop commentedNo hook needed. Resolved problems by using hook_user to add OG roles to $user->roles, and hook_init to redirect http://www.mysite.com/node/add/link?gids[]=29 requests to a customized "node_add" routine. Notated here: http://drupal.org/node/87679