Escalation to target role fails

bob-hinrichs - November 5, 2008 - 00:56
Project:Invite
Version:6.x-2.x-dev
Component:Code
Category:bug report
Priority:normal
Assigned:Unassigned
Status:fixed
Description

After the values are inserted into the user_roles table by the _invite_escalate_role function, they are wiped out by the user_save function called by another hook. Printing the backtrace at that point seems to only show the hooks called from the form.inc user_register_submit function, although it definitely occurs after _invite_escalate_role. The users_roles insert does insert its data, confirmed by stopping the code there. It just gets wiped out by a later user_save where the edit[roles] value does not contain the assigned role. This leads me to believe that there is not enough use of the variable references in your insert case--it is not enough to insert directly into the database at that point. I played with this quite a while adding references and such but could not manage to get a suggestion as to how to change your code.

Notes: email confirmation is required for user registration. Am using autoassignrole to allow the user to select a role at registration. I believe the problem also happened when this was turned off, however.

I inserted this case into my own user hook and it solved the problem, as an ugly workaround, but it suggests a possible cause of the problem, namely the fact that the account and edit variables are being changed, and there is no need to insert role assignments into the database:
$invite = invite_load_from_session();

if (!$invite) {
// Try to look up an invitation in case a user has been invited to join
// the site, but did go straight to the site and signed up without
// using the invite link.
$code = db_result(db_query("SELECT reg_code FROM {invite} WHERE email = '%s'", $account->mail));
if ($code) {
$invite = invite_load($code);
}
}

$roles = array('default');

// Add roles of inviter.
$inviter_uid = db_result(db_query("SELECT uid FROM {invite} WHERE invitee = %d", $account->uid));
if ($inviter_uid && $inviter = user_load(array('uid' => $inviter_uid))) {
$roles = array_merge($roles, array_intersect($inviter->roles, user_roles(0, 'send invitations')));
}

// Map to configured target roles.
$targets = array();
foreach ($roles as $role) {
$role_no_space = str_replace(' ', '_', $role);
$target = variable_get('invite_target_role_'. $role_no_space, DRUPAL_AUTHENTICATED_RID);
if ($target != DRUPAL_AUTHENTICATED_RID) {
$targets[$target] = $target;
}
}

$edit['roles'] += $targets;

#1

Jaapx - February 22, 2009 - 14:32

Thank you for your solution, works like a charm.

Two remarks
1) In my opninion your suggestion is not an 'ugly workaround' but a better approach because the invited user and correct roles are created in one step. Also the necesary invokes are done by the ouser_module, not the invite module which is more simple.
2) Your solution must be placed a few code lines lower in the hook_user to let if function also for the invites that are accepted directly by a-mail. I have attached the code of the complete new hook user that shows how.

Maybe time for a new version of Invite?

AttachmentSize
Invite_implementation_hook_user.zip 998 bytes

#2

shunshifu - April 14, 2009 - 05:10

I tried this but my users are not getting the invite role assigned to them. Bummer

#3

hefox - April 21, 2009 - 16:17

I needed a quick solution to this that didn't span to many lines while wait for this module to be updated with whatever solution works so I inserted this into the invite_user rigfht before 'insert' is finished (line 456ish):
$account = user_load($account->uid);
$edit['roles'] = $account->roles;

By the way shunshifu, it probably didn't work due to none of the helper functions called from invite_user are getting the $edit or $account objects as references (&$edit, $account). S/he didn't copy that part of the code into his/her comment.

#4

Bevan - June 12, 2009 - 06:02
Priority:critical» normal
Status:active» needs review

#314347: Role escalation bug was marked duplicate.

I implemented a similar solution that changes less code in the the attached patch. This patch includes fixes for some other bugs too, so you may need to filter those out. I'll submit a clean patch later.

The solution I've implemented deprecates the need for

<?php
 
// Notify other modules of changed user.
 
$edit = array('roles' => $targets);
 
user_module_invoke('update', $edit, $account);
?>

in _invite_escalate_role() and removes it. This has the side effect of optimizing performance. However some other modules may depend on the change done this way. They will need to be updated to use hook_user('update') as well or instead of hook_user('insert').

AttachmentSize
00 To be sorted and contributed.patch 4.69 KB

#5

Bevan - June 12, 2009 - 06:03
Assigned to:Anonymous» Bevan

#6

Bevan - June 12, 2009 - 06:16
Title:Role assigned at user insert does not survive» Escalation to target role fails

#7

Bevan - June 15, 2009 - 12:32
Assigned to:Bevan» Anonymous

A clean version of this patch is attached. Needs some testing and some input on the removal of the call to user_module_invoke()

AttachmentSize
330233.patch 2.69 KB

#8

hexag - June 17, 2009 - 21:18

works like a bloody charm, no end of hours of stupid stress have been caused by this issue, YAY for the invitee role!! thank you ever so much

#9

Liliplanet - June 26, 2009 - 10:07

Hi Bevan,

Also having problems as invitee does not receive assigned role.

Would you be so kind just to upload your invite.module as unfortunately I cannot perform patches.

Look forward to hearing from you, and thank you.
Lilian

#10

Bevan - June 26, 2009 - 23:05

Lili, I don't think it's a good idea to use a patched module if you don't know how to apply patches or keep up with the development of the patch/fix. That's when patching becomes forking. Patch files are actually relatively human readable. I suggest you take a look at it and have a go at applying it manually, by editing the source code of invite.module. This one isn't the simplest of patches, but it's also not too large for manual application. Once you have done it manually a couple of times you'll want a tool to automate it for you. See http://drupal.org/patch/apply. If that is all too complicated then you should contract a developer, or wait till this is fixed in a release of invite.module.

#11

andypost - July 25, 2009 - 02:32

Looks like duplicate of #322748: Only administrator can send invitations on multilingual installation.

Escalation depends on settings which could be wrong on multilingual sites

#12

Bevan - July 25, 2009 - 12:21

Andypost; This issue occurs on mono-lingual sites which is where I came across it and created this patch.

#13

icarus75 - September 15, 2009 - 20:44
Status:needs review» reviewed & tested by the community

This patch in #7 applies cleanly to a 6.x-2.0-alpha1 invite module. Successfully tested the proper setting of invitee's target role with this patch.

Nice,
Bart.

#14

smk-ka - October 5, 2009 - 12:41

#137495: Other Modules not notifed of role change was the issue that required the addition of user_module_invoke(). Basically, other modules (User Badges in this case) want to get notified if a role change takes place, therefore we cannot remove it.

However, I've taken the patch from #7 to simplify the workflow a lot, the code responsible for processing an invitation has been consolidated into one function (former _invite_accept, now renamed to invite_process), while hook_user() takes care of the role escalation.

This *should* still work, but needs testing with both User Badges and Auto Assign Role modules.

AttachmentSize
330233-escalation.patch 4.66 KB

#15

smk-ka - October 5, 2009 - 12:42
Status:reviewed & tested by the community» needs review

#16

WiseMike - October 29, 2009 - 22:20

I tested this patch in #14 with Auto Assign Role, LoginToboggan and Registration Role Keys modules - successfully. Thanks!

#17

smk-ka - November 15, 2009 - 16:33
Status:needs review» fixed

Committed, thanks all!

 
 

Drupal is a registered trademark of Dries Buytaert.