You are here

fb_permission.module in Drupal for Facebook 7.3

Same filename and directory in other branches
  1. 6.3 contrib/fb_permission.module
  2. 6.2 contrib/fb_permission.module

Code pertaining to Facebook's extended permissions. see http://wiki.developers.facebook.com/index.php/Extended_permissions

File

contrib/fb_permission.module
View source
<?php

/**
 * @file
 * Code pertaining to Facebook's extended permissions.
 * see http://wiki.developers.facebook.com/index.php/Extended_permissions
 */

/**
 * Implements hook_permission().
 */
function fb_permission_permission() {
  return array(
    'edit own extended permissions' => array(
      'title' => t('Edit own extended Facebook permissions'),
    ),
  );
}
function fb_permission_access_perms($perms) {
  if (is_string($perms)) {
    $perms = explode(',', $perms);
  }
  $count = 0;
  extract(fb_vars());
  if ($fbu) {
    try {
      $api_data = fb_api('me/permissions');
      $granted = $api_data['data'][0];
      foreach ($perms as $perm) {
        if (empty($granted[$perm]) || !$granted[$perm]) {
          $auth_url = url('http://www.facebook.com/dialog/oauth/', array(
            'query' => array(
              'scope' => implode(',', $perms),
              'client_id' => $fb_app->id,
              'redirect_uri' => url(request_path(), array(
                'absolute' => TRUE,
              )),
              'response_type' => 'token',
            ),
            'absolute' => TRUE,
          ));
          drupal_set_message(t('Additional permissions are required. <a href="!url">Grant permissions to continue</a>.', array(
            '!url' => $auth_url,
          )), 'error');
          $GLOBALS['_fb_permission_extra_perms'] = $perms;
          return FALSE;
        }
        else {
          $count++;
        }
      }
    } catch (Exception $e) {
      fb_log_exception($e, __FUNCTION__);
    }
  }
  else {

    // User not connected.
    // Ensure all connect buttons on this page include these perms.
    $GLOBALS['_fb_permission_extra_perms'] = $perms;
    drupal_set_message(t('Facebook Connect is required. !login_button', array(
      '!login_button' => theme('fb_login_button', array(
        'text' => t('Connect to continue'),
      )),
    )), 'error');
  }
  return $count == count($perms);
}

/**
 * Helper function for menu item access check.
 */
function fb_permission_access_own($account, $perm) {
  if (fb_facebook_user()) {
    return $GLOBALS['user']->uid == $account->uid && user_access($perm);
  }
}

// TODO: make this work.
function fb_permission_fb($op, $data, &$return) {
  if ($op == FB_OP_JS && FALSE) {

    // Disabled because the login popup not really working.
    // fb.module is adding javascript to the page footer.
    if (!empty($GLOBALS['_fb_permission_extra_perms'])) {

      // We know from access hook that additional perms are required.
      // Use javascript to ask for them.
      $perms = array();
      drupal_alter('fb_required_perms', $perms);
      $perm_string = json_encode(implode(',', $perms));
      $return['fb_permission_0'] = "debugger;";
      $return['fb_permission'] = "FB.login(function(response){}, {scope:{$perm_string}});";

      // Haven't figured out how to make this dialog work.

      //$return['fb_permission'] = "FB.ui({method:'oauth',scope:$perm_string}, function(response){debugger;});";

      //dpm($return);
    }
  }
}

/**
 * Which permissions can we prompt for?
 *
 * @TODO - update this list and/or make it customizable.
 */
function fb_permission_map($fb) {
  static $perms;

  // http://developers.facebook.com/docs/reference/fql/permissions_info
  $result = fb_fql_query($fb, "SELECT permission_name, header, summary FROM permissions_info WHERE 1", array(
    'access_token' => fb_get_token($fb),
  ));
  if (!isset($perms)) {
    foreach ($result as $data) {
      $perms[$data['permission_name']] = 'Allow %application to ' . strtolower($data['summary'] ? $data['summary'] : 'access ' . $data['header']);
    }
  }
  return $perms;
}

/**
 * Implements hook_fb_required_perms_alter().
 *
 * fb_connect.module can calls this to learn when perms to add to login-button.
 */
function fb_permission_fb_required_perms_alter(&$perms) {
  global $_fb, $_fb_app;
  $fb_app_data = fb_get_app_data($_fb_app);
  if (isset($fb_app_data['fb_permission'])) {
    $fb_permission_data = $fb_app_data['fb_permission'];
    foreach ($fb_permission_data['prompt'] as $key => $value) {
      if ($value) {
        $perms[$key] = $key;
      }
    }
  }
  if (!empty($GLOBALS['_fb_permission_extra_perms'])) {

    // Some page require additional perms, and it makes sense to include those on all connect buttons and links.
    foreach ($GLOBALS['_fb_permission_extra_perms'] as $key) {
      $perms[$key] = $key;
    }
  }
}

/**
 * Implements hook_user_categories().
 */
function fb_permission_user_categories() {
  $items = array();

  // A tab for each application
  foreach (fb_get_all_apps() as $fb_app) {

    // TODO: limit only to apps which can be added to a user's account.
    $items[] = array(
      'name' => $fb_app->label,
      'title' => $fb_app->title,
      'access callback' => 'fb_permission_access_own',
      'access arguments' => array(
        1,
        'edit own extended permissions',
      ),
      'weight' => 2,
    );
  }
  return $items;
}

/**
 * Implements hook_form_FORM_ID_alter()
 */
function fb_permission_form_user_profile_form_alter(&$form, &$form_state) {
  $category = $form['#user_category'];
  $account = $form_state['user'];

  // See if the category corresponds to a facebook app.
  $fb_app = fb_get_app(array(
    'label' => $category,
  ));
  if ($fb_app) {
    $fb = fb_api_init($fb_app);
    $map = fb_permission_map($fb);

    // All known permissions.
    // Show only permissions we've configured for this app.
    $fb_app_data = fb_get_app_data($fb_app);
    $fb_permission_data = $fb_app_data['fb_permission'];
    if (is_array($fb_permission_data['map'])) {
      foreach ($fb_permission_data['map'] as $key => $value) {
        if (!$value) {
          unset($map[$key]);
        }
      }
    }

    /* Should not be necessary to wrap in serverfbml, as prompt-permission is documented as XFBML.
       $form = array(
         'perms' => array(
           '#prefix' => '<fb:serverfbml><script type="text/fbml><fb:fbml>',
           '#suffix' => '</fb:fbml></script></fb:serverfbml>',
         ),
       );
       */
    $t_args = array(
      '%application' => $fb_app->title,
    );
    $weight = 0;
    foreach ($map as $key => $text) {
      $has_perm = FALSE;
      try {
        $has_perm = fb_call_method($fb, 'users.hasAppPermission', array(
          'ext_perm' => $key,
          'uid' => fb_get_fbu($account->uid, $fb_app),
        ));
      } catch (Exception $e) {
        fb_log_exception($e, t('Call to users.hasAppPermission(%key) failed.', array(
          '%key' => $key,
        )));
      }
      if (!$has_perm) {
        if ('facebook has fixed fb:prompt-permission bugs' == FALSE) {

          // Ideally, fb:prompt-permission would work.  But it doesn't.
          $form['perms'][$key] = array(
            '#type' => 'markup',
            '#value' => '<fb:prompt-permission perms="' . $key . '">' . t($text, $t_args) . '</fb:prompt-permission>',
            '#weight' => $weight++,
            '#suffix' => "<br/>\n",
          );
        }
        else {

          // Send user to facebook's extended permission page.
          // This is weak.  Would be better to use javascript or fb:prompt-permission.
          $url = url(current_path(), array(
            'absolute' => TRUE,
          ));
          $form['perms'][$key] = array(
            '#type' => 'markup',
            '#value' => l(t($text, $t_args), "http://www.facebook.com/authorize.php", array(
              'html' => TRUE,
              'query' => array(
                'api_key' => $fb_app->apikey,
                'v' => '1.0',
                'ext_perm' => $key,
                'next' => $url,
                'next_cancel' => $url,
              ),
            )),
            '#prefix' => '<p>',
            '#suffix' => '</p>',
            '#weight' => $weight++,
          );
        }
      }
    }
    $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(
        'html' => TRUE,
      )),
      '#prefix' => '<p>',
      '#suffix' => "</p>\n",
      '#weight' => $weight++,
    );
    unset($form['submit']);
    unset($form['delete']);
  }
}

/**
 * Implements hook_form_alter().
 */
function fb_permission_form_alter(&$form, $state, $id) {

  // Add settings to fb_app form
  if (isset($form['fb_app_data'])) {
    $fb_app = $form['#fb_app'];
    $fb = fb_api_init($fb_app);
    $fb_app_data = fb_get_app_data($fb_app);
    $fb_permission_data = isset($fb_app_data['fb_permission']) ? $fb_app_data['fb_permission'] : NULL;
    $form['fb_app_data']['fb_permission'] = array(
      '#type' => 'fieldset',
      '#title' => t('Facebook extended permissions'),
      '#tree' => TRUE,
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#description' => t('Many permissions on the lists below <em>will not actually work!</em> This list is generated automatically, by querying facebook for all known extended permissions.  Some of these are not supported or available only to privileged developers.<br/>  <strong>Choose only <a target=_blank href=http://developers.facebook.com/docs/authentication/permissions/>permissions your application is actually allowed to use</a>.  If you see an "invalid permission" error, return here and un-select that permission.</strong>'),
    );
    if ($fb_app && $fb_app->id) {
      try {

        // http://developers.facebook.com/docs/reference/fql/permissions_info
        // Apparently, this query required an access token, so this won't work when creating an app, only when editing one.
        $result = fb_fql_query($fb, "SELECT permission_name, header, summary FROM permissions_info WHERE 1", array(
          'access_token' => fb_get_token($fb),
        ));
        foreach ($result as $data) {
          $options[$data['permission_name']] = $data['header'] . ' - ' . $data['summary'] . " ({$data['permission_name']})";
        }

        // First the perms that will be required.
        if (!isset($fb_permission_data['prompt'])) {
          $fb_permission_data['prompt'] = array();
        }
        $form['fb_app_data']['fb_permission']['prompt'] = array(
          '#type' => 'checkboxes',
          '#title' => t('Required extended permissions'),
          '#options' => $options,
          '#default_value' => $fb_permission_data['prompt'],
          '#description' => t('Prompt users when they first authorize the application.  Select only the most important features.'),
        );

        // Next the optional perms.
        if (!isset($fb_permission_data['map'])) {
          $fb_permission_data['map'] = array();
        }
        $form['fb_app_data']['fb_permission']['map'] = array(
          '#type' => 'checkboxes',
          '#title' => t('Optional extended permissions'),
          '#options' => $options,
          '#default_value' => $fb_permission_data['map'],
          '#description' => t('Which extended permissions does this application use?  Users will be able to grant these permissions on their user edit pages.'),
        );
      } catch (Exception $e) {
        if ($fb_app->apikey) {

          // If there's an apikey, this is an unexpected error.
          drupal_set_message(t('Failed to get extended permissions.  %msg', array(
            '%msg' => $e
              ->getMessage(),
          )), 'warning');
        }

        // Drupal will not display this properly in the collapsed fieldset.  Not sure how to fix!
        $form['fb_app_data']['fb_permission']['msg'] = array(
          '#type' => 'markup',
          '#value' => t('Failed to get extended permissions from facebook.   Submit this form, then click "edit" to see extended permission options.'),
        );
      }
    }
    else {

      // App not yet configured.
      $form['fb_app_data']['fb_permission']['#description'] = t('First save this form, then click "edit" to return here and see extended permission options.');
      $form['fb_app_data']['fb_permission']['#collapsed'] = FALSE;
    }
  }
}

Functions