? LICENSE.txt ? twitter.oauth.patch ? twitter_actions Index: twitter.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.inc,v retrieving revision 1.3.2.6 diff -u -p -r1.3.2.6 twitter.inc --- twitter.inc 17 Jan 2009 20:01:05 -0000 1.3.2.6 +++ twitter.inc 18 Mar 2009 11:41:03 -0000 @@ -1,5 +1,5 @@ sign_request($signature_method, $consumer, $token); + if ($method == 'GET') { + $request_result = drupal_http_request($request->to_url()); + } + else { + $request_result = drupal_http_request($request->get_normalized_http_url(), array(), 'POST', $request->to_postdata()); + } + + if (_twitter_request_failure($request_result)) { + return FALSE; + } + if ($results = _twitter_convert_xml_to_array($request_result->data)) { + return $results; + } + return FALSE; +} + +/** * Fetch the public timeline for a Twitter.com account. * * Note that this function only requires a screen name, and not a password. As @@ -131,14 +193,11 @@ function twitter_fetch_timeline($screen_ function twitter_set_status($screen_name, $password, $text, $source = 'drupal') { $url = "http://" . variable_get('twitter_api_url', 'twitter.com') . "/statuses/update.xml"; - $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), - 'Content-type' => 'application/x-www-form-urlencoded'); - $data = 'status='. urlencode($text); + $data['status'] = $text; if (!empty($source)) { - $data .= "&source=". urlencode($source); + $data['source'] = $source; } - - return drupal_http_request($url, $headers, 'POST', $data); + return twitter_oauth_request($screen_name, $url, 'POST', $data); } /** @@ -149,33 +208,25 @@ function twitter_set_status($screen_name * * @param $screen_name * The screen name of a Twitter.com user. - * @param $password - * The password of a Twitter.com user. * @param $cache * A boolean indicating whether the account info should be cached in the local * site's database after it's retrieved. * @return * An single Twitter account. */ -function twitter_fetch_account_info($screen_name, $password, $cache = TRUE) { +function twitter_fetch_account_info($screen_name, $cache = TRUE) { $url = "http://" . variable_get('twitter_api_url', 'twitter.com') . "/users/show/$screen_name.xml"; - $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), - 'Content-type' => 'application/x-www-form-urlencoded'); - $results = drupal_http_request($url, $headers, 'GET'); - if (_twitter_request_failure($results)) { + $results = twitter_oauth_request($screen_name, $url); + if (!$results) { return array(); } - - if ($results = _twitter_convert_xml_to_array($results->data)) { - if ($cache) { - foreach($results as $user) { - twitter_cache_account($user); - } + if ($cache) { + foreach($results as $user) { + twitter_cache_account($user); } - return $results[0]; } - return array(); + return $results[0]; } /** @@ -186,8 +237,6 @@ function twitter_fetch_account_info($scr * * @param $screen_name * The screen name of a Twitter.com user. - * @param $password - * The password of a Twitter.com user. * @param $cache * A boolean indicating whether the statuses should be cached in the local * site's database after they're retrieved. @@ -196,16 +245,13 @@ function twitter_fetch_account_info($scr * * @see twitter_fetch_timeline() */ -function twitter_fetch_statuses($screen_name, $password, $cache = TRUE) { - $url = "http://" . variable_get('twitter_api_url', 'twitter.com') . "/statuses/$screen_name.xml"; - $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), - 'Content-type' => 'application/x-www-form-urlencoded'); +function twitter_fetch_statuses($screen_name, $cache = TRUE) { + $url = "http://" . variable_get('twitter_api_url', 'twitter.com') . "/statuses/user_timeline/$screen_name.xml"; - $results = drupal_http_request($url, $headers, 'GET'); - if (_twitter_request_failure($results)) { + $results = twitter_oauth_request($screen_name, $url); + if (!$results) { return array(); } - $results = _twitter_convert_xml_to_array($results->data); if ($cache && !empty($results)) { foreach($results as $status) { @@ -257,13 +303,12 @@ function twitter_fetch_friends($screen_n */ function twitter_fetch_followers($screen_name, $password) { $url = "http://" . variable_get('twitter_api_url', 'twitter.com') . "/statuses/followers/$screen_name.xml"; - $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), - 'Content-type' => 'application/x-www-form-urlencoded'); - $results = drupal_http_request($url, $headers, 'GET'); - if (_twitter_request_failure($results)) { + + $results = twitter_oauth_request($screen_name, $url); + if (!$results) { return array(); } - return _twitter_convert_xml_to_array($results->data); + return $results->data; } /** @@ -276,13 +321,12 @@ function twitter_fetch_followers($screen * @return * A boolean indicating success or failure. */ -function twitter_authenticate($screen_name, $password) { +function twitter_authenticate($screen_name) { $url = "http://" . variable_get('twitter_api_url', 'twitter.com') . "/account/verify_credentials.xml"; - $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), - 'Content-type' => 'application/x-www-form-urlencoded'); - $results = drupal_http_request($url, $headers, 'GET'); - drupal_http_request('http://' . variable_get('twitter_api_url', 'twitter.com') . '/account/end_session', $headers, 'GET'); - return ($results->code == '200'); + + $result = twitter_oauth_request($screen_name, $url); + twitter_oauth_request($screen_name, 'http://' . variable_get('twitter_api_url', 'twitter.com') . '/account/end_session'); + return ($result !== FALSE); } /** @@ -326,7 +370,15 @@ function _twitter_request_failure($resul return FALSE; } - +/** + * Returns tokens stored for this screen name + * @param $screen_name Screen name we want tokens for + * @return tokens if they exist FALSE if not + */ +function _twitter_get_tokens($screen_name) { + $result = db_fetch_array(db_query("SELECT token_key, token_secret FROM {twitter_user} WHERE screen_name = '%s'", $screen_name)); + return $result; +} /** @@ -396,10 +448,8 @@ function twitter_cache_status($status = */ function twitter_get_user_accounts($uid, $only_with_passwords = FALSE) { - $sql = "SELECT ta.*, tu.uid, tu.password, tu.import FROM {twitter_user} tu LEFT JOIN {twitter_account} ta ON (tu.screen_name = ta.screen_name) WHERE tu.uid = %d"; - if ($only_with_passwords) { - $sql .= " AND tu.password IS NOT NULL"; - } + $sql = "SELECT ta.*, tu.uid, tu.token_key, tu.token_secret, tu.import FROM {twitter_user} tu LEFT JOIN {twitter_account} ta ON (tu.screen_name = ta.screen_name) WHERE tu.uid = %d"; + $args = array($uid); $results = db_query($sql, $args); @@ -412,7 +462,6 @@ function twitter_get_user_accounts($uid, function twitter_user_save($account = array(), $force_import = FALSE) { $account += array( - 'screen_name' => '', 'import' => 1, ); @@ -423,12 +472,12 @@ function twitter_user_save($account = ar } if ($force_import && $account['import']) { - if (empty($account['protected']) || empty($account['password'])) { + if (!empty($account['protected'])) { $statuses = twitter_fetch_timeline($account['screen_name']); } else { - twitter_fetch_account_info($account['screen_name'], $account['password']); - $statuses = twitter_fetch_statuses($account['screen_name'], $account['password']); + twitter_fetch_account_info($account['screen_name']); + $statuses = twitter_fetch_statuses($account['screen_name']); } if (!empty($statuses)) { Index: twitter.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.install,v retrieving revision 1.2.2.1 diff -u -p -r1.2.2.1 twitter.install --- twitter.install 17 Jan 2009 20:43:53 -0000 1.2.2.1 +++ twitter.install 18 Mar 2009 11:41:03 -0000 @@ -1,5 +1,5 @@ 'varchar', 'length' => 255 ), - 'password' => array( - 'description' => t("The password for the Twitter account."), - 'type' => 'varchar', - 'length' => 64 + 'token_key' => array( + 'description' => t('Tokens for request and services accesses.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE + ), + 'token_secret' => array( + 'description' => t('Token "password".'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE ), 'import' => array( 'description' => t("Boolean flag indicating whether the {twitter_user}'s posts should be pulled in by the site."), Index: twitter.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.module,v retrieving revision 1.3.2.5 diff -u -p -r1.3.2.5 twitter.module --- twitter.module 10 Feb 2009 19:33:00 -0000 1.3.2.5 +++ twitter.module 18 Mar 2009 11:41:03 -0000 @@ -1,5 +1,5 @@ 'twitter.pages.inc', 'type' => MENU_LOCAL_TASK, ); + + $items['oauth_twitter/callback'] = array( + 'title' => 'OAuth Twitter callback', + 'access callback' => TRUE, + 'page callback' => 'drupal_get_form', + 'page arguments' => array('oauth_twitter_callback'), + 'file' => 'twitter.pages.inc', + 'type' => MENU_CALLBACK, + ); return $items; } Index: twitter.pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.pages.inc,v retrieving revision 1.2.2.4 diff -u -p -r1.2.2.4 twitter.pages.inc --- twitter.pages.inc 17 Jan 2009 20:43:53 -0000 1.2.2.4 +++ twitter.pages.inc 18 Mar 2009 11:41:03 -0000 @@ -1,5 +1,5 @@ l('Identi.ca', 'http://laconi.ca/trac/wiki/TwitterCompatibleAPI'))), ); + $form['consumer'] = array( + '#collapsible' => TRUE, + '#collapsed' => (variable_get('oauth_twitter_consumer_key', '') and variable_get('oauth_twitter_consumer_secret', '')), + '#description' => t('Consumer information is given from the server. Its different for each user. Consider creating a settings page on your module that records these values, so users might enter them.'), + '#title' => t('Consumer information'), + '#type' => 'fieldset', + ); + $form['consumer']['oauth_twitter_consumer_key'] = array( + '#description' => t('Token request consumer key. Consumer key that twitter assigned to your application.'), + '#default_value' => variable_get('oauth_twitter_consumer_key', ''), + '#title' => t('Consumer key'), + '#type' => 'textfield', + ); + $form['consumer']['oauth_twitter_consumer_secret'] = array( + '#description' => t('Token Resquest consumer secret. Consumer secret that twitter assigned to your application.'), + '#default_value' => variable_get('oauth_twitter_consumer_secret', ''), + '#title' => t('Consumer secret'), + '#type' => 'textfield', + ); + return system_settings_form($form); } @@ -179,24 +199,6 @@ function twitter_add_account($form_state '#value' => $account->uid, ); - $form['screen_name'] = array( - '#type' => 'textfield', - '#required' => TRUE, - '#title' => t('Twitter user name'), - ); - $form['password'] = array( - '#type' => 'password', - '#title' => t('Password'), - '#description' => t("If your Twitter account is protected, or you wish to post to Twitter from Drupal, you must enter the Twitter account's password.") - ); - - $form['import'] = array( - '#type' => 'checkbox', - '#title' => t('Import statuses from this account'), - '#default_value' => TRUE, - '#access' => FALSE, - ); - $form['submit'] = array( '#type' => 'submit', '#value' => t('Add account'), @@ -205,30 +207,121 @@ function twitter_add_account($form_state return $form; } -function twitter_add_account_validate($form, &$form_state) { +function twitter_add_account_submit($form, &$form_state) { module_load_include('inc', 'twitter'); + // Use the libraries from OAuth integration + module_load_include('lib.php', 'oauth'); - $verify = FALSE; - - $pass = $form_state['values']['password']; - $name = $form_state['values']['screen_name']; + $values = array(); - if (!empty($pass)) { - $verify = TRUE; - } + // Build the Consumer object + $consumer = new OAuthConsumer( + variable_get('oauth_twitter_consumer_key', ''), + variable_get('oauth_twitter_consumer_secret', '') + ); + + // Build the request data + $request = OAuthRequest::from_consumer_and_token( + $consumer, + NULL, + 'POST', + "http://" . variable_get('twitter_api_url', 'twitter.com') . '/oauth/request_token', + $values + ); + + $signature_method = new OAuthSignatureMethod_HMAC_SHA1(); + $request->sign_request($signature_method, $consumer, NULL); + + $token = drupal_http_request($request->get_normalized_http_url(), array(), 'POST', $request->to_postdata()); + // print_r($request->get_parameters()); + parse_str($token->data, $tok); + + // Build the token object + $token = new OAuthToken( + $tok['oauth_token'], + $tok['oauth_token_secret'] + ); + + // Save token and uid into session + $_SESSION['twitter_token'] = $tok; + $_SESSION['twitter_uid'] = $form_state['values']['uid']; + + // Build the request data + $request = OAuthRequest::from_consumer_and_token( + $consumer, + $token, + 'GET', + "http://" . variable_get('twitter_api_url', 'twitter.com') . '/oauth/authorize', + $values + ); + + $request->sign_request($signature_method, $consumer, NULL); + + drupal_goto($request->to_url()); +} - if ($verify) { - $valid = twitter_authenticate($name, $pass); - if (!$valid) { - form_set_error("password", t('Twitter authentication failed. Please check your account name and try again.')); - } +function oauth_twitter_callback() { + // Show a message in case there is no token in session + if (!$token = $_SESSION['twitter_token']) { + drupal_set_message(t('There is no Token Request saved'), 'error'); + return array(); } -} -function twitter_add_account_submit($form, &$form_state) { + // Use the libraries from OAuth integration + module_load_include('lib.php', 'oauth'); module_load_include('inc', 'twitter'); + + // Build the Consumer object + $consumer = new OAuthConsumer( + variable_get('oauth_twitter_consumer_key', ''), + variable_get('oauth_twitter_consumer_secret', '') + ); + + // Build the token object + $token = new OAuthToken( + $token['oauth_token'], + $token['oauth_token_secret'] + ); + + // Build the request data + $request = OAuthRequest::from_consumer_and_token( + $consumer, + $token, + 'GET', + "http://" . variable_get('twitter_api_url', 'twitter.com') . '/oauth/access_token', + $values + ); + $signature_method = new OAuthSignatureMethod_HMAC_SHA1(); + $request->sign_request($signature_method, $consumer, $token); + $request_result = drupal_http_request($request->get_normalized_http_url(), array(), 'POST', $request->to_postdata()); + + parse_str($request_result->data, $tok); + $account['uid'] = $_SESSION['twitter_uid']; + $account['token_key'] = $tok['oauth_token']; + $account['token_secret'] = $tok['oauth_token_secret']; + + // Lets verify credentioals to get screen name and check if all went well + // Build the token object + $token = new OAuthToken( + $account['token_key'], + $account['token_secret'] + ); + $request = OAuthRequest::from_consumer_and_token( + $consumer, + $token, + 'POST', + "http://" . variable_get('twitter_api_url', 'twitter.com') .'/account/verify_credentials.xml', + $values + ); + $request->sign_request($signature_method, $consumer, $token); + $request_result = drupal_http_request($request->get_normalized_http_url(), array(), 'POST', $request->to_postdata()); + + if (_twitter_request_failure($request_result)) { + return array(); + } - if (!empty($form_state['values']['screen_name'])) { - twitter_user_save($form_state['values'], TRUE); + if ($results = _twitter_convert_xml_to_array($request_result->data)) { + $account['screen_name'] = $results[0]['screen_name']; + twitter_user_save($account, TRUE); } }