I tried to delete a role that I had created on the admin/config/people/roles page and got these "notices".
* Notice: Trying to get property of non-object in user_role_delete() (line 2417 of /home/greg/workspace/drupal-head/modules/user/user.module).
* Notice: Trying to get property of non-object in user_role_delete() (line 2420 of /home/greg/workspace/drupal-head/modules/user/user.module).
* Notice: Trying to get property of non-object in user_role_delete() (line 2424 of /home/greg/workspace/drupal-head/modules/user/user.module).
* Notice: Trying to get property of non-object in block_user_role_delete() (line 913 of /home/greg/workspace/drupal-head/modules/block/block.module).
It also said:
The role has been deleted.
But the role was not deleted.
I did a typecast in user_admin_role_submit()
on line 823 of user.admin.inc
. Now the roles are deleted as they should be.
I think this is a better option than changing the is_int()
to is_numeric()
in user_role_load()
, as that would break things if someone attempted to use a number as the name of the role.
I've provided a patch.
Comment | File | Size | Author |
---|---|---|---|
#40 | user-roles-619584-40.patch | 9.47 KB | David_Rothstein |
#35 | 2010-03-19_editpage.png | 25.98 KB | Georg |
#34 | user_role.patch | 8.27 KB | mr.baileys |
#33 | user_role.patch | 8.27 KB | mr.baileys |
#28 | user-roles-delete.patch | 5.77 KB | mr.baileys |
Comments
Comment #1
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedThis patch works great for me.
In function
user_role_delete
changing param $role to $rid will make better sense.Comment #2
preventingchaos CreditAttribution: preventingchaos commentedI think using
$role
inuser_role_delete()
makes sense, since it is able to accept the role name or the role rid.The problem was that
user_role_delete()
relies onuser_role_load()
which determines whether it got the role rid or role name based on the variable type. If the type of$role
is an integer, it's expecting the role rid. If the type of$role
is not an integer, it's expecting the role name. The role rid thatuser_admin_role_submit()
gets from the form is a string, despite being a numeric value, and is callinguser_role_delete()
with this string, causing an incorrect database query to be run. Drupal 6 didn't have this problem becauseuser_admin_role_submit()
had ran it's own database queries to delete the role by the role rid, rather than calling a special function for doing it like it does in Drupal 7. For Drupal 7, I think the only thing that needs to be changed is to typecast the numeric string to an integer, and everything should as expected.Example without typecasting (
$form_state['values']['rid'] == '1'
):user_admin_role_submit()
callsuser_role_delete($role = '1')
which callsuser_role_load($role = '1')
causes
user_role_load()
to set$field
to'name'
, searching the database for a role named'1'
.With typecasting as an integer (
(int)$form_state['values']['rid'] == 1
):user_admin_role_submit()
callsuser_role_delete($role = 1)
which callsuser_role_load($role = 1)
causes
user_role_load()
to set$field
to'rid'
, searching the database for a role with the rid of1
.Comment #3
mcjim CreditAttribution: mcjim commentedPatch works. Seems the most straight-forward way of solving this.
Comment #4
webchickWe definitely need tests for this. This is critical functionality that should not ever be broken.
Comment #5
mcjim CreditAttribution: mcjim commented@webchick I added a patch for the missing tests here: http://drupal.org/node/624854.
It currently fails automated testing as it needs this patch to go in first, though.
Comment #6
joachim CreditAttribution: joachim commentedTested patch. Patch makes bad thing go away, is good :)
Comment #7
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commented@gcopenhaver I agree with you param $role makes sense. I didn't read the comment line properly then.
Changing title and re-rolling patch with test from #624854: Tests for adding, editing and deleting roles
Comment #8
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedComment #10
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedA better test.
Comment #11
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedComment #13
sun1) $role is altered by reference, so this message will display the renamed role name for %name.
2) Not sure why we presume that a role has been renamed without determining it first, but that's entirely wrong. (It's true that Drupal core does not allow to do something else on the form, but hey, forms can be altered! :)
Whatever this cast to integer tries to fix, it's wrong, because if 'rid' doesn't contain a numeric role id, then something entirely different entirely elsewhere went entirely wrong.
Not strictly necessary.
You want to use max(array_keys($this->admin_user->roles)) instead.
Seems like this can be moved into setUp().
We don't need the additional assertion message ("Successfully...") here.
Wrong indentation.
We want to pass an empty array() instead of $edit here.
No blank line here, please.
This review is powered by Dreditor.
Comment #14
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commented@sun Thank you for reviewing and correcting the mistakes in my patch. Attached is the new patch which addresses all the above mentioned corrections.
Comment #16
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedAttached patch corrects the PHP syntax error.
Comment #18
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedRemoved assertText() as suggested in #13.
Comment #19
sunwuhuhuh? We still have arg() code in HEAD?! OMG.
Do you see a way to remove the usage of arg() for this function?
Or, to shortcut this: We need a menu argument loader function here and the function needs to take $role as argument.
The first condition that checks for anonymous/authenticated/named must be removed and a page request that was redirected here should _never_ reach this function in the first place.
These changes can be reverted, because they have nothing to do with this bug.
This review is powered by Dreditor.
Comment #20
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commented@sun This sounds good for me. But i am struck with menu argument loader, i changed user module's hook_menu item like
This invokes
user_role_load
already define in user.module file but page callbackuser_admin_role
never invoked instead i get drupal's "page not found" error. If i replace "%user_role" with "%" it invokesuser_admin_role
. I even replaced "%user_role" with "%user", '%user_uid_optional' etc. but no hope. In all the case the respective*_load
function is called and drupal's "page not found" error is returned. I cleared cache, ran cron still it doesn't works.Let me know how to proceed with this.
Comment #21
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedIn IRC mbutcher and sdboyer helped me to figure out the problem explained in #20. Attached patch makes the necessary changes mentioned in #19 except status message, because i prefer to have short and more descriptive messages.
Comment #22
sunA user role object as returned from user_admin_role_load().
!empty()
Form validation handler for user_admin_role() form.
Form submit handler for user_admin_role() form.
Do we still have to convert to an integer here? If so, there should be an inline comment above this line that quickly explains why.
s/to alter/to load/
We also want to add
@see user_role_load()
Can be removed.
This inline comment can be removed. (and would have to be above the commented-on line anyway)
Please revert.
UserRoleAdminTestCase
These are technically not required and can be removed.
User role administration
Test adding, editing, and deleting user roles.
Should rather use assertNoLinkByHref()
Powered by Dreditor.
Comment #23
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedNo. It works fine irrespective of type casting.
Thanks for reviewing this. It looks much better now. All the changes has been done in the attached patch.
Comment #24
mr.baileysThere should be a blank line after the first summary line, and there should be a @return directive (See user_load for an example).
Uh oh. This changed the behavior in a way that we can now visit
admin/config/people/roles/edit/<role-name>
too. Not necessarily bad, but I'm not sure we should allow this. I managed to delete the authenticated user role by visiting "admin/config/people/roles/edit/authenticated user" and pressing delete.Powered by Dreditor.
Comment #25
mr.baileysForgot to switch status...
Comment #26
sunNothing unusual here. You can also directly type node/2/edit or even node/2/delete in your browser's address bar.
Comment #27
mr.baileys@sun: that's not exactly the same though... In this case the menu loader checks the $rid against the authenticated and anonymous roles and returns a 404 for them, allowing you to only change custom roles. However, if you use "authenticated user" instead of "2" in the URL, you bypass that check. It's inconsistent.
I'd prefer an additional is_numeric check:
Comment #28
mr.baileysRe-rolled...
Comment #29
mr.baileysComment #30
marcvangendMarked #722636: Don't delete user roles (custom user roles) and #687912: Can't delete custom user roles as duplicates.
Comment #31
David_Rothstein CreditAttribution: David_Rothstein commentedThis is a critical bug, right?
Minor, but I think there should be a blank line before the @ingroup line.
These tests seem a bit fragile... Why aren't we testing that the role is actually found in the database? (Similar comment applies for other tests.)
I think at a minimum this needs a code comment explaining why in the world we want to avoid loading the anonymous and authenticated user roles here...
As stated in the original post, this is going to cause havoc if anyone ever uses a number as the name of their role. Granted, that's a bit of an edge case, but we still don't want it to break. (For some fun, trying applying this patch and then trying to create two roles on your site, both named "22" ... explosions ensue.)
I think the right way to fix this bug is to have two different functions: user_role_load() should only accept a role ID, and user_role_load_by_name() should only accept a role name. This would also be consistent with the way the existing user_load() and user_load_by_name() functions work.
That's an API change, of course. I don't make the decisions, but if it were up to me, I'd definitely think it's worth a minor change to the API in order to fix this bug the right way :)
Comment #32
David_Rothstein CreditAttribution: David_Rothstein commentedActually, more to the point: This type of code belongs in an access callback, not in the loader function. In other words, ideally the menu item should just use %user_role here so that the normal user_role_load() is called, and denying access for anonymous and authenticated should happen in the access callback.
This might only be possible if we make the API change I suggested above - but in that case, it's just another reason why we should do that.
Comment #33
mr.baileysThanks for the feedback David!
Comment #34
mr.baileysFixed typo.
Comment #35
Georg CreditAttribution: Georg commentedAfter applying the last patch, the edit page is broken.
When going to "edit role" it displays following errors:
Comment #36
mr.baileysI'm guessing you need to rebuild the menu since the menu loader was changed. Can you clear your cache (Administer > Configuration > Development > Performance) and report back if this does not make the notices go away?
Comment #37
catchI'd go for user_role_delete() only taking an int. I can't imagine vast numbers of D7 modules are using it with a string, and it didnt exist in D6, so in the scale of API changes it's pretty small. Also why do we load the role if an int is passed, that'd be the ID anyway no?
Comment #38
Georg CreditAttribution: Georg commentedanswering #36: yes, after clearing my cach, everything works correctly!
I tested again against the most current HEAD.
Comment #39
andypost1 and 2 should be a RUPAL_ANONYMOUS_RID and DRUPAL_AUTHENTICATED_RID
Comment #40
David_Rothstein CreditAttribution: David_Rothstein commentedHere's a reroll that addresses #39, and also makes some small fixes/improvements to the documentation and tests.
I didn't change user_role_delete() to only take an integer just yet, since it doesn't seem 100% necessary to fix this bug - the is_int() check should work OK. However, I definitely think it would be a good idea :)
We also should do a followup issue somewhere about why there is no confirmation form on "delete role"... that's a little dangerous. However, it's a preexisting problem.
Comment #41
quicksketchFollowing, as David pointed out to me, this issue would be a tremendous help to #228061: Usability UMN: Allow roles to be weighted.
Comment #42
catchWorks for me. Opened #750290: Add a confirm form for role deletion so it doesn't get lost. RTBC.
Comment #43
Dries CreditAttribution: Dries commentedCommitted to CVS HEAD.
Comment #44
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedFor #40
I have submitted a patch for this #750290: Add a confirm form for role deletion, need reviews.
Comment #45
Sivaji_Ganesh_Jojodae CreditAttribution: Sivaji_Ganesh_Jojodae commentedI find some bug in the above committed patch. When fixing #750290: Add a confirm form for role deletion Sun pointed out that i am missing
page callback
. In the above patchuser_menu()
,$items['admin/people/permissions/roles/edit/%user_role']
does not uses 'page callback' doing so will make the menu system to use parent items callback (@see Return value section http://api.drupal.org/api/function/hook_menu/7). Unfortunately the parent item$items['admin/people/permissions/roles']
uses the requiredpage callback
=>drupal_get_form()
. Any changes we make in parent menu item will break the delete operation isn't it ?Comment #46
andypostit is not, let's continue at #750290: Add a confirm form for role deletion