misc changes to callback url handling
[project/fb.git] / fb_user.module
CommitLineData
186f033e 1<?php
86e52b97
DC
2/**
3 * @file
29be740a
DC
4 * This module manages relations between local Drupal user accounts
5 * and their accounts on facebook.com.
19092d2f 6 *
29be740a
DC
7 * This module can create a new local user account, when a facebook
8 * user authorizes an application hosted on this server.
19092d2f 9 *
29be740a 10 * Links existing local accounts to remote accounts on facebook via
d143d368 11 * fb_user table.
19092d2f 12 *
3cf45120
DC
13 * Drupal refers to a local user id as 'uid'. Facebook's documentation
14 * and code also uses 'uid'. In these modules we use 'fbu' for facebook's
29be740a 15 * id and 'uid' for Drupal's id.
86e52b97
DC
16 */
17
186f033e
DC
18define('FB_USER_OPTION_CREATE_NEVER', 1);
19define('FB_USER_OPTION_CREATE_LOGIN', 2);
186f033e 20
86e52b97 21define('FB_USER_OPTION_MAP_NEVER', 1);
040ff71e
DC
22define('FB_USER_OPTION_MAP_ALWAYS', 2); // Map when user is registered and authorized.
23define('FB_USER_OPTION_MAP_EMAIL', 3); // Map when email is exact match.
86e52b97 24
fa9071e7
DC
25define('FB_USER_VAR_USERNAME_STYLE', 'fb_user_username_style'); // Key used in variables table for this option.
26define('FB_USER_OPTION_USERNAME_FULL', 1); // Get full name from FB
27define('FB_USER_OPTION_USERNAME_FBU', 2); // Use unique name
f54b3a2b 28
8dd84187
DC
29define('FB_USER_VAR_ALTER_REGISTER', 'fb_user_alter_register');
30define('FB_USER_VAR_ALTER_LOGIN', 'fb_user_alter_login');
73a3b338 31define('FB_USER_VAR_ALTER_LOGIN_BLOCK', 'fb_user_alter_login_block');
17bebf6d 32define('FB_USER_VAR_ALTER_CONTACT', 'fb_user_alter_contact');
8dd84187 33
b24ac6ad
DC
34define('FB_USER_VAR_TEXT_REGISTER', 'fb_button_text_register');
35define('FB_USER_VAR_TEXT_LOGIN', 'fb_button_text_login');
36define('FB_USER_VAR_TEXT_LOGIN_BLOCK', 'fb_button_text_login_block');
37
faa4c5d6
DC
38define('FB_USER_VAR_CHECK_SESSION', 'fb_user_check_session');
39
303d3e67
DC
40// Controls - see fb_controls().
41define('FB_USER_CONTROL_NO_CREATE_ACCOUNT', 'fb_user_no_account');
42define('FB_USER_CONTROL_NO_CREATE_MAP', 'fb_user_no_map_create');
43define('FB_USER_CONTROL_NO_HONOR_MAP', 'fb_user_no_map');
93136bfa 44define('FB_USER_CONTROL_NO_REDIRECT', 'fb_user_no_redirect');
303d3e67 45
78672778
DC
46// hook_fb_user().
47define('FB_USER_OP_PRE_USER', 'pre_user'); // Before account creation, fb_user.module
48define('FB_USER_OP_POST_USER', 'post_user'); // After account creation, fb_user.module
49define('FB_USER_OP_POST_EXTERNAL_LOGIN', 'post_external_login'); // user map has changed global user.
5dd2cd82
DC
50define('FB_USER_OP_POST_USER_CONNECT', 'post_user_connect'); // Connected local account to FB account, fb_user.module
51define('FB_USER_OP_POST_USER_DISCONNECT', 'post_user_disconnect'); // Disconnected local account from FB account, fb_user.module
78672778
DC
52
53
ed5232d8 54/**
3cf45120 55 * Implements hook_permission().
ed5232d8 56 */
3cf45120
DC
57function fb_user_permission() {
58 return array(
59 'delete own fb_user authmap' => array(
60 'title' => t('Delete own fb_user authmap'),
61 'description' => t('User can remove their connection to Facebook.'),
62 ),
63 );
72dcacc7 64}
86e52b97
DC
65
66/**
f6ec9cba 67 * Implements hook_menu().
f54b3a2b
DC
68 */
69function fb_user_menu() {
70 $items = array();
19092d2f 71
f54b3a2b
DC
72 // Admin pages
73 $items[FB_PATH_ADMIN . '/fb_user'] = array(
5d87b01a 74 'title' => 'User Settings',
f54b3a2b
DC
75 'description' => 'Local account to facebook account mapping',
76 'page callback' => 'drupal_get_form',
77 'page arguments' => array('fb_user_admin_settings'),
78 'access arguments' => array(FB_PERM_ADMINISTER),
79 'file' => 'fb_user.admin.inc',
80 'type' => MENU_LOCAL_TASK,
81 );
19092d2f 82
f54b3a2b
DC
83 return $items;
84}
85
f54b3a2b 86/**
ed5232d8
DC
87 * Returns configuration for this module, on a per-app basis.
88 */
89function _fb_user_get_config($fb_app) {
67523320 90 $fb_app_data = fb_get_app_data($fb_app);
d8f85b06 91 $fb_user_data = isset($fb_app_data['fb_user']) ? $fb_app_data['fb_user'] : array();
19092d2f 92
ed5232d8
DC
93 // Merge in defaults
94 $fb_user_data += array(
a7339f59 95 'create_account' => FB_USER_OPTION_CREATE_NEVER,
040ff71e
DC
96 'map_account' => array(
97 FB_USER_OPTION_MAP_ALWAYS => FB_USER_OPTION_MAP_ALWAYS,
98 FB_USER_OPTION_MAP_EMAIL => FB_USER_OPTION_MAP_EMAIL,
99 ),
d8f85b06 100 'new_user_rid' => NULL,
93136bfa 101 'connected_user_rid' => NULL,
ed5232d8
DC
102 );
103 return $fb_user_data;
104}
105
106/**
7364859a
DC
107 * There are several pages where we don't want to automatically create a new
108 * account or use an account configured for this app.
86e52b97 109 */
86e52b97 110function _fb_user_special_page() {
3cf45120 111 // fb_app/event is called by facebook. Don't create accounts on that page.
303d3e67 112 return ((arg(0) == 'fb_app' && arg(1) == 'event'));
86e52b97
DC
113}
114
7364859a 115/**
3cf45120 116 * Implements hook_fb.
3a512626 117 */
8fbcf653 118function fb_user_fb($op, $data, &$return) {
81e5e23a
DC
119 $fb_app = isset($data['fb_app']) ? $data['fb_app'] : NULL;
120 $fb = isset($data['fb']) ? $data['fb'] : NULL;
19092d2f 121
8fbcf653 122 global $user;
19092d2f 123
ed5232d8
DC
124 if ($fb_app) {
125 $fb_user_data = _fb_user_get_config($fb_app);
126 }
19092d2f 127
78672778 128 if ($op == FB_OP_POST_INIT && $fb) {
93136bfa 129 $fbu = fb_facebook_user();
040ff71e 130 if (isset($_SESSION['fb_user_fbu']) &&
626faa71
DC
131 $_SESSION['fb_user_fbu'] != $fbu &&
132 !(fb_settings(FB_SETTINGS_CB_SESSION) && !$fbu)) {
133 // User has logged out of facebook, and drupal is only now learning
3cf45120 134 // about it. Check disabled when using FB_SETTINGS_CB_SESSION, because
626faa71
DC
135 // we aren't always passed a signed_request in that case, which would
136 // otherwise trigger this.
faa4c5d6 137 _fb_logout();
93136bfa 138 if (!fb_controls(FB_USER_CONTROL_NO_REDIRECT)) {
a732fef6 139 drupal_goto(current_path()); // @TODO - need request params here?
93136bfa 140 }
040ff71e 141 }
303d3e67
DC
142
143 if (_fb_user_special_page() ||
144 (variable_get('site_offline', FALSE) && !user_access('administer site configuration'))) {
145 // Prevent some behavior.
146 fb_controls(FB_USER_CONTROL_NO_HONOR_MAP, TRUE);
147 fb_controls(FB_USER_CONTROL_NO_CREATE_MAP, TRUE);
148 fb_controls(FB_USER_CONTROL_NO_CREATE_ACCOUNT, TRUE);
149 }
187e24c9 150 if (isset($_REQUEST['_fb_user_fbu'])) {
3cf45120 151 // We've triggered a reload. Don't redirect again, as that will
626faa71
DC
152 // cause infinite loop if browser not accepting third-party cookies.
153 fb_controls(FB_USER_CONTROL_NO_REDIRECT, TRUE);
154 }
155
93136bfa
DC
156 if ($rid = $fb_user_data['connected_user_rid']) {
157 if ($fbu) {
158 // User is connected to facebook.
159 if (!isset($user->roles[$rid])) {
160 $user->roles[$rid] = $rid; // Should be role name, but that requires db query.
161 // Reload user permissions.
ae674940
DC
162 drupal_static_reset('user_access');
163 drupal_static_reset('menu_get_item');
93136bfa
DC
164 }
165 }
166 else {
167 // User is not connected to facebook.
0eefdc90
DC
168 if ($rid != DRUPAL_AUTHENTICATED_RID && isset($user->roles[$rid])) {
169 // Out of paranoia, unset role. This will be reached only if the
170 //user was somehow saved while connected to facebook.
93136bfa
DC
171 unset($user->roles[$rid]);
172 // Reload user permissions.
ae674940
DC
173 drupal_static_reset('user_access');
174 drupal_static_reset('menu_get_item');
93136bfa
DC
175 }
176 }
177 }
040ff71e 178 }
456be90c 179 elseif ($op == FB_OP_GET_FBU) {
3a512626 180 // This is a request to learn the user's FB id.
d143d368 181 $return = _fb_user_get_fbu($data['uid']);
186f033e 182 }
346e5a9b
DC
183 elseif ($op == FB_OP_GET_UID) {
184 // This is a request to learn the facebook user's local id.
e1442496 185 $return = _fb_user_get_uid($data['fbu'], $data['fb_app']);
346e5a9b 186 }
a24a1868 187 elseif ($op == FB_OP_AJAX_EVENT) {
3cf45120 188 // fb.js has notified us of an event via AJAX. Not the same as facebook event callback above.
a24a1868
DC
189 if ($data['event_type'] == 'session_change' && isset($data['event_data']['fbu'])) {
190 // A user has logged in.
7308ca43 191 // Don't trust fbu from $data['event_data'], too easy to spoof.
d143d368 192 // Don't set fb_user if SESSION[fb_user_fbu], could be an old session not properly cleaned up.
040ff71e 193 if (($fbu = fb_facebook_user($data['fb'])) &&
303d3e67
DC
194 $fbu != fb_get_fbu($GLOBALS['user'])) {
195
187e24c9
DC
196 // In ajax callback, there's no reason to redirect even if user
197 // changes. But we should honor session, as even ajax can set a new
198 // cookie.
199 fb_controls(FB_USER_CONTROL_NO_REDIRECT, TRUE);
200
5a247ec5 201 _fb_user_process_authorized_user();
7308ca43 202 }
a24a1868
DC
203 }
204 }
86e52b97
DC
205}
206
3cf45120
DC
207/**
208 * Implements hook_page_alter().
209 *
210 * Reload page if user has changed. This would not make sense during an ajax
211 * callback (or anything else) where a redirect would not refresh the browsers
212 * page. That's why we do it here in page_alter().
213 */
214function fb_user_page_alter(&$page) {
215 _fb_user_check_and_goto();
216}
217
218/**
219 * Detect whether facebook indicates the user has changed. If so, redirect.
220 */
221function _fb_user_check_and_goto() {
5a247ec5 222 if (($fbu = fb_facebook_user()) &&
626faa71 223 !fb_is_tab() && // $fbu is page id, not visitor id, on tabs.
41ae3090 224 $fbu != fb_get_fbu($GLOBALS['user'])) {
303d3e67 225 $uid = $GLOBALS['user']->uid; // Remember original uid.
5a247ec5 226 _fb_user_process_authorized_user();
303d3e67
DC
227 if ($uid != $GLOBALS['user']->uid) {
228 // during user processing, we started a new session.
93136bfa 229 if (!fb_controls(FB_USER_CONTROL_NO_REDIRECT)) {
b389f367
DC
230 // No longer passing _fb_user_fbu, because it causes problem when logging out of one frame then refreshing a frame with that parameter in the URL.
231 drupal_goto(request_path(), array(
232 //'_fb_user_fbu' => $fbu, // Avoid refresh loop, disabled for now. Still needed?
233 ));
93136bfa 234 }
303d3e67
DC
235 }
236 }
237}
5a247ec5 238
303d3e67 239/**
3cf45120
DC
240 * Test facebook session by calling into facebook. This is expensive, so
241 * limit check to once per session. Use session variable to flag that we have
303d3e67
DC
242 * completed the test.
243 */
244function _fb_user_check_session($fbu) {
d143d368 245 // Make sure facebook session is valid and fb_user table is correct.
303d3e67
DC
246 // Relatively expensive operations, so we perform them only once per session.
247 if (!isset($_SESSION['fb_user_fbu']) || $_SESSION['fb_user_fbu'] != $fbu) {
248 if ($valid_session = fb_api_check_session($GLOBALS['_fb'])) { // Expensive check.
249 $_SESSION['fb_user_fbu'] = $fbu;
250 }
251 else {
252 unset($_SESSION['fb_user_fbu']);
253 }
254 }
255 return (isset($_SESSION['fb_user_fbu']) && $_SESSION['fb_user_fbu'] == $fbu);
256}
257
258/**
259 * If facebook user has authorized app, and account map exists, login as the local user.
260 *
261 * @return - TRUE, if user_external_login succeeds.
262 */
fa9071e7 263function _fb_user_external_login($account = NULL) {
303d3e67 264 $fbu = fb_facebook_user();
fa9071e7
DC
265 if (!$account) {
266 $account = fb_user_get_local_user($fbu, $GLOBALS['_fb_app']);
267 }
303d3e67
DC
268 if ($account &&
269 $account->uid == $GLOBALS['user']->uid) {
270 // Already logged in.
271 return $account;
272 }
273 elseif ($fbu &&
274 $account &&
275 $account->uid != $GLOBALS['user']->uid &&
276 !fb_controls(FB_USER_CONTROL_NO_HONOR_MAP)) {
626faa71 277
3cf45120 278 // Map exists. Log in as local user.
626faa71 279 $session_id = session_id();
303d3e67
DC
280 if (fb_verbose() === 'extreme') { // debug
281 watchdog("fb_user", "fb_user_fb changing user to $account->uid");
303d3e67 282 }
626faa71 283
5a247ec5
DC
284 // user_external_login() fails if already logged in, so log out first.
285 if ($GLOBALS['user']->uid) {
faa4c5d6 286 _fb_logout();
5a247ec5 287 }
626faa71 288
3cf45120
DC
289 // user_external_login() removed in D7, no replacement. Let's hope the following works.
290 $GLOBALS['user'] = $account;
291 $drupal_sux = (array) $account;
292 user_login_finalize($drupal_sux);
626faa71
DC
293
294 // Special effort to support browsers without third-party cookies.
295 if (function_exists('fb_sess_regenerate_hack')) {
296 fb_sess_regenerate_hack();
297 }
298
303d3e67
DC
299 if (fb_verbose() === 'extreme') { // debug
300 watchdog("fb_user", "fb_user_fb changed session from $session_id to " . session_id());
301 }
626faa71 302
3cf45120
DC
303 // Session changed after external login. Invoking hook here allows modules to drupal_set_message().
304 fb_invoke(FB_USER_OP_POST_EXTERNAL_LOGIN, array('account' => $account), NULL, 'fb_user');
305 return $account;
303d3e67
DC
306 }
307 return FALSE;
308}
309
310/**
311 * Create a map linking the facebook account to the currently logged in local user account.
312 *
313 * @return - TRUE, if map created.
314 */
315function _fb_user_create_map() {
316 if ($GLOBALS['user']->uid) {
317 $fbu = fb_facebook_user();
d143d368 318 $account = fb_user_get_local_user($fbu);
303d3e67
DC
319 if ($fbu &&
320 !$account &&
321 !fb_controls(FB_USER_CONTROL_NO_CREATE_MAP)) {
d143d368 322 _fb_user_set_map($GLOBALS['user'], $fbu);
5dd2cd82
DC
323 fb_invoke(FB_USER_OP_POST_USER_CONNECT, array(
324 'account' => $GLOBALS['user'],
325 'fbu' => $fbu,
326 ), NULL, 'fb_user');
303d3e67
DC
327 return TRUE;
328 }
329 }
330 return FALSE;
331}
332
333function _fb_user_create_map_by_email() {
334 $fbu = fb_facebook_user();
335 $account = fb_user_get_local_user($fbu, $GLOBALS['_fb_app']);
336 if ($fbu &&
337 !$account &&
338 ($email_account = fb_user_get_local_user_by_email($fbu)) &&
339 !fb_controls(FB_USER_CONTROL_NO_CREATE_MAP)) {
d143d368 340 _fb_user_set_map($email_account, $fbu);
5dd2cd82
DC
341 fb_invoke(FB_USER_OP_POST_USER_CONNECT, array(
342 'account' => $GLOBALS['user'],
343 'fbu' => $fbu,
344 ), NULL, 'fb_user');
303d3e67
DC
345 return TRUE;
346 }
347 return FALSE;
348}
349
350/**
351 * Helper function to create local account for the currently authorized user.
352 */
353function _fb_user_create_local_account() {
354 $fbu = fb_facebook_user();
d143d368 355 $account = fb_user_get_local_user($fbu);
303d3e67
DC
356 if ($fbu &&
357 !$account &&
358 !fb_controls(FB_USER_CONTROL_NO_CREATE_ACCOUNT)) {
359 $config = _fb_user_get_config($GLOBALS['_fb_app']);
19092d2f
DC
360
361 // Establish user name.
fa9071e7
DC
362 // Case 1: use name from FB
363 // Case 2: create a unique user name ourselves
19092d2f 364 // Which we use is determined by the setting at
3cf45120 365 // admin/structure/fb/fb_user
19092d2f 366 if (variable_get(FB_USER_VAR_USERNAME_STYLE, FB_USER_OPTION_USERNAME_FBU) == FB_USER_OPTION_USERNAME_FULL) {
fa9071e7 367 try {
3cf45120 368 // Use fb->api() rather than fb_users_getInfo(). Later fails to learn name on test accounts.
fa9071e7
DC
369 $info = $GLOBALS['_fb']->api($fbu);
370 $username = $info['name'];
371 } catch (Exception $e) {
372 fb_log_exception($e, t('Failed to learn full name of new user'), $GLOBALS['_fb']);
373 }
374 }
375 else {
376 // Create a name that is likely to be unique.
377 $username = "$fbu@facebook";
378 }
379
303d3e67
DC
380 if ($config['new_user_rid']) {
381 $roles = array($config['new_user_rid'] => TRUE);
382 }
383 else {
384 $roles = array();
385 }
386
d143d368 387 $account = fb_user_create_local_user($GLOBALS['_fb'], $GLOBALS['_fb_app'],
303d3e67
DC
388 $fbu, array(
389 'name' => $username,
390 'roles' => $roles,
391 ));
19092d2f 392 watchdog('fb_user',
303d3e67
DC
393 t("Created new user !username for application %app", array(
394 '!username' => l($account->name, 'user/' . $account->uid),
fa9071e7 395 '%app' => $GLOBALS['_fb_app']->label)));
19092d2f 396
303d3e67
DC
397 return $account;
398 }
399 return FALSE;
400}
401
402/**
403 * Create local account or account map for a facebook user who has authorized the application.
404 */
405function _fb_user_process_authorized_user() {
406 $fbu = fb_facebook_user();
407 $mapped = FALSE;
626faa71 408
faa4c5d6
DC
409 if ($fbu &&
410 (!variable_get(FB_USER_VAR_CHECK_SESSION, FALSE) || _fb_user_check_session($fbu))) {
5a5422ab 411 $fb_app = $GLOBALS['_fb_app'];
303d3e67 412 // First check if map already exists.
5a5422ab
DC
413 $account = fb_user_get_local_user($fbu, $fb_app);
414 $config = _fb_user_get_config($fb_app);
626faa71 415
303d3e67 416 if (!$account) {
303d3e67
DC
417 if ($GLOBALS['user']->uid > 0 &&
418 $config['map_account'][FB_USER_OPTION_MAP_ALWAYS]) {
419 // Create map for logged in user.
420 $mapped = _fb_user_create_map();
421 }
422 if (!$mapped &&
423 $config['map_account'][FB_USER_OPTION_MAP_EMAIL]) {
424 // Create map if email matches.
425 $mapped = _fb_user_create_map_by_email();
426 }
626faa71 427
303d3e67
DC
428 if (!$mapped &&
429 $config['create_account'] == FB_USER_OPTION_CREATE_LOGIN) {
430 // Create new local account with map.
431 $mapped = _fb_user_create_local_account();
432 }
626faa71 433
303d3e67 434 if ($mapped) {
5a5422ab 435 $account = fb_user_get_local_user($fbu, $fb_app);
303d3e67
DC
436 }
437 }
626faa71 438
303d3e67
DC
439 if ($account) {
440 // Ensure the user has any roles associated with this app.
441 $rid = $config['new_user_rid'];
442 if ($account && $rid &&
fa9071e7 443 (!isset($account->roles[$rid]) || !$account->roles[$rid])) {
303d3e67 444 // there should be an API for this...
3cf45120
DC
445 $query = db_insert('users_roles')
446 ->fields(array(
447 'uid' => $account->uid,
448 'rid' => $rid))
449 ->execute();
303d3e67 450 watchdog('fb_user', "Added role %role to existing user !username for application %app", array(
fa9071e7 451 '!username' => theme('username', $account),
303d3e67
DC
452 '%app' => $fb_app->label,
453 '%role' => $rid));
454 }
fa9071e7
DC
455
456 // Login as facebook user, if not already.
457 _fb_user_external_login($account);
303d3e67
DC
458 }
459 }
460}
19092d2f 461
303d3e67 462
17bebf6d 463function _fb_user_facebook_data($fb) {
329b36aa
DC
464 if ($fbu = fb_facebook_user($fb)) {
465 try {
466 $data = fb_api($fbu);
467 return $data;
468 }
469 catch (FacebookApiException $e) {
470 fb_log_exception($e, t('Failed lookup of %fbu.', array('%fbu' => $fbu)));
471 }
17bebf6d
DC
472 }
473}
474
8dd84187 475/**
73a3b338
DC
476 * Helper function to retrieve button text.
477 */
478function _fb_user_button_text($form_id) {
3cf45120 479 $button_text = &drupal_static(__FUNCTION__);
73a3b338
DC
480
481 if (!isset($button_text)) {
482 $button_text = array(
c592885c 483 'user_register_form' => variable_get(FB_USER_VAR_TEXT_REGISTER, NULL),
b24ac6ad
DC
484 'user_login' => variable_get(FB_USER_VAR_TEXT_LOGIN, NULL),
485 'user_login_block' => variable_get(FB_USER_VAR_TEXT_LOGIN_BLOCK, NULL),
73a3b338
DC
486 );
487 }
488
489 return isset($button_text[$form_id]) ? $button_text[$form_id] : '';
490}
491
492/**
8dd84187
DC
493 * Implements hook_form_alter().
494 */
a9167ce4 495function fb_user_form_alter(&$form, &$form_state, $form_id) {
81e5e23a 496 if (isset($form['fb_app_data'])) {
040ff71e
DC
497 // Add our settings to the fb_app edit form.
498 module_load_include('inc', 'fb_user', 'fb_user.admin');
499 fb_user_admin_form_alter($form, $form_state, $form_id);
186f033e 500 }
456be90c 501 elseif ($form_id == 'user_edit' && ($app = $form['#fb_app'])) {
7364859a
DC
502 // Disable buttons on user/edit/app pages, nothing to submit
503 unset($form['submit']);
504 unset($form['delete']);
505 }
17bebf6d
DC
506
507 // Add name and email to some forms.
93136bfa
DC
508 if (isset($GLOBALS['_fb'])) {
509 $fb = $GLOBALS['_fb'];
b26c58b4 510 if (!$GLOBALS['user']->uid && // No alters to user add form.
c592885c 511 (($form_id == 'user_register_form' && variable_get(FB_USER_VAR_ALTER_REGISTER, TRUE)) ||
b26c58b4
DC
512 ($form_id == 'user_login' && variable_get(FB_USER_VAR_ALTER_LOGIN, TRUE)) ||
513 ($form_id == 'user_login_block' && variable_get(FB_USER_VAR_ALTER_LOGIN_BLOCK, TRUE)))) {
3cf45120 514
8dd84187
DC
515 if ($fbu = fb_facebook_user()) {
516 // Facebook user has authorized app.
93136bfa 517
8dd84187
DC
518 // Show user name and picture.
519 $form['fb_user'] = array(
520 'name' => array(
3cf45120 521 '#markup' => '<fb:name uid="' . $fbu . '" useyou="false" linked="false"></fb:name>',
8dd84187
DC
522 '#prefix' => '<div class="fb_user_name">',
523 '#suffix' => '</div>',
524 ),
525 'picture' => array(
3cf45120 526 '#markup' => '<fb:profile-pic uid="' . $fbu . '" linked="false"></fb:profile-pic>',
8dd84187
DC
527 '#prefix' => '<div class="fb_user_picture">',
528 '#suffix' => '</div>',
529 ),
530 '#weight' => -1,
531 );
19092d2f 532
c592885c 533 if ($form_id == 'user_register_form') {
8dd84187 534 // Provide defaults for name and email.
17bebf6d 535 if ($data = _fb_user_facebook_data($fb)) {
303d3e67 536 $form['fb_user']['#fb_user'] = $data;
19092d2f 537
8dd84187
DC
538 if (isset($form['name']) && !$form['name']['#default_value']) {
539 // @TODO - ensure name is unique to Drupal.
540 $form['name']['#default_value'] = $data['name'];
541 }
303d3e67
DC
542 elseif (isset($form['account']) && isset($form['account']['name']) &&
543 !$form['account']['name']['#default_value']) {
544 // @TODO - ensure name is unique to Drupal.
545 $form['account']['name']['#default_value'] = $data['name'];
546 }
8dd84187
DC
547 if (isset($form['mail']) && !$form['mail']['#default_value']) {
548 $form['mail']['#default_value'] = $data['email'];
549 }
303d3e67
DC
550 elseif (isset($form['account']['mail']) && isset($form['account']['mail']) &&
551 !$form['account']['mail']['#default_value']) {
552 $form['account']['mail']['#default_value'] = $data['email'];
553 }
8dd84187 554 }
9f770b6e
DC
555 }
556 }
19092d2f 557
8dd84187
DC
558 else {
559 // facebook user has not authorized app.
3cf45120 560 $fb_button = theme('fb_login_button', array('text' => t(_fb_user_button_text($form_id))));
8dd84187 561 $form['fb_user'] = array(
8dd84187 562 '#type' => 'markup',
3cf45120 563 '#markup' => $fb_button,
73a3b338 564 '#weight' => -1, // Ideally, we'd put ourself next to openid login, but doesn't look right when next to form buttons.
475821b8 565 '#prefix' => '<div class="fb_user-login-button-wrapper">',
73a3b338 566 '#suffix' => '</div>',
8dd84187 567 );
9f770b6e
DC
568 }
569 }
ae674940 570 elseif ($form_id == 'contact_site_form' && variable_get(FB_USER_VAR_ALTER_CONTACT, TRUE)) {
17bebf6d
DC
571 if ($data = _fb_user_facebook_data($fb)) {
572 if (!$form['name']['#default_value'] || strpos($form['name']['#default_value'], '@facebook')) {
573 $form['name']['#default_value'] = $data['name'];
574 }
575 if (!$form['mail']['#default_value']) {
576 $form['mail']['#default_value'] = $data['email'];
577 }
578 }
579 }
9f770b6e 580 }
19092d2f 581
1038c8a6
DC
582}
583
584/**
2b70138f
DC
585 * Helper function for menu item access check.
586 */
587function fb_user_access_own($account, $perm, $allow_admin) {
588 if ($GLOBALS['user']->uid == $account->uid && user_access($perm)) {
589 return TRUE;
590 }
456be90c 591 elseif ($allow_admin) {
2b70138f
DC
592 return user_access('administer users');
593 }
594}
595
3cf45120 596
86e52b97 597/**
3cf45120
DC
598 * Implements hook_user_load.
599 *
600 * Use no standard email, use proxy email if available
86e52b97 601 */
3cf45120
DC
602function fb_user_user_load($users) {
603 global $_fb_app;
604
605 foreach ($users as $account) {
606 if ($account->uid && $_fb_app) {
607 if (!$account->mail && ($fbu = _fb_user_get_fbu($account->uid))) {
608 // Use proxied email, if facebook app is active and user uses it.
609 // TODO: confirm drupal never saves proxied address to users.mail.
610 $account->mail = fb_user_get_proxied_email($fbu, $_fb_app);
611 $account->fb_user_proxied_mail = $account->mail; // Remember where we got address.
612 }
613 }
614 }
615}
616
617/**
618 * Implements hook_user_login.
619 *
620 * Map local Drupal user to FB user under certain circumstances.
621 */
622function fb_user_user_login(&$edit, $account) {
d143d368 623 global $user, $_fb_app;
19092d2f 624
3cf45120
DC
625 // A facebook user has logged in. We can map the two accounts together.
626 $fb_user_data = _fb_user_get_config($_fb_app);
627 if (($fbu = fb_facebook_user()) &&
475821b8 628 $fb_user_data['map_account'][FB_USER_OPTION_MAP_ALWAYS] &&
3cf45120
DC
629 !fb_controls(FB_USER_CONTROL_NO_CREATE_MAP)) {
630
631 // Create fb_user record if it doesn't exist or update existing one
632 _fb_user_set_map($account, $fbu);
633
634 // @TODO - if the app has a role, make sure the user gets that role. (presently,
635 // that will not happen until their next request)
1038c8a6 636 }
3cf45120 637}
1038c8a6 638
3cf45120
DC
639/**
640 * Implements hook_user_insert.
641 *
642 * When user is created create record
643 * in fb_user to map local Drupal user to FB user.
644 */
645function fb_user_user_insert(&$edit, $account, $category) {
646 global $user, $_fb_app;
647
648 // Map the two accounts together.
d143d368
DC
649 $fb_user_data = _fb_user_get_config($_fb_app);
650 if (($fbu = fb_facebook_user()) &&
475821b8 651 $fb_user_data['map_account'][FB_USER_OPTION_MAP_ALWAYS] &&
303d3e67 652 !fb_controls(FB_USER_CONTROL_NO_CREATE_MAP)) {
19092d2f 653
f6ec9cba
DC
654 // Create fb_user record if it doesn't exist or update existing one.
655 if ($account->uid == $user->uid) {
656 _fb_user_set_map($account, $fbu);
657 }
19092d2f 658
303d3e67 659 // @TODO - if the app has a role, make sure the user gets that role. (presently, that will not happen until their next request)
86e52b97 660 }
3cf45120
DC
661}
662
663/**
664 * Implements hook_user_view.
665 *
666 * Show extra info when user being viewed.
667 */
668function fb_user_user_view($account, $view_mode, $langcode) {
669
670}
671
672/**
41ae3090 673 * Implements hook_user_update().
3cf45120
DC
674 *
675 * User is about to be updated.
676 */
677function fb_user_user_update(&$edit, $account, $category) {
678 if ($edit['map']) {
679 _fb_user_set_map($account, $edit['map']);
86e52b97 680 }
3cf45120
DC
681 else {
682 // Delete account mapping, because administrator has unchecked the connect option.
683 $num_deleted = db_delete('fb_user')
684 ->condition('uid', $account->uid)
685 ->execute();
19092d2f 686
5dd2cd82 687 fb_invoke(FB_USER_OP_POST_USER_DISCONNECT, array('account' => $account), NULL, 'fb_user');
86e52b97 688 }
3cf45120 689}
19092d2f 690
3cf45120
DC
691/**
692 * Implements hook_user_delete.
693 *
694 * User is about to be deleted.
695 */
696function fb_user_user_delete($account) {
697 $num_deleted = db_delete('fb_user')
698 ->condition('uid', $account->uid)
699 ->execute();
700}
19092d2f 701
3cf45120
DC
702/**
703 * Implements hook_user_logout.
704 *
705 * User has logged out.
706 */
707function fb_user_user_logout($account) {
708 global $user, $_fb_app;
19092d2f 709
3cf45120
DC
710 if (fb_facebook_user() &&
711 fb_api_check_session($GLOBALS['_fb'])) {
712 // Log out of facebook, as well as Drupal. Note that code in
713 // fb_connect.js and fb_canvas.js attempts to call FB.logout. However,
714 // that code is not reached if the user types "/logout" directly into
715 // the browser URL. Also, a sometimes-occuring bug in firefox prevents
716 // FB.logout from always succeeding.
717
718 // Figure out where to send the user.
719 if (isset($_REQUEST['destination'])) {
720 $next_url = url($_REQUEST['destination'], array('absolute' => TRUE, 'fb_canvas' => fb_is_canvas()));
721 // Unset desination so drupal_goto() below does what we need it to do.
722 unset($_REQUEST['destination']);
723 }
724 else {
725 $next_url = url('<front>', array('absolute' => TRUE, 'fb_canvas' => fb_is_canvas()));
726 }
727 $logout_url = $GLOBALS['_fb']->getLogoutUrl(array(
728 'next' => $next_url,
729 'cancel_url' => $next_url,
730 ));
731 drupal_goto($logout_url);
732 }
733}
8f184418 734
3cf45120
DC
735/**
736 * Implements hook_form_user_profile_form_alter.
737 */
738function fb_user_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
739 global $user, $_fb_app;
8f184418 740
3cf45120
DC
741 if (!user_access('administer users') &&
742 !(user_access('delete own fb_user authmap') &&
743 $user->uid == $form['#user']->uid))
744 return; // hide from this user
19092d2f 745
3cf45120 746 $fb_user_data = _fb_user_get_config($_fb_app);
fdc2c009
DC
747 $account = $form['#user'];
748 $fbu = _fb_user_get_fbu($account->uid);
3cf45120
DC
749
750 if ($fbu) {
fdc2c009
DC
751 // The drupal user is a facebook user.
752 $form['fb_user'] = array(
3cf45120 753 '#type' => 'fieldset',
fdc2c009 754 '#title' => t('Facebook Application ' . $_fb_app->title),
3cf45120
DC
755 '#collapsed' => false,
756 '#collapsible' => false,
757 );
fdc2c009 758 $form['fb_user']['map'] = array(
3cf45120 759 '#type' => 'checkbox',
fdc2c009 760 '#title' => t('Connect to facebook.com'),
3cf45120
DC
761 '#default_value' => $fbu,
762 '#return_value' => $fbu,
763 '#description' => '',
764 );
fdc2c009
DC
765 // Now, learn more from facebook.
766 try {
767 $data = fb_api($fbu, array('access_token' => fb_get_token()));
768 if (count($data)) {
769 $form['fb_user']['map']['#description'] .=
770 t('Local account !username corresponds to !profile_page on Facebook.com.',
771 array(
772 '!username' => l($account->name, 'user/' . $account->uid),
773 '!profile_page' => l($data['name'], $data['link'])));
86e52b97 774 }
fdc2c009
DC
775 }
776 catch (Exception $e) {
777 fb_log_exception($e, t('Failed to get user data from facebook.'));
778 }
3cf45120 779
fdc2c009
DC
780 if (fb_facebook_user() == $fbu) {
781 // The user is currently connected to facebook. Depending on
782 // config, they may not be able to break the connection.
783 $form['fb_user']['map']['#disabled'] = TRUE;
784 $form['fb_user']['map']['#description'] .= '<br/>' . t('(Checkbox disabled because you are currently connected to facebook.)');
785 }
786 else {
787 $form['fb_user']['map']['#description'] .= '<br/>' . t('Uncheck then click save to delete this connection.');
3cf45120
DC
788 }
789 }
790
791 if (!$fbu) { // this tells us that a mapping hasn't been created
fdc2c009 792 if ($user->uid == $account->uid) {
3cf45120 793 // Could not obtain the $fbu from an existing map.
3cf45120
DC
794 $fbu = fb_facebook_user();
795
796 if ($fbu) { // they are connected to facebook; give option to map
797
fdc2c009 798 $form['fb_user'] = array(
3cf45120 799 '#type' => 'fieldset',
fdc2c009 800 '#title' => t('Facebook Application ' . $_fb_app->title),
3cf45120
DC
801 '#collapsed' => false,
802 '#collapsible' => false,
803 );
804
fdc2c009 805 $form['fb_user']['map'] = array(
3cf45120
DC
806 '#type' => 'checkbox',
807 '#title' => t('Connect account to facebook.com'),
808 '#default_value' => 0,
809 '#return_value' => $fbu,
810 '#description' => '',
811 );
fdc2c009 812 $form['fb_user']['message'] = array(
ae674940
DC
813 '#markup' => t('If checked, link local account (!username) to facebook.com account (!fb_name).', array(
814 '!username' => theme('username', array('account' => $form['#user'])),
815 '!fb_name' => "<fb:name uid=$fbu useyou=false></fb:name>",
816 )),
d143d368
DC
817 '#prefix' => "\n<p>",
818 '#suffix' => "</p>\n",
819 );
3cf45120
DC
820
821 }
fdc2c009 822 elseif (!$fbu && $_fb_app) {
3cf45120 823 // they are not connected to facebook; give option to connect here
3cf45120 824 $form['fb_user'] = array(
fdc2c009
DC
825 '#type' => 'fieldset',
826 '#title' => t('Facebook Application ' . $_fb_app->title),
827 '#collapsed' => false,
828 '#collapsible' => false,
829 );
830
6982d7f1 831 $fb_button = theme('fb_login_button', array('text' => t('Connect with Facebook')));
fdc2c009 832 $form['fb_user']['button'] = array(
3cf45120
DC
833 '#markup' => $fb_button,
834 '#weight' => -1,
835 '#prefix' => "\n<p>",
836 '#suffix' => "</p>\n",
837 );
86e52b97 838 }
72dcacc7
DC
839 }
840 else {
fdc2c009 841 $form['fb_user'] = array(
3cf45120 842 '#type' => 'fieldset',
fdc2c009 843 '#title' => t('Facebook Application ' . $_fb_app->title),
3cf45120
DC
844 '#collapsed' => false,
845 '#collapsible' => false,
846 );
847
fdc2c009 848 $form['fb_user']['message'] = array(
3cf45120
DC
849 '#markup' => t('Local account !username is not connected to facebook.com.',
850 array('!username' => theme('username', array('account' => $form['#user'])),
851 )),
852 '#prefix' => "\n<p>",
853 '#suffix' => "</p>\n",
72dcacc7
DC
854 );
855 }
86e52b97 856 }
3cf45120
DC
857
858 if (isset($form)) {
fdc2c009 859 $form['fb_user']['map']['#tree'] = TRUE;
4847eea8 860 }
3cf45120
DC
861 else {
862 // Could add a facebook connect button or canvas page authorization link.
863 $form['description'] = array(
864 '#markup' => t('This account is not associated with a Facebook Application.'),
865 '#prefix' => '<p>',
866 '#suffix' => '</p>',
867 );
72dcacc7 868 }
3cf45120
DC
869
870 // On user/edit, hide proxied email
871 if (isset($form['account']) && isset($form['account']['mail'])) {
872 $account = $form['#user'];
873 if (isset($account->fb_user_proxied_mail) &&
874 ($form['account']['mail']['#default_value'] == $account->fb_user_proxied_mail)) {
875 unset($form['account']['mail']['#default_value']);
1026ebc4
DC
876 }
877 }
3cf45120
DC
878
879 return $form;
86e52b97
DC
880}
881
86e52b97
DC
882
883/**
d143d368 884 * Helper function to add or update a row in the fb_user table, which maps local uid to facebook ids.
bad80793 885 */
d143d368 886function _fb_user_set_map($account, $fbu) {
3cf45120 887 if ($fbu && $account->uid != 0) {
19092d2f 888
fdc2c009
DC
889 // Delete any pre-existing mapping that might exist for this local uid or fbu.
890 db_query("DELETE FROM {fb_user} WHERE uid=:uid OR fbu=:fbu", array(
891 ':uid' => $account->uid,
892 ':fbu' => $fbu,
893 ));
894
895 // Create the new mapping.
896 db_query("INSERT INTO {fb_user} (uid, fbu) VALUES (:uid, :fbu)", array(
897 ':uid' => $account->uid,
898 ':fbu' => $fbu,
899 ));
19092d2f 900
bad80793 901 if (fb_verbose()) {
d143d368 902 watchdog('fb_user', 'Using fb_user to associate user !user with facebook user id %fbu.',
bad80793
DC
903 array('!user' => l($account->name, 'user/' . $account->uid),
904 '%fbu' => $fbu,
905 ));
906 }
907 }
908}
909
910
911/**
86e52b97 912 * Creates a local Drupal account for the specified facebook user id.
19092d2f 913 *
86e52b97
DC
914 * @param fbu
915 * The facebook user id corresponding to this account.
19092d2f 916 *
fdd0a700 917 * @param edit
3cf45120 918 * An associative array with user configuration. As would be passed to user_save().
86e52b97 919 */
c38a8224 920function fb_user_create_local_user($fb, $fb_app, $fbu,
fdd0a700 921 $edit = array()) {
19092d2f 922
aa2f15ae
DC
923 // Ensure $fbu is a real facebook user id.
924 if (!$fbu || !is_numeric($fbu)) {
925 return;
926 }
19092d2f 927
d143d368 928 $account = fb_user_get_local_user($fbu);
19092d2f 929
186f033e
DC
930 if (!$account) {
931 // Create a new user in our system
19092d2f 932
fdd0a700 933 // Learn some details from facebook.
3907c6ee 934 $infos = fb_users_getInfo(array($fbu), $fb);
fdd0a700 935 $info = $infos[0];
19092d2f 936
fdd0a700
DC
937 // All Drupal users get authenticated user role.
938 $edit['roles'][DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
19092d2f 939
fdd0a700
DC
940 if (isset($edit['name']) && $edit['name']) {
941 $username = $edit['name'];
942 }
943 else {
fa9071e7 944 // Fallback, should never be reached.
fdd0a700
DC
945 $username = "$fbu@facebook";
946 $edit['name'] = $username;
947 }
3cf45120
DC
948 $i = 0;
949
950 // Keep looking until we find a username_n that isn't being used.
951 while (db_query("SELECT 1 FROM {users} WHERE name = :name", array(':name' => $edit['name']))->fetchField(0)) {
fdd0a700
DC
952 $i++;
953 $edit['name'] = $username . '_' . $i;
954 }
303d3e67
DC
955
956 // Give modules a way to suppress new account creation.
957 $edit['fb_user_do_create'] = TRUE;
19092d2f 958
fdd0a700 959 // Allow third-party module to adjust any of our data before we create
86e52b97 960 // the user.
78672778
DC
961 $edit = fb_invoke(FB_USER_OP_PRE_USER, array(
962 'fbu' => $fbu,
963 'fb' => $GLOBALS['_fb'],
964 'fb_app' => $fb_app,
965 'info' => $info,
966 ), $edit, 'fb_user');
303d3e67
DC
967
968 if ($edit['fb_user_do_create']) {
969 unset($edit['fb_user_do_create']); // Don't confuse user_save.
19092d2f 970
303d3e67
DC
971 // Fill in any default that are missing.
972 $defaults = array(
973 'pass' => user_password(),
3cf45120 974 'init' => $fbu . '@facebook', // Supposed to be email, but we may not know it.
303d3e67 975 'status' => 1,
303d3e67 976 );
475821b8
DC
977
978 // Mail available only if user has granted email extended permission.
979 if (isset($info['email'])) {
303d3e67
DC
980 $defaults['mail'] = $info['email'];
981 }
19092d2f 982
303d3e67
DC
983 // Merge defaults
984 $edit = array_merge($defaults, $edit);
19092d2f 985
3cf45120
DC
986 // Confirm username is not taken. FB_USER_OP_PRE_USER may have changed it.
987 if ($uid = db_query("SELECT uid FROM {users} WHERE name = :name", array(':name' => $edit['name']))->fetchField(0)) {
303d3e67 988 // The desired name is taken.
3cf45120 989 watchdog('fb_user', 'Failed to create new user %name. That name is already in the users table.',
fa9071e7 990 array('%name' => $edit['name']),
303d3e67
DC
991 WATCHDOG_ERROR, l(t('view user'), 'user/' . $uid));
992 }
993 else {
994 $account = user_save('', $edit);
19092d2f 995
d143d368 996 _fb_user_set_map($account, $fbu);
19092d2f
DC
997
998 watchdog('fb_user', 'New user: %name %email.',
3cf45120
DC
999 array('%name' => $account->name, '%email' => '<' . $account->mail . '>'),
1000 WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
19092d2f 1001
303d3e67 1002 // Allow third-party modules to act after account creation.
78672778
DC
1003 fb_invoke(FB_USER_OP_POST_USER, array(
1004 'account' => $account,
1005 'fb_app' => $fb_app,
1006 'fb' => $fb,
1007 ), NULL, 'fb_user');
303d3e67 1008 }
aa2f15ae 1009 }
186f033e 1010 }
186f033e
DC
1011 return $account;
1012}
1013
86e52b97
DC
1014/**
1015 * Given an app and facebook user id, return the corresponding local user.
f54b3a2b 1016 *
d143d368
DC
1017 * @param $fbu
1018 * User's id on facebook.com
1019 *
1020 * @param $fb_app
3cf45120 1021 * Historically, this method took the app details into account when mapping user ids. Presently, this parameter is not used.
86e52b97 1022 */
d143d368 1023function fb_user_get_local_user($fbu, $fb_app = NULL) {
346e5a9b
DC
1024 if ($uid = _fb_user_get_uid($fbu, $fb_app)) {
1025 return user_load($uid);
1026 }
1027}
1028
3cf45120 1029// TODO $fb_app is holdover and can be removed in the future
346e5a9b 1030function _fb_user_get_uid($fbu, $fb_app = NULL) {
3cf45120
DC
1031 $result = db_query("SELECT uid FROM {fb_user} WHERE fbu = :fbu", array(
1032 ':fbu' => $fbu,
1033 ))->fetchObject();
1034
1035 if (is_object($result)) {
1036 return $result->uid;
1037 }
1038 else {
1039 return 0;
1040 }
186f033e
DC
1041}
1042
7e1a7e15 1043/**
040ff71e
DC
1044 * Try to determine the local user account by the email address.
1045 */
1046function fb_user_get_local_user_by_email($fbu) {
1047 global $_fb;
1048 if (isset($_fb) && $fbu) {
43256e0a
DC
1049 try {
1050 $info = $_fb->api($fbu);
1051 if (isset($info['email']) &&
1052 ($email = $info['email'])) {
6135c77d 1053 return user_load_by_mail($email);
43256e0a
DC
1054 }
1055 }
1056 catch (Exception $e) {
1057 // This can occur when user logs out of facebook in another window, then returns to our site.
1058 if (fb_verbose()) {
1059 fb_log_exception($e, t('Failed to get facebook user email.'));
1060 }
040ff71e
DC
1061 }
1062 }
1063}
1064
1065/**
7e1a7e15 1066 * Returns local uids of friends of a given user.
19092d2f 1067 *
3cf45120 1068 * Query is relatively efficient for the current user of a canvas page. For
7e1a7e15 1069 * all other users, and non-canvas pages it requires expensive call to
3cf45120 1070 * facebook. That said, our local database query may be inefficient for users
7e1a7e15 1071 * with large numbers of friends, so use with caution.
19092d2f 1072 *
7e1a7e15 1073 * TODO: should this function cache results?
19092d2f 1074 *
7e1a7e15
DC
1075 * Note: the api takes fbu as a parameter, but this usually causes problems
1076 * because facebook restricts users to query only about their own friends.
1077 * For the time being, expect this function to work only on canvas pages to
1078 * find friends of the current user.
f54b3a2b
DC
1079 *
1080 * Only works if the "map accounts" feature is enabled.
7e1a7e15
DC
1081 */
1082function fb_user_get_local_friends($fbu = NULL, $fb_app = NULL) {
1083 if (!isset($fbu)) {
1084 $fbu = fb_facebook_user();
1085 }
1086 $uids = array();
1087 if ($fbus = fb_get_friends($fbu, $fb_app)) {
3cf45120
DC
1088 $result = db_select('fb_user', 'fb')
1089 ->fields('fb', array('uid'))
1090 ->condition('fb.fbu', $fbus, 'IN')
1091 ->execute();
19092d2f 1092
3cf45120 1093 foreach ($result as $data) {
6737bc61
DC
1094 if ($data->uid) {
1095 $uids[] = $data->uid;
1096 }
7e1a7e15
DC
1097 }
1098 }
1099 return $uids;
1100}
1101
3a512626
DC
1102
1103/**
3cf45120 1104 * Given a local user id, find the facebook id. This is for internal use.
3a512626 1105 * Outside modules use fb_get_fbu().
f54b3a2b 1106 *
d143d368 1107 * Only works if the "map accounts" feature is enabled, or the account was created by this module.
3a512626 1108 */
d143d368 1109function _fb_user_get_fbu($uid) {
3cf45120 1110 $cache = &drupal_static(__FUNCTION__); // cache to avoid excess queries.
19092d2f 1111
81e5e23a 1112 if (!isset($cache[$uid])) {
3a512626 1113 // Look up this user in the authmap
3cf45120 1114 $result = db_query("SELECT fbu FROM {fb_user} WHERE uid = :uid", array(
b389f367 1115 ':uid' => $uid,
3cf45120 1116 ))->fetchObject();
f54b3a2b 1117 if ($result) {
3cf45120 1118 $cache[$uid] = $result->fbu;
3a512626 1119 }
b389f367
DC
1120 else {
1121 $cache[$uid] = NULL;
1122 }
3a512626 1123 }
f54b3a2b 1124
b389f367 1125 return $cache[$uid];
3a512626
DC
1126}
1127
d143d368 1128//// token module hooks.
3a512626 1129
4c0bff53
DC
1130function fb_user_token_list($type = 'all') {
1131 if ($type == 'all' || $type == 'fb' || $type == 'fb_app') {
1132 $tokens['fb_app']['fb-app-user-fbu'] = t('Current user\'s Facebook ID');
1133 $tokens['fb_app']['fb-app-user-name'] = t('Current user\'s name on Facebook (TODO)');
1134 $tokens['fb_app']['fb-app-user-name-fbml'] = t('Current user\'s name for display on Facebook profile and canvas pages.');
1135 $tokens['fb_app']['fb-app-profile-url'] = t('Current user\'s Facebook profile URL');
cb150b03 1136 return $tokens;
4c0bff53 1137 }
4c0bff53
DC
1138}
1139
1140function fb_user_token_values($type = 'all', $object = NULL) {
8f2c7e1f 1141 $values = array();
4c0bff53
DC
1142 if ($type == 'fb_app' && $object) {
1143 $fb_app = $object;
1144 global $user;
d143d368 1145 $fbu = _fb_user_get_fbu($user->uid);
4c0bff53
DC
1146 if ($fbu) {
1147 $values['fb-app-user-fbu'] = $fbu;
5d87b01a 1148 //$values['fb-app-user-name'] = ''; // @TODO
3cf45120 1149 $values['fb-app-user-name-fbml'] = '<fb:name uid="' . $fbu . '" />';
19092d2f 1150 $values['fb-app-profile-url'] =
3cf45120 1151 'http://www.facebook.com/profile.php?id=' . $fbu;
4c0bff53
DC
1152 }
1153 }
1154 return $values;
1155}
030e44e8
DC
1156
1157/**
e70105e5
DC
1158 * Learn the user's proxied email address. If fb_user_app.module is enabled,
1159 * it will defer to that module, which queries a local database. If not, ask
1160 * facebook for the data.
1161 *
1162 * @TODO: Facebook may no longer provide proxied_email. Does this work?
030e44e8
DC
1163 */
1164function fb_user_get_proxied_email($fbu, $fb_app) {
1165 $mail = "";
19092d2f 1166
030e44e8
DC
1167 if (function_exists("fb_user_app_get_proxied_email")) {
1168 // Function at fb_user_app module queries fb_use_app table first
1169 $mail = fb_user_app_get_proxied_email($fbu, $fb_app);
1170 }
19092d2f 1171
030e44e8
DC
1172 if (!$mail) {
1173 // Ask facebook for info.
1174 $fb = fb_api_init($fb_app);
dc41c986 1175 $info = fb_users_getInfo(array($fbu), $fb); // TODO deprecated
f6ec9cba 1176 $data = $info[0];
e70105e5
DC
1177 if (isset($data['email'])) {
1178 $mail = $data['email'];
1179 }
1180 elseif (isset($data['proxied_email'])) {
1181 $mail = $data['proxied_email'];
1182 }
030e44e8 1183 }
19092d2f 1184
030e44e8
DC
1185 return $mail;
1186}