'AllPlayers.com Connection', 'page callback' => 'allplayers_connect_page', 'page arguments' => array(2), 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); $items['allplayers/auth'] = array( 'title' => 'Authorized...', 'page callback' => 'allplayers_authorize_page', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); $items['admin/settings/allplayers'] = array( 'title' => t('AllPlayers.com OAuth settings'), 'page callback' => 'drupal_get_form', 'page arguments' => array('allplayers_settings_form'), 'access arguments' => array('administer site configuration'), 'file' => 'includes/allplayers.pages.inc', 'description' => 'Configure site for AllPlayers.com OAuth connection and API info.', 'type' => MENU_NORMAL_ITEM, ); $items['admin/settings/allplayers/default'] = array( 'title' => 'Settings', 'type' => MENU_DEFAULT_LOCAL_TASK ); $items['admin/settings/allplayers/actions'] = array( 'title' => 'Actions', 'page callback' => 'drupal_get_form', 'page arguments' => array('allplayers_actions_settings_form'), 'access arguments' => array('administer site configuration'), 'file' => 'includes/allplayers.pages.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 5 ); $items['user/%user/allplayers'] = array( 'title' => t('AllPlayers.com settings'), 'page callback' => 'allplayers_user_form', 'page arguments' => array(1), 'access callback' => 'user_edit_access', 'access arguments' => array(1), 'file' => 'includes/allplayers.pages.inc', ); return $items; } /** * Implements hook_theme(). */ function allplayers_theme() { return array( 'allplayers_action_connect' => array(), 'allplayers_iframe' => array(), 'allplayers_user_form_connect' => array( 'arguments' => array('uid' => NULL, 'uuid' => NULL), ), 'allplayers_user_info' => array( 'arguments' => array('account' => NULL), 'file' => 'includes/allplayers.pages.inc', ), ); } /** * Implements hook_block(). */ function allplayers_block($op = 'list', $delta = '', $edit = array()) { switch ($op) { case 'list': return allplayers_block_info(); case 'view': return allplayers_block_view($delta); case 'configure': return allplayers_block_configure($delta); case 'save': allplayers_block_save($delta, $edit); } } /** * Implements hook_block_save(). */ function allplayers_block_save($delta, $edit = array()) { if ($delta == 'group_register' && !empty($edit)) { variable_set('allplayers_group_register_web_address', $edit['group_web_address']); } } /** * Implements hook_block_configure(). */ function allplayers_block_configure($delta) { $form = array(); if ($delta == 'group_register') { $form['group_web_address'] = array( '#type' => 'textfield', '#title' => t('Group Web Address'), '#default_value' => variable_get('allplayers_group_register_web_address', ''), '#field_prefix' => variable_get('allplayers_domain', 'https://www.allplayers.com') . '/g/', '#field_suffix' => '/register', '#size' => 25, '#description' => t('You can find this in the groups URL.'), '#required' => TRUE, ); } return $form; } /** * Implements hook_block_info(). */ function allplayers_block_info() { $blocks['login'] = array( 'info' => t('AllPlayers.com login'), ); $blocks['register'] = array( 'info' => t('AllPlayers.com register'), ); $blocks['group_register'] = array( 'info' => t('AllPlayers.com Group Registration'), ); return $blocks; } /** * Implements hook_block_view(). */ function allplayers_block_view($delta) { $block = array(); switch ($delta) { case 'login': case 'register': $block['content'] = allplayers_show_connect_link($delta); break; case 'group_register': $block['content'] = allplayers_show_group_register(variable_get('allplayers_group_register_web_address', '')); break; } return $block; } /** * Show the allplayers connect link. */ function allplayers_show_connect_link($op = 'login') { $output = ''; if (variable_get('allplayers_key', '') && !allplayers_uuid_load()) { $theme_variables = array('op' => $op); $theme_variables['url'] = url(variable_get('allplayers_redirect', ''), array('absolute' => TRUE)); $button_variable = $op == 'register' ? 'allplayers_register_button' : 'allplayers_button'; $theme_variables['button'] = variable_get($button_variable, 'link'); $theme_variables['op_display'] = ucfirst($op); return theme('allplayers_action_connect', $theme_variables); } return $output; } /** * Show the group registration iFrame. */ function allplayers_show_group_register($group_web_address = '') { $output = ''; if (!empty($group_web_address)) { $theme_variables = array( 'group_web_address' => $group_web_address, 'op' => 'group_register', ); $output = theme('allplayers_iframe', $theme_variables); } return $output; } /** * Load a AllPlayers UUID given a Drupal User ID. */ function allplayers_uuid_load($uid = NULL) { $uid = isset($uid) ? $uid : $GLOBALS['user']->uid; $result = db_query("SELECT authname FROM {authmap} WHERE uid = %d AND module = 'allplayers'", $uid); $uuid = db_result($result); return $uuid ? $uuid : FALSE; } /** * Implements hook_form_FORM_ID_alter(). */ function allplayers_form_user_profile_form_alter(&$form, &$form_state) { $uid = $form['#uid']; $uuid = allplayers_uuid_load($uid); $apoauth_form = array( '#type' => 'item', '#title' => t('AllPlayers.com'), '#children' => theme('allplayers_user_form_connect', $uid, $uuid), ); // The account settings move around in this form. $account_form = isset($form['account']) ? $form['account'] : $form; // Inject the AllPlayers.com options after the e-mail settings. No weights are on // these elements by default, so we have to put it in order. $temp_form = array(); foreach (element_children($account_form) as $child) { $temp_form[$child] = $account_form[$child]; if ($child == 'mail') { if (isset($temp_form[$child]['#weight'])) { $apoauth_form['#weight'] = $temp_form[$child]['#weight']; } $temp_form['apoauth'] = $apoauth_form; } unset($account_form[$child]); } $account_form += $temp_form; if (isset($form['account'])) { $form['account'] = $account_form; } else { $form = $account_form; } } /** * Get a client initialized and signed (if keys are provided) */ function _allplayers_client_handle($path = 'https://www.allplayers.com/api/v1/rest', $token = FALSE, $secret = FALSE) { // TODO: consider using autoload module require_once drupal_get_path('module', 'allplayers') . '/vendor/autoload.php'; $consumer_key = variable_get('allplayers_key', ''); $consumer_secret = variable_get('allplayers_secret', ''); // TODO: Set header info based on site id info $client = new \Guzzle\Http\Client($path, array( 'curl.CURLOPT_SSL_VERIFYPEER' => TRUE, 'curl.CURLOPT_CAINFO' => drupal_get_path('module', 'allplayers') . '/assets/mozilla.pem', 'curl.CURLOPT_FOLLOWLOCATION' => FALSE, )); if ($token !== FALSE) { $oauth = new \Guzzle\Http\Plugin\OauthPlugin(array( 'consumer_key' => $consumer_key, 'consumer_secret' => $consumer_secret, 'token' => $token, 'token_secret' => $secret, )); $client->addSubscriber($oauth); } return $client; } /** * Utility function for retrieving admins user groups. */ function _allplayers_get_user_groups($admin_auth = array()) { if (empty($admin_auth)) { $admin_auth = variable_get('allplayers_admin_auth', array()); } $domain = variable_get('allplayers_domain', 'https://www.allplayers.com'); $client = _allplayers_client_handle($domain . '/api/v1/rest', $admin_auth['token'], $admin_auth['secret']); $response = $client->get('users/current/groups.json?limit=0')->send(); // Note: getLocation returns full URL info, but seems to work as a request in Guzzle $response = $client->get($response->getLocation())->send(); $groups = json_decode($response->getBody(TRUE)); return $groups; } /** * Redirect a request to AllPlayers.com to begin auth process. * * @see http://develop.allplayers.com/oauth.html */ function allplayers_connect_page($op) { global $base_url; // Redirect to a signed init. request $domain = variable_get('allplayers_domain', 'https://www.allplayers.com'); $consumer_key = variable_get('allplayers_key', ''); $consumer_secret = variable_get('allplayers_secret', ''); $client = _allplayers_client_handle($domain . '/oauth'); $oauth = new \Guzzle\Http\Plugin\OauthPlugin(array( 'consumer_key' => $consumer_key, 'consumer_secret' => $consumer_secret, 'token' => FALSE, 'token_secret' => FALSE, )); $timestamp = time(); $params = $oauth->getParamsToSign($client->get('request_token'), $timestamp); $params['oauth_signature'] = $oauth->getSignature($client->get('request_token'), $timestamp); $response = $client->get('request_token?' . http_build_query($params, '', '&'))->send(); // Parse oauth tokens from response object $oauth_tokens = array(); parse_str($response->getBody(TRUE), $oauth_tokens); $_SESSION['allplayers_oauth']['access_token'] = $oauth_tokens['oauth_token']; $_SESSION['allplayers_oauth']['access_secret'] = $oauth_tokens['oauth_token_secret']; $authorize = '/oauth/authorize?oauth_token=' . $oauth_tokens['oauth_token']; if ($op == 'register') { $authorize .= '®ister=1'; } $authorize .= '&oauth_callback=' . rawurlencode($base_url . '/index.php/?q=allplayers/auth'); // Redirect to OAuth auth page drupal_goto($domain . $authorize); } /** * Process a authorization request from AllPlayers.com. * * @see http://develop.allplayers.com/oauth.html */ function allplayers_authorize_page() { // Getting here gives us a token to sign user requests to create an account. $domain = variable_get('allplayers_domain', 'https://www.allplayers.com'); $access_token = $_SESSION['allplayers_oauth']['access_token']; $access_secret = $_SESSION['allplayers_oauth']['access_secret']; if (!empty($access_token) && !empty($access_secret)) { $client = _allplayers_client_handle($domain . '/oauth', $access_token, $access_secret); $response = $client->get('access_token')->send(); // Parse oauth tokens from response object $oauth_tokens = array(); parse_str($response->getBody(TRUE), $oauth_tokens); // TODO: Persist these to relation with DB user $auth_token = $_SESSION['allplayers_oauth']['auth_token'] = $oauth_tokens['oauth_token']; $auth_secret = $_SESSION['allplayers_oauth']['auth_secret'] = $oauth_tokens['oauth_token_secret']; _allplayers_user_connect($auth_token, $auth_secret); $url = url(variable_get('allplayers_redirect', ''), array('absolute' => TRUE)); drupal_set_header('Refresh:1;URL=' . $url); drupal_add_js('if (window.name=="ConnectWithOAuth") {window.close();}', 'inline'); return l('Click here to continue.', $url); } } /** * AllPlayers.com OAuth callback for relating a Drupal connection. */ function _allplayers_user_connect($auth_token, $auth_secret) { global $user; $domain = variable_get('allplayers_domain', 'https://www.allplayers.com'); $client = _allplayers_client_handle($domain . '/api/v1/rest', $auth_token, $auth_secret); $response = $client->get('users/current.json')->send(); // Note: getLocation returns full URL info, but seems to work as a request in Guzzle $response = $client->get($response->getLocation())->send(); $apuser = json_decode($response->getBody(TRUE)); $account = user_external_load($apuser->uuid); // If the user has logged in before, load their account and login. if (!$user->uid && $account) { allplayers_login_user($account); module_invoke_all('allplayers_user_connect', 'after_login', $apuser, $account); } // If the AllPlayers.com e-mail address matches an existing account, bind them // together and log in as that account. elseif (!empty($apuser->email) && ($account = user_load(array('mail' => $apuser->email)))) { user_set_authmaps($account, array('authname_allplayers' => $apuser->uuid)); module_invoke_all('allplayers_user_connect', 'after_connect', $apuser, $account); // Logins will be denied if the user's account is blocked. if (allplayers_login_user($account)) { drupal_set_message(t('You\'ve connected your account with AllPlayers.com.')); module_invoke_all('allplayers_user_connect', 'after_login', $apuser, $account); } } else { // If the user is already logged in, associate the two accounts. if ($user->uid) { user_set_authmaps(user_load($user->uid), array('authname_allplayers' => $apuser->uuid)); module_invoke_all('allplayers_user_connect', 'after_connect', $apuser, $user); drupal_set_message(t('You\'ve connected your account with AllPlayers.com.')); } // Register a new user only if allowed. elseif (variable_get('user_register', 1)) { // user_external_login_register ? $account = allplayers_create_user($apuser); // Load the account fresh just to have a fully-loaded object. $account = user_load($account->uid); // TODO: Consider hook_user @see fboauth_user user_set_authmaps($account, array('authname_allplayers' => $apuser->uuid)); module_invoke_all('allplayers_user_connect', 'after_connect', $apuser, $account); // If the account requires administrator approval the new account will // have a status of '0' and not be activated yet. if ($account->status == 0) { _user_mail_notify('register_pending_approval', $account); drupal_set_message(t('An account has been created for you on @sitename but an administrator needs to approve your account. In the meantime, a welcome message with further instructions has been sent to your e-mail address.', array('@sitename' => variable_get('site_name', '')))); } // Log in the user if no approval is required. elseif (allplayers_login_user($account)) { module_invoke_all('allplayers_user_connect', 'after_login', $apuser, $account); drupal_set_message(t('Welcome to @sitename. Basic information has been imported from AllPlayers.com into your account. You may want to edit your account to confirm the details and set a password.', array('@sitename' => variable_get('site_name', ''), '!edit' => url('user/' . $account->uid . '/edit')))); } // If the login fails, allplayers_login_user() throws its own error message. } // Since user's can't create new accounts on their own, show an error. else { drupal_set_message('Your AllPlayers.com e-mail address does not match any existing accounts. If you have an account, you must first log in before you can connect your account to AllPlayers.com. Creation of new accounts on this site is disabled.'); } } // HACK: Store admin token and secret in a variable to reuse (consider // refactoring into a join on authmap entry. if ($user->uid == 1) { if (!empty($auth_secret)) { variable_set('allplayers_admin_auth', array( 'token' => $auth_token, 'secret' => $auth_secret, )); } } } function allplayers_allplayers_user_connect($op, $apuser, $matched_user) { // HACK: Single action to perform on the API after joining (currently only // group join). @see: allplayers_actions_settings_form:allplayers_groupjoin if ($op == 'after_connect') { $groupjoin_uuid = variable_get('allplayers_groupjoin', ''); if (!empty($groupjoin_uuid)) { $a_token_secret = variable_get('allplayers_admin_auth', array()); if (!empty($a_token_secret) && count($a_token_secret) == 2) { $userjoin_uuid = $apuser->uuid; $domain = variable_get('allplayers_domain', 'https://www.allplayers.com'); // @TODO: Refactor this to use AllPlayer/Client.php impl. $client = _allplayers_client_handle($domain . '/api/v1/rest', $a_token_secret['token'], $a_token_secret['secret']); $response = $client->post("groups/$groupjoin_uuid/join/$userjoin_uuid")->send(); } } } } /** * Given a AllPlayers.com user object, associate or save a Drupal user account. */ function allplayers_create_user($apuser, $options = array()) { // Set default options. $defaults = array( 'username' => 'username', 'picture' => variable_get('user_pictures', 0) ? 'picture' : '', 'status' => variable_get('user_register', 1) == 1 ? 1 : 0, ); $options += $defaults; // Use their AllPlayers.com user name (if defined), otherwise their real name. // If an account already exists with that name, increment until the namespace // is available. if ($options['username'] === 'username' && !empty($apuser->username)) { $username = $apuser->username; } else { $username = $apuser->uuid; } $query = "SELECT uid FROM {users} WHERE name = '%s'"; $uid = db_result(db_query($query, $username)); $i = 0; while ($uid) { $i++; $uid = db_result(db_query($query, $username . $i)); } if ($i > 0) { $username = $username . $i; } // Initialize basic properties that are unlikely to need changing. $edit = array( 'name' => $username, 'mail' => !empty($apuser->email) ? $apuser->email : '', // If user_register is "1", then no approval required. 'status' => $options['status'], 'apoauth' => TRUE, // Signify this is being imported by AllPlayers.com OAuth. 'apoauth_uuid' => $apuser->uuid, // So that other modules can load the account. ); // Profile module support. if (module_exists('profile')) { module_load_include('inc', 'allplayers', '/includes/allplayers.profile'); allplayers_profile_create_user($edit, $apuser); } // Allow other modules to manipulate the user information before save. foreach (module_implements('allplayers_user_presave') as $module) { $function = $module . '_allplayers_user_presave'; $function($edit, $apuser); } $account = user_save(NULL, $edit); // Retrieve the user's picture from AllPlayers.com and save it locally. if ($account->uid && $options['picture'] === 'picture') { $path = file_create_path('pictures'); file_check_directory($path, FILE_CREATE_DIRECTORY); $picture_result = drupal_http_request($apuser->picture); $picture_path = $path . '/picture-' . $account->uid . '.jpg'; $file = fopen($picture_path, 'w'); fwrite($file, $picture_result->data); fclose($file); // Check to make sure the picture isn't too large for the site settings. $picture_info = image_get_info($picture_path); list($max_dimensions['width'], $max_dimensions['height']) = explode('x', variable_get('user_picture_dimensions', '85x85')); if (image_get_toolkit() && $picture_info['width'] > $max_dimensions['width'] || $picture_info['height'] > $max_dimensions['height']) { image_scale($picture_path, $picture_path, $max_dimensions['width'], $max_dimensions['height']); } // Update the database record. db_query("UPDATE {users} SET picture = '%s' WHERE uid = %d", $picture_path, $account->uid); } // TODO: Allow other modules to manipulate the user information after save. return $account; } /** * Given a Drupal user object, log the user in. * * This acts as a wrapper around user_external_login() in Drupal 6 and as a full * replacement function in Drupal 7, since no direct equivalent exists. * * @param $account * A Drupal user account or UID. */ function allplayers_login_user($account) { return user_external_login($account); } function theme_allplayers_iframe($variables) { static $allplayers_js_settings; $op = $variables['op']; $allplayers_js_settings['allplayers']['windowproxy_ids'][$op] = $op; drupal_set_html_head(''); drupal_add_js(drupal_get_path('module', 'allplayers') . '/allplayers_iframe.js'); drupal_add_js($allplayers_js_settings, 'setting'); $iframe = "