You are here

janrain_capture.module in Janrain Registration 7.3

This module implements authentication endpoints for Janrain Capture.

File

janrain_capture.module
View source
<?php

/**
 * @file
 * This module implements authentication endpoints for Janrain Capture.
 *
 * @see http://www.janrain.com/products/capture
 */

// Defaults for the social sharing settings.
define('JANRAIN_CAPTURE_SHARE_MESSAGE_NODES', t('Shared [node:title] on [site:name].'));
define('JANRAIN_CAPTURE_SHARE_LINKTEXT_NODES', '[node:title]');
define('JANRAIN_CAPTURE_SHARE_TITLE_NODES', '[node:title] | [site:name]');
define('JANRAIN_CAPTURE_SHARE_SUMMARY_NODES', '[node:body]');
define('JANRAIN_CAPTURE_SHARE_MESSAGE_COMMENTS', t('Commented on [site:name].'));
define('JANRAIN_CAPTURE_SHARE_LINKTEXT_COMMENTS', '[comment:subject]');
define('JANRAIN_CAPTURE_SHARE_TITLE_COMMENTS', '[node:title] | [site:name]');
define('JANRAIN_CAPTURE_SHARE_SUMMARY_COMMENTS', '[comment:body]');

// Capture version constants
define('JANRAIN_CAPTURE_VERSION_LEGACY', '1.0');
define('JANRAIN_CAPTURE_VERSION_WIDGET', '2.0');
define('JANRAIN_CAPTURE_VERSION_DEFAULT', JANRAIN_CAPTURE_VERSION_WIDGET);

/**
 * Implements hook_page_build().
 */
function janrain_capture_page_build(&$page) {

  // Check to see if settings are configured before proceeding
  if (!janrain_capture_configured()) {
    drupal_set_message(t('Janrain Capture: Capture cannot start because one or more settings is not properly configured.'), 'error');
    return;
  }

  // Initialise Janrain Capture's Fancybox functions
  module_load_include('inc', 'janrain_capture', 'includes/janrain_capture.fancybox');
  janrain_capture_fancybox_init();

  // Get the selected version of Capture
  $janrain_capture_ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);

  // Set up the settings array with values from the admin page
  $profile_sync_options = array(
    'absolute' => TRUE,
  );
  if ($_GET['q']) {
    $profile_sync_options['query'] = array(
      'destination' => $_GET['q'],
    );
  }
  $settings = array(
    'janrainCapture' => array(
      'profile_sync_url' => url('janrain_capture/profile_sync', $profile_sync_options),
      'token_expired_url' => url('janrain_capture/token_expired/' . drupal_get_token('janrain_capture_token_expired')),
      'logout_url' => url('user/logout', array(
        'absolute' => TRUE,
        'real_logout' => TRUE,
      )),
      'enforce' => variable_get('janrain_capture_enforce', FALSE),
      'ver' => $janrain_capture_ver,
      // janrain.settings.capture.redirectUri may be changed by JS to include
      // a destination param, depending on where the user clicks to start the
      // signin flow. Save the original redirect URL in case we need to roll
      // back.
      'originalRedirectUri' => url('janrain_capture/oauth', array(
        'absolute' => TRUE,
      )),
    ),
  );

  // Set up the scripts array
  $scripts = array(
    'file' => array(),
    'inline' => array(),
    'external' => array(),
  );
  $scripts['file'][] = drupal_get_path('module', 'janrain_capture') . '/janrain_capture.js';
  if ($janrain_capture_ver == JANRAIN_CAPTURE_VERSION_LEGACY) {
    module_load_include('inc', 'janrain_capture', 'includes/janrain_capture.legacy');
    janrain_capture_legacy_add_settings($settings);
    janrain_capture_legacy_add_scripts($scripts);
  }
  else {
    module_load_include('inc', 'janrain_capture', 'includes/janrain_capture.widget');
    janrain_capture_widget_add_settings($settings);
    janrain_capture_widget_add_scripts($scripts);
    $screens = janrain_capture_widget_signin_screens();
    drupal_add_js($screens['js'], array(
      'type' => 'inline',
      'every_page' => TRUE,
      'weight' => 4,
      'preprocess' => FALSE,
    ));
    $page['page_bottom']['janrainCaptureSigninScreen'] = array(
      '#weight' => 0,
      '#markup' => $screens['html'],
    );
  }

  /*$capture_client_id = !empty($janrain_capture_main['capture_client_id'])
    ? $janrain_capture_main['capture_client_id'] : '';*/

  // Add the jQuery BBQ plugin to handle destination redirects.
  drupal_add_library('system', 'jquery.bbq', TRUE);
}

/**
 * Implements hook_menu().
 */
function janrain_capture_menu() {
  $items['janrain_capture/oauth'] = array(
    'title' => 'Capture Oauth Receiver',
    'page callback' => 'janrain_capture_oauth',
    'access callback' => 'janrain_capture_oauth_access_callback',
    'type' => MENU_CALLBACK,
    'file' => 'includes/janrain_capture.endpoints.inc',
  );
  $items['janrain_capture/signin_redirect'] = array(
    'title' => 'Capture redirect page',
    'page callback' => 'janrain_capture_signin_redirect',
    'access callback' => 'user_is_logged_in',
    'type' => MENU_CALLBACK,
    'file' => 'includes/janrain_capture.endpoints.inc',
  );
  $items['janrain_capture/profile'] = array(
    'title' => 'Capture Profile',
    'page callback' => 'janrain_capture_profile',
    'access callback' => 'user_is_logged_in',
    'type' => MENU_CALLBACK,
    'file' => 'includes/janrain_capture.endpoints.inc',
  );
  $items['janrain_capture/public_profile'] = array(
    'title' => 'Public Profile',
    'page callback' => 'janrain_capture_public_profile',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'file' => 'includes/janrain_capture.endpoints.inc',
  );
  $items['janrain_capture/profile_sync'] = array(
    'title' => 'Capture Profile Receiver',
    'page callback' => 'janrain_capture_profile_sync',
    'access callback' => 'user_is_logged_in',
    'type' => MENU_CALLBACK,
    'file' => 'includes/janrain_capture.endpoints.inc',
  );
  $items['janrain_capture/resend_verification_email'] = array(
    'title' => 'Capture Verification Email Resent',
    'page callback' => 'janrain_capture_resend_verification_email',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'file' => 'includes/janrain_capture.endpoints.inc',
  );
  $items['janrain_capture/token_expired/%'] = array(
    'title' => 'Capture Token Expired',
    'page callback' => 'janrain_capture_token_expired',
    'access callback' => 'janrain_capture_token_expired_access',
    'access arguments' => array(
      2,
    ),
    'type' => MENU_CALLBACK,
    'file' => 'includes/janrain_capture.endpoints.inc',
  );
  $janrain_capture_ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);
  $ver = !empty($janrain_capture_ver) ? $janrain_capture_ver : JANRAIN_CAPTURE_VERSION_LEGACY;
  $ver = substr($ver, 0, 1);
  if ($ver == "1") {
    $ver = '';
  }

  // Create a no frills logout URL if SSO is enabled.
  $conf = $janrain_capture_ver == JANRAIN_CAPTURE_VERSION_LEGACY ? variable_get('janrain_capture_optional', array()) : variable_get('janrain_capture_federate2', array());
  if ($janrain_capture_ver == JANRAIN_CAPTURE_VERSION_LEGACY && !empty($conf['capture_sso_address']) || isset($conf['capture_sso_enabled'])) {
    $items['janrain_capture/simple_logout'] = array(
      'title' => 'Plain logout page',
      'page callback' => 'janrain_capture_simple_logout_page',
      'access callback' => 'user_is_logged_in',
      'type' => MENU_CALLBACK,
      'file' => "janrain_capture.pages.inc",
    );
  }
  return $items;
}

/**
 * Implements hook_menu_alter().
 */
function janrain_capture_menu_alter(&$items) {
  if (variable_get('janrain_capture_enforce', FALSE)) {

    // Make capture the only way to log in to the site.
    foreach (array(
      'user/login',
      'user/register',
    ) as $key) {
      $items[$key]['page callback'] = 'janrain_capture_signin';
      unset($items[$key]['page arguments']);
      unset($items[$key]['file']);

      // Override to be callbacks instead of tabs.
      $items[$key]['type'] = MENU_CALLBACK;
    }

    // Let logged in users use the shortcut to their profile.
    $items['user']['access callback'] = 'user_is_logged_in';

    // All password reset requests should go via Capture.
    $items['user/password']['access callback'] = FALSE;
  }
}

/**
 * Access callback for the Capture Oauth Receiver endpoint.
 */
function janrain_capture_oauth_access_callback() {

  // This path is for anonymous users only, unless they are trying to confirm an
  // email address.
  $url_type = isset($_REQUEST['url_type']) ? $_REQUEST['url_type'] : NULL;
  if ($url_type == 'verify' || isset($_REQUEST['verification_code']) || user_is_anonymous()) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Access callback for janrain_capture_token_expired().
 */
function janrain_capture_token_expired_access($token) {

  // This path is for authenticated users and is protected from CSRF with a token.
  return user_is_logged_in() && $token === drupal_get_token('janrain_capture_token_expired');
}

/**
 * Implements hook_token_info().
 * Provide a token for:
 * - SSO URL
 *  ` the href attribute of the sign-in link. Allows
 *    use of the URL in Content (where tokens are available)
 */
function janrain_capture_token_info() {
  $types['janrain_capture'] = array(
    'name' => t("Janrain Capture Tokens"),
    'description' => t("Tokens for Janrain Capture."),
  );

  // Janrain Capture specific tokens.
  $janrain_capture['sso_url'] = array(
    'name' => t("Janrain SSO URL"),
    'description' => t("A link for Social Sign-On using Janrain Capture"),
  );
  return array(
    'types' => $types,
    'tokens' => array(
      'janrain_capture' => $janrain_capture,
    ),
  );
}

/**
 * Implements hook_tokens().
 */
function janrain_capture_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $replacements = array();
  if ($type == 'janrain_capture') {
    foreach ($tokens as $name => $original) {
      switch ($name) {
        case 'sso_url':
          $replacements[$original] = janrain_capture_url();
          break;
      }
    }
  }
  return $replacements;
}

/**
 * Helper function to determine if a user is associated with a Capture account.
 */
function janrain_capture_mapping_exists($uid) {

  // Check to see if this user is already mapped to a Capture uuid.
  return (bool) db_query("SELECT 1 FROM {authmap} WHERE module = 'janrain_capture' AND uid = :uid", array(
    ':uid' => $uid,
  ))
    ->fetchField();
}

/**
 * Checks whether the module has been configured.
 */
function janrain_capture_configured() {
  $capture_version = variable_get('janrain_capture_ver');
  if ($capture_version == JANRAIN_CAPTURE_VERSION_LEGACY) {
    $janrain_capture_main = variable_get('janrain_capture_main', array());
    if (isset($janrain_capture_main['capture_address']) && !empty($janrain_capture_main['capture_address']) && (isset($janrain_capture_main['capture_client_id']) && !empty($janrain_capture_main['capture_client_id'])) && (isset($janrain_capture_main['capture_client_secret']) && !empty($janrain_capture_main['capture_client_secret']))) {
      return TRUE;
    }
    else {
      return FALSE;
    }
  }
  elseif ($capture_version == JANRAIN_CAPTURE_VERSION_WIDGET) {
    $janrain_capture_main = variable_get('janrain_capture_main2', array());
    if (isset($janrain_capture_main['capture_address']) && !empty($janrain_capture_main['capture_address']) && (isset($janrain_capture_main['capture_client_id']) && !empty($janrain_capture_main['capture_client_id'])) && (isset($janrain_capture_main['capture_app_id']) && !empty($janrain_capture_main['capture_app_id'])) && (isset($janrain_capture_main['capture_client_secret']) && !empty($janrain_capture_main['capture_client_secret']))) {
      return TRUE;
    }
    else {
      return FALSE;
    }
  }
  else {
    return FALSE;
  }
}

/**
 * Returns the full URL of a specified CaptureUI screen
 *
 * @param array $options
 *   An associative array of options to use in constructing the URL
 *
 * @return string
 *   The full URL string of the Capture URL screen being requested
 */
function janrain_capture_url($options = NULL) {

  //TODO: set new
  $ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);
  if ($ver == JANRAIN_CAPTURE_VERSION_LEGACY) {
    $janrain_capture_main = variable_get('janrain_capture_main', array());
    $janrain_capture_optional = variable_get('janrain_capture_optional', array());
    if (!empty($janrain_capture_main['capture_address']) && !empty($janrain_capture_main['capture_client_id'])) {
      $required = array(
        'redirect_uri' => url('janrain_capture/oauth', array(
          'absolute' => TRUE,
        )),
        'xd_receiver' => url(NULL, array(
          'absolute' => TRUE,
        )) . drupal_get_path('module', 'janrain_capture') . '/xdcomm.html',
        'client_id' => $janrain_capture_main['capture_client_id'],
      );
      if (!$options || strpos($options['action'], 'profile') !== 0) {
        if (!$options) {
          $options = array();
        }
        $defaults = array(
          'action' => 'signin',
          'recover_password_callback' => 'Drupal.janrainCapture.closeRecoverPassword',
          'response_type' => 'code',
        );
      }
      else {
        $defaults = array(
          'callback' => 'Drupal.janrainCapture.closeProfileEditor',
        );
      }
      $args = array_merge($required, $defaults, $options);
      $action = $args['action'];
      unset($args['action']);
      $url = 'https://' . (!empty($janrain_capture_optional['captureui_address']) ? $janrain_capture_optional['captureui_address'] : $janrain_capture_main['capture_address']) . '/oauth/' . $action . '?' . http_build_query($args, '', '&');
    }
    else {
      return '';
    }
  }
  else {
    return '';
  }
  return $url;
}

/**
 * Implements hook_url_outbound_alter().
 */
function janrain_capture_url_outbound_alter(&$path, &$options, $original_path) {

  // Override logout link
  switch ($path) {
    case 'user/logout':
      $ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);
      if ($ver == JANRAIN_CAPTURE_VERSION_LEGACY) {
        $conf = variable_get('janrain_capture_optional', array());
        if ((!isset($conf['capture_sso_address']) || trim($conf['capture_sso_address'] == '')) && (!isset($conf['capture_sso_enabled']) || !$conf['capture_sso_enabled']) && !isset($options['real_logout'])) {
          $path = 'javascript:CAPTURE.logout()';
          $options['external'] = TRUE;
        }
      }
      break;
  }
}

/**
 * Menu callback to override user/login and user/register.
 */
function janrain_capture_signin() {
  $url = janrain_capture_url();
  if (isset($_GET['destination'])) {
    $destination = $_GET['destination'];

    // TODO: we have to unset this here because otherwise drupal_goto will just
    // go to the destination, but how can we tell Janrain Capture to redirect to
    // this page afterwards?
    // ??? drupal_get_destination();
    unset($_GET['destination']);
  }
  drupal_goto($url);
}

/**
 * Implements hook_block_view_MODULE_DELTA_alter().
 */
function janrain_capture_block_view_user_login_alter(&$data, $block) {
  if (!janrain_capture_configured()) {
    return;
  }
  if (variable_get('janrain_capture_enforce', FALSE)) {

    // Change the user login block so that instead of presenting a login form it
    // presents the contents of the Janrain Capture block, i.e. a link to login
    // via Capture or, if already logged in, a link to the profile edit screen.
    global $user;
    if (!$user->uid) {
      $data['content'] = janrain_capture_block_content();
    }
  }
}

/**
 * Returns a render array for the 'Register / Sign in' link for Janrain Capture.
 */
function janrain_capture_signin_link() {
  $ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);
  if ($ver == JANRAIN_CAPTURE_VERSION_LEGACY) {
    $link = array(
      '#type' => 'link',
      '#title' => t('Register / Sign in'),
      '#href' => janrain_capture_url(),
      '#attributes' => array(
        'class' => array(
          'janrain_capture_anchor',
          'janrain_capture_signin',
        ),
      ),
    );
  }
  else {
    $link = array(
      '#type' => 'link',
      '#title' => t('Register / Sign in'),
      '#href' => janrain_capture_url(),
      '#attributes' => array(
        'class' => array(
          'capture_modal_open',
        ),
      ),
    );
  }
  return $link;
}

/**
 * Returns a render array for the 'Edit profile' link for Janrain Capture.
 */
function janrain_capture_profile_link() {
  global $base_url;
  $link = array(
    '#type' => 'link',
    '#title' => t('View / Edit Profile'),
    '#href' => 'janrain_capture/profile',
    '#options' => array(
      'absolute' => TRUE,
    ),
    '#attributes' => array(
      'class' => array(
        'janrain_capture_anchor',
      ),
    ),
  );
  return $link;
}

/**
 * Generates a 'Logout' link for Janrain Capture.
 */
function janrain_capture_render_logout_link() {
  $ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);
  if ($ver == JANRAIN_CAPTURE_VERSION_LEGACY) {
    $janrain_capture_optional = variable_get('janrain_capture_optional', array());
  }
  else {
    $janrain_capture_optional = variable_get('janrain_capture_federate2', array());
  }

  // TODO: Actually change the logout link
  if ($ver == JANRAIN_CAPTURE_VERSION_WIDGET && $janrain_capture_optional['capture_sso_enabled'] == 1) {
    $link = '<a href="javascript:CAPTURE.logout();">' . t('Log out') . '</a>';
  }
  elseif ($ver == JANRAIN_CAPTURE_VERSION_LEGACY && $janrain_capture_optional['capture_sso_address'] != '') {
    $link = '<a href="javascript:CAPTURE.logout()">' . t('Log out') . '</a>';
  }
  else {
    $link = l(t('Log out'), 'user/logout');
  }
  return $link;
}

/**
 * Provides the content for the Janrain Capture block, and is also used to
 * replace the user login block content if the "enforce" setting is on.
 */
function janrain_capture_block_content() {
  global $user;
  $items = array();

  // Provide either a "Register / Sign in" link or a "View Profile" link
  // depending on whether the user is logged in.
  $link_type = $user->uid ? 'profile' : 'signin';
  $link_func = sprintf('janrain_capture_%s_link', $link_type);
  $link = $link_func();
  $items[] = drupal_render($link);

  // Add a logout link for logged in users.
  if ($user->uid) {
    $items[] = janrain_capture_render_logout_link();
  }
  return theme('item_list', array(
    'items' => $items,
  ));
}

/**
 * Modifies the user account with values from the Janrain Capture profile array.
 *
 * Invokes a hook to allow other modules to modify the account as well.
 *
 * @param $account
 *   The account object to modify with values from the Janrain Capture profile
 * @param array $profile
 *   The Janrain Capture profile array.
 */
function janrain_capture_sync_account($account, $profile) {
  $ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);
  $janrain_capture_fields = $ver == JANRAIN_CAPTURE_VERSION_LEGACY ? variable_get('janrain_capture_fields', array()) : variable_get('janrain_capture_fields2', array());
  if (!isset($janrain_capture_fields['capture_no_email']) || !$janrain_capture_fields['capture_no_email']) {
    $account->mail = $profile['email'];
  }

  // Set the profile email address as the default username - this can be overridden
  // either by implementing the janrain_capture_profile_sync hook or using the mapping
  // submodule.
  $account->name = $profile['email'];

  // Set the uuid field value from the Capture uuid. Hardcoding LANGUAGE_NONE here
  // should be ok as the field is not translatable.
  $account->field_janrain_capture_uuid[LANGUAGE_NONE][0]['value'] = $profile['uuid'];

  // Map the profile pic if configured to do so. This requires special handling.
  if (isset($janrain_capture_fields['capture_map_profile_pic']) && $janrain_capture_fields['capture_map_profile_pic']) {
    if (!empty($profile['photos'])) {
      $preferred = isset($janrain_capture_fields['capture_preferred_photo_variant']) ? $janrain_capture_fields['capture_preferred_photo_variant'] : 'small';
      $found = NULL;
      foreach ($profile['photos'] as $variant) {
        if ($variant['type'] == $preferred) {
          $found = $variant;
          break;
        }
        else {
          if ($variant['type'] == 'other') {
            $found = $variant;
          }
        }
      }
      if ($found != NULL) {
        _janrain_capture_update_picture($account, $found);
      }
      else {
        watchdog('janrain_capture', 'No suitable user picture found in the Capture profile', array(), WATCHDOG_WARNING);
      }
    }
    elseif (!empty($account->picture)) {

      // We have a local picture, but picture was removed on server. Delete!
      $account->picture = new stdClass();
      db_delete('janrain_capture_photos')
        ->condition('uid', $account->uid)
        ->execute();
    }
  }
  module_invoke_all('janrain_capture_profile_sync', $account, $profile);
}

/**
 * Helper function for updating a user picture.
 */
function _janrain_capture_update_picture($account, $variant) {
  $args = array(
    ':uid' => $account->uid,
    ':uri' => $variant['value'],
  );
  if (empty($account->picture) || !db_query('SELECT uid FROM {janrain_capture_photos} WHERE uid = :uid and uri = :uri', $args)
    ->fetchField()) {

    // Either first or updated user profile image. Download remote image,
    // save locally and set user picture to this image.
    $image_response = drupal_http_request($variant['value']);
    if ($image_response->code == 200 && !empty($image_response->data)) {
      $image_file = file_save_data($image_response->data);
      if (!empty($image_file)) {

        // Make the file non-permanent, so we can get it moved and
        // renamed as a proper user picture on the righ path. (which
        // happens inside user_save()).
        $image_file->status = 0;
        $image_file = file_save($image_file);
        $account->picture = $image_file;

        // Keep track of the remote image URI so we only download it once.
        db_merge('janrain_capture_photos')
          ->key(array(
          'uid' => $account->uid,
        ))
          ->fields(array(
          'uid' => $account->uid,
          'uri' => $variant['value'],
        ))
          ->execute();
      }
    }
  }
}

/**
 * Adds share widget JS to the page.
 */
function janrain_capture_share_js() {
  static $added = FALSE;

  // Only attempt to add javascript once
  if ($added == TRUE) {
    return FALSE;
  }
  $conf2 = variable_get('janrain_capture_main2', array());
  if (!isset($conf2['engage_address'])) {
    watchdog('janrain_capture', 'janrain_capture_share_js: no Engage URL has been configured; social share won\'t work', array(), WATCHDOG_ERROR);
    return FALSE;
  }
  else {
    $url = $conf2['engage_address'];
    $app_alias = str_replace(array(
      'https://',
      'http://',
      '.rpxnow.com',
    ), '', $url);
  }
  $ver = variable_get('janrain_capture_ver', JANRAIN_CAPTURE_VERSION_DEFAULT);

  // Add Social Sharing related code.
  $output = '<!-- Begin Janrain Engage Social Sharing. Visit http://www.rpxnow.com/ -->';
  if ($ver == JANRAIN_CAPTURE_VERSION_LEGACY) {
    $output .= "\n(function() {\nif (typeof window.janrain !== 'object') window.janrain = {};\nif (typeof window.janrain.settings !== 'object') window.janrain.settings = {};\nif (typeof window.janrain.settings.share !== 'object') window.janrain.settings.share = {};\nif (typeof window.janrain.settings.packages !== 'object') janrain.settings.packages = [];\njanrain.settings.packages.push('share');\n\njanrain.settings.share.message = '';\n\nfunction isReady() { janrain.ready = true; };\nif (document.addEventListener) { document.addEventListener('DOMContentLoaded', isReady, false); }\nelse { window.attachEvent('onload', isReady); }\nvar e = document.createElement('script');\ne.type = 'text/javascript';\ne.id = 'janrainWidgets';\nif (document.location.protocol === 'https:') { e.src = 'https://rpxnow.com/js/lib/{$app_alias}/widget.js'; }\nelse { e.src = 'http://widget-cdn.rpxnow.com/js/lib/{$app_alias}/widget.js'; }\nvar s = document.getElementsByTagName('script')[0];\ns.parentNode.insertBefore(e, s);\n})();\n";
  }
  $output .= "\n//janrain.settings.share = {providers : [\"facebook\",\"twitter\"]};\nfunction janrainCaptureSetShare(url, title, desc, msg, provider) {\n  janrain.engage.share.setUrl(url);\n  janrain.engage.share.setTitle(title);\n  janrain.engage.share.setDescription(desc);\n  janrain.engage.share.setMessage(msg);\n  janrain.engage.share.showProvider(provider);\n  janrain.engage.share.show();\n}";
  $output .= '<!-- End Janrain Engage Social Sharing -->';
  drupal_add_js($output, array(
    'type' => 'inline',
    'scope' => 'header',
    'preprocess' => FALSE,
  ));
  $added = TRUE;
}

/*
 * Implements hook_form_FORM_ID_alter().
 *
 * Adds social sharing settings to the content type edit form.
 */
function janrain_capture_form_node_type_form_alter(&$form, &$form_state) {
  $type = $form['#node_type']->type;
  $group = 'janrain_capture_share';
  $form[$group] = array(
    '#type' => 'fieldset',
    '#title' => t('Janrain Social Share'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#weight' => 25,
    '#group' => 'additional_settings',
  );
  $form[$group]['content_title'] = array(
    '#type' => 'markup',
    '#title' => t('Content title'),
    '#markup' => t('<strong>CONTENT</strong>'),
  );
  $sgroup = 'share_button';
  $form[$group][$sgroup] = array(
    '#type' => 'fieldset',
    '#title' => t('Share button settings'),
    '#description' => t('Display the content "share" button in the following locations for this content type:'),
  );
  $name = $group . '_teasers';
  $vname = $name . '_' . $type;
  $form[$group][$sgroup][$name] = array(
    '#type' => 'checkbox',
    '#title' => t('Teasers'),
    '#default_value' => variable_get($vname, 0),
  );
  $name = $group . '_nodelink';
  $vname = $name . '_' . $type;
  $form[$group][$sgroup][$name] = array(
    '#type' => 'checkbox',
    '#title' => t('Links area'),
    '#default_value' => variable_get($vname, 0),
  );
  $name = $group . '_nodecont';
  $vname = $name . '_' . $type;
  $form[$group][$sgroup][$name] = array(
    '#type' => 'checkbox',
    '#title' => t('Content region'),
    '#default_value' => variable_get($vname, 0),
  );
  $name = $group . '_weight';
  $vname = $name . '_' . $type;
  $form[$group][$sgroup][$name] = array(
    '#type' => 'weight',
    '#title' => t('Weight for "share" button'),
    '#title_display' => 'invisible',
    '#default_value' => variable_get($vname, 40),
    '#delta' => 50,
    '#description' => t('Weight value for the "share" button displayed in content region.'),
  );
  $form[$group]['comments_title'] = array(
    '#type' => 'markup',
    '#title' => t('Comments title'),
    '#markup' => t('<strong>COMMENTS</strong>'),
  );
  $sgroup = 'comments';
  $form[$group][$sgroup] = array(
    '#type' => 'fieldset',
    '#title' => t('Comments settings'),
  );
  $name = $group . '_popup';
  $vname = $name . '_' . $type;
  $form[$group][$sgroup][$name] = array(
    '#type' => 'checkbox',
    '#title' => t('Automatically launch social sharing widget after comment submission'),
    '#default_value' => variable_get($vname, 0),
  );
  $name = $group . '_attach';
  $vname = $name . '_' . $type;
  $form[$group][$sgroup][$name] = array(
    '#type' => 'checkbox',
    '#title' => t('Attach "share" link to comments'),
    '#default_value' => variable_get($vname, 0),
  );
}

/**
 * Implements hook_comment_view_alter().
 *
 * Add Engage social sharing to comment links and, if a comment's just been
 * added, pop-up the social widget.
 *
 * @see janrain_capture_comment_insert()
 */
function janrain_capture_comment_view_alter(&$build) {
  $conf = variable_get('janrain_capture_share', array());

  // Should we bother?
  if ($build['#view_mode'] != 'full' || !isset($conf['enabled']) || !$conf['enabled'] || isset($build['#comment']->in_preview)) {
    return;
  }
  global $user;
  $comment = $build['#comment'];
  $node = node_load($comment->nid);
  $attach_share = variable_get('janrain_capture_share_attach_' . $node->type, FALSE);

  // We should automatically pop up the Social Sharing widget if this is the
  // comment that has just been added.
  $popup_social = variable_get('janrain_capture_share_popup_' . $node->type, FALSE) && isset($_SESSION['janrain_capture_comment_social_cid']) && $comment->cid == $_SESSION['janrain_capture_comment_social_cid'];
  if (!$attach_share && !$popup_social) {
    return;
  }
  $url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . request_uri() . '#comment-' . $comment->cid;

  // Prepare arguments for Social Sharing
  $args = array();
  foreach (array(
    'message',
    'title',
    'summary',
  ) as $arg) {
    $args[$arg] = $conf['comments']['default_' . $arg];

    // We disable sanitize for token_replace() to prevent it from encoding
    // apostrophes and such.
    $args[$arg] = filter_xss(token_replace($args[$arg], array(
      'node' => $node,
      'user' => $user,
      'comment' => $comment,
    ), array(
      'clear' => TRUE,
      'sanitize' => FALSE,
    )));
  }
  $summary = addslashes(text_summary(strip_tags($args['summary']), NULL, 150) . '...');

  // Attach a "share" link to this comment.
  $attributes = array(
    'class' => array(
      'janrain-capture-link-social',
    ),
    'id' => 'janrain-capture-link-social-comment-' . $comment->cid,
    'onclick' => "janrainCaptureSetShare('{$url}','{$args['title']}','{$args['message']}','{$summary}','facebook'); return false;",
  );
  $build['links']['comment']['#links']['comment-janrain-capture-share'] = array(
    'title' => t('share'),
    'href' => $url,
    'attributes' => $attributes,
  );

  // output the js
  janrain_capture_share_js();

  // Pass arguments for the social widget that will be invoked for this
  // comment immediately upon page reload.
  if ($popup_social) {

    // FIXME: this is prone to race conditions; should fire when the widget
    // finishes loading instead.
    $output = "setTimeout(function(){janrainCaptureSetShare('{$url}','{$args['message']}','{$args['title']}','{$summary}','facebook')},600);";
    drupal_add_js($output, array(
      'type' => 'inline',
      'scope' => 'footer',
      'preprocess' => FALSE,
    ));
    unset($_SESSION['janrain_capture_comment_social_cid']);
  }
}

/**
 * Implements hook_comment_insert().
 *
 * @see janrain_capture_comment_view_alter()
 */
function janrain_capture_comment_insert($comment) {
  $_SESSION['janrain_capture_comment_social_cid'] = $comment->cid;
}

/**
 * Implements hook_node_view().
 *
 * Attaches the "share" button.
 */
function janrain_capture_node_view($node, $view_mode, $langcode) {
  $conf = variable_get('janrain_capture_share', array());
  if (!isset($conf['enabled']) || !$conf['enabled']) {
    return;
  }

  // Should we attach to teasers?
  if ($view_mode == 'teaser' && !variable_get('janrain_capture_share_teasers_' . $node->type, FALSE)) {
    return;
  }

  // Attach to node links section.
  if (variable_get('janrain_capture_share_nodelink_' . $node->type, FALSE)) {
    $node->content['links']['#links']['janrain_capture_share_button'] = array(
      'title' => _janrain_capture_share_button($node),
      'html' => TRUE,
    );
  }

  // Attach to node contents section.
  if (variable_get('janrain_capture_share_nodecont_' . $node->type, FALSE)) {
    $node->content['janrain_capture_share_button'] = array(
      '#markup' => _janrain_capture_share_button($node),
      '#weight' => variable_get('janrain_capture_share_weight_' . $node->type, 40),
    );
  }
}

/**
 * Returns HTML markup for the social share button.
 */
function _janrain_capture_share_button($node) {
  global $user;
  $conf = variable_get('janrain_capture_share', array());

  // Prepare arguments for the share widget.
  $args = array();
  foreach (array(
    'message',
    'title',
    'summary',
  ) as $arg) {
    $args[$arg] = $conf['nodes']['default_' . $arg];

    // We disable sanitize for token_replace() to prevent it from encoding
    // apostrophes and such.
    $args[$arg] = filter_xss(token_replace($args[$arg], array(
      'node' => $node,
      'user' => $user,
    ), array(
      'clear' => TRUE,
      'sanitize' => FALSE,
    )));
  }
  $args['summary'] = addslashes(text_summary(strip_tags($args['summary']), NULL, 128) . '...');
  $args['url'] = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . request_uri();
  janrain_capture_share_js();
  return theme('janrain_capture_share_button', array(
    'args' => $args,
    'node' => $node,
  ));
}

/**
 * Returns markup for the "share" button.
 */
function theme_janrain_capture_share_button($variables) {
  $node = $variables['node'];
  $args = $variables['args'];
  $button_style = array(
    'janrain-share-container',
  );
  $text = isset($args['text']) ? $args['text'] : 'Share on';
  $attributes = array(
    'class' => $button_style,
    'id' => 'janrain-capture-link-social-node-' . $node->nid,
  );
  return '<div' . drupal_attributes($attributes) . '><span class="janrain-share-text">' . $text . '</span>' . theme('janrain_capture_share_icons', array(
    'args' => $args,
    'node' => $node,
  )) . '</div>';
}

/**
 * Returns markup for enabled social share provider icons.
 */
function theme_janrain_capture_share_icons($variables) {
  $args = $variables['args'];
  $node = $variables['node'];
  $conf = variable_get('janrain_capture_share', array());
  $providers = $conf['nodes']['providers'];
  $icons = '';
  foreach ($providers as $provider) {
    $icons .= theme('janrain_capture_icon', array(
      'args' => $args,
      'provider' => $provider,
      'size' => 'small',
      'node' => $node,
    ));
  }
  return $icons;
}

/**
 * Returns markup for a specific provider icon.
 */
function theme_janrain_capture_icon($variables) {
  $provider = $variables['provider'];
  if (isset($variables['node'])) {
    $nid = $variables['node']->nid;
  }
  $size = $variables['size'] == 'small' ? '16' : '32';
  $style = array(
    'janrain-provider-icon-' . $size,
    'janrain-provider-icon-' . $provider,
    'janrain-capture-link-social',
  );
  if ($variables['style']) {
    $style[] = $variables['style'];
  }
  if (isset($variables['args'])) {
    $args = $variables['args'];
    return '<span' . drupal_attributes(array(
      'class' => $style,
      'id' => 'janrain-capture-link-social-node-' . $nid,
      'rel' => $provider,
      'onclick' => "janrainCaptureSetShare('{$args['url']}','{$args['title']}','{$args['message']}','{$args['summary']}',this.getAttribute('rel')); return false;",
    )) . '></span>';
  }
  else {
    return '<div' . drupal_attributes(array(
      'class' => $style,
      'id' => 'janrain-capture-link-social-node-' . $nid,
    )) . '></div>';
  }
}

/**
 * Implements hook_theme().
 */
function janrain_capture_theme() {
  return array(
    'janrain_capture_icon' => array(
      'variables' => array(
        'provider' => NULL,
        'size' => 'small',
        'style' => NULL,
      ),
    ),
    'janrain_capture_share_button' => array(
      'node' => NULL,
    ),
    'janrain_capture_share_icons' => array(),
  );
}

/*
 * Helper: retrieve and return a file from the capture screens folder.
 *
 * Return empty string on failure to retrieve.
 */
function _janrain_capture_get_screen($fname) {
  if (module_exists('janrain_capture_screens')) {
    if (!in_array($fname, _janrain_capture_get_screens())) {
      return '';
    }
    if ($screen_file = _janrain_capture_get_screen_file($fname)) {
      return file_get_contents($screen_file);
    }
    return '';
  }
  else {
    $url = variable_get('janrain_capture_screens_folder', 'file:///sites/all/themes/janrain-capture-screens/');
    if (!isset($url)) {
      watchdog('janrain_capture', 'No Capture screens folder specified in the Janrain Capture settings.', array(), WATCHDOG_WARNING);
      return '';
    }
    if (strpos($url, 'file:///', 0) === 0) {
      global $base_path;
      $path = DRUPAL_ROOT . str_replace('file://', '', $url) . $fname;
      $result = @file_get_contents($path);
      if (!$result) {
        drupal_set_message(t('Janrain Capture: Could not load screen file "@filename." Please make sure your screens folder is in the correct location.', array(
          '@filename' => $fname,
        )), 'error');
        return false;
      }
    }
    else {
      $url_type = isset($_REQUEST['url_type']) ? $_REQUEST['url_type'] : false;

      // allow only alpha-numeric (and dashes) to prevent hijacking
      if ($url_type && !ctype_alnum(str_replace('-', '', $url_type))) {
        header('HTTP/1.1 400 Bad Request');
        exit;
      }
      $url .= $fname;
      $resp = drupal_http_request($url);
      if (isset($resp->error)) {
        watchdog('janrain_capture', 'Failed to retrieve a Capture screen with the following URL: %url', array(
          '%url' => $url,
        ), WATCHDOG_WARNING);
        $result = '';
      }
      else {
        $result = $resp->data;
      }
    }
    if (!$result) {
      $result = '';
    }
    return $result;
  }
}

/*
 * Determines the default load.js URL
 */
function _janrain_capture_default_loadjs_url() {

  // Parse engage app name to load.js path. If engage address is given engage app name will be parsed else default will be parsed.
  $janrain_capture_main = variable_get('janrain_capture_main2', array());
  $engageAppUrl = $janrain_capture_main['engage_address'];
  if ($engageAppUrl != '') {
    $engageAppName = strstr(parse_url($engageAppUrl, PHP_URL_HOST), '.', true);
  }
  else {
    $engageAppName = 'default';
  }
  return 'd16s8pqtk4uodx.cloudfront.net/' . $engageAppName . '/load.js';
}

Functions

Namesort descending Description
janrain_capture_block_content Provides the content for the Janrain Capture block, and is also used to replace the user login block content if the "enforce" setting is on.
janrain_capture_block_view_user_login_alter Implements hook_block_view_MODULE_DELTA_alter().
janrain_capture_comment_insert Implements hook_comment_insert().
janrain_capture_comment_view_alter Implements hook_comment_view_alter().
janrain_capture_configured Checks whether the module has been configured.
janrain_capture_form_node_type_form_alter
janrain_capture_mapping_exists Helper function to determine if a user is associated with a Capture account.
janrain_capture_menu Implements hook_menu().
janrain_capture_menu_alter Implements hook_menu_alter().
janrain_capture_node_view Implements hook_node_view().
janrain_capture_oauth_access_callback Access callback for the Capture Oauth Receiver endpoint.
janrain_capture_page_build Implements hook_page_build().
janrain_capture_profile_link Returns a render array for the 'Edit profile' link for Janrain Capture.
janrain_capture_render_logout_link Generates a 'Logout' link for Janrain Capture.
janrain_capture_share_js Adds share widget JS to the page.
janrain_capture_signin Menu callback to override user/login and user/register.
janrain_capture_signin_link Returns a render array for the 'Register / Sign in' link for Janrain Capture.
janrain_capture_sync_account Modifies the user account with values from the Janrain Capture profile array.
janrain_capture_theme Implements hook_theme().
janrain_capture_tokens Implements hook_tokens().
janrain_capture_token_expired_access Access callback for janrain_capture_token_expired().
janrain_capture_token_info Implements hook_token_info(). Provide a token for:
janrain_capture_url Returns the full URL of a specified CaptureUI screen
janrain_capture_url_outbound_alter Implements hook_url_outbound_alter().
theme_janrain_capture_icon Returns markup for a specific provider icon.
theme_janrain_capture_share_button Returns markup for the "share" button.
theme_janrain_capture_share_icons Returns markup for enabled social share provider icons.
_janrain_capture_default_loadjs_url
_janrain_capture_get_screen
_janrain_capture_share_button Returns HTML markup for the social share button.
_janrain_capture_update_picture Helper function for updating a user picture.

Constants