From 30eee590685349e20b4ded9127da7c19794a70be Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 3 Sep 2010 00:53:39 -0400 Subject: don't save statuses from protected users --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 7c624fdb3..964abc0d3 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -215,6 +215,13 @@ class TwitterStatusFetcher extends ParallelizingDaemon continue; } + // Don't save it if the user is protected + // FIXME: save it but treat it as private + + if ($status->user->protected) { + continue; + } + $this->saveStatus($status, $flink); } -- cgit v1.2.3-54-g00ecf From f7d69c38af60fbc984743d20340bd0fd02fd6d77 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 3 Sep 2010 01:46:02 -0400 Subject: save reply status for Twitter notices --- .../TwitterBridge/daemons/twitterstatusfetcher.php | 48 +++++++++++++++------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 964abc0d3..cf75e48f6 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -241,10 +241,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon return; } - $statusUri = 'http://twitter.com/' - . $status->user->screen_name - . '/status/' - . $status->id; + $statusUri = $this->makeStatusURI($status->user->screen_name, $status->id); // check to see if we've already imported the status @@ -270,7 +267,23 @@ class TwitterStatusFetcher extends ParallelizingDaemon ); $notice->source = 'twitter'; + $notice->reply_to = null; + + if (!empty($status->in_reply_to_status_id)) { + $replyUri = $this->makeStatusURI($status->in_reply_to_screen_name, $status->in_reply_to_status_id); + $reply = Notice::staticGet('uri', $replyUri); + if (!empty($reply)) { + $notice->reply_to = $reply->id; + $notice->conversation = $reply->conversation; + } + } + + if (empty($notice->conversation)) { + $conv = Conversation::create(); + $notice->conversation = $conv->id; + } + $notice->is_local = Notice::GATEWAY; $notice->content = common_shorten_links($status->text); @@ -292,23 +305,28 @@ class TwitterStatusFetcher extends ParallelizingDaemon Event::handle('EndNoticeSave', array($notice)); } - $orig = clone($notice); - $conv = Conversation::create(); - - $notice->conversation = $conv->id; - - if (!$notice->update($orig)) { - common_log_db_error($notice, 'UPDATE', __FILE__); - common_log(LOG_ERR, $this->name() . - ' - Problem saving notice.'); - } - Inbox::insertNotice($flink->user_id, $notice->id); $notice->blowOnInsert(); return $notice; } + /** + * Make an URI for a status. + * + * @param object $status status object + * + * @return string URI + */ + + function makeStatusURI($username, $id) + { + return 'http://twitter.com/' + . $username + . '/status/' + . $id; + } + /** * Look up a Profile by profileurl field. Profile::staticGet() was * not working consistently. -- cgit v1.2.3-54-g00ecf From 0e356d01c13408d0541b0dc04111f613c8d33120 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 3 Sep 2010 16:37:18 -0400 Subject: push notices through the bridge if they're in reply to a twitter notice --- plugins/TwitterBridge/twitter.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 306ba2442..9c2ba502b 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -115,9 +115,12 @@ function is_twitter_bound($notice, $flink) { // Check to see if notice should go to Twitter if (!empty($flink) && ($flink->noticesync & FOREIGN_NOTICE_SEND)) { - // If it's not a Twitter-style reply, or if the user WANTS to send replies. + // If it's not a Twitter-style reply, or if the user WANTS to send replies, + // or if it's in reply to a twitter notice + if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || - ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) { + ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) || + is_twitter_notice($notice->reply_to)) { return true; } } @@ -125,6 +128,18 @@ function is_twitter_bound($notice, $flink) { return false; } +function is_twitter_notice($id) +{ + $notice = Notice::staticGet('id', $id); + + if (empty($notice)) { + // it's not any kind of notice, so it's definitely not a Twitter notice. + return false; + } + + return ($notice->source == 'twitter'); +} + function broadcast_twitter($notice) { $flink = Foreign_link::getByUserID($notice->profile_id, @@ -159,7 +174,6 @@ function twitter_update_params($notice) return $params; } - function broadcast_oauth($notice, $flink) { $user = $flink->getUser(); $statustxt = format_status($notice); -- cgit v1.2.3-54-g00ecf From 8b34978892e0302e09ec471d03fabcb1cc4cf9a3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 3 Sep 2010 17:34:10 -0400 Subject: do a real retweet for a local repeat --- plugins/TwitterBridge/twitter.php | 34 ++++++++++++++++++++++++---- plugins/TwitterBridge/twitteroauthclient.php | 15 ++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 9c2ba502b..20cdf42b8 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -145,17 +145,43 @@ function broadcast_twitter($notice) $flink = Foreign_link::getByUserID($notice->profile_id, TWITTER_SERVICE); - if (is_twitter_bound($notice, $flink)) { - if (TwitterOAuthClient::isPackedToken($flink->credentials)) { + // Don't bother with basic auth, since it's no longer allowed + + if (!empty($flink) && TwitterOAuthClient::isPackedToken($flink->credentials)) { + if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) { + return retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of)); + } else if (is_twitter_bound($notice, $flink)) { return broadcast_oauth($notice, $flink); - } else { - return broadcast_basicauth($notice, $flink); } } return true; } +function retweet_notice($flink, $notice) +{ + $token = TwitterOAuthClient::unpackToken($flink->credentials); + $client = new TwitterOAuthClient($token->key, $token->secret); + + $id = twitter_status_id($notice); + + try { + $status = $client->statusesRetweet($id); + } catch (OAuthClientException $e) { + return process_error($e, $flink, $notice); + } +} + +function twitter_status_id($notice) +{ + if ($notice->source == 'twitter' && + preg_match('#^http://twitter.com/[\w_.]+/status/(\d+)$#', $notice->uri, $match)) { + return $match[1]; + } + + return null; +} + /** * Pull any extra information from a notice that we should transfer over * to Twitter beyond the notice text itself. diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index d895d8c73..5e5761360 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -277,4 +277,19 @@ class TwitterOAuthClient extends OAuthClient return $ids; } + /** + * Calls Twitter's /statuses/retweet/id.json API method + * + * @param int $id id of the notice to retweet + * + * @return retweeted status + */ + + function statusesRetweet($id) + { + $url = "http://api.twitter.com/1/statuses/retweet/$id.json"; + $response = $this->oAuthPost($url); + $status = json_decode($response); + return $status; + } } -- cgit v1.2.3-54-g00ecf From 3249370646c9af4a89be532cfee151b1bea0051f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 3 Sep 2010 17:51:28 -0400 Subject: if something's a retweet, save it as a repeat in bridge --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index cf75e48f6..848e86669 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -231,14 +231,14 @@ class TwitterStatusFetcher extends ParallelizingDaemon $flink->update(); } - function saveStatus($status, $flink) + function saveStatus($status, $flink=null) { $profile = $this->ensureProfile($status->user); if (empty($profile)) { common_log(LOG_ERR, $this->name() . ' - Problem saving notice. No associated Profile.'); - return; + return null; } $statusUri = $this->makeStatusURI($status->user->screen_name, $status->id); @@ -253,7 +253,14 @@ class TwitterStatusFetcher extends ParallelizingDaemon $this->name() . " - Ignoring duplicate import: $statusUri" ); - return; + return $dupe; + } + + // If it's a retweet, save it as a repeat! + + if (!empty($status->retweeted_status)) { + $original = $this->saveStatus($status->retweeted_status); + return $original->repeat($profile->id, 'twitter'); } $notice = new Notice(); @@ -305,7 +312,9 @@ class TwitterStatusFetcher extends ParallelizingDaemon Event::handle('EndNoticeSave', array($notice)); } - Inbox::insertNotice($flink->user_id, $notice->id); + if (!empty($flink)) { + Inbox::insertNotice($flink->user_id, $notice->id); + } $notice->blowOnInsert(); return $notice; -- cgit v1.2.3-54-g00ecf From 86e8af45a241c6cddffc8fe8789048e3933f5bd3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 11:37:34 -0400 Subject: some info notices in twitter status fetch for repeats and replies --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 848e86669..9892ffc05 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -259,8 +259,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon // If it's a retweet, save it as a repeat! if (!empty($status->retweeted_status)) { + common_log(LOG_INFO, "Status {$status->id} is a retweet of {$status->retweeted_status->id}."); $original = $this->saveStatus($status->retweeted_status); - return $original->repeat($profile->id, 'twitter'); + $repeat = $original->repeat($profile->id, 'twitter'); + common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}"); + return $repeat; } $notice = new Notice(); @@ -278,9 +281,13 @@ class TwitterStatusFetcher extends ParallelizingDaemon $notice->reply_to = null; if (!empty($status->in_reply_to_status_id)) { + common_log(LOG_INFO, "Status {$status->id} is a reply to status {$status->in_reply_to_status_id}"); $replyUri = $this->makeStatusURI($status->in_reply_to_screen_name, $status->in_reply_to_status_id); $reply = Notice::staticGet('uri', $replyUri); - if (!empty($reply)) { + if (empty($reply)) { + common_log(LOG_INFO, "Couldn't find local notice for status {$status->in_reply_to_status_id}"); + } else { + common_log(LOG_INFO, "Found local notice {$reply->id} for status {$status->in_reply_to_status_id}"); $notice->reply_to = $reply->id; $notice->conversation = $reply->conversation; } @@ -289,6 +296,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon if (empty($notice->conversation)) { $conv = Conversation::create(); $notice->conversation = $conv->id; + common_log(LOG_INFO, "No known conversation for status {$status->id} so making a new one {$conv->id}."); } $notice->is_local = Notice::GATEWAY; -- cgit v1.2.3-54-g00ecf From 60b1e4afb7c8c78463119b7d2424c861816f57be Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 11:40:33 -0400 Subject: move inbox insert code to status saver main loop --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 9892ffc05..e3f9553ff 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -222,7 +222,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon continue; } - $this->saveStatus($status, $flink); + $notice = $this->saveStatus($status); + + if (!empty($notice)) { + Inbox::insertNotice($flink->user_id, $notice->id); + } } // Okay, record the time we synced with Twitter for posterity @@ -231,7 +235,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon $flink->update(); } - function saveStatus($status, $flink=null) + function saveStatus($status) { $profile = $this->ensureProfile($status->user); @@ -320,9 +324,6 @@ class TwitterStatusFetcher extends ParallelizingDaemon Event::handle('EndNoticeSave', array($notice)); } - if (!empty($flink)) { - Inbox::insertNotice($flink->user_id, $notice->id); - } $notice->blowOnInsert(); return $notice; -- cgit v1.2.3-54-g00ecf From c307aee06e512da3e3ab1be614bc8ea5ce3d8abf Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 12:45:15 -0400 Subject: debug code to dump new status data --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index e3f9553ff..9f0f91fc9 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -260,6 +260,8 @@ class TwitterStatusFetcher extends ParallelizingDaemon return $dupe; } + common_debug("Saving status {$status->id} with data " . print_r($status, true)); + // If it's a retweet, save it as a repeat! if (!empty($status->retweeted_status)) { -- cgit v1.2.3-54-g00ecf From 45bdbcdc78cdacdacecee082871ad40cd3c342eb Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 12:54:20 -0400 Subject: switch twitterstatusfetcher from friends_timeline to home_timeline --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 9f0f91fc9..601b84ebd 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -186,7 +186,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon $timeline = null; try { - $timeline = $client->statusesFriendsTimeline(); + $timeline = $client->statusesHomeTimeline(); } catch (Exception $e) { common_log(LOG_WARNING, $this->name() . ' - Twitter client unable to get friends timeline for user ' . -- cgit v1.2.3-54-g00ecf From 93001a28a650fb87827b6b3d2cd5e47175d907ad Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 12:54:46 -0400 Subject: use home_timeline instead of friends_timeline --- plugins/TwitterBridge/twitteroauthclient.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index 5e5761360..32844a16f 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -188,7 +188,7 @@ class TwitterOAuthClient extends OAuthClient } /** - * Calls Twitter's /statuses/friends_timeline API method + * Calls Twitter's /statuses/home_timeline API method * * @param int $since_id show statuses after this id * @param int $max_id show statuses before this id @@ -197,11 +197,11 @@ class TwitterOAuthClient extends OAuthClient * * @return mixed an array of statuses */ - function statusesFriendsTimeline($since_id = null, $max_id = null, - $cnt = null, $page = null) + function statusesHomeTimeline($since_id = null, $max_id = null, + $cnt = null, $page = null) { - $url = 'https://twitter.com/statuses/friends_timeline.json'; + $url = 'https://twitter.com/statuses/home_timeline.json'; $params = array('since_id' => $since_id, 'max_id' => $max_id, 'count' => $cnt, -- cgit v1.2.3-54-g00ecf From 1f020125bf979271ff2682e1b1c95f2916e7a1ae Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 12:58:20 -0400 Subject: remove basic auth code for Twitter since it's no longer supported --- .../TwitterBridge/daemons/synctwitterfriends.php | 4 +- .../TwitterBridge/daemons/twitterstatusfetcher.php | 3 +- plugins/TwitterBridge/twitter.php | 46 ----- plugins/TwitterBridge/twitterbasicauthclient.php | 229 --------------------- 4 files changed, 3 insertions(+), 279 deletions(-) delete mode 100644 plugins/TwitterBridge/twitterbasicauthclient.php diff --git a/plugins/TwitterBridge/daemons/synctwitterfriends.php b/plugins/TwitterBridge/daemons/synctwitterfriends.php index df7da0943..5641142d3 100755 --- a/plugins/TwitterBridge/daemons/synctwitterfriends.php +++ b/plugins/TwitterBridge/daemons/synctwitterfriends.php @@ -144,8 +144,8 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon $client = new TwitterOAuthClient($token->key, $token->secret); common_debug($this->name() . '- Grabbing friends IDs with OAuth.'); } else { - $client = new TwitterBasicAuthClient($flink); - common_debug($this->name() . '- Grabbing friends IDs with basic auth.'); + common_debug("Skipping Twitter friends for {$flink->user_id} since not OAuth."); + return $friends; } try { diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 601b84ebd..dfd2d274c 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -179,8 +179,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon $client = new TwitterOAuthClient($token->key, $token->secret); common_debug($this->name() . ' - Grabbing friends timeline with OAuth.'); } else { - $client = new TwitterBasicAuthClient($flink); - common_debug($this->name() . ' - Grabbing friends timeline with basic auth.'); + common_debug("Skipping friends timeline for $flink->foreign_id since not OAuth."); } $timeline = null; diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 20cdf42b8..99ca2ada6 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -244,52 +244,6 @@ function broadcast_oauth($notice, $flink) { return true; } -function broadcast_basicauth($notice, $flink) -{ - $user = $flink->getUser(); - - $statustxt = format_status($notice); - $params = twitter_update_params($notice); - - $client = new TwitterBasicAuthClient($flink); - $status = null; - - try { - $status = $client->statusesUpdate($statustxt, $params); - } catch (BasicAuthException $e) { - return process_error($e, $flink, $notice); - } - - if (empty($status)) { - - $errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' . - 'trying to post notice %d for %s (user id %d).', - $notice->id, - $user->nickname, - $user->id); - - common_log(LOG_WARNING, $errmsg); - - $errmsg = sprintf('No data returned by Twitter API when ' . - 'trying to post notice %d for %s (user id %d).', - $notice->id, - $user->nickname, - $user->id); - common_log(LOG_WARNING, $errmsg); - return false; - } - - $msg = sprintf('Twitter bridge - posted notice %d to Twitter using ' . - 'HTTP basic auth for User %s (user id %d).', - $notice->id, - $user->nickname, - $user->id); - - common_log(LOG_INFO, $msg); - - return true; -} - function process_error($e, $flink, $notice) { $user = $flink->getUser(); diff --git a/plugins/TwitterBridge/twitterbasicauthclient.php b/plugins/TwitterBridge/twitterbasicauthclient.php deleted file mode 100644 index 2c18c9469..000000000 --- a/plugins/TwitterBridge/twitterbasicauthclient.php +++ /dev/null @@ -1,229 +0,0 @@ -. - * - * @category Integration - * @package StatusNet - * @author Zach Copley - * @copyright 2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * General Exception wrapper for HTTP basic auth errors - * - * @category Integration - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * - */ -class BasicAuthException extends Exception -{ -} - -/** - * Class for talking to the Twitter API with HTTP Basic Auth. - * - * @category Integration - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * - */ -class TwitterBasicAuthClient -{ - var $screen_name = null; - var $password = null; - - /** - * constructor - * - * @param Foreign_link $flink a Foreign_link storing the - * Twitter user's password, etc. - */ - function __construct($flink) - { - $fuser = $flink->getForeignUser(); - $this->screen_name = $fuser->nickname; - $this->password = $flink->credentials; - } - - /** - * Calls Twitter's /statuses/update API method - * - * @param string $status text of the status - * @param mixed $params optional other parameters to pass to Twitter, - * as defined. For back-compatibility, if an int - * is passed we'll consider it a reply-to ID. - * - * @return mixed the status - */ - function statusesUpdate($status, $in_reply_to_status_id = null) - { - $url = 'https://twitter.com/statuses/update.json'; - if (is_numeric($params)) { - $params = array('in_reply_to_status_id' => intval($params)); - } - $params['status'] = $status; - $params['source'] = common_config('integration', 'source'); - $response = $this->httpRequest($url, $params); - $status = json_decode($response); - return $status; - } - - /** - * Calls Twitter's /statuses/friends_timeline API method - * - * @param int $since_id show statuses after this id - * @param int $max_id show statuses before this id - * @param int $cnt number of statuses to show - * @param int $page page number - * - * @return mixed an array of statuses - */ - function statusesFriendsTimeline($since_id = null, $max_id = null, - $cnt = null, $page = null) - { - $url = 'https://twitter.com/statuses/friends_timeline.json'; - $params = array('since_id' => $since_id, - 'max_id' => $max_id, - 'count' => $cnt, - 'page' => $page); - $qry = http_build_query($params); - - if (!empty($qry)) { - $url .= "?$qry"; - } - - $response = $this->httpRequest($url); - $statuses = json_decode($response); - return $statuses; - } - - /** - * Calls Twitter's /statuses/friends API method - * - * @param int $id id of the user whom you wish to see friends of - * @param int $user_id numerical user id - * @param int $screen_name screen name - * @param int $page page number - * - * @return mixed an array of twitter users and their latest status - */ - function statusesFriends($id = null, $user_id = null, $screen_name = null, - $page = null) - { - $url = "https://twitter.com/statuses/friends.json"; - - $params = array('id' => $id, - 'user_id' => $user_id, - 'screen_name' => $screen_name, - 'page' => $page); - $qry = http_build_query($params); - - if (!empty($qry)) { - $url .= "?$qry"; - } - - $response = $this->httpRequest($url); - $friends = json_decode($response); - return $friends; - } - - /** - * Calls Twitter's /statuses/friends/ids API method - * - * @param int $id id of the user whom you wish to see friends of - * @param int $user_id numerical user id - * @param int $screen_name screen name - * @param int $page page number - * - * @return mixed a list of ids, 100 per page - */ - function friendsIds($id = null, $user_id = null, $screen_name = null, - $page = null) - { - $url = "https://twitter.com/friends/ids.json"; - - $params = array('id' => $id, - 'user_id' => $user_id, - 'screen_name' => $screen_name, - 'page' => $page); - $qry = http_build_query($params); - - if (!empty($qry)) { - $url .= "?$qry"; - } - - $response = $this->httpRequest($url); - $ids = json_decode($response); - return $ids; - } - - /** - * Make an HTTP request - * - * @param string $url Where to make the request - * @param array $params post parameters - * - * @return mixed the request - * @throws BasicAuthException - */ - function httpRequest($url, $params = null, $auth = true) - { - $request = HTTPClient::start(); - $request->setConfig(array( - 'follow_redirects' => true, - 'connect_timeout' => 120, - 'timeout' => 120, - 'ssl_verify_peer' => false, - 'ssl_verify_host' => false - )); - - if ($auth) { - $request->setAuth($this->screen_name, $this->password); - } - - if (isset($params)) { - // Twitter is strict about accepting invalid "Expect" headers - $headers = array('Expect:'); - $response = $request->post($url, $headers, $params); - } else { - $response = $request->get($url); - } - - $code = $response->getStatus(); - - if ($code < 200 || $code >= 400) { - throw new BasicAuthException($response->getBody(), $code); - } - - return $response->getBody(); - } - -} -- cgit v1.2.3-54-g00ecf From a3a6ad26d5b0ba8cbabce19b8714dba361e91c3d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 13:00:37 -0400 Subject: remove require_once for disappeared TwitterBasicAuthClient --- plugins/TwitterBridge/daemons/synctwitterfriends.php | 1 - plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 1 - plugins/TwitterBridge/twitter.php | 1 - 3 files changed, 3 deletions(-) diff --git a/plugins/TwitterBridge/daemons/synctwitterfriends.php b/plugins/TwitterBridge/daemons/synctwitterfriends.php index 5641142d3..02546a02c 100755 --- a/plugins/TwitterBridge/daemons/synctwitterfriends.php +++ b/plugins/TwitterBridge/daemons/synctwitterfriends.php @@ -33,7 +33,6 @@ END_OF_TRIM_HELP; require_once INSTALLDIR . '/scripts/commandline.inc'; require_once INSTALLDIR . '/lib/parallelizingdaemon.php'; require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php'; -require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php'; require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php'; /** diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index dfd2d274c..e5fac1fec 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -40,7 +40,6 @@ require_once INSTALLDIR . '/scripts/commandline.inc'; require_once INSTALLDIR . '/lib/common.php'; require_once INSTALLDIR . '/lib/daemon.php'; require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php'; -require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php'; require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php'; /** diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 99ca2ada6..b8e545740 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -23,7 +23,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { define('TWITTER_SERVICE', 1); // Twitter is foreign_service ID 1 -require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php'; require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php'; function add_twitter_user($twitter_id, $screen_name) -- cgit v1.2.3-54-g00ecf From cbcd811d614dda597868047cec2e59fcd9431671 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 15:05:38 -0400 Subject: do our own repeating so we can pass in a uri --- .../TwitterBridge/daemons/twitterstatusfetcher.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index e5fac1fec..4e4befe06 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -265,9 +265,23 @@ class TwitterStatusFetcher extends ParallelizingDaemon if (!empty($status->retweeted_status)) { common_log(LOG_INFO, "Status {$status->id} is a retweet of {$status->retweeted_status->id}."); $original = $this->saveStatus($status->retweeted_status); - $repeat = $original->repeat($profile->id, 'twitter'); - common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}"); - return $repeat; + if (empty($original)) { + return null; + } else { + $author = $original->getProfile(); + // TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'. + // TRANS: %1$s is the repeated user's name, %2$s is the repeated notice. + $content = sprintf(_('RT @%1$s %2$s'), + $author->nickname, + $original->content); + $repeat = Notice::saveNew($profile->id, + $content, + 'twitter', + array('repeat_of' => $original->id, + 'uri' => $statusUri)); + common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}"); + return $repeat; + } } $notice = new Notice(); -- cgit v1.2.3-54-g00ecf From 4aca91d05d428c6e9fb7541c4d627e992b221c34 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 23:00:18 -0400 Subject: add in_reply_to_status_id if notice is from twitter --- plugins/TwitterBridge/twitter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index b8e545740..33d5443c2 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -196,6 +196,10 @@ function twitter_update_params($notice) $params['lat'] = $notice->lat; $params['long'] = $notice->lon; } + if (!empty($notice->reply_to) && is_twitter_notice($notice->reply_to)) { + $reply = Notice::staticGet('id', $notice->reply_to); + $params['in_reply_to_status_id'] = twitter_status_id($reply); + } return $params; } -- cgit v1.2.3-54-g00ecf From 16b219f1efbb9ed078a279a798b60ce1ac4ed100 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 23:45:55 -0400 Subject: Save notice-to-status mapping in its own table Introduce a table mapping notices to Twitter statuses. Initialize this table at checkSchema() time. Save the mapping when we push or pull statuses. Use the table to determine if a notice has a Twitter equivalent. --- plugins/TwitterBridge/Notice_to_status.php | 166 +++++++++++++++++++++ plugins/TwitterBridge/TwitterBridgePlugin.php | 60 +++++++- .../TwitterBridge/daemons/twitterstatusfetcher.php | 2 + plugins/TwitterBridge/twitter.php | 25 ++-- 4 files changed, 236 insertions(+), 17 deletions(-) create mode 100644 plugins/TwitterBridge/Notice_to_status.php diff --git a/plugins/TwitterBridge/Notice_to_status.php b/plugins/TwitterBridge/Notice_to_status.php new file mode 100644 index 000000000..ecd4905dc --- /dev/null +++ b/plugins/TwitterBridge/Notice_to_status.php @@ -0,0 +1,166 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2010, StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; + +/** + * Data class for mapping notices to statuses + * + * Notices flow back and forth between Twitter and StatusNet. We use this + * table to remember which StatusNet notice corresponds to which Twitter + * status. + * + * Note that notice_id is unique only within a single database; if you + * want to share this data for some reason, get the notice's URI and use + * that instead, since it's universally unique. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * @see DB_DataObject + */ + +class Notice_to_status extends Memcached_DataObject +{ + public $__table = 'notice_to_status'; // table name + public $notice_id; // int(4) primary_key not_null + public $status_id; // int(4) + public $created; // datetime + + /** + * Get an instance by key + * + * This is a utility method to get a single instance with a given key value. + * + * @param string $k Key to use to lookup + * @param mixed $v Value to lookup + * + * @return Notice_to_status object found, or null for no hits + * + */ + + function staticGet($k, $v=null) + { + return Memcached_DataObject::staticGet('Notice_to_status', $k, $v); + } + + /** + * return table definition for DB_DataObject + * + * DB_DataObject needs to know something about the table to manipulate + * instances. This method provides all the DB_DataObject needs to know. + * + * @return array array of column definitions + */ + + function table() + { + return array('notice_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'status_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); + } + + /** + * return key definitions for DB_DataObject + * + * DB_DataObject needs to know about keys that the table has, since it + * won't appear in StatusNet's own keys list. In most cases, this will + * simply reference your keyTypes() function. + * + * @return array list of key field names + */ + + function keys() + { + return array_keys($this->keyTypes()); + } + + /** + * return key definitions for Memcached_DataObject + * + * Our caching system uses the same key definitions, but uses a different + * method to get them. This key information is used to store and clear + * cached data, so be sure to list any key that will be used for static + * lookups. + * + * @return array associative array of key definitions, field name to type: + * 'K' for primary key: for compound keys, add an entry for each component; + * 'U' for unique keys: compound keys are not well supported here. + */ + + function keyTypes() + { + return array('notice_id' => 'K', 'status_id' => 'U'); + } + + /** + * Magic formula for non-autoincrementing integer primary keys + * + * If a table has a single integer column as its primary key, DB_DataObject + * assumes that the column is auto-incrementing and makes a sequence table + * to do this incrementation. Since we don't need this for our class, we + * overload this method and return the magic formula that DB_DataObject needs. + * + * @return array magic three-false array that stops auto-incrementing. + */ + + function sequenceKey() + { + return array(false, false, false); + } + + /** + * Save a mapping between a notice and a status + * + * @param integer $notice_id ID of the notice in StatusNet + * @param integer $status_id ID of the status in Twitter + * + * @return Notice_to_status new object for this value + */ + + static function saveNew($notice_id, $status_id) + { + $n2s = new Notice_to_status(); + + $n2s->notice_id = $notice_id; + $n2s->status_id = $status_id; + $n2s->created = common_sql_now(); + + $n2s->insert(); + + return $n2s; + } +} diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index 8e3eba318..5676025c2 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -194,18 +194,21 @@ class TwitterBridgePlugin extends Plugin */ function onAutoload($cls) { + $dir = dirname(__FILE__); + switch ($cls) { case 'TwittersettingsAction': case 'TwitterauthorizationAction': case 'TwitterloginAction': case 'TwitteradminpanelAction': - include_once INSTALLDIR . '/plugins/TwitterBridge/' . - strtolower(mb_substr($cls, 0, -6)) . '.php'; + include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; case 'TwitterOAuthClient': case 'TwitterQueueHandler': - include_once INSTALLDIR . '/plugins/TwitterBridge/' . - strtolower($cls) . '.php'; + include_once $dir . '/' . strtolower($cls) . '.php'; + return false; + case 'Notice_to_status': + include_once $dir . '/' . $cls . '.php'; return false; default: return true; @@ -360,5 +363,52 @@ class TwitterBridgePlugin extends Plugin } } -} + /** + * Database schema setup + * + * We maintain a table mapping StatusNet notices to Twitter statuses + * + * @see Schema + * @see ColumnDef + * + * @return boolean hook value; true means continue processing, false means stop. + */ + + function onCheckSchema() + { + $schema = Schema::get(); + + // For storing user-submitted flags on profiles + + $schema->ensureTable('notice_to_status', + array(new ColumnDef('notice_id', 'integer', null, + false, 'PRI'), + new ColumnDef('status_id', 'integer', null, + false, 'UNI'), + new ColumnDef('created', 'datetime', null, + false))); + // We update any notices that may have come in from + // Twitter that we don't have a status_id for. Note that + // this won't catch notices that originated at this StatusNet site. + + $n = new Notice(); + + $n->query('SELECT notice.id, notice.uri ' . + 'FROM notice LEFT JOIN notice_to_status ' . + 'ON notice.id = notice_to_status.notice_id ' . + 'WHERE notice.source = "twitter"' . + 'AND notice_to_status.status_id = NULL'); + + while ($n->fetch()) { + if (preg_match('#^http://twitter.com/[\w_.]+/status/(\d+)$#', $n->uri, $match)) { + + $status_id = $match[1]; + + Notice_to_status::saveNew($n->id, $status_id); + } + } + + return true; + } +} diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 4e4befe06..ae66c50ae 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -280,6 +280,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon array('repeat_of' => $original->id, 'uri' => $statusUri)); common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}"); + Notice_to_status::saveNew($repeat->id, $status->id); return $repeat; } } @@ -338,6 +339,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon Event::handle('EndNoticeSave', array($notice)); } + Notice_to_status::saveNew($notice->id, $status->id); $notice->blowOnInsert(); return $notice; diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 33d5443c2..94eaedee5 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -129,14 +129,9 @@ function is_twitter_bound($notice, $flink) { function is_twitter_notice($id) { - $notice = Notice::staticGet('id', $id); + $n2s = Notice_to_status::staticGet('notice_id', $id); - if (empty($notice)) { - // it's not any kind of notice, so it's definitely not a Twitter notice. - return false; - } - - return ($notice->source == 'twitter'); + return (!empty($n2s)); } function broadcast_twitter($notice) @@ -166,6 +161,9 @@ function retweet_notice($flink, $notice) try { $status = $client->statusesRetweet($id); + if (!empty($status)) { + Notice_to_status::saveNew($notice->id, $status->id); + } } catch (OAuthClientException $e) { return process_error($e, $flink, $notice); } @@ -173,12 +171,12 @@ function retweet_notice($flink, $notice) function twitter_status_id($notice) { - if ($notice->source == 'twitter' && - preg_match('#^http://twitter.com/[\w_.]+/status/(\d+)$#', $notice->uri, $match)) { - return $match[1]; + $n2s = Notice_to_status::staticGet('notice_id', $id); + if (empty($n2s)) { + return null; + } else { + return $n2s->status_id; } - - return null; } /** @@ -214,6 +212,9 @@ function broadcast_oauth($notice, $flink) { try { $status = $client->statusesUpdate($statustxt, $params); + if (!empty($status)) { + Notice_to_status::saveNew($notice->id, $status->id); + } } catch (OAuthClientException $e) { return process_error($e, $flink, $notice); } -- cgit v1.2.3-54-g00ecf From b2bcbf4a777c1fa7af91df6041296d5814b585b2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 23:49:52 -0400 Subject: use Notice_to_status to check for duplicates --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index ae66c50ae..027e572b0 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -247,15 +247,15 @@ class TwitterStatusFetcher extends ParallelizingDaemon // check to see if we've already imported the status - $dupe = $this->checkDupe($profile, $statusUri); + $n2s = Notice_to_status::staticGet('status_id', $status->id); - if (!empty($dupe)) { + if (!empty($n2s)) { common_log( LOG_INFO, $this->name() . - " - Ignoring duplicate import: $statusUri" + " - Ignoring duplicate import: {$status->id}" ); - return $dupe; + return Notice::staticGet('id', $n2s->notice_id); } common_debug("Saving status {$status->id} with data " . print_r($status, true)); -- cgit v1.2.3-54-g00ecf From 3e8569d99f6283ba5cdf52d4f58e616ef1e2dd4a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 23:52:26 -0400 Subject: Delete Notice_to_status when a notice is deleted --- plugins/TwitterBridge/TwitterBridgePlugin.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index 5676025c2..b0f99c179 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -411,4 +411,21 @@ class TwitterBridgePlugin extends Plugin return true; } + + /** + * If a notice gets deleted, remove the Notice_to_status mapping + * + * @param Notice $notice The notice getting deleted + * + * @return boolean hook value + */ + + function onNoticeDeleteRelated($notice) + { + $n2s = Notice_to_status::staticGet('notice_id', $notice->id); + if (!empty($n2s)) { + $n2s->delete(); + } + return true; + } } -- cgit v1.2.3-54-g00ecf From f8a4a8f5bad2102c672f691a998fb15eef73f334 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Sep 2010 23:55:53 -0400 Subject: SQL syntax error when initializing notice_to_status table --- plugins/TwitterBridge/TwitterBridgePlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index b0f99c179..a13c15cc7 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -398,7 +398,7 @@ class TwitterBridgePlugin extends Plugin 'FROM notice LEFT JOIN notice_to_status ' . 'ON notice.id = notice_to_status.notice_id ' . 'WHERE notice.source = "twitter"' . - 'AND notice_to_status.status_id = NULL'); + 'AND notice_to_status.status_id IS NULL'); while ($n->fetch()) { if (preg_match('#^http://twitter.com/[\w_.]+/status/(\d+)$#', $n->uri, $match)) { -- cgit v1.2.3-54-g00ecf From 0a5e1f2d88f8841dac65e2cd0e3bc0b12ef79501 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:05:11 -0400 Subject: do a uniqueness check before saving new notice-to-status mapping --- plugins/TwitterBridge/Notice_to_status.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/TwitterBridge/Notice_to_status.php b/plugins/TwitterBridge/Notice_to_status.php index ecd4905dc..0d94927e4 100644 --- a/plugins/TwitterBridge/Notice_to_status.php +++ b/plugins/TwitterBridge/Notice_to_status.php @@ -153,6 +153,18 @@ class Notice_to_status extends Memcached_DataObject static function saveNew($notice_id, $status_id) { + $n2s = Notice_to_status::staticGet('notice_id', $notice_id); + + if (!empty($n2s)) { + return $n2s; + } + + $n2s = Notice_to_status::staticGet('status_id', $status_id); + + if (!empty($n2s)) { + return $n2s; + } + $n2s = new Notice_to_status(); $n2s->notice_id = $notice_id; -- cgit v1.2.3-54-g00ecf From 73ff960ef6e96d055038e6a1ee4d63e18b65d2bc Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:07:02 -0400 Subject: debug output when saving new mapping --- plugins/TwitterBridge/Notice_to_status.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/TwitterBridge/Notice_to_status.php b/plugins/TwitterBridge/Notice_to_status.php index 0d94927e4..2e32ba963 100644 --- a/plugins/TwitterBridge/Notice_to_status.php +++ b/plugins/TwitterBridge/Notice_to_status.php @@ -165,6 +165,8 @@ class Notice_to_status extends Memcached_DataObject return $n2s; } + common_debug("Mapping notice {$notice_id} to Twitter status {$status_id}"); + $n2s = new Notice_to_status(); $n2s->notice_id = $notice_id; -- cgit v1.2.3-54-g00ecf From 9d52d5b4f7dd0fc04f50d7d4afc5b75d009aa25b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:11:31 -0400 Subject: use bigint for status_ids --- plugins/TwitterBridge/TwitterBridgePlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index a13c15cc7..ed1732943 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -383,7 +383,7 @@ class TwitterBridgePlugin extends Plugin $schema->ensureTable('notice_to_status', array(new ColumnDef('notice_id', 'integer', null, false, 'PRI'), - new ColumnDef('status_id', 'integer', null, + new ColumnDef('status_id', 'bigint', null, // XXX: check for PostgreSQL false, 'UNI'), new ColumnDef('created', 'datetime', null, false))); -- cgit v1.2.3-54-g00ecf From 1fbc8adf476b34dfc31081dad1da7fed48666e06 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:22:37 -0400 Subject: correctly check for local notice to status mappings when notice originated here --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 027e572b0..06c59959a 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -301,14 +301,18 @@ class TwitterStatusFetcher extends ParallelizingDaemon if (!empty($status->in_reply_to_status_id)) { common_log(LOG_INFO, "Status {$status->id} is a reply to status {$status->in_reply_to_status_id}"); - $replyUri = $this->makeStatusURI($status->in_reply_to_screen_name, $status->in_reply_to_status_id); - $reply = Notice::staticGet('uri', $replyUri); - if (empty($reply)) { + $n2s = Notice_to_status::staticGet('status_id', $status->in_reply_to_status_id); + if (empty($n2s)) { common_log(LOG_INFO, "Couldn't find local notice for status {$status->in_reply_to_status_id}"); } else { - common_log(LOG_INFO, "Found local notice {$reply->id} for status {$status->in_reply_to_status_id}"); - $notice->reply_to = $reply->id; - $notice->conversation = $reply->conversation; + $reply = Notice::staticGet('id', $n2s->notice_id); + if (empty($reply)) { + common_log(LOG_INFO, "Couldn't find local notice for status {$status->in_reply_to_status_id}"); + } else { + common_log(LOG_INFO, "Found local notice {$reply->id} for status {$status->in_reply_to_status_id}"); + $notice->reply_to = $reply->id; + $notice->conversation = $reply->conversation; + } } } -- cgit v1.2.3-54-g00ecf From fdcaf7022c6ad993b8ca2e9d6a592ecf7c62b0f2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:25:58 -0400 Subject: correctly mark repeats from Twitter as non-local --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 06c59959a..6f0bddd04 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -278,7 +278,8 @@ class TwitterStatusFetcher extends ParallelizingDaemon $content, 'twitter', array('repeat_of' => $original->id, - 'uri' => $statusUri)); + 'uri' => $statusUri, + 'is_local' => Notice::GATEWAY)); common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}"); Notice_to_status::saveNew($repeat->id, $status->id); return $repeat; -- cgit v1.2.3-54-g00ecf From 981f6a47492f893f4d039fced0f66bed94a18bbc Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:32:56 -0400 Subject: truncate retweeted stuff if it's too long --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 6f0bddd04..e897cc6ea 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -274,6 +274,12 @@ class TwitterStatusFetcher extends ParallelizingDaemon $content = sprintf(_('RT @%1$s %2$s'), $author->nickname, $original->content); + + if (Notice::contentTooLong($content)) { + $contentlimit = Notice::maxContent(); + $content = mb_substr($content, 0, $contentlimit - 4) . ' ...'; + } + $repeat = Notice::saveNew($profile->id, $content, 'twitter', -- cgit v1.2.3-54-g00ecf From a29356a03051c97ba65544354269ac3acf855734 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:42:58 -0400 Subject: check status_id before trying to retweet it --- plugins/TwitterBridge/twitter.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 94eaedee5..408463354 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -143,7 +143,10 @@ function broadcast_twitter($notice) if (!empty($flink) && TwitterOAuthClient::isPackedToken($flink->credentials)) { if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) { - return retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of)); + $retweet = retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of)); + if (!empty($retweet)) { + Notice_to_status::saveNew($notice->id, $retweet->id); + } } else if (is_twitter_bound($notice, $flink)) { return broadcast_oauth($notice, $flink); } @@ -159,11 +162,14 @@ function retweet_notice($flink, $notice) $id = twitter_status_id($notice); + if (empty($id)) { + common_log(LOG_WARNING, "Trying to retweet notice {$notice->id} with no known status id."); + return null; + } + try { $status = $client->statusesRetweet($id); - if (!empty($status)) { - Notice_to_status::saveNew($notice->id, $status->id); - } + return $status; } catch (OAuthClientException $e) { return process_error($e, $flink, $notice); } -- cgit v1.2.3-54-g00ecf From 26864d14532199501745f5f0a946ee0407262397 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 00:45:45 -0400 Subject: using null variable in twitter_status_id() --- plugins/TwitterBridge/twitter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php index 408463354..90b0f0f14 100644 --- a/plugins/TwitterBridge/twitter.php +++ b/plugins/TwitterBridge/twitter.php @@ -177,7 +177,7 @@ function retweet_notice($flink, $notice) function twitter_status_id($notice) { - $n2s = Notice_to_status::staticGet('notice_id', $id); + $n2s = Notice_to_status::staticGet('notice_id', $notice->id); if (empty($n2s)) { return null; } else { -- cgit v1.2.3-54-g00ecf From 4deea8e2db5a58de74269f6a7b98d49bdbfc404a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 01:07:11 -0400 Subject: Notify Twitter when StatusNet user faves/disfaves a Twitter notice --- plugins/TwitterBridge/TwitterBridgePlugin.php | 73 +++++++++++++++++++++++++++ plugins/TwitterBridge/twitteroauthclient.php | 32 ++++++++++++ 2 files changed, 105 insertions(+) diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index ed1732943..f7d3b6659 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -428,4 +428,77 @@ class TwitterBridgePlugin extends Plugin } return true; } + + /** + * Notify remote users when their notices get favorited. + * + * @param Profile or User $profile of local user doing the faving + * @param Notice $notice being favored + * @return hook return value + */ + + function onEndFavorNotice(Profile $profile, Notice $notice) + { + $flink = Foreign_link::getByUserID($profile->id, + TWITTER_SERVICE); // twitter service + + if (empty($flink)) { + return true; + } + + if (!TwitterOAuthClient::isPackedToken($flink->credentials)) { + $this->log(LOG_INFO, "Skipping fave processing for {$profile->id} since link is not OAuth."); + return true; + } + + $status_id = twitter_status_id($notice); + + if (empty($status_id)) { + return true; + } + + $token = TwitterOAuthClient::unpackToken($flink->credentials); + $client = new TwitterOAuthClient($token->key, $token->secret); + + $client->favoritesCreate($status_id); + + return true; + } + + /** + * Notify remote users when their notices get de-favorited. + * + * @param Profile $profile Profile person doing the de-faving + * @param Notice $notice Notice being favored + * + * @return hook return value + */ + + function onEndDisfavorNotice(Profile $profile, Notice $notice) + { + $flink = Foreign_link::getByUserID($profile->id, + TWITTER_SERVICE); // twitter service + + if (empty($flink)) { + return true; + } + + if (!TwitterOAuthClient::isPackedToken($flink->credentials)) { + $this->log(LOG_INFO, "Skipping fave processing for {$profile->id} since link is not OAuth."); + return true; + } + + $status_id = twitter_status_id($notice); + + if (empty($status_id)) { + return true; + } + + $token = TwitterOAuthClient::unpackToken($flink->credentials); + $client = new TwitterOAuthClient($token->key, $token->secret); + + $client->favoritesDestroy($status_id); + + return true; + } } diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index 32844a16f..22ccaba07 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -292,4 +292,36 @@ class TwitterOAuthClient extends OAuthClient $status = json_decode($response); return $status; } + + /** + * Calls Twitter's /favorites/create API method + * + * @param int $id ID of the status to favorite + * + * @return object faved status + */ + + function favoritesCreate($id) + { + $url = "http://api.twitter.com/1/favorites/create/$id.json"; + $response = $this->oAuthPost($url); + $status = json_decode($response); + return $status; + } + + /** + * Calls Twitter's /favorites/destroy API method + * + * @param int $id ID of the status to unfavorite + * + * @return object unfaved status + */ + + function favoritesDestroy($id) + { + $url = "http://api.twitter.com/1/favorites/destroy/$id.json"; + $response = $this->oAuthPost($url); + $status = json_decode($response); + return $status; + } } -- cgit v1.2.3-54-g00ecf From 32f33320070a6c518ea470cf1bb1d813d764ca9c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 01:17:56 -0400 Subject: delete Twitter notice if it was posted from here --- plugins/TwitterBridge/TwitterBridgePlugin.php | 26 ++++++++++++++++++++++++++ plugins/TwitterBridge/twitteroauthclient.php | 16 ++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index f7d3b6659..bad6a3941 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -423,7 +423,33 @@ class TwitterBridgePlugin extends Plugin function onNoticeDeleteRelated($notice) { $n2s = Notice_to_status::staticGet('notice_id', $notice->id); + if (!empty($n2s)) { + + $user = common_current_user(); + + if (empty($user) || $user->id != $notice->profile_id) { + $this->log(LOG_INFO, "Skipping deleting notice for {$notice->id} since it doesn't seem to be by the author."); + return true; + } + + $flink = Foreign_link::getByUserID($notice->profile_id, + TWITTER_SERVICE); // twitter service + + if (empty($flink)) { + return true; + } + + if (!TwitterOAuthClient::isPackedToken($flink->credentials)) { + $this->log(LOG_INFO, "Skipping deleting notice for {$notice->id} since link is not OAuth."); + return true; + } + + $token = TwitterOAuthClient::unpackToken($flink->credentials); + $client = new TwitterOAuthClient($token->key, $token->secret); + + $client->statusesDestroy($n2s->status_id); + $n2s->delete(); } return true; diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index 22ccaba07..0f5e4dbda 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -324,4 +324,20 @@ class TwitterOAuthClient extends OAuthClient $status = json_decode($response); return $status; } + + /** + * Calls Twitter's /statuses/destroy API method + * + * @param int $id ID of the status to destroy + * + * @return object destroyed + */ + + function statusesDestroy($id) + { + $url = "http://api.twitter.com/1/statuses/destroy/$id.json"; + $response = $this->oAuthPost($url); + $status = json_decode($response); + return $status; + } } -- cgit v1.2.3-54-g00ecf From 865075e6488760426032c236423790ae60f91659 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 01:25:48 -0400 Subject: include entities in the results of home_timeline --- plugins/TwitterBridge/twitteroauthclient.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index 0f5e4dbda..0d27e5990 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -205,7 +205,8 @@ class TwitterOAuthClient extends OAuthClient $params = array('since_id' => $since_id, 'max_id' => $max_id, 'count' => $cnt, - 'page' => $page); + 'page' => $page, + 'include_entities' => 1); $qry = http_build_query($params); if (!empty($qry)) { -- cgit v1.2.3-54-g00ecf From 76f42ba83fbfdbd74bef4b800c4b6c89b00c0480 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 01:40:15 -0400 Subject: better param handling in hometimeline --- plugins/TwitterBridge/twitteroauthclient.php | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index 0d27e5990..5d10d8f71 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -202,12 +202,23 @@ class TwitterOAuthClient extends OAuthClient { $url = 'https://twitter.com/statuses/home_timeline.json'; - $params = array('since_id' => $since_id, - 'max_id' => $max_id, - 'count' => $cnt, - 'page' => $page, - 'include_entities' => 1); - $qry = http_build_query($params); + + $params = array('include_entities' => 'true'); + + if (!empty($since_id)) { + $params['since_id'] = $since_id; + } + if (!empty($max_id)) { + $params['max_id'] = $max_id; + } + if (!empty($cnt)) { + $params['count'] = $cnt; + } + if (!empty($page)) { + $params['page'] = $page; + } + + $qry = http_build_query($params); if (!empty($qry)) { $url .= "?$qry"; -- cgit v1.2.3-54-g00ecf From 5bcfd62eea6d0f6f53d0020aa075a727b7ec294a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 01:49:49 -0400 Subject: better handling of params in oauthget --- plugins/TwitterBridge/twitteroauthclient.php | 56 ++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index 5d10d8f71..876e30425 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -218,13 +218,7 @@ class TwitterOAuthClient extends OAuthClient $params['page'] = $page; } - $qry = http_build_query($params); - - if (!empty($qry)) { - $url .= "?$qry"; - } - - $response = $this->oAuthGet($url); + $response = $this->oAuthGet($url, $params); $statuses = json_decode($response); return $statuses; } @@ -244,17 +238,25 @@ class TwitterOAuthClient extends OAuthClient { $url = "https://twitter.com/statuses/friends.json"; - $params = array('id' => $id, - 'user_id' => $user_id, - 'screen_name' => $screen_name, - 'page' => $page); - $qry = http_build_query($params); + $params = array(); + + if (!empty($id)) { + $params['id'] = $id; + } + + if (!empty($user_id)) { + $params['user_id'] = $user_id; + } - if (!empty($qry)) { - $url .= "?$qry"; + if (!empty($screen_name)) { + $params['screen_name'] = $screen_name; } - $response = $this->oAuthGet($url); + if (!empty($page)) { + $params['page'] = $page; + } + + $response = $this->oAuthGet($url, $params); $friends = json_decode($response); return $friends; } @@ -274,17 +276,25 @@ class TwitterOAuthClient extends OAuthClient { $url = "https://twitter.com/friends/ids.json"; - $params = array('id' => $id, - 'user_id' => $user_id, - 'screen_name' => $screen_name, - 'page' => $page); - $qry = http_build_query($params); + $params = array(); + + if (!empty($id)) { + $params['id'] = $id; + } + + if (!empty($user_id)) { + $params['user_id'] = $user_id; + } - if (!empty($qry)) { - $url .= "?$qry"; + if (!empty($screen_name)) { + $params['screen_name'] = $screen_name; + } + + if (!empty($page)) { + $params['page'] = $page; } - $response = $this->oAuthGet($url); + $response = $this->oAuthGet($url, $params); $ids = json_decode($response); return $ids; } -- cgit v1.2.3-54-g00ecf From 3da2b316525a95ef965a07a0fe9acbb4681fc02c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 13:16:04 -0400 Subject: add Twitter-approved links to Twitter statuses --- .../TwitterBridge/daemons/twitterstatusfetcher.php | 85 ++++++++++++++++++++-- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index e897cc6ea..45cb17855 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -331,11 +331,8 @@ class TwitterStatusFetcher extends ParallelizingDaemon $notice->is_local = Notice::GATEWAY; - $notice->content = common_shorten_links($status->text); - $notice->rendered = common_render_content( - $notice->content, - $notice - ); + $notice->content = html_entity_decode($status->text); + $notice->rendered = $this->linkify($status); if (Event::handle('StartNoticeSave', array(&$notice))) { @@ -701,6 +698,84 @@ class TwitterStatusFetcher extends ParallelizingDaemon return true; } + + const URL = 1; + const HASHTAG = 2; + const MENTION = 3; + + function linkify($status) + { + $text = $status->text; + + if (empty($status->entities)) { + return $text; + } + + // Move all the entities into order so we can + // replace them in reverse order and thus + // not mess up their indices + + $toReplace = array(); + + if (!empty($status->entities->urls)) { + foreach ($status->entities->urls as $url) { + $toReplace[$url->indices[0]] = array(self::URL, $url); + } + } + + if (!empty($status->entities->hashtags)) { + foreach ($status->entities->hashtags as $hashtag) { + $toReplace[$hashtag->indices[0]] = array(self::HASHTAG, $hashtag); + } + } + + if (!empty($status->entities->user_mentions)) { + foreach ($status->entities->user_mentions as $mention) { + $toReplace[$mention->indices[0]] = array(self::MENTION, $mention); + } + } + + // sort in reverse order by key + + krsort($toReplace); + + foreach ($toReplace as $part) { + list($type, $object) = $part; + switch($type) { + case self::URL: + $linkText = $this->makeUrlLink($object); + break; + case self::HASHTAG: + $linkText = $this->makeHashtagLink($object); + break; + case self::MENTION: + $linkText = $this->makeMentionLink($object); + break; + default: + continue; + } + $text = substr_replace($text, + $linkText, + $object->indices[0], + $object->indices[1] - $object->indices[0]); + } + return $text; + } + + function makeUrlLink($object) + { + return "{$object->url}"; + } + + function makeHashtagLink($object) + { + return "{$object->text}"; + } + + function makeMentionLink($object) + { + return "{$object->screen_name}"; + } } $id = null; -- cgit v1.2.3-54-g00ecf From 033712b1f2afcb6f29b3a1bd10544cc323af9da3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 5 Sep 2010 13:19:49 -0400 Subject: add back in # and @ for links --- plugins/TwitterBridge/daemons/twitterstatusfetcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index 45cb17855..b310b8f36 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -769,12 +769,12 @@ class TwitterStatusFetcher extends ParallelizingDaemon function makeHashtagLink($object) { - return "{$object->text}"; + return "#{$object->text}"; } function makeMentionLink($object) { - return "{$object->screen_name}"; + return "@{$object->screen_name}"; } } -- cgit v1.2.3-54-g00ecf From 8e131652d675e9855bc26484f4d996944fc62337 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 6 Sep 2010 08:54:04 -0400 Subject: save Twitter mentions as StatusNet replies --- .../TwitterBridge/daemons/twitterstatusfetcher.php | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index b310b8f36..e092cd1dd 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -348,6 +348,9 @@ class TwitterStatusFetcher extends ParallelizingDaemon } Notice_to_status::saveNew($notice->id, $status->id); + + $this->saveStatusMentions($notice, $status); + $notice->blowOnInsert(); return $notice; @@ -776,6 +779,29 @@ class TwitterStatusFetcher extends ParallelizingDaemon { return "@{$object->screen_name}"; } + + function saveStatusMentions($notice, $status) + { + $mentions = array(); + + if (empty($status->entities) || empty($status->entities->user_mentions)) { + return; + } + + foreach ($status->entities->user_mentions as $mention) { + $flink = Foreign_link::getByForeignID($mention->id, TWITTER_SERVICE); + if (!empty($flink)) { + $user = User::staticGet('id', $flink->user_id); + if (!empty($user)) { + $reply = new Reply(); + $reply->notice_id = $notice->id; + $reply->profile_id = $user->id; + common_log(LOG_INFO, __METHOD__ . ": saving reply: notice {$notice->id} to profile {$user->id}"); + $id = $reply->insert(); + } + } + } + } } $id = null; -- cgit v1.2.3-54-g00ecf