'fb_friend_request_submit_page', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); $items[FB_FRIEND_PATH_REQUEST_ACCEPT] = array( 'page callback' => 'fb_friend_request_accept_page', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); return $items; } function fb_friend_request_submit_page() { // Parse args $params = array(); $i = FB_FRIEND_PATH_REQUEST_SUBMIT_ARGS; while (($key = arg($i)) && ($value = arg($i+1))) { $params[$key] = $value; $i += 2; } if (isset($_POST['ids']) && count($_POST['ids'])) { $params['ids'] = $_POST['ids']; // Notify third parties $redirect = fb_invoke(FB_FRIEND_OP_REQUEST_SUBMIT, $params, NULL, 'fb_friend'); } else { // User pressed skip instead of inviting. $redirect = fb_invoke(FB_FRIEND_OP_REQUEST_SKIP, $params, NULL, 'fb_friend'); } if ($redirect) { if (FALSE && function_exists('fb_canvas_goto')) { fb_canvas_goto($redirect); } else { drupal_goto($redirect); } } return "fb_friend_request_submit_page"; } function fb_friend_request_accept_page() { // Parse args $params = array(); $i = FB_FRIEND_PATH_REQUEST_SUBMIT_ARGS; while (($key = arg($i)) && ($value = arg($i+1))) { $params[$key] = $value; $i += 2; } if ($fbu = fb_facebook_user()) { // Confirm invitation is in the fb_friend table. $where = array('fbf.status > %d', 'fbf.fbu_target = %d'); $args = array(0, $fbu); foreach (array( 'ref_id' => '%s', 'module' => "'%s'", ) as $key => $pattern) { if (isset($params[$key])) { $where[] = "fbf.$key = $pattern"; $args[] = $params[$key]; } } $result = db_query("SELECT * FROM {fb_friend} AS fbf WHERE " . implode(' AND ', $where), $args); $rows = array(); while ($row = db_fetch_array($result)) { // Update fb_friend.status to indicate accepted. $row['status'] = FB_FRIEND_STATUS_REQUEST_ACCEPTED; if (fb_friend_write_record($row, 'fb_friend_id')) { $rows[] = $row; } } $params['fb_friend'] = $rows; } // Notify third parties $redirect = fb_invoke(FB_FRIEND_OP_REQUEST_ACCEPT, $params, NULL, 'fb_friend'); if ($redirect) { if (FALSE && function_exists('fb_canvas_goto')) { fb_canvas_goto($redirect); } else { drupal_goto($redirect); } } return "fb_friend_request_accept_page"; } function fb_friend_request_submit_path($params) { $path = FB_FRIEND_PATH_REQUEST_SUBMIT; foreach ($params as $key => $value) { $path .= "/$key/$value"; } return $path; } function fb_friend_request_accept_path($params) { $path = FB_FRIEND_PATH_REQUEST_ACCEPT; foreach ($params as $key => $value) { $path .= "/$key/$value"; } return $path; } /** * Implementation of hook_block(). * * Blocks include * - Invite friends to install the application. * - Invite friends to visit the page currently being browsed. * - Show which friends are already users of the current application. * */ function fb_friend_block($op = 'list', $delta = 0, $edit = array()) { if ($op == 'list') { $items = array(); // Blocks which use the current application. $items[FB_FRIEND_DELTA_INVITE_PAGE] = array( 'info' => t('Invite Facebook friends to current page'), ); $items[FB_FRIEND_DELTA_INVITE_APP] = array( 'info' => t('Invite Facebook friends to install the current app'), ); $items[FB_FRIEND_DELTA_AUTHORIZED] = array( 'info' => t('Facebook friends who have authorized the current app'), ); return $items; } elseif ($op == 'view') { try { // Calls to facebook can fail. // None of our blocks are shown if user is not logged in. $fbu = fb_facebook_user(); if (!$fbu) return; // Our blocks use current application global $_fb, $_fb_app; if ($delta == FB_FRIEND_DELTA_INVITE_PAGE) { $content = fb_friend_request_content( array( 'module' => 'fb_friend_invite_page', 'delta' => FB_FRIEND_DELTA_INVITE_PAGE, ), array( 'hook' => 'fb_friend_invite_page', 'invite' => TRUE, 'action_path' => fb_scrub_urls($_GET['q']), // Where sender goes on submit or skip. 'accept_path' => fb_scrub_urls($_GET['q']), // Where recipient goes on accept. )); return array('subject' => t('Invite friends to visit this page'), 'content' => drupal_render($content), ); } elseif ($delta == FB_FRIEND_DELTA_INVITE_APP) { // Exclude users who have already installed. $rs = fb_fql_query($_fb, "SELECT uid FROM user WHERE has_added_app=1 and uid IN (SELECT uid2 FROM friend WHERE uid1 = $fbu)"); // FQL not SQL, no {curly_brackets} $exclude_ids = array(); // Build an delimited list of users... if ($rs) { foreach ($rs as $data) { $exclude_ids[] = $data["uid"]; } } $content = fb_friend_request_content( array( 'module' => 'fb_friend_invite_app', 'delta' => FB_FRIEND_DELTA_INVITE_APP, 'next' => fb_scrub_urls($_GET['q']), ), array( 'hook' => 'fb_friend_invite_app', 'invite' => TRUE, 'title' => variable_get('site_name', $GLOBALS['_fb_app']->title), 'exclude_ids' => $exclude_ids, )); return array('subject' => t('Invite friends to this application'), 'content' => drupal_render($content), ); } elseif ($delta == FB_FRIEND_DELTA_INVITE_APP && FALSE) { // Old way... $app_url = url('', array('absolute' => TRUE, 'fb_canvas' => fb_is_canvas())); $page_url = url($_GET['q'], array('absolute' => TRUE, 'fb_canvas' => fb_is_canvas())); $site_name = variable_get('site_name', t('application')); // Build the alterable data structure. // http://wiki.developers.facebook.com/index.php/Fb:request-form $fbml = fb_form_requestform( array( 'type' => $site_name, 'content' => array( 'markup' => array('#value' => t('You may like this site - !site.', array('!url' => $app_url, '!site' => $site_name))), 'choice' => array('#type' => 'fb_form_req_choice', '#attributes' => array( 'url' => $app_url, 'label' => t('Accept'))), ), 'invite' => TRUE, 'action' => $page_url, 'method' => 'POST', )); // Exclude users who have already installed. $rs = fb_fql_query($_fb, "SELECT uid FROM user WHERE has_added_app=1 and uid IN (SELECT uid2 FROM friend WHERE uid1 = $fbu)"); // FQL not SQL, no {curly_brackets} // @TODO - confirm new API returns same data structure in $rs! $arFriends = ''; $exclude_ids = ''; // Build an delimited list of users... if ($rs) { $exclude_ids .= $rs[0]["uid"]; for ( $i = 1; $i < count($rs); $i++ ) { if ( $exclude_ids != "" ) $exclude_ids .= ","; $exclude_ids .= $rs[$i]["uid"]; } } $fbml['selector'] = fb_form_multi_selector( array('actiontext' => t('Invite friends'), 'exclude_ids' => $exclude_ids, )); // Allow third-party to modify the form drupal_alter('fb_friend_invite_app', $fbml); if ($fbml) { // Wrap in serverfbml. $xfbml = array('#type' => 'fb_form_serverfbml', 'fbml' => $fbml); } // Allow third-party to modify wrapper drupal_alter('fb_friend_invite_app_wrap', $xfbml); $content = drupal_render($xfbml); return array('subject' => t('Invite friends to use !site', array('!site' => $site_name)), 'content' => $content, ); } elseif ($delta == FB_FRIEND_DELTA_AUTHORIZED) { if ($fbu = fb_facebook_user()) { // Get list of friends who have authorized this app. $rs = fb_fql_query($_fb, "SELECT uid FROM user WHERE has_added_app=1 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = $fbu)"); // FQL not SQL, no {curly_brackets} // @TODO - confirm the data structure returned from new API still works with this code. if (isset($rs) && is_array($rs)) { foreach ($rs as $friend_data) { $friend_fbu = $friend_data['uid']; // TODO: make size and markup configurable $content .= ""; } } $subject = t('Friends who use !app', array( '!app' => $GLOBALS['_fb_app']->label)); // TODO - fix title return array( 'subject' => $subject, 'content' => $content); } } } catch (Exception $e) { // We reach this when Facebook Connect sessions are no longer valid. // Javascript should detect this and refresh. Relatively harmless. if (fb_verbose() === 'extreme') { fb_log_exception($e, t('Failed to render fb_friend block.')); } } } } /** * Implements hook_fb_friend(). */ function fb_friend_fb_friend($op, $data, &$return) { if ($data['module'] != 'fb_friend_invite_app') { return; } if ($data['delta'] == FB_FRIEND_DELTA_INVITE_APP) { if ($op == FB_FRIEND_OP_REQUEST_SUBMIT) { // Save the invites to fb_friend table. $data['data'] = serialize(array('delta' => $data['delta'])); $results = fb_friend_write_records($data, $data['ids']); $return = $data['next']; } elseif ($op == FB_FRIEND_OP_REQUEST_SKIP) { $return = $data['next']; } elseif ($op == FB_FRIEND_OP_REQUEST_ACCEPT) { // @TODO present a connect button? $return = ''; } } } /** * @deprecated use fb_friend_request_content instead. */ function fb_friend_invite_page_fbml($alter_hook = NULL, $submit_path = NULL, $accept_path = NULL) { // Defaults if (!isset($submit_path)) { $submit_path = $_GET['q']; } if (!isset($accept_path)) { $accept_path = $_GET['q']; } $submit_url = url($submit_path, array('absolute' => TRUE)); $accept_url = url($accept_path, array('absolute' => TRUE)); // Build the alterable data structure. // http://developers.facebook.com/docs/reference/fbml/request-form $fbml = fb_form_requestform( array( 'type' => variable_get('site_name', t('page view')), //'style' => "width: 500px;", 'content' => array( 'markup' => array('#value' => t('You may want to see this. !title', array('!url' => $accept_url, '!title' => drupal_get_title()))), 'choice' => array('#type' => 'fb_form_req_choice', '#attributes' => array( 'url' => $accept_url, 'label' => t('Accept'))), ), 'invite' => TRUE, 'action' => $submit_url, 'method' => 'POST', //'target' => '_top', // for canvas pages )); $fbml['selector'] = fb_form_multi_selector( array( 'actiontext' => t('Invite friends'), //'target' => '_top', )); // Allow third-party to modify the form if (isset($alter_hook)) { drupal_alter($alter_hook, $fbml); } if ($fbml) { // Wrap in serverfbml. $xfbml = array('#type' => 'fb_form_serverfbml', 'fbml' => $fbml, '#prefix' => '
', '#suffix' => '
', ); // Allow third-party to modify wrapper if (isset($alter_hook)) { drupal_alter($alter_hook . '_wrap', $xfbml); } return $xfbml; } } /** * Builds a data structure, similar to Drupal's form API structure, which renders a facebook request-form. * * By default, hook_fb_friend will be invoked both when the user submits the * invitation form and when their friends accept the invitation. (Default * behavior can be overridden by passing parameters in $form_data.) * * @param $invite_data * Name-value pairs describing the invitation or request. Recommended to include: * - 'module': Not necessarily the name of a module, but identifies which module is responsible for this invite. * - 'ref_id': Node id or other drupal object. Along with 'module', identifies what the invitation is about. * * @param $form_data * Name-value pairs used in building the request-form markup. * @TODO - better documentation here. */ function fb_friend_request_content($invite_data, $form_data) { // defaults $defaults = array( 'action_path' => fb_friend_request_submit_path($invite_data), 'action_text' => 'Invite', 'accept_path' => fb_friend_request_accept_path($invite_data), 'accept_text' => 'Accept', 'exclude_ids' => array(), 'text' => 'has invited you to !title.', 'title' => drupal_get_title(), 'type' => variable_get('site_name', t('page view')), 'invite' => FALSE, 'target' => '_top', // _top helpful on canvas pages. 'hook' => NULL, 'ref_id' => NULL, 'module' => NULL, 'style' => NULL, ); $params = array_merge($defaults, $form_data, $invite_data); $submit_url = url($params['action_path'], array('absolute' => TRUE, 'fb_canvas' => FALSE)); // No canvas, http://forum.developers.facebook.net/viewtopic.php?pid=209230#p209230 $accept_url = url($params['accept_path'], array('absolute' => TRUE, 'fb_canvas' => fb_is_canvas())); // Learn which users to exclude $result = db_query("SELECT fbu_target FROM {fb_friend} WHERE module='%s' AND fbu_actor=%d AND ref_id=%d", $params['module'], fb_facebook_user(), $params['ref_id']); while ($data = db_fetch_object($result)) { $params['exclude_ids'][] = $data->fbu_target; } if (!$params['title']) { $params['title'] = variable_get('site_name', $GLOBALS['_fb_app']->title); } //dpm($params['exclude_ids'], "exclude_ids"); // debug // Build the alterable data structure. // http://developers.facebook.com/docs/reference/fbml/request-form $fbml = fb_form_requestform( array( 'type' => $params['type'], 'style' => $params['style'], 'content' => array( 'markup' => array('#value' => t($params['text'], array('!url' => $accept_url, '!title' => t($params['title'])))), 'choice' => array('#type' => 'fb_form_req_choice', '#attributes' => array( 'url' => $accept_url, 'label' => t($params['accept_text']))), ), 'invite' => $params['invite'], 'action' => $submit_url, 'method' => 'POST', 'target' => $params['target'], )); $fbml['selector'] = fb_form_multi_selector( array( 'actiontext' => t($params['action_text']), 'target' => $params['target'], 'exclude_ids' => implode(',', $params['exclude_ids']), )); // Change some of facebook's bizarre defaults. foreach (array('cols', 'email_invite', 'import_external_friends') as $key) { if (isset($params[$key])) { $fbml['selector']['#attributes'][$key] = $params[$key]; } } // Allow third-party to modify the form if ($params['hook']) { drupal_alter($params['hook'], $fbml); } if ($fbml) { // Wrap in serverfbml. $xfbml = array( '#type' => 'fb_form_serverfbml', 'fbml' => $fbml, '#prefix' => '
', '#suffix' => '
', ); // Allow third-party to modify wrapper if ($params['hook']) { drupal_alter($params['hook'] . '_wrap', $xfbml); } return $xfbml; } } function fb_friend_write_record(&$row, $update = array()) { if (!isset($row['created'])) $row['created'] = time(); if (!isset($row['fbu_actor'])) $row['fbu_actor'] = fb_facebook_user(); if (!isset($row->label) && isset($GLOBALS['_fb_app'])) { $row['label'] = $GLOBALS['_fb_app']->label; } return drupal_write_record('fb_friend', $row, $update); } function fb_friend_write_records($data, $targets) { if (!isset($data['created'])) $data['created'] = time(); if (!isset($data['fbu_actor'])) $data['fbu_actor'] = fb_facebook_user(); if (!isset($row->label) && isset($GLOBALS['_fb_app'])) { $data['label'] = $GLOBALS['_fb_app']->label; } $rows = array(); foreach ($targets as $fbu) { $row = $data; $row['fbu_target'] = $fbu; $result = fb_friend_write_record($row); if ($result) { $rows[] = $row; } } return $rows; } function fb_friend_query_records($args) { $types = array( 'fbu_actor' => '%d', 'fbu_target' => '%d', 'ref_id' => '%d', 'module' => "'%s'", 'label' => "'%s'", ); $where = array(); $a = array(); foreach ($args as $key => $value) { if ($type = $types[$key]) { $where[] = "$key=$type"; $a[] = $value; } } $result = db_query("SELECT * FROM {fb_friend} WHERE " . implode(' AND ', $where), $a); $items = array(); while ($row = db_fetch_array($result)) { $items[$row['fb_friend_id']] = $row; } return $items; }