Make the TwitterQueuehandler post to Twitter using OAuth

This commit is contained in:
Zach Copley 2009-08-03 22:46:01 +00:00 committed by Evan Prodromou
parent e9edaab358
commit 500f0c7072
4 changed files with 122 additions and 113 deletions

View File

@ -67,39 +67,57 @@ class TwitterauthorizationAction extends Action
if (empty($this->oauth_token)) { if (empty($this->oauth_token)) {
// Get a new request token and authorize it try {
$client = new TwitterOAuthClient(); // Get a new request token and authorize it
$req_tok = $client->getRequestToken();
// Sock the request token away in the session temporarily $client = new TwitterOAuthClient();
$req_tok = $client->getRequestToken();
$_SESSION['twitter_request_token'] = $req_tok->key; // Sock the request token away in the session temporarily
$_SESSION['twitter_request_token_secret'] = $req_tok->key;
$_SESSION['twitter_request_token'] = $req_tok->key;
$_SESSION['twitter_request_token_secret'] = $req_tok->key;
$auth_link = $client->getAuthorizeLink($req_tok);
} catch (TwitterOAuthClientException $e) {
$msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
$e->getCode(), $e->getMessage());
$this->serverError(_('Couldn\'t link your Twitter account.'));
}
$auth_link = $client->getAuthorizeLink($req_tok);
common_redirect($auth_link); common_redirect($auth_link);
} else { } else {
// Check to make sure Twitter sent us the same request token we sent // Check to make sure Twitter returned the same request
// token we sent them
if ($_SESSION['twitter_request_token'] != $this->oauth_token) { if ($_SESSION['twitter_request_token'] != $this->oauth_token) {
$this->serverError(_('Couldn\'t link your Twitter account.')); $this->serverError(_('Couldn\'t link your Twitter account.'));
} }
$client = new TwitterOAuthClient($_SESSION['twitter_request_token'], try {
$_SESSION['twitter_request_token_secret']);
// Exchange the request token for an access token $client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
$_SESSION['twitter_request_token_secret']);
$atok = $client->getAccessToken(); // Exchange the request token for an access token
// Save the access token and Twitter user info $atok = $client->getAccessToken();
$client = new TwitterOAuthClient($atok->key, $atok->secret); // Save the access token and Twitter user info
$twitter_user = $client->verify_credentials(); $client = new TwitterOAuthClient($atok->key, $atok->secret);
$twitter_user = $client->verify_credentials();
} catch (OAuthClientException $e) {
$msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
$e->getCode(), $e->getMessage());
$this->serverError(_('Couldn\'t link your Twitter account.'));
}
$user = common_current_user(); $user = common_current_user();

View File

@ -645,13 +645,14 @@ function mail_twitter_bridge_removed($user)
$subject = sprintf(_('Your Twitter bridge has been disabled.')); $subject = sprintf(_('Your Twitter bridge has been disabled.'));
$body = sprintf(_("Hi, %1\$s. We're sorry to inform you that your " . $site_name = common_config('site', 'name');
'link to Twitter has been disabled. Your Twitter credentials ' .
'have either changed (did you recently change your Twitter ' . $body = sprintf(_('Hi, %1$s. We\'re sorry to inform you that your ' .
'password?) or you have otherwise revoked our access to your ' . 'link to Twitter has been disabled. We no longer seem to have ' .
"Twitter account.\n\n" . 'permission to update your Twitter status. (Did you revoke ' .
'You can re-enable your Twitter bridge by visiting your ' . '%3$s\'s access?)' . "\n\n" .
"Twitter settings page:\n\n\t%2\$s\n\n" . 'You can re-enable your Twitter bridge by visiting your ' .
"Twitter settings page:\n\n\t%2\$s\n\n" .
"Regards,\n%3\$s\n"), "Regards,\n%3\$s\n"),
$profile->getBestName(), $profile->getBestName(),
common_local_url('twittersettings'), common_local_url('twittersettings'),
@ -679,11 +680,11 @@ function mail_facebook_app_removed($user)
$site_name = common_config('site', 'name'); $site_name = common_config('site', 'name');
$subject = sprintf( $subject = sprintf(
_('Your %1\$s Facebook application access has been disabled.', _('Your %1$s Facebook application access has been disabled.',
$site_name)); $site_name));
$body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " . $body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " .
'unable to update your Facebook status from %2\$s, and have disabled ' . 'unable to update your Facebook status from %2$s, and have disabled ' .
'the Facebook application for your account. This may be because ' . 'the Facebook application for your account. This may be because ' .
'you have removed the Facebook application\'s authorization, or ' . 'you have removed the Facebook application\'s authorization, or ' .
'have deleted your Facebook account. You can re-enable the ' . 'have deleted your Facebook account. You can re-enable the ' .

View File

@ -360,106 +360,74 @@ function is_twitter_bound($notice, $flink) {
function broadcast_twitter($notice) function broadcast_twitter($notice)
{ {
$flink = Foreign_link::getByUserID($notice->profile_id, $flink = Foreign_link::getByUserID($notice->profile_id,
TWITTER_SERVICE); TWITTER_SERVICE);
if (is_twitter_bound($notice, $flink)) { if (is_twitter_bound($notice, $flink)) {
$fuser = $flink->getForeignUser(); $user = $flink->getUser();
$twitter_user = $fuser->nickname;
$twitter_password = $flink->credentials;
$uri = 'http://www.twitter.com/statuses/update.json';
// XXX: Hack to get around PHP cURL's use of @ being a a meta character // XXX: Hack to get around PHP cURL's use of @ being a a meta character
$statustxt = preg_replace('/^@/', ' @', $notice->content); $statustxt = preg_replace('/^@/', ' @', $notice->content);
$options = array( $client = new TwitterOAuthClient($flink->token, $flink->credentials);
CURLOPT_USERPWD => "$twitter_user:$twitter_password",
CURLOPT_POST => true,
CURLOPT_POSTFIELDS =>
array(
'status' => $statustxt,
'source' => common_config('integration', 'source')
),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FAILONERROR => true,
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => "Laconica",
CURLOPT_CONNECTTIMEOUT => 120, // XXX: How long should this be?
CURLOPT_TIMEOUT => 120,
# Twitter is strict about accepting invalid "Expect" headers $status = null;
CURLOPT_HTTPHEADER => array('Expect:')
);
$ch = curl_init($uri); try {
curl_setopt_array($ch, $options); $status = $client->statuses_update($statustxt);
$data = curl_exec($ch); } catch (OAuthClientCurlException $e) {
$errmsg = curl_error($ch);
$errno = curl_errno($ch);
if (!empty($errmsg)) { if ($e->getMessage() == 'The requested URL returned error: 401') {
common_debug("cURL error ($errno): $errmsg - " .
"trying to send notice for $twitter_user.",
__FILE__);
$user = $flink->getUser(); $errmsg = sprintf('User %1$s (user id: %2$s) has an invalid ' .
'Twitter OAuth access token.',
$user->nickname, $user->id);
common_log(LOG_WARNING, $errmsg);
if ($errmsg == 'The requested URL returned error: 401') { // Bad auth token! We need to delete the foreign_link
common_debug(sprintf('User %s (user id: %s) ' . // to Twitter and inform the user.
'has bad Twitter credentials!',
$user->nickname, $user->id));
// Bad credentials we need to delete the foreign_link remove_twitter_link($flink);
// to Twitter and inform the user. return true;
remove_twitter_link($flink);
return true;
} else {
// Some other error happened, so we should try to
// send again later
return false;
}
}
curl_close($ch);
if (empty($data)) {
common_debug("No data returned by Twitter's " .
"API trying to send update for $twitter_user",
__FILE__);
// XXX: Not sure this represents a failure to send, but it
// probably does
return false;
} else { } else {
// Twitter should return a status // Some other error happened, so we should probably
$status = json_decode($data); // try to send again later.
if (empty($status)) { $errmsg = sprintf('cURL error trying to send notice to Twitter ' .
common_debug("Unexpected data returned by Twitter " . 'for user %1$s (user id: %2$s) - ' .
" API trying to send update for $twitter_user", 'code: %3$s message: $4$s.',
__FILE__); $user->nickname, $user->id,
$e->getCode(), $e->getMessage());
common_log(LOG_WARNING, $errmsg);
// XXX: Again, this could represent a failure posting return false;
// or the Twitter API might just be behaving flakey.
// We're treating it as a failure to post.
return false;
}
} }
} }
if (empty($status)) {
// This could represent a failure posting,
// or the Twitter API might just be behaving flakey.
$errmsg = sprint('No data returned by Twitter API when ' .
'trying to send update for %1$s (user id %2$s).',
$user->nickname, $user->id);
common_log(LOG_WARNING, $errmsg);
return false;
}
// Notice crossed the great divide
$msg = sprintf('Twitter bridge posted notice %s to Twitter.',
$notice->id);
common_log(LOG_INFO, $msg);
}
return true; return true;
} }
@ -480,17 +448,20 @@ function remove_twitter_link($flink)
// Notify the user that her Twitter bridge is down // Notify the user that her Twitter bridge is down
if (isset($user->email)) {
$result = mail_twitter_bridge_removed($user); $result = mail_twitter_bridge_removed($user);
if (!$result) { if (!$result) {
$msg = 'Unable to send email to notify ' . $msg = 'Unable to send email to notify ' .
"$user->nickname (user id: $user->id) " . "$user->nickname (user id: $user->id) " .
'that their Twitter bridge link was ' . 'that their Twitter bridge link was ' .
'removed!'; 'removed!';
common_log(LOG_WARNING, $msg); common_log(LOG_WARNING, $msg);
} }
}
} }

View File

@ -2,6 +2,8 @@
require_once('OAuth.php'); require_once('OAuth.php');
class OAuthClientCurlException extends Exception { }
class TwitterOAuthClient class TwitterOAuthClient
{ {
public static $requestTokenURL = 'https://twitter.com/oauth/request_token'; public static $requestTokenURL = 'https://twitter.com/oauth/request_token';
@ -54,6 +56,16 @@ class TwitterOAuthClient
return $twitter_user; return $twitter_user;
} }
function statuses_update($status, $in_reply_to_status_id = null)
{
$url = 'https://twitter.com/statuses/update.json';
$params = array('status' => $status,
'in_reply_to_status_id' => $in_reply_to_status_id);
$response = $this->oAuthPost($url, $params);
$status = json_decode($response);
return $status;
}
function oAuthGet($url) function oAuthGet($url)
{ {
$request = OAuthRequest::from_consumer_and_token($this->consumer, $request = OAuthRequest::from_consumer_and_token($this->consumer,
@ -91,19 +103,26 @@ class TwitterOAuthClient
// Twitter is strict about accepting invalid "Expect" headers // Twitter is strict about accepting invalid "Expect" headers
CURLOPT_HTTPHEADER => array('Expect:') CURLOPT_HTTPHEADER => array('Expect:')
); );
if (isset($params)) { if (isset($params)) {
$options[CURLOPT_POST] = true; $options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = $params; $options[CURLOPT_POSTFIELDS] = $params;
} }
$ch = curl_init($url); $ch = curl_init($url);
curl_setopt_array($ch, $options); curl_setopt_array($ch, $options);
$response = curl_exec($ch); $response = curl_exec($ch);
curl_close($ch);
return $response; if ($response === false) {
$msg = curl_error($ch);
$code = curl_errno($ch);
throw new OAuthClientCurlException($msg, $code);
}
curl_close($ch);
return $response;
} }
} }