Hi there,
Say you have a group's home page displaying a teaser list of nodes. You have a module installed that provides a link (i.e. hook_link()), but only if a user_access() call returns true. This link won't get displayed within the group using OG User Roles, as the call to user_access() returns false.
I think the reason behind this is the cacheing that user_access() does. The first time you call user_access() it will remember the permissions that user has (if it has some permissions; if it has none, I don't think the caching actually happens). Adding roles later therefore doesn't have any influence on the results of user_access(). As the caching is done with a static variable, local to user_access(), I don't see an easy way around this, other than perhaps trying to load the roles provided by the group context even earlier than init() (you need to catch it before the first permission gets queried, which is administer menus, menu.inc:873 where I am).
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | ogur.patch | 590 bytes | dmhouse |
Comments
Comment #1
somebodysysop commentedThis is exactly what the OG module does: calls user_access to determine which "create" links are displayed on the group menu for a user. Are you saying that og_user_roles is not displaying the correct group menu links, or just the link from your module?
What module is it that wants to create a link that should be displayed on the group home page, but is not? Have you tried weighting OG User Roles lighter than this module?
Same thing happens when sitewide caching disabled?
What is an example url in the case where the link in question is not displayed? Have you looked at the og_user_test table to see what permissions are being returned by og_user_roles at this url?
Do you have any suggestions for loading roles earlier than init()? Right now, it's done when (if) the $user object is loaded and in hook_init().
Comment #2
dmhouse commentedBy "create" links do you mean the 'Create <content type>' links within the Group details block? That's not what I'm talking about. When you have a teaser list of nodes, each node can have a list of links associated with it. For example, I've hacked modr8 to display 'Approve' or 'Delete' links alongside each node that's pending moderation (I also had to write a menu callback handler for this to work). Links can be added with hook_link().
How do you weight modules?
It will do, yes: if you look at the code for user_access(), it doesn't check to see if caching is enabled.
I've var_dump()'d the $user object in user_access() when the appropriate call goes through. $user->roles has been correctly set to array('authenticated user', 'contributor', 'editor') at this point. However, this isn't looked at, as the caching that user_access() does (inside its local and static $perm variable) holds the permissions that were fetched the very first time that user_access() was called in this request, before og_user_roles had a change to add the extra items to $user->roles. These cached permissions are the ones that are used.
I would have thought that doing it when the $user object is loaded would be early enough, as this should be earlier than any user_access() calls. What do you mean be "(if)" here? Under what circumstances would $user not get loaded?
Comment #3
dmhouse commentedAfter digging a bit more, I found the problem was that the code executed in og_user_roles_user('load') wasn't grabbing the group ID successfully. Adding the following code in og_user_roles_getgid(), before the 'return $gid' line, fixed the issue for me:
I'm wondering whether this code will be enough to grab the gid every time, or whether we still need the two other queries in that function.
I've attached a patch which contains my fix.
Comment #4
somebodysysop commentedThanks for the code! Why didn't I think of that!
I am concerned about this section:
If the node belongs to more than one group, and the group in question isn't the one returned, then we have the same problem. Also: Suppose that this node belongs to two groups, and the user belongs to both groups, but has different permissions in each group? How do we determine which gid to bring back?
That's what I need to work on next.
Comment #5
somebodysysop commentedWould you see if this code works for you?:
This adds some logic to try to address the issue of one node in two groups with a user who also belongs to the two groups.
Thanks.
Comment #6
dmhouse commentedThis is a valid concern. I guess, instead of looking for the group ID, we need to find all group IDs which apply to this page.
I think the right thing to do is to give the user all roles from all groups which apply to this node. My reasoning is that if you're looking at a node in a given group, you expect to have the roles for that group. This applies to all groups, so you would expect to have the roles for all groups. To do this og_user_roles_getgid() and og_user_roles_all_roles() need to be refactored to deal with more than one gid, and to fetch the roles for all of these gids.
It works fine. However, I'm not sure it's the right approach, I think my above comments would be a better solution.
Thanks for your attention on this issue.
Comment #7
somebodysysop commentedYou are right. I reached the same conclusion. og_user_roles_getgid() should return all groups a node belongs to, and og_user_roles_all_roles() should calculate all the permissions a user has for the node in all groups.
However, that's a major undertaking. So, right now, just trying my best to get the *current* group a node is in. The logic being that if the user doesn't have the correct permissions in the *current* group for the node, then deny access (even if he does have the correct permissions for the node in another group that the node belongs to).
I agree it's not the best logic, but at least it's consistent for now.
Thanks for tracking down this issue and testing code.
Comment #8
dmhouse commentedOK. It will indeed be a large undertaking. Perhaps you could apply that patch, close this issue, then begin work on multiple gid support. In the mean time consider the issue fixed for me, as in my case a group will never be a member of more than one group.
Comment #9
dmhouse commentedErr, sorry, I meant a node will never be a member of more than one group!
Comment #10
somebodysysop commentedCode from #5 will be committed to 2.3 release.
Comment #11
somebodysysop commentedChanges committed to 2.3 release.
Comment #12
somebodysysop commentedAs a follow up, finally discovered the issue with user_access caching. Submitted patch to Drupal core here: http://drupal.org/node/170524
They rejected it, so I've made the patch available for download and added OG User Roles settings to be able to use it to "clear the cache". http://drupal.org/node/166566
Comment #13
somebodysysop commentedI've finally addressed the issue of a user belonging to two groups with different permissions here: http://drupal.org/node/258976#comment-850935
OGR now has a new function: og_user_roles_user_access($string, $gid, $uid). It is called during nodeapi('validate') and will make sure a user has permission to post in all groups that are listed in his group audience.