uc_roles fail when setting multiple roles feature

Posts: 12
Joined: 11/30/2007
Bug Finder

When you apply multiple roles to be applied when a product is purchased only one actually gets applied.

The expiration information is properly added into the database for all rolls but only one of the roles actually get applied to the user.

The reason is the on line 286/287 in uc_roles.module it loads the $order_user object by calling

$order_user = user_load(array('uid' => $order->uid))

After this it cycles through the products ordered and applies all roles.

When _role_action('grant'....

gets called the function _role_action()

saves the user object with

$roles_list = $user->roles + array($rid => _get_role_name($rid));
user_save($user, array('roles' => $roles_list));

then continues to insert the expiration information into the uc_roles_expirations table

The problem is the user_save function deletes all the users current roles before adding the the roles sitting in the $user->roles array

The $user object passed to _role_action() never gets the new user object containing the newly added roles. So you basically end up with probably the last role in the list of roles to be added.

SOLUTION:
1:Either build the entire new $role_list array containing all the new roles the user should get before calling _role_action() so when user_save gets called it saves all the user_roles the user should get.

or

2:Afteer about line 292 while ($role = db_fetch_object($roles)) {
The new user information needs to get loaded again so it has the new list of roles the user has.
I just simply added
$order_user = user_load(array('uid' => $order->uid)); directly after line 292

Solution 1 seems like a better solution so the user_load only gets called once and would also improve performance because user_save would only needed to be called once as well.

Posts: 332
Joined: 08/07/2007
Administrator

You're right, I think at the time I wasn't familiar with the internals of user_save. Good eyes there, thanks for spotting that. I've given you a bug finder badge. I also went with hidden solution #3: insert $order_user = user_load(array('uid' => $order->uid)); below line 307. This has the simplicity #2 without the performance drawback (user_load only needs to be called if a role promotion has taken place).

--

-Shawn Conn: If the Name Don't Rhyme It Ain't Mine