'Register Users', 'page callback' => 'fb_register_detail_page', 'page arguments' => array(FB_PATH_ADMIN_APPS_ARGS), 'access arguments' => array(FB_PERM_ADMINISTER), 'type' => MENU_LOCAL_TASK, ); // Callback to register users, right now instead of waiting for cron. $items[FB_PATH_ADMIN_APPS . '/%fb/fb_register/doit/%'] = array( 'title' => 'Register Users', 'page callback' => 'fb_register_all_users', 'page arguments' => array(FB_PATH_ADMIN_APPS_ARGS, FB_PATH_ADMIN_APPS_ARGS + 3), 'access arguments' => array(FB_PERM_ADMINISTER), 'type' => MENU_CALLBACK, ); return $items; } function fb_register_detail_page($fb_app) { $output = ''; if (isset($_REQUEST['how_many'])) { $how_many = $_REQUEST['how_many']; } else { $how_many = variable_get('fb_register_limit', 100); } $output .= '

' . t('Use this form below to test user registration. Press the Register button to emulate one cron iteration.') . '

'; $output .= drupal_get_form('fb_register_now_form', $fb_app, $how_many); $output .= '

' . t('The registration module is enabled for this application. Users will be registered during cron jobs and when they change email addresses.
Click here to register ALL users now.', array('!url' => url('fb_register/' . $fb_app->label . '/' . $how_many))) . "

\n"; $output .= '
' . print_r($fb_app, 1) . "
\n"; // debug return $output; } /** * This callback will register a chunk of users, then redirect to * itself to register another chunk. And so on, to quickly register * all users of a site, rather than waiting for cron jobs to take care * of it all. */ function fb_register_all_users($fb_app, $how_many) { $success_count = _fb_register_register_users($fb_app, $how_many); drupal_set_message(t("%count users successfully registered.", array('%count' => $success_count))); $output = '

' . _fb_register_summary($fb_app) . "

\n"; if ($success_count > 0) { $output .= '

' . t('This page will refresh, to register another batch of users...') . '

'; drupal_set_html_head(''); } elseif ($success_count < 0) { $output .= '

' . t('Encountered an error. Not refreshing page.') . "

\n"; } return $output; } /** * TODO: This should probably be a theme function. */ function _fb_register_summary($fb_app) { // Display a summary. $cache = cache_get('fb_register_cache'); if (!$cache) { $cache = new stdClass(); $cache->data = array($fb_app->apikey => 0); } $last_uid_registered = $cache->data[$fb_app->apikey]; $registered = db_result(db_query("SELECT count(uid) as count FROM {fb_register} WHERE uid <= %d", $last_uid_registered)); $local = db_result(db_query("SELECT count(u.uid) FROM {users} u WHERE uid > 0")); $registerable = db_result(db_query("SELECT count(u.uid) FROm {users} u WHERE u.uid > 0 ANd u.mail IS NOT NULL AND u.mail <> ''")); $summary = t("%registered of %registerable accounts have been registered for !app.
(Of %local total users, %registerable have email addresses.)", array( '%registered' => $registered, '%registerable' => $registerable, '%local' => $local, '!app' => $fb_app->label, )); return $summary; } function fb_register_now_form($form_state, $fb_app, $how_many) { //dpm(func_get_args(), "fb_register_now_form"); // Display a summary. $form['summary'] = array( '#type' => 'markup', '#value' => _fb_register_summary($fb_app), ); $form['how_many'] = array( '#type' => 'textfield', '#title' => 'Register (up to) how many local users?', '#default_value' => $how_many, ); $form['fb_app_label'] = array( '#type' => 'value', '#value' => $fb_app->label, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Register Now'), ); return $form; } function fb_register_now_form_submit($form, &$form_state) { $values = $form_state['values']; //dpm($values, "fb_register_now_form_submit"); $fb_app = fb_get_app(array('label' => $values['fb_app_label'])); $success_count = _fb_register_register_users($fb_app, $values['how_many']); drupal_set_message(t('%count email addresses registered.', array('%count' => $success_count))); } /** * Register a chunk of users. */ function _fb_register_register_users($fb_app, $how_many) { // Use cache to keep track of how many users we've already registered. // Joining {users} and {fb_register} tables does not give us this // information, because we must register users for each application // hosted on this Drupal. $cache = cache_get('fb_register_cache'); if (!$cache) { $cache = new stdClass(); $cache->data = array($fb_app->apikey => 0); } $last_uid_registered = $cache->data[$fb_app->apikey]; // Initialize facebook api for this app. $fb = fb_api_init($fb_app); $result = db_query("SELECT u.uid, u.name, u.mail, fbr.email_hash FROM {users} u LEFT JOIN {fb_register} fbr ON fbr.uid=u.uid WHERE (fbr.uid IS NULL OR u.uid > %d) AND u.mail IS NOT NULL AND u.mail <> '' ORDER BY u.uid LIMIT %d, %d", $last_uid_registered, 0, $how_many // limits ); while ($account = db_fetch_object($result)) { $register_data[] = array( 'email_hash' => fb_register_email_hash($account->mail), 'account_url' => url('user/' . $account->uid, array('absolute' => TRUE)), ); $user_data[] = $account; } $success_count = 0; $error_count = 0; if (isset($register_data) && count($register_data)) { try { $success_data = $fb->api_client->connect_registerUsers(json_encode($register_data)); // Check results foreach ($register_data as $i => $data) { $account = $user_data[$i]; if (isset($success_data[$i]) && $success_data[$i] == $data['email_hash']) { // Success db_query("DELETE FROM {fb_register} WHERE uid=%d", $account->uid); db_query("INSERT INTO {fb_register} (uid, email_hash) VALUES (%d, '%s')", $account->uid, $data['email_hash']); $success_count++; $last_uid_registered = max($last_uid_registered, $account->uid); } else { // Failure if (fb_verbose()) { watchdog('fb_register', '%application failed to register email hash %hash for user %uid (%name)', array('%application' => $fb_app->title, '%hash' => $data['email_hash'], '%uid' => $account->uid, '%name' => $account->name, ), WATCHDOG_ERROR); } $error_count++; // Make certain we try this user again next time. db_query("DELETE FROM {fb_register} WHERE uid=%d", $account->uid); } } // debugging //dpm($register_data, "register data"); //dpm($success_data, "success data"); } catch (Exception $e) { fb_log_exception($e, t('Failed to register users via connect_registerUsers')); $error_count++; } fb_report_errors($fb, t('Failed to register email hash')); } else { drupal_set_message(t('Found no users to register.')); } // Remember any progress we've made. $cache->data[$fb_app->apikey] = $last_uid_registered; cache_set('fb_register_cache', $cache->data, 'cache', CACHE_PERMANENT); if ($error_count > 0) return (-1 * $error_count); else return $success_count; } /** * Implementation of hook_form_alter(). * * Add our settings to each Facebook Application form. */ function fb_register_form_alter(&$form, &$form_state, $form_id) { // Add our settings to the fb_app edit form. if (isset($form['fb_app_data'])) { $fb_app = $form['#fb_app']; $fb_app_data = fb_get_app_data($fb_app); $fb_register_data = isset($fb_app_data['fb_register']) ? $fb_app_data['fb_register'] : array('register_users' => FALSE); $form['fb_app_data']['fb_register'] = array( '#type' => 'fieldset', '#title' => t('Register Users'), '#tree' => TRUE, '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['fb_app_data']['fb_register']['register_users'] = array( '#type' => 'checkbox', '#title' => t('Register Local Users on Facebook'), '#description' => t('Use Connect.registerUsers to help map local accounts to Facebook accounts. This will share information about your users with Facebook.'), '#default_value' => $fb_register_data['register_users'], ); } } /** * Implementation of hook_cron(). * * Register users with Facebook during cron jobs. */ function fb_register_cron() { $all_apps = fb_get_all_apps(); // All applications foreach ($all_apps as $fb_app) { $fb_app_data = fb_get_app_data($fb_app); $fb_register_data = isset($fb_app_data['fb_register']) ? $fb_app_data['fb_register'] : array('register_users' => FALSE); if (is_array($fb_register_data) && $fb_register_data['register_users']) { // This app has registration enabled. $count = _fb_register_register_users($fb_app, variable_get('fb_register_limit', 100)); if ($count < 0) { // errors watchdog('fb_register', "Errors incountered while registering users for Facebook App %app", array('%app' => $fb_app->label), WATCHDOG_ERROR); } elseif ($count > 0) { watchdog('fb_register', "Registered %count users for Facebook App !app", array('%count' => $count, '%app' => $fb_app->label)); } } } } /** * Implementation of hook_user(). * * Register users whenever an email address may have changed. */ function fb_register_user($op, &$edit, &$account, $category = NULL) { if ($op == 'delete') { db_query("DELETE FROM {fb_register} WHERE uid = %d", $account->uid); } elseif ($op == 'insert' || $op == 'update') { // Re-register on update, as mail address may have changed. // Register on insert is optional. if ($edit['mail']) { $hash = fb_register_email_hash($edit['mail']); $register_data = array( array('email_hash' => $hash, 'account_url' => url('user/' . $account->uid, array('absolute' => TRUE)), ) ); db_query("DELETE FROM {fb_register} WHERE uid = %d", $account->uid); db_query("INSERT INTO {fb_register} (uid, email_hash) VALUES (%d, '%s')", $account->uid, $hash); $apps = fb_get_all_apps(); foreach ($apps as $app) { $fb_app_data = fb_get_app_data($app); $fb_register_data = isset($fb_app_data['fb_register']) ? $fb_app_data['fb_register'] : array(); if (is_array($fb_register_data) && isset($fb_register_data['register_users']) && $fb_register_data['register_users']) { $fb = fb_api_init($app); $success_data = $fb->api_client->connect_registerUsers(json_encode($register_data)); if (fb_verbose()) { watchdog('fb_register', '%application sent email hash for !user. Facebook returned %num_returned successfully registered.', array('%application' => $app->title, '!user' => l($edit['name'], 'user/' . $account->uid), '%num_returned' => count($success_data), )); } } } } } } /** * Implementation of hook_fb(). Here we customize the behavior of * Drupal for Facebook. * * Here we detect whether the user has previously been registered. If * so, we map the facebook account to our local account. */ function fb_register_fb($op, $data, &$return) { if ($op == FB_APP_OP_EVENT) { if ($data['event_type'] == FB_APP_EVENT_POST_AUTHORIZE) { // User has authorized the application. $fbu = fb_facebook_user(); $info = fb_users_getInfo(array($fbu)); if (is_array($info[0]['email_hashes'])) { $result = db_query("SELECT * FROM {fb_register} WHERE email_hash IN (" . db_placeholders($info[0]['email_hashes'], 'varchar') . ")", $info[0]['email_hashes']); if ($d = db_fetch_object($result)) { // We found a mapping to a local user. $account = user_load(array('uid' => $d->uid)); list($module, $authname) = _fb_user_get_authmap($data['fb_app'], $fbu); user_set_authmaps($account, array($module => $authname)); if (fb_verbose()) { watchdog('fb_register', 'Mapping facebook %fbu to local account !user', array( '%fbu' => $fbu, '!user' => l($account->name, 'user/' . $account->uid), )); } } } } } } /** * Compute email hash as specified in http://wiki.developers.facebook.com/index.php/Connect.registerUsers */ function fb_register_email_hash($mail) { $mail = strtolower(trim($mail)); $crc32 = sprintf('%u', crc32($mail)); $md5 = md5($mail); $hash = $crc32 . '_' . $md5; return $hash; }