I just want to start off with thanks for creating/maintaining this module! I couldn't find anything else on this subject (but if I missed it, I'm sorry!), so I hope this helps anyone trying to find a similar solution...

One thing I wanted to do is automatically create a user if an email of a non-member is entered into the invite member form. Not sure if anyone else was looking for a solution to do this, but I thought I'd share what I came up with. Always open for suggestions on how to do this better :)

First off, I implemented a hook_form_alter in a custom module to add a nice admin interface to configure this new option:

<?php
function mymodule_form_alter(&$form, &$form_state, $form_id) {
  switch ($form_id) {
    case 'og_invite_link_admin':
      $form['registration']['mymodule_og_invite_link_allow_auto_registration'] = array(
        '#type' => 'checkbox',
        '#title' => t('Allow automatic user registration.'),
        '#description' => t('If enabled, non-member email invitations will be automatically registered to a new user account.'),
        '#default_value' => variable_get('mymodule_og_invite_link_allow_auto_registration', 0),
      );
      $roles = user_roles(TRUE);
      $form['registration']['mymodule_og_invite_link_auto_registration_role'] = array(
        '#type' => 'checkboxes',
        '#title' => t('Automatic User Registration Role(s)'),
        '#description' => t('If automatic user registration is enabled, the new user will be assigned the selected role.'),
        '#options' => $roles,
        '#default_value' => variable_get('mymodule_og_invite_link_auto_registration_roles', -1),
      );
      break;
?>

I'm also overriding the submit handler of the og_invite_link_invite_page_form in the same form alter:

<?php
    case 'og_invite_link_invite_page_form':
      $form['#submit'][0] = 'mymodule_invite_page_form_submit';
      break;
    default:
      break;
  }
}
?>

New custom submit handler...
As you can see, I just copied the entire og_invite_link_invite_page_form_submit callback function and have $invitation_result call mymodule_invite_users_to_groups() instead of og_invite_link_invite_users_to_groups():

<?php
function mymodule_invite_page_form_submit($form, &$form_state) {
  // $invitation_result = og_invite_link_invite_users_to_groups(array(
  $invitation_result = mymodule_invite_users_to_groups(array(
      'groups' => $form_state['values']['groups'],
      'invitees' => $form_state['values']['invitees'],
      'additional_message' => $form_state['values']['additional_message'],
    )
  );
  // Here we should not have more than one group.
  $group = current($form_state['values']['groups']);
  // Set a message for the invited users
  if (!empty($invitation_result['invitees'][$group->nid])) {
    drupal_set_message(t('An invite has been sent to !users', array('!users' => implode(', ', $invitation_result['invitees'][$group->nid]))));
  }

  // Set a message for the invitees already in the group
  if (!empty($invitation_result['in_group'][$group->nid])) {
    drupal_set_message(t('The following invitees are already members: !users', array('!users' => implode(', ', $invitation_result['in_group'][$group->nid]))), 'warning');
  }

  // Set a message for the invalid invitees
  if (!empty($invitation_result['invalid'])) {
    drupal_set_message(t('The following invitees are either not users, or are invalid email addresses: !users', array('!users' => implode(', ', $invitation_result['invalid']))), 'error');
  }
?>

Then, I pretty much copied the entire og_invite_link_invite_users_to_groups function to my custom callback function:

<?php
function mymodule_invite_users_to_groups($params) {
  if (count($params['groups'])) {
    // Extract the additional message from the parameters.
    $message = filter_xss($params['additional_message']);
    // Extract the user names to send invites to
    $names = explode(',', $params['invitees']);
    // Track the valid invitees
    $invitees = array();
    // Track the invalid invitees
    $invalid = array();
    // Track the valid invitees that are already group members
    $in_group = array();

    // Attempt to load the users based on names, to determine which are real
    // users and which are not. We need to load each user individually instead
    // of using a single query because we need to determine which groups each
    // user belongs to in order to avoid inviting them to a group of theirs
    foreach ($names as $name) {
      // Trim and sanitize the name
      $name = trim(filter_xss(strip_tags($name)));

      // Make sure we have a name to invite after the filtering
      if (strlen($name) == 0) {
        continue;
      }

      // Attempt to load the user
      if (valid_email_address($name)) {
        // Load based on email address
        $account = user_load(array('mail' => $name));
      }
      else {
        // Load based on user name
        $account = user_load(array('name' => $name));  
      }
      
      // Check if we have a valid user object
      if (is_object($account)) {
        // Invalid if the user is inactive
        if (!$account->status) {
          $invalid[] = $name;
          continue; 
        }
      }
      // Check if we are allowed to invite non-users
      else if (variable_get('og_invite_link_invite_unregistered', 0)) {
        // Make sure we have a valid, non-banned email address
        if (valid_email_address($name) && !drupal_is_denied('mail', $name)) {

?>

Added my overrides here:

<?php
        // start custom overrides ******************************** //
          if (variable_get('mymodule_og_invite_link_allow_auto_registration', 0)) {
	    $fields = array(
              'name' => $name,
              'mail' => $name,
              'pass' => user_password(8),
              'status' => 1,
              'roles' => variable_get('mymodule_og_invite_link_auto_registration_roles', -1),
            );
            $account = user_save('', $fields);
          }
          else {
            // Build a user object
            $account = new stdClass;
            $account->uid = 0;
            $account->mail = $name;
          }
        // end custom overrides ******************************** //
?>

And the rest of the stock code from the og_invite_link_invite_users_to_groups function:

<?php
        }
        else {
          $invalid[] = $name;
          continue; 
        }
      }
      // We have nothing valid
      else {
        $invalid[] = $name;
        continue; 
      }
      
      foreach ($params['groups'] as $key => $group) {
        if (!is_array($invitees[$group->nid])) {
          $invitees[$group->nid] = array();
        }
        if (!is_array($in_group[$group->nid])) {
          $in_group[$group->nid] = array();
        }
        // Check for duplicates
        if (isset($invitees[$group->nid][$account->uid]) || 
         isset($invitees[$group->nid][$account->mail]) || 
         isset($in_group[$group->nid][$account->uid])) {
          continue;
        }
        // See if the user is already a member
        // Don't use og_is_group_member() because it's horrible
        if (isset($account->og_groups[$group->nid])) {
          $in_group[$group->nid][$account->uid] = theme('username', $account);
        }
        else {
          // Invite the user
          og_invite_link_send_invite($account, $group, $message);
          if ($account->uid) {
            $invitees[$group->nid][$account->uid] = theme('username', $account);  
          }
          else {
            $invitees[$group->nid][$account->mail] = $account->mail; 
          }
          
        }
      }
    }
    return array('invitees' => $invitees, 'in_group' => $in_group, 'invalid' => $invalid);
  }
}
?>

Hope this helps!

Comments

johnnydarkko’s picture

Issue summary: View changes

Added else condition in custom override so that it doesn't break when the new feature is disabled.

tcowin’s picture

Thanks for the code - this seems like a really obvious and intuitive need, and I'm surprised there isn't more discussion here.
I'm using it with the latest D6.28, og and og_invite_link, and I have a couple questions for you.

In the first section you set the #default_value of the set of checkboxes to 'mymodule_og_invite_link_auto_registration_roles' with a default of -1 - I believe that it should not be plural - I think it ought to be 'mymodule_og_invite_link_auto_registration_role', and that the default should be an array that matches the number of user_roles that you have? Like:

'#default_value' => variable_get('mymodule_og_invite_link_auto_registration_role', array(0 => 1, 1 => 1, 2 => 1, 3 => 1)),

Does that make sense?

Also - I thought the user would be brought to the form where they could create their account, but it is also neat and painless that the account is auto-created for them. The only problem is that they aren't told their password....AFAICT - I guess you could just duplicate the new user email action in the user module to do this? How hard would it be to have them create their account in the standard form, and then not have to have the admin approve it? That is - without opening up the site to anyone adding an account? I guess that's the real challenge?

Thanks for the code - it really is a great addition and ought to be offered as a patch to og_invite_link...

johnnydarkko’s picture

@tcowin - Awesome! I'm glad this code was useful for you!

I had checkboxes for the config page because my site in particular needed multiple roles applied to the user. Whether it's best practice to make this checkboxes or radios can be debated by the maintainers :)
Also, it's not very general to specify the roles since every site has many different sets of roles, I just wanted to keep it super generic and set the default to be 'none'

When the user is created, there's a random password generated and yes, they wouldn't have the info to log in unless the site was configured to send an email to the new user with the password within the email or just be given a one-time use reset link which is the option that I went with to keep the log-in process painless. I agree that the workflow may not work well with all environments, but then again I'll go ahead and leave that for the maintainers to debate :)

Thanks for the input, feel free to modify the code and post up your changes just in case someone else comes across this post that's looking for a solution that you might have come up with.

johnnydarkko’s picture

Issue summary: View changes

Added PHP tags for readability.