'Tracking', 'description' => 'Settings that track statistics in Drupal for Facebook', 'page callback' => 'drupal_get_form', 'page arguments' => array('fb_user_app_admin_settings'), 'access arguments' => array(FB_PERM_ADMINISTER), 'file' => 'fb_user_app.admin.inc', 'type' => MENU_LOCAL_TASK, ); return $items; } /** * Implementation of hook_fb() */ function fb_user_app_fb($op, $data, &$return) { $fb_app = isset($data['fb_app']) ? $data['fb_app'] : NULL; $fb = isset($data['fb']) ? $data['fb'] : NULL; global $user; if ($op == FB_OP_APP_IS_AUTHORIZED && variable_get(FB_USER_APP_VAR_TRACK_EVERY_PAGE, FALSE)) { // This hook is called on every page request, if the user has authorized // the app/page and permission has been granted in the settings. We used // to create accounts and maps here. That code is now // in FB_OP_AJAX_EVENT, because it turns out this hook is invoked even on // page not found and access denied pages. fb_user_app_track($fb, $fb_app, $user); } elseif ($op == FB_APP_OP_EVENT) { // Facebook has notified us of some event. // We handle some of the events here. $event_type = $data['event_type']; // Ensure fb_user_app table accurately reflects whether user has authorized. if ($event_type == FB_APP_EVENT_POST_AUTHORIZE) { // Track new facebook user, $GLOBAL['user'] not valid dufing post-autorize. fb_user_app_track($fb, $fb_app); } elseif ($event_type == FB_APP_EVENT_POST_REMOVE) { $fbu = fb_settings(FB_SETTINGS_FBU); // User has removed the app from their account. db_query("DELETE FROM {fb_user_app} WHERE apikey=:apikey AND fbu=:fbu", array( ':apikey' => $fb_app->apikey, ':fbu' => $fbu, )); } } elseif ($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 = :apikey and fbu = :fbu AND session_key_expires > :time", array( ':apikey' => $fb_app->apikey, ':fbu' => $fbu, ':time' => REQUEST_TIME, )); $data = $result->fetchObject(); if ($data && $data->session_key) // Return array with FB id and apikey. $return = array($data->fbu, $data->session_key); } elseif ($op == FB_OP_AJAX_EVENT) { // handle internal login // @TODO - global user is not correct here. // fb.js has notified us of an event via AJAX. Not the same as facebook event callback above. if ($data['event_type'] == 'session_change' && isset($data['event_data']['fbu'])) { // A user has logged in. fb_user_app_track($fb, $fb_app, $user); } } } /** * Implements hook_user_delete(). * * @TODO confirm there is no race condition between this module and fb_user. * That is, during delete, does fb_get_fbu() still work? */ function fb_user_app_user_delete($account) { // Given the uid, fetch the fbu so that we can delete $fbu = fb_get_fbu($account->uid); db_query('DELETE FROM {fb_user_app} WHERE fbu=:fbu', array( ':fbu' => $fbu, )); } /** * Keep track of when the user has visited the app, and whether they've * authorized the app or not. * * Historically this supported infinite sessions. I believe if this data is * no longer necessary for the offline access extended permission. */ function fb_user_app_track($fb, $fb_app) { // Coming from a user adding the app or a page adding the app? $fb_user_type = "user"; $fbu = fb_facebook_user($fb); if (array_key_exists('fb_sig_page_added', $_REQUEST)) { // It's a post-authorize event for app added to page. $fb_user_type = "page"; $fbu = $_REQUEST['fb_sig_page_id']; } // test if we are tracking only those apps that have been granted offline // access. $fb_session = $fb->getSession(); // when 'expires' == 0 app has been granted offline access if ($fb_user_type == 'user' && $fb_session["expires"] <> 0 && variable_get(FB_USER_APP_VAR_USERS_THAT_GRANT_OFFLINE, FALSE)) return; // Track this event only if allowed to and only for users, not pages if ((variable_get(FB_USER_APP_VAR_TRACK_USERS, TRUE) && $fb_user_type = "user") || (variable_get(FB_USER_APP_VAR_TRACK_PAGES, TRUE) && $fb_user_type = "page")) { $session = $fb->getSession(); $session_key = isset($session['session_key']) ? $session['session_key'] : ''; $result1 = db_query("UPDATE {fb_user_app} SET time_access=:time, session_key=:token, session_key_expires=:expires, user_type=:type WHERE apikey=:apikey AND fbu=:fbu", array( ':time' => REQUEST_TIME, ':token' => $session_key, ':expires' => $session['expires'], ':type' => $fb_user_type, ':apikey' => $fb_app->apikey, ':fbu' => fb_facebook_user($fb), )); if ($result1 && !db_affected_rows()) { // XXX upgrade to D7. how? // The row for this user was never inserted, or it was deleted, or the times were the same. $fbu = fb_facebook_user($fb); if ($fbu) { //First make sure it was not just the same time $result = db_query("SELECT * FROM {fb_user_app} WHERE apikey=:apikey AND fbu=:fbu", array( ':apikey' => $fb_app->apikey, ':fbu' => $fbu, )); if (!$result->fetchObject()) { //This row does not exist, even with the same time. Insert now $info = fb_users_getInfo(array($fbu), $fb); $data = $info[0]; $fb_user_type = "user"; $result = db_query("INSERT INTO {fb_user_app} (apikey, fbu, added, user_type, session_key, session_key_expires, time_access, proxied_email, time_cron) VALUES (:apikey, :fbu, :added, :user_type, :session_key, :session_key_expires, :time_access, :proxied_email, :time_cron)", array( ':apikey' => $fb_app->apikey, ':fbu' => $fbu, ':added' => $data['is_app_user'], ':user_type' => $fb_user_type, ':session_key' => $session['session_key'], ':session_key_expires' => $session['expires'], ':time_access' => REQUEST_TIME, ':proxied_email' => $data['proxied_email'], ':time_cron' => 0, )); } } } if ($result === FALSE) { // XXX upgrade to D7??? watchdog('fb_user_app', "Failed to update fb_user_app table.", array(), WATCHDOG_ERROR); } } } /** * Learn the user's proxied email address. * */ function fb_user_app_get_proxied_email($fbu, $fb_app) { // Try to learn from local database $result = db_query("SELECT * FROM {fb_user_app} WHERE apikey=:apikey AND fbu=:fbu", array( ':apikey' => $fb_app->apikey, ':fbu' => $fbu, )); if ($data = $result->fetchObject()) { $mail = $data->proxied_email; } if (!$mail) { // Ask facebook for info. $fb = fb_api_init($fb_app); $info = fb_users_getInfo(array($fbu), $fb); $data = $info[0]; $mail = $data['proxied_email']; if ($mail && variable_get(FB_USER_APP_VAR_TRACK_USERS, TRUE)) { // Store locally. $result = db_query("UPDATE {fb_user_app} SET proxied_email=:mail WHERE apikey=:apikey AND fbu=:fbu", array( ':mail' => $mail, ':apikey' => $fb_app->apikey, ':fbu' => $fbu, )); } } return $mail; }