* (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 <http://www.gnu.org/licenses/>. */ define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..')); $helptext = <<<ENDOFHELP USAGE: initialize_notice_to_status.php Initializes the notice_to_status table with existing Twitter synch data. Only necessary if you've had the Twitter bridge enabled before version 0.9.5. ENDOFHELP; require_once INSTALLDIR . '/scripts/commandline.inc'; // 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 IS 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); } }
/** * If a notice gets deleted, remove the Notice_to_status mapping and * delete the status on Twitter. * * @param User $user The user doing the deleting * @param Notice $notice The notice getting deleted * * @return boolean hook value */ function onStartDeleteOwnNotice(User $user, Notice $notice) { $n2s = Notice_to_status::getKV('notice_id', $notice->id); if (!empty($n2s)) { $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; } try { $token = TwitterOAuthClient::unpackToken($flink->credentials); $client = new TwitterOAuthClient($token->key, $token->secret); $client->statusesDestroy($n2s->status_id); } catch (Exception $e) { common_log(LOG_ERR, "Error attempting to delete bridged notice from Twitter: " . $e->getMessage()); } $n2s->delete(); } return true; }
function saveStatus($status) { $profile = $this->ensureProfile($status->user); if (empty($profile)) { common_log(LOG_ERR, $this->name() . ' - Problem saving notice. No associated Profile.'); return null; } $statusId = twitter_id($status); $statusUri = $this->makeStatusURI($status->user->screen_name, $statusId); // check to see if we've already imported the status $n2s = Notice_to_status::staticGet('status_id', $statusId); if (!empty($n2s)) { common_log(LOG_INFO, $this->name() . " - Ignoring duplicate import: {$statusId}"); return Notice::staticGet('id', $n2s->notice_id); } // If it's a retweet, save it as a repeat! if (!empty($status->retweeted_status)) { common_log(LOG_INFO, "Status {$statusId} is a retweet of " . twitter_id($status->retweeted_status) . "."); $original = $this->saveStatus($status->retweeted_status); 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(_m('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', array('repeat_of' => $original->id, '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, $statusId); return $repeat; } } $notice = new Notice(); $notice->profile_id = $profile->id; $notice->uri = $statusUri; $notice->url = $statusUri; $notice->created = strftime('%Y-%m-%d %H:%M:%S', strtotime($status->created_at)); $notice->source = 'twitter'; $notice->reply_to = null; $replyTo = twitter_id($status, 'in_reply_to_status_id'); if (!empty($replyTo)) { common_log(LOG_INFO, "Status {$statusId} is a reply to status {$replyTo}"); $n2s = Notice_to_status::staticGet('status_id', $replyTo); if (empty($n2s)) { common_log(LOG_INFO, "Couldn't find local notice for status {$replyTo}"); } else { $reply = Notice::staticGet('id', $n2s->notice_id); if (empty($reply)) { common_log(LOG_INFO, "Couldn't find local notice for status {$replyTo}"); } else { common_log(LOG_INFO, "Found local notice {$reply->id} for status {$replyTo}"); $notice->reply_to = $reply->id; $notice->conversation = $reply->conversation; } } } if (empty($notice->conversation)) { $conv = Conversation::create(); $notice->conversation = $conv->id; common_log(LOG_INFO, "No known conversation for status {$statusId} so making a new one {$conv->id}."); } $notice->is_local = Notice::GATEWAY; $notice->content = html_entity_decode($status->text, ENT_QUOTES, 'UTF-8'); $notice->rendered = $this->linkify($status); if (Event::handle('StartNoticeSave', array(&$notice))) { $id = $notice->insert(); if (!$id) { common_log_db_error($notice, 'INSERT', __FILE__); common_log(LOG_ERR, $this->name() . ' - Problem saving notice.'); } Event::handle('EndNoticeSave', array($notice)); } Notice_to_status::saveNew($notice->id, $statusId); $this->saveStatusMentions($notice, $status); $this->saveStatusAttachments($notice, $status); $notice->blowOnInsert(); return $notice; }
/** * If a notice gets deleted, remove the Notice_to_status mapping and * delete the status on Twitter. * * @param User $user The user doing the deleting * @param Notice $notice The notice getting deleted * * @return boolean hook value */ function onStartDeleteOwnNotice(User $user, Notice $notice) { $n2s = Notice_to_status::staticGet('notice_id', $notice->id); if (!empty($n2s)) { $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; }
/** * Save a mapping between a notice and a status * Warning: status_id values may not fit in 32-bit integers. * * @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) { if (empty($notice_id)) { throw new Exception("Invalid notice_id {$notice_id}"); } $n2s = Notice_to_status::staticGet('notice_id', $notice_id); if (!empty($n2s)) { return $n2s; } if (empty($status_id)) { throw new Exception("Invalid status_id {$status_id}"); } $n2s = Notice_to_status::staticGet('status_id', $status_id); if (!empty($n2s)) { return $n2s; } common_debug("Mapping notice {$notice_id} to Twitter status {$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; }
function broadcast_oauth($notice, $flink) { $user = $flink->getUser(); $statustxt = format_status($notice); $params = twitter_update_params($notice); $token = TwitterOAuthClient::unpackToken($flink->credentials); $client = new TwitterOAuthClient($token->key, $token->secret); $status = null; try { $status = $client->statusesUpdate($statustxt, $params); if (!empty($status)) { Notice_to_status::saveNew($notice->id, twitter_id($status)); } } catch (OAuthClientException $e) { return process_error($e, $flink, $notice); } if (empty($status)) { // This could represent a failure posting, // or the Twitter API might just be behaving flakey. $errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' . 'trying to post notice %d for User %s (user id %d).', $notice->id, $user->nickname, $user->id); common_log(LOG_WARNING, $errmsg); return false; } // Notice crossed the great divide $msg = sprintf('Twitter bridge - posted notice %d to Twitter using ' . 'OAuth for User %s (user id %d).', $notice->id, $user->nickname, $user->id); common_log(LOG_INFO, $msg); return true; }