uid || $user->uid == $fb_user_data['not_logged_in_uid'] || $user->uid == $fb_user_data['logged_in_uid']) { $result =db_query("REPLACE INTO {fb_user_app} (apikey, fbu, added, time_access, session_key, session_key_expires) VALUES ('%s', %d, %d, %d, '%s', %d)", $fb_app->apikey, fb_facebook_user(), $fb->api_client->users_isAppAdded(), time(), $fb->api_client->session_key, $_REQUEST['fb_sig_expires'] ); } else { // Uid is accurate. $result =db_query("REPLACE INTO {fb_user_app} (apikey, fbu, uid, added, time_access, session_key, session_key_expires) VALUES ('%s', %d, %d, %d, %d, '%s', %d)", $fb_app->apikey, fb_facebook_user(), $user->uid, $fb->api_client->users_isAppAdded(), time(), $fb->api_client->session_key, $_REQUEST['fb_sig_expires'] ); } if ($result === FALSE) { watchdog('fb_user', t("Failed to update fb_user_app table."), WATCHDOG_ERROR); } } /** * Implementation of hook_fb. */ function fb_user_fb($op, $data, &$return) { $fb_app = $data['fb_app']; $fb = $data['fb']; global $user; $fb_app_data = fb_app_get_data($fb_app); $fb_user_data = $fb_app_data['fb_user']; // our configuration if ($op == FB_OP_CANVAS_INITIALIZE) { // Here we ask facebook to prompt the user to authorize the app. if (fb_user_authentication_is_required($fb_app)) { $fb->require_login(); } } else if ($op == FB_OP_CANVAS_POST_INIT) { // Observe special rules for canvas page users without local accounts if (!$user->uid && !_fb_user_special_page() && !$_REQUEST['form_id']) { if ($fbu = fb_facebook_user($fb)) { $uid = $fb_app_data['fb_user']['logged_in_uid']; } else { $uid = $fb_app_data['fb_user']['not_logged_in_uid']; } if ($uid) { $user = user_load(array('uid' => $uid)); } } // TODO: is it now necessary to redirect the user back to current page? } else if ($op == FB_OP_APP_IS_AUTHORIZED) { // We reach this point if the user has authorized the app. // Could be they visited a canvas page, // or could be they clicked a fbConnect link. $fbu = $data['fbu']; // The user id on facebook. // Remember the original uid $original_uid = $user->uid; if ($user->fbu != $fbu) { // Try the application-specific account. $account = user_external_load("$fbu-$fb_app->apikey@facebook.com"); if (!$account) // Try the cross-application account. $account = user_external_load("$fbu@facebook.com"); if ($account) { $account->fbu = $fbu; if ($user->uid == 0) $user = $account; // change the global user else { watchdog('fb_user', t('fb_user encountered something it cannot handle. The current user, !user1 is logged in. But the facebook user id %fbu is associated with another user, !user2', array('!user1' => theme('username', $user), '!user2' => theme('username', $account), '%fbu' => $fbu)), WATCHDOG_ERROR); } } else { // There is no account associated with the facebook id. // If the user is not anonymous, we can make an association now. if ($user->uid != 0 && $user->uid != $fb_app_data['fb_user']['logged_in_uid']) { if ($fb_user_data['map_account'] == FB_USER_OPTION_MAP_ALWAYS) { list($module, $authname) = _fb_user_get_authmap($fb_app, $fbu); user_set_authmaps($account, array($module => $authname)); // is this right? $user->fbu = $fbu; dpm("setting up authmap to associate " . theme('username', $user) . " with fbu $fbu"); watchdog('fb_user', t('Using authmap to associate user !user with facebook user id %fbu.', array('!user' => theme('username', $user), '%fbu' => $fbu))); } } } } // Check if we need to create a local account for this user. if (($fb_user_data['create_account'] == FB_USER_OPTION_CREATE_ADD && $fb->api_client->users_isAppAdded()) || ($fb_user_data['create_account'] == FB_USER_OPTION_CREATE_LOGIN)) { // Check if the local account is already made. if ($user->fbu != fb_facebook_user($fb) && (!_fb_user_special_page())) { // We need to make a local account for this facebook user. $user = fb_user_create_local_user($fb, $fb_app, fb_facebook_user($fb), array('app_specific' => $fb_user_data['unique_account'], 'roles' => array($fb_user_data['new_user_rid'] => TRUE), )); watchdog('fb_user', t("Created new user !username for application %app", array('!username' => theme('username', $user), '%app' => $fb_app->label))); } } // It's possible the user was already created by another app. // In this case we need to add our role. if ($user->fbu == fb_facebook_user() && $fb_user_data['new_user_rid'] && !$user->roles[$fb_user_data['new_user_rid']]) { // there should be an API for this... db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $user->uid, $fb_user_data['new_user_rid']); watchdog('fb_user', t("Added role %role to existing user !username for application %app", array('!username' => theme('username', $user), '%app' => $fb_app->label, '%role' => $fb_user_data['new_user_rid']))); } if ($user->uid != $original_uid) { // We've changed the user. In order to ensure that drupal handles // permissions properly, the user must make the request all over // again. Skip this for the profile tab, as facebook does not allow // redirects (or persistent session) there. if (function_exists('fb_canvas_is_fbml') && (fb_canvas_is_fbml() || fb_canvas_is_iframe()) && (!$_REQUEST['fb_sig_in_profile_tab'])) { // Redirect to a canvas page $url = fb_canvas_fix_url(url(fb_scrub_urls($_REQUEST['q']), NULL, NULL, TRUE), $fb_app); if (fb_verbose()) watchdog('fb_debug', "User uid is now {$user->uid} (was {$original_uid}), redirecting to $url to ensure permissions are correct."); // debug $fb->redirect($url); } } // Keep a record of when user accesses app, and whether they have added it. _fb_user_track($fb, $fb_app, $user); // We don't want user's who are not logged in (in the facebook sense) to // login locally. So let's make sure they've added the app before doing // anything related to Drupal accounts. /** I _think_ the new api no longer requires this. TODO: confirm. if (strpos($_GET['q'],'user/login') === 0) { // Have to check idAppAdded in case of iframe. if (!$fb->api_client->users_isAppAdded()) $fb->require_login(); } else if (strpos($_GET['q'],'user/register') === 0) { if (!$fb->api_client->users_isAppAdded()) $fb->require_login(); } */ // Now do I need a goto or some such??? // debug /* drupal_set_message("To Drupal, you are " . theme('username', $user)); drupal_set_message("Facebook user id is " . fb_facebook_user()); drupal_set_message("Facebook logged in is " . $fb->get_loggedin_user()); */ } else if ($op == FB_OP_GET_FBU) { // This is a request to learn the user's FB id. $return = _fb_user_get_fbu($data['uid'], $fb_app); } else if ($op == FB_OP_GET_USER_SESSION) { // The fb module is asking for session login information. For example, to // log in as the user when not on a canvas page. This module may be able // to provide it, depending on whether the user has logged in, and whether // the session has expired. $fbu = $data['fbu']; $result = db_query("SELECT * FROM {fb_user_app} WHERE apikey = '%s' and fbu = %d AND session_key_expires > %d", $fb_app->apikey, $fbu, time()); $data = db_fetch_object($result); if ($data && $data->session_key) // Return array with FB id and apikey. $return = array($data->fbu, $data->session_key); } else if ($op == FB_APP_OP_EVENT) { // Facebook has notified us of some event. // We handle some of the events here. $event_type = $data['event_type']; if ($event_type == FB_APP_EVENT_POST_AUTHORIZE) { // User has authorized us to know some details about her, // A.K.A. "logged in" in the facebook sense. // You might think we'd create a new account for the user now, but we // don't have to. Because facebook passes parameters as if the user // browsed the callback URL, our normal init code does everything we // need to do. } else if ($event_type == FB_APP_EVENT_POST_REMOVE) { // User has removed the app from their account. // As described above, we don't have to do anything here, because our // normal init code tracks the user. Perhaps we could delete all record // of the user here, but why bother? We just flag them as having // uninstalled the app (in _fb_user_track()). } } } /** * Determines whether authentication is required to serve the current * page. This will return true if the application has been configured * to require login for all canvas pages. Except in special cases, * such as profile tabs. * * @return TRUE only for canvas pages if authentication is required to * use the application and the page is not a special exception to the * rule. */ function fb_user_authentication_is_required($fb_app) { $fb_app_data = fb_app_get_data($fb_app); $fb_user_data = $fb_app_data['fb_user']; // our configuration if ($fb_user_data['require_login'] == FB_USER_OPTION_REQUIRE_LOGIN) { // The application is configured to require login on all canvas pages. // However, there are exceptions. if (isset($_REQUEST['fb_sig_in_profile_tab']) && $_REQUEST['fb_sig_in_profile_tab']) { // Redirects are not allowed for the profile tab. return FALSE; } // There may be other exceptions, for example some ajax callbacks. Potential todo item. // No exceptions apply, authentication is required. return TRUE; } } function fb_user_form_alter($form_id, &$form) { //drupal_set_message("fb_user_form_alter($form_id) " . dpr($form, 1)); // Add our settings to the fb_app edit form. if (is_array($form['fb_app_data'])) { $node = $form['#node']; $fb_app_data = fb_app_get_data($node->fb_app); $fb_user_data = $fb_app_data['fb_user']; $form['fb_app_data']['fb_user'] = array('#type' => 'fieldset', '#title' => t('Facebook user settings'), '#tree' => TRUE, '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['fb_app_data']['fb_user']['require_login'] = array('#type' => 'radios', '#title' => t('Require Login'), '#description' => t('If some of your canvas pages are visible to the public at large, allow anyone. You will have to call Facebook\'s require_login() on pages that require more information about the user.
Allow only logged-in users if you want Drupal for Facebook to call require_login() on every page.'), '#options' => array(FB_USER_OPTION_ALLOW_ANON => t('Allow anyone'), FB_USER_OPTION_REQUIRE_LOGIN => t('Allow logged-in users'), ), '#default_value' => isset($fb_user_data['require_login']) ? $fb_user_data['require_login'] : FB_USER_OPTION_ALLOW_ANON, '#required' => TRUE, ); $form['fb_app_data']['fb_user']['create_account'] = array('#type' => 'radios', '#title' => t('Create Local Account'), '#description' => t('This option will create a local account automatically and create an entry in the authmap table. This happens whenever the user visits a canvas page, except pages whose path starts with "user/" and the landing page for anonymous users. Choose never to use Drupal\'s built in user registration.'), '#options' => array(FB_USER_OPTION_CREATE_NEVER => t('Never (user/register page will still work)'), FB_USER_OPTION_CREATE_LOGIN => t('If user has logged in'), ), '#default_value' => isset($fb_user_data['create_account']) ? $fb_user_data['create_account'] : FB_USER_OPTION_CREATE_LOGIN, '#required' => TRUE, ); $form['fb_app_data']['fb_user']['map_account'] = array('#type' => 'radios', '#title' => t('Map Accounts'), '#description' => t('Mapping an account means creating an entry in the authmap table. This entry allows Drupal to know which Facebook id corresponds to which local uid.'), '#options' => array(FB_USER_OPTION_MAP_NEVER => t('Never map accounts'), FB_USER_OPTION_MAP_ALWAYS => t('Map account when both local uid and Facebook id are known'), ), '#default_value' => isset($fb_user_data['map_account']) ? $fb_user_data['map_account'] : FB_USER_OPTION_MAP_ALWAYS, '#required' => TRUE, ); $form['fb_app_data']['fb_user']['unique_account'] = array('#type' => 'checkbox', '#title' => t('Make Account Mapping Unique (experimental, not recommended)'), '#description' => t('If checked, the relationship between the local uid and the Facebook id applies only to this Application. This matters only when you host more than one application on this instance of Drupal.'), '#default_value' => $fb_user_data['unique_account'], ); // TODO: prompt for role with a select. Don't make user figure out id $form['fb_app_data']['fb_user']['new_user_rid'] = array('#type' => 'select', '#title' => t('New user role'), '#options' => user_roles(1), '#description' => t('When the local uid is known and the user has logged in (in the Facebook sense) to the app, the user will be granted this role.'), '#default_value' => $fb_user_data['new_user_rid'], ); // Experimental. May be removed or drastically changed anytime // TODO: fix this so that it prompts for username with autocomplete, not a uid. $form['fb_app_data']['fb_user']['not_logged_in_uid'] = array('#type' => 'textfield', '#title' => t('Not logged in user (uid)'), '#description' => t('If allowing non-logged in users, when such a user visits the site, which Drupal user should they be treated as? Use 0 for the anonymous user (recommended - this feature is experimental and likely to disappear).'), '#default_value' => $fb_user_data['not_logged_in_uid'], ); $form['fb_app_data']['fb_user']['logged_in_uid'] = array('#type' => 'textfield', '#title' => t('Logged in user (uid)'), '#description' => t('If allowing logged in users, when such a user visits the site, and they do not have a local Drupal account, which Drupal user should they be treated as? Use 0 for the Anonymous user (recommended - this feature is experimental and likely to disappear), or create a dedicated account for this purpose.'), '#default_value' => $fb_user_data['logged_in_uid'], ); } else if ($form_id == 'user_edit' && ($app = $form['#fb_app'])) { // Disable buttons on user/edit/app pages, nothing to submit unset($form['submit']); unset($form['delete']); } } /** * Implementation of hook_user. */ function fb_user_user($op, &$edit, &$account, $category = NULL) { global $user; static $apps; // If form posted from an FBML canvas page, we learn the app and fbu from the post. // TODO: do we need additional validation here? (i.e. an fb_api_init to confirm the facebook params?) if ($_REQUEST['fb_sig']) { //watchdog('debug', dprint_r($_REQUEST, 'fb_user_user request')); $fb_app = fb_get_app(array('apikey' => $_REQUEST['fb_sig_api_key'])); $fbu = $_REQUEST['fb_sig_user']; } else if ($GLOBALS['fb']) { // Post from iframe $fbu = fb_facebook_user(); } if ($fb_app && $op == 'insert' || $op == 'login') { // A facebook user has logged in. We can map the two acounts together. $fb_app_data = fb_app_get_data($fb_app); $fb_user_data = $fb_app_data['fb_user']; // our configuration if ($fbu && $fb_user_data['map_account'] == FB_USER_OPTION_MAP_ALWAYS) { list($module, $authname) = _fb_user_get_authmap($fb_app, $fbu); if ($op == 'insert') { // User has registered, we set up the authmap this way... $edit['authname_fb_user'] = $authname; } else if ($op == 'login') { // On login, we set up the map this way... user_set_authmaps($account, array($module => $authname)); } // TODO: if the app has a role, make sure the user gets that role. (presently, that will not happen until their next request) } } // Add tabs on user edit pages to manage maps between local accounts and facebook accounts. if ($op == 'categories') { // A tab for administrators $items[] = array('name' => 'fb_user', 'title' => t('Facebook Applications'), 'weight' => 1, ); // A tab for each application the user has authorized $result = _fb_app_query_all(); $apps = array(); while ($fb_app = db_fetch_object($result)) { $apps[$fb_app->label] = $fb_app; $fb_app_data = fb_app_get_data($fb_app); $fb_user_data = $fb_app_data['fb_user']; // our configuration $fbu = _fb_user_get_fbu($account->uid, $fb_app); if ($fbu && !$info[$fbu]) { // The drupal user is a facebook user. Now, learn more from facebook. $fb = fb_api_init($fb_app, FB_FBU_ANY); // Note: this requires infinite session with facebook. TODO: fallback to fb_user_app table. $info[$fbu] = $fb->api_client->users_getInfo(array($fbu), array('name', 'is_app_user', )); if ($info[$fbu][0]['is_app_user']) { $items[] = array('name' => $fb_app->label, 'title' => $fb_app->title, 'weight' => 2); } } } return $items; } else if ($op == 'form' && $category == 'fb_user') { $form['map'] = array('#tree' => TRUE); // Iterate through all facebook apps, because they do not all use the same // map scheme. $result = _fb_app_query_all(); while ($fb_app = db_fetch_object($result)) { $fb_app_data = fb_app_get_data($fb_app); $fb_user_data = $fb_app_data['fb_user']; // our configuration $fbu = _fb_user_get_fbu($account->uid, $fb_app); if ($fbu && !$info[$fbu]) { // The drupal user is a facebook user. Now, learn more from facebook. $fb = fb_api_init($fb_app, FB_FBU_ANY); // Note: this requires infinite session with facebook. TODO: fallback to fb_user_app table. $info[$fbu] = $fb->api_client->users_getInfo(array($fbu), array('name', 'is_app_user', )); //dpm($info[$fbu], "Info from facebook for $fbu"); } if ($fbu) { list($module, $authname) = _fb_user_get_authmap($fb_app, $fbu); if ($fb_user_data['unique_account']) { $form['map'][$module] = array('#type' => 'checkbox', '#title' => $fb_app->title, '#default_value' => $authname, '#return_value' => $authname, ); } else { $shared_maps[] = $fb_app->title; $shared_fbu = $fbu; // Same for all shared apps. $shared_module = $module; $shared_authname = $authname; } } if ($shared_maps) { $form['map'][$shared_module] = array('#type' => 'checkbox', '#title' => implode('
', $shared_maps), '#default_value' => $shared_authname, '#return_value' => $shared_authname, ); if ($info[$shared_fbu]) { $data = $info[$shared_fbu][0]; $fb_link = l($data['name'], 'http://www.facebook.com/profile.php', NULL, 'id='.$data['uid']); $form['map'][$shared_module]['#description'] .= t('Local account (!username) corresponds to !profile_page on Facebook.com.', array('!username' => theme('username', $account), '!profile_page' => $fb_link)); } } if (!$fbu) { if ($user->uid == $account->uid) { // TODO: give a user a way to map their facebook account to their local account. } else { $form[$fb_app->nid] = array('#type' => 'markup', '#value' => t('!username does not use !application.', array('!username' => theme('username', $account), '!application' => l($fb_app->title, 'node/'.$fb_app->nid), )), '#prefix' => "\n

", '#suffix' => "

\n", ); } } } return $form; } else if ($op == 'form' && ($fb_app = $apps[$category])) { // Application-specific settings $form['#fb_app'] = $fb_app; // used in hook_form_alter. if (function_exists('fb_canvas_is_fbml') && fb_canvas_is_fbml()) { $sections = array('profile', 'info'); foreach ($sections as $section) { $form[$section] = array('#type' => 'markup', '#value' => '', ); } } // http://wiki.developers.facebook.com/index.php/Extended_permissions $permissions = array('email' => 'Allow %application to send you email', 'offline_access' => 'Grant %application access to your Facebook profile.', 'status_update' => 'Allow %application to set your status.', 'photo_upload' => 'Allow %application to upload photos.', 'create_listing' => 'Allow %application to create marketplace listings on your behalf.', 'create_event' => 'Allow %application to create events on your behalf.', 'rsvp_event' => 'Allow %application to RSVP to events on your behalf', 'sms' => 'Allow %application to send you SMS text messages.', ); foreach ($permissions as $key => $t) { if (function_exists('fb_canvas_is_fbml') && fb_canvas_is_fbml()) { $form[$key] = array('#type' => 'markup', '#value' => ''. t($t, array('%application' => $fb_app->title)) . '
', ); } else { // Non-fbml page // TODO: use API to hide permissions we already have $url = url($_GET['q'], NULL, NULL, TRUE); $form[$key] = array('#type' => 'markup', '#value' => l(t($t, array('%application' => $fb_app->title)), "http://www.facebook.com/authorize.php", array(), "api_key={$fb_app->api_key}&v=1.0&ext_perm={$key}&next={$url}&next_cancel={$url}"), ); } } // Add buttons for boxes and info $sections = array('profile', 'info'); foreach ($sections as $section) { if (function_exists('fb_canvas_is_fbml') && fb_canvas_is_fbml()) { $form[$section] = array('#type' => 'markup', '#value' => '', ); } // No way to add these to a non-canvas page at the moment } $form['description'] = array('#type' => 'markup', '#value' => l(t('All settings for %application (and other Facebook Applications).', array('%application' => $fb_app->title)), 'http://www.facebook.com/editapps.php', array(), NULL, NULL, FALSE, TRUE), '#prefix' => '

', '#suffix' => "

\n", ); return $form; } else if ($op == 'update' && $category == 'fb_user') { //dpm($edit, "fb_user_user($op)"); if (is_array($edit['map'])) foreach ($edit['map'] as $module => $authname) { user_set_authmaps($account, array($module => $authname)); } } } /** * Helper function to create an authname for the authmap table. * * When a single Drupal instance hosts multiple Facebook apps, the apps can * share the same mapping, or each have their own. * * @return an array with both a 'module' and an authname. A * data structure necessary for Drupal's authmap api. */ function _fb_user_get_authmap($fb_app, $fbu) { $fb_app_data = fb_app_get_data($fb_app); $fb_user_data = $fb_app_data['fb_user']; // our configuration $app_specific = $fb_user_data['unique_account']; // map fbu to uid, include apikey if user is app_specific if ($app_specific) { // would rather use the shorter app id (not apikey), but no way to query it $authname = "$fbu-$fb_app->apikey@facebook.com"; $module = "fb_user-$fb_app->nid"; } else { $authname = "$fbu@facebook.com"; $module = "fb_user"; } //return array('module' => $module, 'authname' => $authname); return array($module, $authname); } /** * Creates a local Drupal account for the specified facebook user id. * * @param fbu * The facebook user id corresponding to this account. * * @param config * An associative array with user configuration. Possible values include: * 'app_specific' - Set to true if the same facebook id might correspond to different local accounts, depending on which apps the user has used. Set to false if the user shares one local account across facebook apps. * 'roles' - an array with keys corresponding to role ids the new user should receive. */ function fb_user_create_local_user($fb, $fb_app, $fbu, $config = array()) { // TODO: ensure $fbu is a real user, not FB_FB_ANY or FB_FBU_CURRENT // debugging. //drupal_set_message("Facebook knows you as $username ($fbu)"); $authmap = _fb_user_get_authmap($fb_app, $fbu); $account = user_external_load($authmap); if (!$account) { // Create a new user in our system // We need a username that will not collide with any already in our // system. Could use $authmap, but this will be just slightly more // user-friendly. if ($config['app_specific'] && !$config['username']) $config['username'] = "$fbu-$fb_app->label@facebook"; else $config['username'] = "$fbu@facebook"; // Allow third-party module to adjust any of our settings before we create // the user. $config = fb_invoke(FB_OP_PRE_USER, array('fbu' => $fbu, 'fb' => $GLOBALS['fb'], 'fb_app' => $fb_app), $config); // TODO: double-check that username is not taken. $user_default = array('name' => $config['username'], 'pass' => user_password(), 'init' => db_escape_string($config['username']), 'status' => 1, 'authname_fb_user' => $authmap, ); // Allow $config to set other values, including mail $user_default = array_merge($user_default, $config); $user_default['roles'][DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; if (count($config['roles'])) foreach ($config['roles'] as $rid => $value) if ($rid) $user_default['roles'][$rid] = $value; $user_default['fbu'] = $fbu; // Will get saved as user data. $account = user_save('', $user_default); watchdog('fb_user', t('New user: %name %email.', array('%name' => $name, '%email' => '<'. $mail .'>')), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit')); // Allow third-party modules to act after account creation. //$config = fb_invoke($fb_app, FB_OP_POST_USER, NULL, array('account' => $account)); fb_invoke(FB_OP_POST_USER, array('account' => $account, 'fb_app' => $fb_app, 'fb' => $fb)); // TODO: move this to fb_action. Temporarily disabled. if (FALSE) { // Prepare to send an email. $base = url('', NULL, NULL, TRUE); $variables = array('!username' => $account->name, '!site' => variable_get('site_name', 'Drupal'), '!password' => $user_default['pass'], '!uri' => $base, '!uri_brief' => substr($base, strlen('http://')), '!mailto' => $mail, '!date' => format_date(time()), '!login_uri' => url('user', NULL, NULL, TRUE), '!edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), '!login_url' => user_pass_reset_url($account)); $subject = _user_mail_text('welcome_subject', $variables); $body = _user_mail_text('welcome_body', $variables); // Fix links $subject = fb_scrub_urls($subject); $body = fb_scrub_urls($body); // TODO: make it configurable whether an email is sent, and what it contains. $fb->api_client->notifications_sendEmail($fbu, $subject, $body, $body); } } if (!$account->fbu) { // This should only happen on older, automatically created accounts. $account->fbu = $fbu; user_save($account, array('fbu' => $fbu)); } return $account; } /** * Given an app and facebook user id, return the corresponding local user. */ function fb_user_get_local_user($fbu, $fb_app) { // TODO: this function should probably use user_external_load, rather than query the database directly. See deprecated fb_user_load for example. // TODO: this query probably needs to search for one authname or the other, not both. // Alternately, use the fb_user_app table rather than authmap to look up this information. $result = db_query("SELECT am.* FROM authmap am WHERE am.authname='%s' OR am.authname='%s' ORDER BY am.authname", "$fbu-$fb_app->apikey@facebook.com", "$fbu@facebook.com"); if ($data = db_fetch_object($result)) { $account = user_load(array('uid' => $data->uid)); return $account; } } /** * Returns local uids of friends of a given user. * * Query is relatively efficient for the current user of a canvas page. For * all other users, and non-canvas pages it requires expensive call to * facebook. That said, our local database query may be inefficient for users * with large numbers of friends, so use with caution. * * TODO: should this function cache results? * * Note: the api takes fbu as a parameter, but this usually causes problems * because facebook restricts users to query only about their own friends. * For the time being, expect this function to work only on canvas pages to * find friends of the current user. */ function fb_user_get_local_friends($fbu = NULL, $fb_app = NULL) { if (!isset($fbu)) { $fbu = fb_facebook_user(); } $uids = array(); if ($fbus = fb_get_friends($fbu, $fb_app)) { // Should this query be limited to users of the app? $query = "SELECT uid FROM {fb_user_app} WHERE fbu in (%s)"; $args[] = implode(',', $fbus); $result = db_query($query, $args); while ($data = db_fetch_object($result)) { if ($data->uid) { $uids[] = $data->uid; } } } return $uids; } /** * Given a local user id, find the facebook id. This is for internal use. * Outside modules use fb_get_fbu(). */ // TODO: change this to use the newly added uid column in fb_user_app table. function _fb_user_get_fbu($uid, $fb_app) { static $cache = array(); if (!$cache[$uid]) { $cache[$uid] = array(); // Look up this user in the authmap $result = db_query("SELECT * FROM {authmap} WHERE uid=%d AND authname LIKE '%@facebook.com'", $uid); while (!$fbu && $data = db_fetch_object($result)) { // get the part before the '@' $substr = substr($data->authname, 0, strpos($data->authname, '@')); // then split at the '-' $parts = explode('-', $substr); if ($parts[1]) // $parts[1] is app id $cache[$uid][$parts[1]] = $parts[0]; else $cache[$uid]['global'] = $parts[0]; } } // Return either the global or the app-specific mapping, depending on the app configuration. $fb_app_data = fb_app_get_data($fb_app); $fb_user_data = $fb_app_data['fb_user']; // our configuration if ($fb_user_data['unique_account']) // Return the app-specific mapping return $cache[$uid][$fb_app->apikey]; else // Return the global mapping return $cache[$uid]['global']; } function fb_user_token_list($type = 'all') { if ($type == 'all' || $type == 'fb' || $type == 'fb_app') { $tokens['fb_app']['fb-app-user-fbu'] = t('Current user\'s Facebook ID'); $tokens['fb_app']['fb-app-user-name'] = t('Current user\'s name on Facebook (TODO)'); $tokens['fb_app']['fb-app-user-name-fbml'] = t('Current user\'s name for display on Facebook profile and canvas pages.'); $tokens['fb_app']['fb-app-profile-url'] = t('Current user\'s Facebook profile URL'); } return $tokens; } function fb_user_token_values($type = 'all', $object = NULL) { if ($type == 'fb_app' && $object) { $fb_app = $object; global $user; $fbu = _fb_user_get_fbu($user->uid, $fb_app); if ($fbu) { $values['fb-app-user-fbu'] = $fbu; $values['fb-app-user-name'] = 'TODO XXX'; $values['fb-app-user-name-fbml'] = ''; $values['fb-app-profile-url'] = 'http://www.facebook.com/profile.php?id='.$fbu; } } return $values; } ?>