| 1 |
<?php |
<?php |
| 2 |
// $Id: invite.module,v 1.24 2008/08/20 14:01:39 smk Exp $ |
// $Id: invite.module,v 1.25 2008/09/02 17:02:14 smk Exp $ |
| 3 |
|
|
| 4 |
/** |
/** |
| 5 |
* @file |
* @file |
| 144 |
|
|
| 145 |
// Frontend menu items |
// Frontend menu items |
| 146 |
$items['invite'] = array( |
$items['invite'] = array( |
| 147 |
'title' => t('Invite a friend'), |
'title' => 'Invite a friend', |
| 148 |
'title callback' => 'invite_page_title', |
'title callback' => 'invite_page_title', |
| 149 |
'page callback' => 'drupal_get_form', |
'page callback' => 'drupal_get_form', |
| 150 |
'page arguments' => array('invite_form', 'page', array()), |
'page arguments' => array('invite_form', 'page', array()), |
| 173 |
|
|
| 174 |
// User profile tabs |
// User profile tabs |
| 175 |
$items['user/%user/invites'] = array( |
$items['user/%user/invites'] = array( |
| 176 |
'title' => 'Track invitations', |
'title' => 'Invitations', |
| 177 |
'page callback' => 'invite_user_overview', |
'page callback' => 'invite_user_overview', |
| 178 |
'access callback' => 'invite_access_callback', |
'access callback' => 'invite_user_access', |
| 179 |
'access arguments' => array('track invitations', 1), |
'access arguments' => array('track invitations', 1), |
| 180 |
'type' => MENU_LOCAL_TASK, |
'type' => MENU_LOCAL_TASK, |
| 181 |
'file' => 'invite_admin.inc', |
'file' => 'invite_admin.inc', |
| 184 |
'title' => 'Accepted', |
'title' => 'Accepted', |
| 185 |
'page callback' => 'invite_user_overview', |
'page callback' => 'invite_user_overview', |
| 186 |
'page arguments' => array('accepted'), |
'page arguments' => array('accepted'), |
| 187 |
'access callback' => 'invite_access_callback', |
'access callback' => 'invite_user_access', |
| 188 |
'access arguments' => array('track invitations', 1), |
'access arguments' => array('track invitations', 1), |
| 189 |
'type' => MENU_DEFAULT_LOCAL_TASK, |
'type' => MENU_DEFAULT_LOCAL_TASK, |
| 190 |
'weight' => -5, |
'weight' => -5, |
| 194 |
'title' => 'Pending', |
'title' => 'Pending', |
| 195 |
'page callback' => 'invite_user_overview', |
'page callback' => 'invite_user_overview', |
| 196 |
'page arguments' => array('pending'), |
'page arguments' => array('pending'), |
| 197 |
'access callback' => 'invite_access_callback', |
'access callback' => 'invite_user_access', |
| 198 |
'access arguments' => array('track invitations', 1), |
'access arguments' => array('track invitations', 1), |
| 199 |
'type' => MENU_LOCAL_TASK, |
'type' => MENU_LOCAL_TASK, |
| 200 |
'file' => 'invite_admin.inc', |
'file' => 'invite_admin.inc', |
| 203 |
'title' => 'Expired', |
'title' => 'Expired', |
| 204 |
'page callback' => 'invite_user_overview', |
'page callback' => 'invite_user_overview', |
| 205 |
'page arguments' => array('expired'), |
'page arguments' => array('expired'), |
| 206 |
'access callback' => 'invite_access_callback', |
'access callback' => 'invite_user_access', |
| 207 |
'access arguments' => array('track invitations', 1), |
'access arguments' => array('track invitations', 1), |
| 208 |
'type' => MENU_LOCAL_TASK, |
'type' => MENU_LOCAL_TASK, |
| 209 |
'weight' => 5, |
'weight' => 5, |
| 213 |
'title' => 'New invitation', |
'title' => 'New invitation', |
| 214 |
'page callback' => 'drupal_get_form', |
'page callback' => 'drupal_get_form', |
| 215 |
'page arguments' => array('invite_form', 'page', array()), |
'page arguments' => array('invite_form', 'page', array()), |
| 216 |
'access callback' => 'invite_access_callback', |
'access callback' => 'invite_user_access', |
| 217 |
'access arguments' => array('send invitations', 1), |
'access arguments' => array('send invitations', 1), |
| 218 |
'type' => MENU_LOCAL_TASK, |
'type' => MENU_LOCAL_TASK, |
| 219 |
'weight' => 10, |
'weight' => 10, |
| 223 |
} |
} |
| 224 |
|
|
| 225 |
/** |
/** |
| 226 |
|
* Implementation of hook_menu_alter(). |
| 227 |
|
* |
| 228 |
|
* Override the user/register menu access handler with a custom |
| 229 |
|
* implementation. |
| 230 |
|
*/ |
| 231 |
|
function invite_menu_alter(&$items) { |
| 232 |
|
if (invite_user_registration_by_invite_only()) { |
| 233 |
|
$items['user/register']['access callback'] = 'invite_user_register_access'; |
| 234 |
|
} |
| 235 |
|
} |
| 236 |
|
|
| 237 |
|
/** |
| 238 |
|
* Determine if user registration mode is set to invite only. |
| 239 |
|
*/ |
| 240 |
|
function invite_user_registration_by_invite_only() { |
| 241 |
|
return (variable_get('user_register', 1) === '1-inviteonly'); |
| 242 |
|
} |
| 243 |
|
|
| 244 |
|
/** |
| 245 |
|
* Access callback; determine access to user registration form. |
| 246 |
|
*/ |
| 247 |
|
function invite_user_register_access() { |
| 248 |
|
$invite = invite_load_from_session(); |
| 249 |
|
|
| 250 |
|
// Legacy url support (user/register/regcode). |
| 251 |
|
if (!$invite && $code = arg(2)) { |
| 252 |
|
if ($invite = invite_load($code)) { |
| 253 |
|
if (invite_validate($invite)) { |
| 254 |
|
$_SESSION[INVITE_SESSION] = $invite->reg_code; |
| 255 |
|
} |
| 256 |
|
} |
| 257 |
|
} |
| 258 |
|
if (!$invite && !user_access('administer users')) { |
| 259 |
|
drupal_set_message(t('Sorry, new user registration by invitation only.')); |
| 260 |
|
return FALSE; |
| 261 |
|
} |
| 262 |
|
|
| 263 |
|
// Let the default handler take care of standard conditions. |
| 264 |
|
return user_register_access(); |
| 265 |
|
} |
| 266 |
|
|
| 267 |
|
/** |
| 268 |
* Title callback allowing for customization of the invite page title. |
* Title callback allowing for customization of the invite page title. |
| 269 |
* |
* |
| 270 |
* @param $title |
* @param $title |
| 292 |
* @param $account |
* @param $account |
| 293 |
* A user object. |
* A user object. |
| 294 |
*/ |
*/ |
| 295 |
function invite_access_callback($permission, $account) { |
function invite_user_access($permission, $account) { |
| 296 |
return ($account->uid == $GLOBALS['user']->uid && user_access($permission)); |
return ($account->uid == $GLOBALS['user']->uid && user_access($permission)); |
| 297 |
} |
} |
| 298 |
|
|
| 336 |
function invite_form_alter(&$form, $form_state, $form_id) { |
function invite_form_alter(&$form, $form_state, $form_id) { |
| 337 |
switch ($form_id) { |
switch ($form_id) { |
| 338 |
case 'user_admin_settings': |
case 'user_admin_settings': |
| 339 |
// Add new registration mode. |
// Add new registration mode 'by invitation only'. By prepending the |
| 340 |
// We prepend the option value with a numeric value to make 3rd party |
// option value with a numeric value, other modules still work as |
| 341 |
// modules like LoginToboggan act like expected. This works because |
// expected, as long as they are using the non-strict PHP comparison |
| 342 |
// checking for ('1-inviteonly' == 1) returns TRUE. To reliably determine |
// operator (since '1-inviteonly' == 1 yields TRUE). To determine the real |
| 343 |
// the variable value later, we need to use the strict equality operator |
// setting use invite_user_registration_by_invite_only(). |
| 344 |
// (===). |
// |
| 345 |
$form['registration']['user_register']['#options']['1-inviteonly'] = t('New user registration by invitation only.'); |
// However, setting the new mode is only allowed if no other module |
| 346 |
|
// has overridden the menu access handler for the user registration form. |
| 347 |
|
$item = menu_get_item('user/register'); |
| 348 |
|
if (in_array($item['access_callback'], array('user_register_access', 'invite_user_register_access'))) { |
| 349 |
|
$form['registration']['user_register']['#options']['1-inviteonly'] = t('New user registration by invitation only.'); |
| 350 |
|
} |
| 351 |
|
// Clear menu cache on submit to allow our custom access handler to |
| 352 |
|
// snap in. |
| 353 |
|
$form['#submit'][] = 'menu_rebuild'; |
| 354 |
break; |
break; |
| 355 |
|
|
| 356 |
case 'user_register': |
case 'user_register': |
| 368 |
} |
} |
| 369 |
} |
} |
| 370 |
} |
} |
|
|
|
| 371 |
if ($invite) { |
if ($invite) { |
| 372 |
// Preset the e-mail field. |
// Preset the e-mail field. |
| 373 |
if (isset($form['account'])) { |
if (isset($form['account'])) { |
| 380 |
$field['mail']['#default_value'] = $invite->email; |
$field['mail']['#default_value'] = $invite->email; |
| 381 |
} |
} |
| 382 |
} |
} |
|
else if (variable_get('user_register', 1) === '1-inviteonly' && !user_access('administer users')) { |
|
|
drupal_set_message(t('Sorry, new user registration by invitation only.')); |
|
|
drupal_goto(); |
|
|
} |
|
| 383 |
break; |
break; |
| 384 |
|
|
| 385 |
case 'user_login_block': |
case 'user_login_block': |
| 386 |
// Remove temptation for non members to try and register. |
// Remove temptation for non members to try and register. |
| 387 |
if (variable_get('user_register', 1) === '1-inviteonly') { |
if (invite_user_registration_by_invite_only()) { |
| 388 |
$new_items = array(); |
$new_items = array(); |
| 389 |
$new_items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.')))); |
$new_items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.')))); |
| 390 |
$form['links']['#value'] = theme('item_list', $new_items); |
$form['links']['#value'] = theme('item_list', $new_items); |
| 515 |
* The user object of the invitee. |
* The user object of the invitee. |
| 516 |
*/ |
*/ |
| 517 |
function _invite_escalate_role($account) { |
function _invite_escalate_role($account) { |
| 518 |
// Default target role. |
// Add a dummy entry to retrieve the default target role setting. |
| 519 |
$roles = array('default'); |
$roles = array('default' => 'default'); |
| 520 |
|
|
| 521 |
// Add roles of inviter. |
// Add roles of inviter. |
| 522 |
$inviter_uid = db_result(db_query("SELECT uid FROM {invite} WHERE invitee = %d", $account->uid)); |
$inviter_uid = db_result(db_query("SELECT uid FROM {invite} WHERE invitee = %d", $account->uid)); |
| 523 |
if ($inviter_uid && $inviter = user_load(array('uid' => $inviter_uid))) { |
if ($inviter_uid && $inviter = user_load(array('uid' => $inviter_uid))) { |
| 524 |
$roles = array_merge($roles, array_intersect($inviter->roles, user_roles(0, 'send invitations'))); |
$roles = array_merge($roles, array_intersect($inviter->roles, user_roles(FALSE, 'send invitations'))); |
| 525 |
} |
} |
| 526 |
|
|
| 527 |
// Map to configured target roles. |
// Map to configured target roles. |
| 528 |
$targets = array(); |
$targets = array(); |
| 529 |
foreach ($roles as $role) { |
foreach ($roles as $rid => $role) { |
| 530 |
$role_no_space = str_replace(' ', '_', $role); |
$target = variable_get('invite_target_role_'. $rid, DRUPAL_AUTHENTICATED_RID); |
|
$target = variable_get('invite_target_role_'. $role_no_space, DRUPAL_AUTHENTICATED_RID); |
|
| 531 |
if ($target != DRUPAL_AUTHENTICATED_RID) { |
if ($target != DRUPAL_AUTHENTICATED_RID) { |
| 532 |
$targets[$target] = $target; |
$targets[$target] = $target; |
| 533 |
} |
} |
| 595 |
/** |
/** |
| 596 |
* Generate the invite forms. |
* Generate the invite forms. |
| 597 |
* |
* |
| 598 |
|
* @param $form_satate |
| 599 |
|
* A keyed array containing the current state of the form. |
| 600 |
* @param $op |
* @param $op |
| 601 |
* The type of form to generate, 'page' or 'block'. |
* The type of form to generate, 'page' or 'block'. |
| 602 |
* @param $edit |
* @param $edit |
| 673 |
} |
} |
| 674 |
else { |
else { |
| 675 |
$remaining = invite_get_role_limit($account); |
$remaining = invite_get_role_limit($account); |
|
|
|
| 676 |
if ($remaining > 0) { |
if ($remaining > 0) { |
| 677 |
// Legacy support. |
// Legacy support. |
| 678 |
$sent = db_result(db_query("SELECT COUNT(*) FROM {invite} WHERE uid = %d", $account->uid)); |
$sent = db_result(db_query("SELECT COUNT(*) FROM {invite} WHERE uid = %d", $account->uid)); |
| 701 |
} |
} |
| 702 |
|
|
| 703 |
$role_limit = 0; |
$role_limit = 0; |
| 704 |
foreach (user_roles(0, 'send invitations') as $role) { |
foreach (user_roles(FALSE, 'send invitations') as $rid => $role) { |
| 705 |
$role_no_space = str_replace(' ', '_', $role); |
if (array_key_exists($rid, $account->roles)) { |
| 706 |
if (in_array($role, $account->roles)) { |
$role_max = variable_get('invite_maxnum_'. $rid, INVITE_UNLIMITED); |
|
$role_max = variable_get('invite_maxnum_'. $role_no_space, INVITE_UNLIMITED); |
|
| 707 |
if ($role_max == INVITE_UNLIMITED) { |
if ($role_max == INVITE_UNLIMITED) { |
| 708 |
return INVITE_UNLIMITED; |
return INVITE_UNLIMITED; |
| 709 |
} |
} |
| 760 |
$form['email'] = array( |
$form['email'] = array( |
| 761 |
'#title' => t('To'), |
'#title' => t('To'), |
| 762 |
'#default_value' => $failed_emails, |
'#default_value' => $failed_emails, |
| 763 |
'#description' => format_plural($allow_multiple ? 99 : 1, 'Type the e-mail address of the person you would like to invite.', 'Type the e-mail addresses of the persons you would like to invite. Addresses should be separated by newlines or commas.'), |
'#description' => format_plural($allow_multiple ? 99 : 1, 'Enter the e-mail address of the person you would like to invite.', 'Enter the e-mail addresses of the persons you would like to invite. To specify multiple recipients, enter one e-mail address per line or separate each address with a comma.'), |
| 764 |
'#required' => TRUE, |
'#required' => TRUE, |
| 765 |
); |
); |
| 766 |
if ($allow_multiple) { |
if ($allow_multiple) { |
| 798 |
} |
} |
| 799 |
// Add prefix. |
// Add prefix. |
| 800 |
$prefix = t('Re:'); |
$prefix = t('Re:'); |
| 801 |
if ($edit && substr($subject, 0, strlen($prefix)) != $prefix) { |
if ($edit && drupal_substr($subject, 0, strlen($prefix)) != $prefix) { |
| 802 |
$subject = $prefix .' '. $subject; |
$subject = $prefix .' '. $subject; |
| 803 |
} |
} |
| 804 |
if (variable_get('invite_subject_editable', FALSE)) { |
if (variable_get('invite_subject_editable', FALSE)) { |
| 832 |
|
|
| 833 |
$form['submit'] = array( |
$form['submit'] = array( |
| 834 |
'#type' => 'submit', |
'#type' => 'submit', |
| 835 |
'#value' => t('Submit'), |
'#value' => t('Send invite'), |
| 836 |
); |
); |
| 837 |
|
|
| 838 |
return $form; |
return $form; |
| 944 |
$error .= implode(', ', $failed_emails); |
$error .= implode(', ', $failed_emails); |
| 945 |
drupal_set_message($error, 'error'); |
drupal_set_message($error, 'error'); |
| 946 |
} |
} |
| 947 |
|
} |
| 948 |
|
|
| 949 |
|
if (!empty($emails)) { |
| 950 |
// Filter out already invited users, but pass validation. |
// Filter out already invited users, but pass validation. |
| 951 |
$failed_emails = _invite_validate_emails("SELECT email FROM {invite} WHERE email IN (". db_placeholders($emails, 'varchar') .") AND uid = %d AND canceled = 0", $emails, $user->uid); |
$failed_emails = _invite_validate_emails("SELECT email FROM {invite} WHERE email IN (". db_placeholders($emails, 'varchar') .") AND uid = %d AND canceled = 0", $emails, $user->uid); |
| 952 |
if (count($failed_emails)) { |
if (count($failed_emails)) { |
| 953 |
$error = format_plural(count($failed_emails), 'You did already invite the following recipient:', 'You did already invite the following recipients:') .'<br />'; |
$error = format_plural(count($failed_emails), 'You have already invited the following recipient:', 'You have already invited the following recipients:') .'<br />'; |
| 954 |
$error .= implode(', ', array_map('check_plain', $failed_emails)); |
$error .= implode(', ', array_map('check_plain', $failed_emails)); |
| 955 |
drupal_set_message($error, 'error'); |
drupal_set_message($error, 'error'); |
| 956 |
} |
} |
| 957 |
|
} |
| 958 |
|
|
| 959 |
// Check that there is at least one valid e-mail remaining after filtering |
// Check that there is at least one valid e-mail remaining after filtering |
| 960 |
// out dupes. |
// out dupes. |
| 961 |
if (count($emails) == 0) { |
if (count($emails) == 0) { |
| 962 |
form_set_error('email'); |
form_set_error('email'); |
| 963 |
return; |
return; |
| 964 |
} |
} |
| 965 |
|
|
| 966 |
// Check invite limit, fail to let the user choose which ones to send. |
// Check invite limit, fail to let the user choose which ones to send. |
| 967 |
if (isset($form_state['values']['remaining_invites']) && count($emails) > $form_state['values']['remaining_invites']) { |
if (isset($form_state['values']['remaining_invites']) && count($emails) > $form_state['values']['remaining_invites']) { |
| 968 |
form_set_error('email', format_plural($form_state['values']['remaining_invites'], 'You have only 1 invite left.', 'You have only @count invites left.')); |
form_set_error('email', format_plural($form_state['values']['remaining_invites'], 'You have only 1 invite left.', 'You have only @count invites left.')); |
| 969 |
return; |
return; |
| 970 |
} |
} |
| 971 |
|
|
| 972 |
// Check number of e-mails. |
// Check number of e-mails. |
| 973 |
if (!user_access('send mass invitations') && count($emails) > 1) { |
if (!user_access('send mass invitations') && count($emails) > 1) { |
| 974 |
form_set_error('email', t('You cannot send more than one invitation.')); |
form_set_error('email', t('You cannot send more than one invitation.')); |
| 975 |
return; |
return; |
|
} |
|
| 976 |
} |
} |
| 977 |
} |
} |
| 978 |
|
|
| 1002 |
|
|
| 1003 |
$emails = array_unique(split("[,\n\r]", $string)); |
$emails = array_unique(split("[,\n\r]", $string)); |
| 1004 |
foreach ($emails as $email) { |
foreach ($emails as $email) { |
| 1005 |
$email = trim($email); |
$email = preg_replace('/^.*<(.*)>$/', '${1}', trim($email)); |
| 1006 |
if ($email) { |
if ($email) { |
| 1007 |
if (preg_match($rx, $email, $match)) { |
if (preg_match($rx, $email, $match)) { |
| 1008 |
$valid_emails[] = $match[1]; |
$valid_emails[] = $match[1]; |
| 1211 |
/** |
/** |
| 1212 |
* Menu callback; display confirm form to delete an invitation. |
* Menu callback; display confirm form to delete an invitation. |
| 1213 |
* |
* |
| 1214 |
|
* @param $form_satate |
| 1215 |
|
* A keyed array containing the current state of the form. |
| 1216 |
* @param $origin |
* @param $origin |
| 1217 |
* String denoting the orginating invite status page. |
* A string denoting the orginating status page to return the user to |
| 1218 |
|
* afterwards. |
| 1219 |
* @param $code |
* @param $code |
| 1220 |
* A registration code to remove the invitation for. |
* A registration code to remove the invitation for. |
| 1221 |
*/ |
*/ |
| 1222 |
function invite_cancel($origin, $code) { |
function invite_cancel(&$form_state, $origin, $code) { |
| 1223 |
global $user; |
global $user; |
| 1224 |
|
|
| 1225 |
$invite = invite_load($code); |
$invite = invite_load($code); |
| 1259 |
/** |
/** |
| 1260 |
* Submit handler to delete an invitation. |
* Submit handler to delete an invitation. |
| 1261 |
*/ |
*/ |
| 1262 |
function invite_cancel_submit($form, $form_state) { |
function invite_cancel_submit($form, &$form_state) { |
| 1263 |
$invite = $form_state['values']['invite']; |
$invite = $form_state['values']['invite']; |
| 1264 |
|
|
| 1265 |
db_query("UPDATE {invite} SET canceled = 1 WHERE reg_code = '%s'", $invite->reg_code); |
db_query("UPDATE {invite} SET canceled = 1 WHERE reg_code = '%s'", $invite->reg_code); |
| 1312 |
* Implementation of hook_disable(). |
* Implementation of hook_disable(). |
| 1313 |
*/ |
*/ |
| 1314 |
function invite_disable() { |
function invite_disable() { |
| 1315 |
if (variable_get('user_register', 1) === '1-inviteonly') { |
if (invite_user_registration_by_invite_only()) { |
| 1316 |
variable_set('user_register', 1); |
variable_set('user_register', 1); |
| 1317 |
drupal_set_message(t('User registration option reset to %no_approval.', array('%no_approval' => t('Visitors can create accounts and no administrator approval is required.')))); |
drupal_set_message(t('User registration option reset to %no_approval.', array('%no_approval' => t('Visitors can create accounts and no administrator approval is required.')))); |
| 1318 |
} |
} |