diff options
-rw-r--r-- | actions/twitapiaccount.php | 19 | ||||
-rw-r--r-- | actions/twitapiblocks.php | 10 | ||||
-rw-r--r-- | actions/twitapidirect_messages.php | 76 | ||||
-rw-r--r-- | actions/twitapifavorites.php | 80 | ||||
-rw-r--r-- | actions/twitapifriendships.php | 36 | ||||
-rw-r--r-- | actions/twitapihelp.php | 4 | ||||
-rw-r--r-- | actions/twitapistatuses.php | 399 | ||||
-rw-r--r-- | actions/twitapiusers.php | 13 | ||||
-rw-r--r-- | lib/twitterapi.php | 95 |
9 files changed, 360 insertions, 372 deletions
diff --git a/actions/twitapiaccount.php b/actions/twitapiaccount.php index 8b956f897..b5e7b91da 100644 --- a/actions/twitapiaccount.php +++ b/actions/twitapiaccount.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -51,7 +53,8 @@ class TwitapiaccountAction extends TwitterapiAction parent::handle($args); if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } @@ -60,24 +63,20 @@ class TwitapiaccountAction extends TwitterapiAction if (!is_null($location) && mb_strlen($location) > 255) { // XXX: But Twitter just truncates and runs with it. -- Zach - $this->clientError(_('That\'s too long. Max notice size is 255 chars.'), 406, $apidate['content-type']); + $this->clientError(_('That\'s too long. Max notice size is 255 chars.'), + 406, $apidate['content-type']); return; } - $user = $apidata['user']; + $user = $apidata['user']; // Always the auth user $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - $orig_profile = clone($profile); $profile->location = $location; $result = $profile->update($orig_profile); - if (!$result) { + if (empty($result)) { common_log_db_error($profile, 'UPDATE', __FILE__); $this->serverError(_('Couldn\'t save profile.')); return; diff --git a/actions/twitapiblocks.php b/actions/twitapiblocks.php index 8135adef3..0e3509162 100644 --- a/actions/twitapiblocks.php +++ b/actions/twitapiblocks.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -31,12 +33,12 @@ class TwitapiblocksAction extends TwitterapiAction $blockee = $this->get_user($apidata['api_arg'], $apidata); - if (!$blockee) { + if (empty($blockee)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } - $user = $apidata['user']; + $user = $apidata['user']; // Always the auth user if ($user->hasBlocked($blockee) || $user->block($blockee)) { $type = $apidata['content-type']; @@ -53,7 +55,7 @@ class TwitapiblocksAction extends TwitterapiAction parent::handle($args); $blockee = $this->get_user($apidata['api_arg'], $apidata); - if (!$blockee) { + if (empty($blockee)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php index d2dbdb619..85c788d6a 100644 --- a/actions/twitapidirect_messages.php +++ b/actions/twitapidirect_messages.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -38,42 +40,34 @@ class Twitapidirect_messagesAction extends TwitterapiAction function show_messages($args, $apidata, $type) { - $user = $apidata['user']; - - $count = $this->arg('count'); - $since = $this->arg('since'); - $since_id = $this->arg('since_id'); - $max_id = $this->arg('max_id'); - - $page = $this->arg('page'); - - if (!$page) { - $page = 1; - } + $user = $apidata['user']; // Always the auth user - if (!$count) { - $count = 20; - } - - $message = new Message(); - - $title = null; + $message = new Message(); + $title = null; $subtitle = null; - $link = null; - $server = common_root_url(); + $link = null; + $server = common_root_url(); if ($type == 'received') { $message->to_profile = $user->id; $title = sprintf(_("Direct messages to %s"), $user->nickname); - $subtitle = sprintf(_("All the direct messages sent to %s"), $user->nickname); + $subtitle = sprintf(_("All the direct messages sent to %s"), + $user->nickname); $link = $server . $user->nickname . '/inbox'; } else { $message->from_profile = $user->id; $title = _('Direct Messages You\'ve Sent'); - $subtitle = sprintf(_("All the direct messages sent from %s"), $user->nickname); + $subtitle = sprintf(_("All the direct messages sent from %s"), + $user->nickname); $link = $server . $user->nickname . '/outbox'; } + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); + if ($max_id) { $message->whereAdd("id <= $max_id"); } @@ -82,25 +76,23 @@ class Twitapidirect_messagesAction extends TwitterapiAction $message->whereAdd("id > $since_id"); } - $since = strtotime($this->arg('since')); - if ($since) { $d = date('Y-m-d H:i:s', $since); $message->whereAdd("created > '$d'"); } $message->orderBy('created DESC, id DESC'); - $message->limit((($page-1)*20), $count); + $message->limit((($page-1)*$count), $count); $message->find(); switch($apidata['content-type']) { - case 'xml': + case 'xml': $this->show_xml_dmsgs($message); break; - case 'rss': + case 'rss': $this->show_rss_dmsgs($message, $title, $link, $subtitle); break; - case 'atom': + case 'atom': $selfuri = common_root_url() . 'api/direct_messages'; $selfuri .= ($type == 'received') ? '.atom' : '/sent.atom'; $taguribase = common_config('integration', 'taguri'); @@ -111,12 +103,13 @@ class Twitapidirect_messagesAction extends TwitterapiAction $id = "tag:$taguribase:DirectMessages:" . $user->id; } - $this->show_atom_dmsgs($message, $title, $link, $subtitle, $selfuri, $id); + $this->show_atom_dmsgs($message, $title, $link, $subtitle, + $selfuri, $id); break; - case 'json': + case 'json': $this->show_json_dmsgs($message); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -128,22 +121,24 @@ class Twitapidirect_messagesAction extends TwitterapiAction parent::handle($args); if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } $user = $apidata['user']; - $source = $this->trimmed('source'); // Not supported by Twitter. + $source = $this->trimmed('source'); // Not supported by Twitter. $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - if (!$source || in_array($source, $reserved_sources)) { + if (empty($source) || in_array($source, $reserved_sources)) { $source = 'api'; } $content = $this->trimmed('text'); - if (!$content) { - $this->clientError(_('No message text!'), $code = 406, $apidata['content-type']); + if (empty($content)) { + $this->clientError(_('No message text!'), + $code = 406, $apidata['content-type']); } else { $content_shortened = common_shorten_links($content); if (mb_strlen($content_shortened) > 140) { @@ -155,8 +150,9 @@ class Twitapidirect_messagesAction extends TwitterapiAction $other = $this->get_user($this->trimmed('user')); - if (!$other) { - $this->clientError(_('Recipient user not found.'), $code = 403, $apidata['content-type']); + if (empty($other)) { + $this->clientError(_('Recipient user not found.'), + $code = 403, $apidata['content-type']); return; } else if (!$user->mutuallySubscribed($other)) { $this->clientError(_('Can\'t send direct messages to users who aren\'t your friend.'), diff --git a/actions/twitapifavorites.php b/actions/twitapifavorites.php index 31dce341b..8656adbe8 100644 --- a/actions/twitapifavorites.php +++ b/actions/twitapifavorites.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -31,50 +33,39 @@ class TwitapifavoritesAction extends TwitterapiAction $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - if (!$user) { + if (empty($user)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - - $page = $this->arg('page'); - - if (!$page) { - $page = 1; - } - - if (!$count) { - $count = 20; - } + $sitename = common_config('site', 'name'); + $title = sprintf(_('%s / Favorites from %s'), $sitename, + $user->nickname); + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:Favorites:".$user->id; + $link = common_local_url('favorites', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('%s updates favorited by %s / %s.'), $sitename, + $profile->getBestName(), $user->nickname); - $notice = $user->favoriteNotices((($page-1)*20), $count); + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - if (!$notice) { - $this->serverError(_('Could not retrieve favorite notices.')); - return; - } - - $sitename = common_config('site', 'name'); - $title = sprintf(_('%s / Favorites from %s'), $sitename, $user->nickname); - $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:Favorites:".$user->id; - $link = common_local_url('favorites', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('%s updates favorited by %s / %s.'), $sitename, $profile->getBestName(), $user->nickname); + $notice = $user->favoriteNotices(($page-1)*$count, $count); switch($apidata['content-type']) { - case 'xml': + case 'xml': $this->show_xml_timeline($notice); break; - case 'rss': + case 'rss': $this->show_rss_timeline($notice, $title, $link, $subtitle); break; - case 'atom': + case 'atom': if (isset($apidata['api_arg'])) { $selfuri = $selfuri = common_root_url() . 'api/favorites/' . $apidata['api_arg'] . '.atom'; @@ -82,12 +73,13 @@ class TwitapifavoritesAction extends TwitterapiAction $selfuri = $selfuri = common_root_url() . 'api/favorites.atom'; } - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, null, $selfuri); break; - case 'json': + case 'json': $this->show_json_timeline($notice); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -100,7 +92,8 @@ class TwitapifavoritesAction extends TwitterapiAction // Check for RESTfulness if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { // XXX: Twitter just prints the err msg, no XML / JSON. - $this->clientError(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST or DELETE.'), + 400, $apidata['content-type']); return; } @@ -109,25 +102,27 @@ class TwitapifavoritesAction extends TwitterapiAction return; } - $this->auth_user = $apidata['user']; - $user = $this->auth_user; + $user = $apidata['user']; // Always the auth user + $notice_id = $apidata['api_arg']; $notice = Notice::staticGet($notice_id); - if (!$notice) { - $this->clientError(_('No status found with that ID.'), 404, $apidata['content-type']); + if (empty($notice)) { + $this->clientError(_('No status found with that ID.'), + 404, $apidata['content-type']); return; } // XXX: Twitter lets you fave things repeatedly via api. if ($user->hasFave($notice)) { - $this->clientError(_('This notice is already a favorite!'), 403, $apidata['content-type']); + $this->clientError(_('This notice is already a favorite!'), + 403, $apidata['content-type']); return; } $fave = Fave::addNew($user, $notice); - if (!$fave) { + if (empty($fave)) { $this->serverError(_('Could not create favorite.')); return; } @@ -149,7 +144,8 @@ class TwitapifavoritesAction extends TwitterapiAction $this->serverError(_('API method under construction.'), $code=501); } - // XXX: these two funcs swiped from faves. Maybe put in util.php, or some common base class? + // XXX: these two funcs swiped from faves. + // Maybe put in util.php, or some common base class? function notify($fave, $notice, $user) { diff --git a/actions/twitapifriendships.php b/actions/twitapifriendships.php index 2f8250e0d..b1c277748 100644 --- a/actions/twitapifriendships.php +++ b/actions/twitapifriendships.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -29,23 +31,25 @@ class TwitapifriendshipsAction extends TwitterapiAction parent::handle($args); if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } - $id = $apidata['api_arg']; - + $id = $apidata['api_arg']; $other = $this->get_user($id); - if (!$other) { - $this->clientError(_('Could not follow user: User not found.'), 403, $apidata['content-type']); + if (empty($other)) { + $this->clientError(_('Could not follow user: User not found.'), + 403, $apidata['content-type']); return; } $user = $apidata['user']; if ($user->isSubscribed($other)) { - $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), $other->nickname); + $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), + $other->nickname); $this->clientError($errmsg, 403, $apidata['content-type']); return; } @@ -60,8 +64,9 @@ class TwitapifriendshipsAction extends TwitterapiAction $result = $sub->insert(); - if (!$result) { - $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), $other->nickname); + if (empty($result)) { + $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), + $other->nickname); $this->clientError($errmsg, 400, $apidata['content-type']); return; } @@ -82,7 +87,8 @@ class TwitapifriendshipsAction extends TwitterapiAction parent::handle($args); if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { - $this->clientError(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST or DELETE.'), + 400, $apidata['content-type']); return; } @@ -91,7 +97,7 @@ class TwitapifriendshipsAction extends TwitterapiAction # We can't subscribe to a remote person, but we can unsub $other = $this->get_profile($id); - $user = $apidata['user']; + $user = $apidata['user']; // Alwyas the auth user $sub = new Subscription(); $sub->subscriber = $user->id; @@ -102,7 +108,8 @@ class TwitapifriendshipsAction extends TwitterapiAction $sub->delete(); $sub->query('COMMIT'); } else { - $this->clientError(_('You are not friends with the specified user.'), 403, $apidata['content-type']); + $this->clientError(_('You are not friends with the specified user.'), + 403, $apidata['content-type']); return; } @@ -128,8 +135,9 @@ class TwitapifriendshipsAction extends TwitterapiAction $user_a = $this->get_user($user_a_id); $user_b = $this->get_user($user_b_id); - if (!$user_a || !$user_b) { - $this->clientError(_('Two user ids or screen_names must be supplied.'), 400, $apidata['content-type']); + if (empty($user_a) || empty($user_b)) { + $this->clientError(_('Two user ids or screen_names must be supplied.'), + 400, $apidata['content-type']); return; } diff --git a/actions/twitapihelp.php b/actions/twitapihelp.php index db5892baf..bdef1314a 100644 --- a/actions/twitapihelp.php +++ b/actions/twitapihelp.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 1fbde6639..94f624afb 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -26,64 +28,45 @@ class TwitapistatusesAction extends TwitterapiAction function public_timeline($args, $apidata) { - parent::handle($args); - - $sitename = common_config('site', 'name'); - $title = sprintf(_("%s public timeline"), $sitename); - - $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:PublicTimeline"; - $link = common_root_url(); - - $subtitle = sprintf(_("%s updates from everyone!"), $sitename); - - // Number of public statuses to return by default -- Twitter sends 20 - $MAX_PUBSTATUSES = 20; - - // FIXME: To really live up to the spec we need to build a list + // XXX: To really live up to the spec we need to build a list // of notices by users who have custom avatars, so fix this SQL -- Zach - $page = $this->arg('page'); - $since_id = $this->arg('since_id'); - $max_id = $this->arg('max_id'); - - if (!$page) { - $page = 1; - } - if (!$since_id) { - $since_id = 0; - } - if (!$max_id) { - $max_id = 0; - } + parent::handle($args); - $since = strtotime($this->arg('since')); + $sitename = common_config('site', 'name'); + $title = sprintf(_("%s public timeline"), $sitename); + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:PublicTimeline"; + $link = common_root_url(); + $subtitle = sprintf(_("%s updates from everyone!"), $sitename); - $notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $max_id, $since); + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - if ($notice) { + $notice = Notice::publicStream(($page-1)*$count, $count, $since_id, + $max_id, $since); - switch($apidata['content-type']) { - case 'xml': - $this->show_xml_timeline($notice); - break; - case 'rss': - $this->show_rss_timeline($notice, $title, $link, $subtitle); - break; - case 'atom': - $selfuri = common_root_url() . 'api/statuses/public_timeline.atom'; - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); - break; - case 'json': - $this->show_json_timeline($notice); - break; - default: - $this->clientError(_('API method not found!'), $code = 404); - break; - } - - } else { - $this->serverError(_('Couldn\'t find any statuses.'), $code = 503); + switch($apidata['content-type']) { + case 'xml': + $this->show_xml_timeline($notice); + break; + case 'rss': + $this->show_rss_timeline($notice, $title, $link, $subtitle); + break; + case 'atom': + $selfuri = common_root_url() . 'api/statuses/public_timeline.atom'; + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, null, $selfuri); + break; + case 'json': + $this->show_json_timeline($notice); + break; + default: + $this->clientError(_('API method not found!'), $code = 404); + break; } } @@ -92,68 +75,57 @@ class TwitapistatusesAction extends TwitterapiAction { parent::handle($args); - $since = $this->arg('since'); - $since_id = $this->arg('since_id'); - $count = $this->arg('count'); - $page = $this->arg('page'); - $max_id = $this->arg('max_id'); - - if (!$page) { - $page = 1; - } - - if (!$count) { - $count = 20; - } - - if (!$since_id) { - $since_id = 0; - } - - if (!$max_id) { - $max_id = 0; - } - - $since = strtotime($this->arg('since')); $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $user; if (empty($user)) { - $this->clientError(_('No such user!'), 404, $apidata['content-type']); + $this->clientError(_('No such user!'), 404, + $apidata['content-type']); return; } - $profile = $user->getProfile(); - $sitename = common_config('site', 'name'); - $title = sprintf(_("%s and friends"), $user->nickname); + $profile = $user->getProfile(); + $sitename = common_config('site', 'name'); + $title = sprintf(_("%s and friends"), $user->nickname); $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:FriendsTimeline:" . $user->id; - $link = common_local_url('all', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename); + $id = "tag:$taguribase:FriendsTimeline:" . $user->id; + $link = common_local_url('all', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), + $user->nickname, $sitename); + + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - $notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $max_id, $since); + $notice = $user->noticesWithFriends(($page-1)*$count, + $count, $since_id, $max_id,$since); switch($apidata['content-type']) { - case 'xml': + case 'xml': $this->show_xml_timeline($notice); break; - case 'rss': + case 'rss': $this->show_rss_timeline($notice, $title, $link, $subtitle); break; - case 'atom': + case 'atom': if (isset($apidata['api_arg'])) { $selfuri = common_root_url() . - 'api/statuses/friends_timeline/' . $apidata['api_arg'] . '.atom'; + 'api/statuses/friends_timeline/' . + $apidata['api_arg'] . '.atom'; } else { $selfuri = common_root_url() . 'api/statuses/friends_timeline.atom'; } - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, null, $selfuri); break; - case 'json': + case 'json': $this->show_json_timeline($notice); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -166,48 +138,21 @@ class TwitapistatusesAction extends TwitterapiAction $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - if (!$user) { + if (empty($user)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - - $count = $this->arg('count'); - $since = $this->arg('since'); - $since_id = $this->arg('since_id'); - $page = $this->arg('page'); - $max_id = $this->arg('max_id'); - - if (!$page) { - $page = 1; - } - - if (!$count) { - $count = 20; - } - - if (!$since_id) { - $since_id = 0; - } - - if (!$max_id) { - $max_id = 0; - } - - $since = strtotime($this->arg('since')); - - $sitename = common_config('site', 'name'); - $title = sprintf(_("%s timeline"), $user->nickname); + $sitename = common_config('site', 'name'); + $title = sprintf(_("%s timeline"), $user->nickname); $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:UserTimeline:".$user->id; - $link = common_local_url('showstream', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('Updates from %1$s on %2$s!'), $user->nickname, $sitename); + $id = "tag:$taguribase:UserTimeline:".$user->id; + $link = common_local_url('showstream', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('Updates from %1$s on %2$s!'), + $user->nickname, $sitename); # FriendFeed's SUP protocol # Also added RSS and Atom feeds @@ -215,26 +160,34 @@ class TwitapistatusesAction extends TwitterapiAction $suplink = common_local_url('sup', null, null, $user->id); header('X-SUP-ID: '.$suplink); - # XXX: since + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - $notice = $user->getNotices((($page-1)*20), $count, $since_id, $max_id, $since); + $notice = $user->getNotices(($page-1)*$count, + $count, $since_id, $max_id, $since); switch($apidata['content-type']) { case 'xml': $this->show_xml_timeline($notice); break; case 'rss': - $this->show_rss_timeline($notice, $title, $link, $subtitle, $suplink); + $this->show_rss_timeline($notice, $title, $link, + $subtitle, $suplink); break; case 'atom': if (isset($apidata['api_arg'])) { $selfuri = common_root_url() . - 'api/statuses/user_timeline/' . $apidata['api_arg'] . '.atom'; + 'api/statuses/user_timeline/' . + $apidata['api_arg'] . '.atom'; } else { $selfuri = common_root_url() . 'api/statuses/user_timeline.atom'; } - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri); + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, $suplink, $selfuri); break; case 'json': $this->show_json_timeline($notice); @@ -247,7 +200,6 @@ class TwitapistatusesAction extends TwitterapiAction function update($args, $apidata) { - parent::handle($args); if (!in_array($apidata['content-type'], array('xml', 'json'))) { @@ -256,21 +208,24 @@ class TwitapistatusesAction extends TwitterapiAction } if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } - $this->auth_user = $apidata['user']; - $user = $this->auth_user; + $user = $apidata['user']; // Always the auth user + $status = $this->trimmed('status'); $source = $this->trimmed('source'); - $in_reply_to_status_id = intval($this->trimmed('in_reply_to_status_id')); + $in_reply_to_status_id = + intval($this->trimmed('in_reply_to_status_id')); $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - if (!$source || in_array($source, $reserved_sources)) { + + if (empty($source) || in_array($source, $reserved_sources)) { $source = 'api'; } - if (!$status) { + if (empty($status)) { // XXX: Note: In this case, Twitter simply returns '200 OK' // No error is given, but the status is not posted to the @@ -288,9 +243,9 @@ class TwitapistatusesAction extends TwitterapiAction // as "truncated." Sending this error may screw up some clients // that assume Twitter will truncate for them. Should we just // truncate too? -- Zach - $this->clientError(_('That\'s too long. Max notice size is 140 chars.'), $code = 406, $apidata['content-type']); + $this->clientError(_('That\'s too long. Max notice size is 140 chars.'), + $code = 406, $apidata['content-type']); return; - } } @@ -321,13 +276,15 @@ class TwitapistatusesAction extends TwitterapiAction if ($reply) { $reply_to = $in_reply_to_status_id; } else { - $this->clientError(_('Not found'), $code = 404, $apidata['content-type']); + $this->clientError(_('Not found'), $code = 404, + $apidata['content-type']); return; } } - $notice = Notice::saveNew($user->id, html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'), - $source, 1, $reply_to); + $notice = Notice::saveNew($user->id, + html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'), + $source, 1, $reply_to); if (is_string($notice)) { $this->serverError($notice); @@ -343,71 +300,55 @@ class TwitapistatusesAction extends TwitterapiAction function mentions($args, $apidata) { - parent::handle($args); - $since = $this->arg('since'); - $count = $this->arg('count'); - $page = $this->arg('page'); - $since_id = $this->arg('since_id'); - $max_id = $this->arg('max_id'); - $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $apidata['user']; + + if (empty($user)) { + $this->clientError(_('No such user!'), 404, + $apidata['content-type']); + return; + } + $profile = $user->getProfile(); - $sitename = common_config('site', 'name'); - $title = sprintf(_('%1$s / Updates mentioning %2$s'), + $sitename = common_config('site', 'name'); + $title = sprintf(_('%1$s / Updates mentioning %2$s'), $sitename, $user->nickname); $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:Mentions:".$user->id; - $link = common_local_url('replies', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), + $id = "tag:$taguribase:Mentions:".$user->id; + $link = common_local_url('replies', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), $sitename, $user->nickname, $profile->getBestName()); - if (!$page) { - $page = 1; - } + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - if (!$count) { - $count = 20; - } - - if (!$since_id) { - $since_id = 0; - } - - if (!$max_id) { - $max_id = 0; - } - - $since = strtotime($this->arg('since')); - - $notice = $user->getReplies((($page-1)*20), + $notice = $user->getReplies(($page-1)*$count, $count, $since_id, $max_id, $since); - $notices = array(); - - while ($notice->fetch()) { - $notices[] = clone($notice); - } switch($apidata['content-type']) { - case 'xml': - $this->show_xml_timeline($notices); + case 'xml': + $this->show_xml_timeline($notice); break; - case 'rss': - $this->show_rss_timeline($notices, $title, $link, $subtitle); + case 'rss': + $this->show_rss_timeline($notice, $title, $link, $subtitle); break; - case 'atom': + case 'atom': $selfuri = common_root_url() . ltrim($_SERVER['QUERY_STRING'], 'p='); - $this->show_atom_timeline($notices, $title, $id, $link, $subtitle, + $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); break; - case 'json': - $this->show_json_timeline($notices); + case 'json': + $this->show_json_timeline($notice); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -428,8 +369,8 @@ class TwitapistatusesAction extends TwitterapiAction } $this->auth_user = $apidata['user']; - $notice_id = $apidata['api_arg']; - $notice = Notice::staticGet($notice_id); + $notice_id = $apidata['api_arg']; + $notice = Notice::staticGet($notice_id); if ($notice) { if ($apidata['content-type'] == 'xml') { @@ -438,15 +379,16 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_single_json_status($notice); } } else { - // XXX: Twitter just sets a 404 header and doens't bother to return an err msg - $this->clientError(_('No status with that ID found.'), 404, $apidata['content-type']); + // XXX: Twitter just sets a 404 header and doens't bother + // to return an err msg + $this->clientError(_('No status with that ID found.'), + 404, $apidata['content-type']); } } function destroy($args, $apidata) { - parent::handle($args); if (!in_array($apidata['content-type'], array('xml', 'json'))) { @@ -457,17 +399,18 @@ class TwitapistatusesAction extends TwitterapiAction // Check for RESTfulness if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { // XXX: Twitter just prints the err msg, no XML / JSON. - $this->clientError(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST or DELETE.'), + 400, $apidata['content-type']); return; } - $this->auth_user = $apidata['user']; - $user = $this->auth_user; + $user = $apidata['user']; // Always the auth user $notice_id = $apidata['api_arg']; - $notice = Notice::staticGet($notice_id); + $notice = Notice::staticGet($notice_id); - if (!$notice) { - $this->clientError(_('No status found with that ID.'), 404, $apidata['content-type']); + if (empty($notice)) { + $this->clientError(_('No status found with that ID.'), + 404, $apidata['content-type']); return; } @@ -483,7 +426,8 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_single_json_status($notice); } } else { - $this->clientError(_('You may not delete another user\'s status.'), 403, $apidata['content-type']); + $this->clientError(_('You may not delete another user\'s status.'), + 403, $apidata['content-type']); } } @@ -514,42 +458,41 @@ class TwitapistatusesAction extends TwitterapiAction function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false) { - $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - if (!$user) { + if (empty($user)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } - $page = $this->trimmed('page'); - - if (!$page || !is_numeric($page)) { - $page = 1; - } - $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - $sub = new Subscription(); $sub->$user_attr = $profile->id; - $since = strtotime($this->trimmed('since')); - - if ($since) { - $d = date('Y-m-d H:i:s', $since); - $sub->whereAdd("created > '$d'"); - } - $sub->orderBy('created DESC'); + // Normally, page 100 friends at a time + if (!$onlyIDs) { - $sub->limit(($page-1)*100, 100); + $page = $this->arg('page', 1); + $count = $this->arg('count', 100); + $sub->limit(($page-1)*$count, $count); + } else { + + // If we're just looking at IDs, return + // ALL of them, unless the user specifies a page, + // in which case, return 500 per page. + + $page = $this->arg('page'); + if (!empty($page)) { + if ($page < 1) { + $page = 1; + } + $count = 500; + $sub->limit(($page-1)*$count, $count); + } } $others = array(); @@ -578,21 +521,21 @@ class TwitapistatusesAction extends TwitterapiAction function show_profiles($profiles, $type) { switch ($type) { - case 'xml': + case 'xml': $this->elementStart('users', array('type' => 'array')); foreach ($profiles as $profile) { $this->show_profile($profile); } $this->elementEnd('users'); break; - case 'json': + case 'json': $arrays = array(); foreach ($profiles as $profile) { $arrays[] = $this->twitter_user_array($profile, true); } print json_encode($arrays); break; - default: + default: $this->clientError(_('unsupported file type')); } } @@ -600,21 +543,21 @@ class TwitapistatusesAction extends TwitterapiAction function showIDs($profiles, $type) { switch ($type) { - case 'xml': + case 'xml': $this->elementStart('ids'); foreach ($profiles as $profile) { $this->element('id', null, $profile->id); } $this->elementEnd('ids'); break; - case 'json': + case 'json': $ids = array(); foreach ($profiles as $profile) { $ids[] = (int)$profile->id; } print json_encode($ids); break; - default: + default: $this->clientError(_('unsupported file type')); } } @@ -627,8 +570,8 @@ class TwitapistatusesAction extends TwitterapiAction function supported($cmd) { - - $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand', 'FavCommand', 'OnCommand', 'OffCommand'); + $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand', + 'FavCommand', 'OnCommand', 'OffCommand'); if (in_array(get_class($cmd), $cmdlist)) { return true; diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php index b90bbfa98..13a8746cd 100644 --- a/actions/twitapiusers.php +++ b/actions/twitapiusers.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -51,18 +53,11 @@ class TwitapiusersAction extends TwitterapiAction $user = $apidata['user']; } - if (!$user) { + if (empty($user)) { $this->client_error(_('Not found.'), 404, $apidata['content-type']); return; } - $profile = $user->getProfile(); - - if (!$profile) { - common_server_error(_('User has no profile.')); - return; - } - $twitter_user = $this->twitter_user_array($profile, true); if ($apidata['content-type'] == 'xml') { diff --git a/lib/twitterapi.php b/lib/twitterapi.php index ca8b03cdc..569bc6d7a 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -17,7 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} class TwitterapiAction extends Action { @@ -521,11 +523,11 @@ class TwitterapiAction extends Action function init_document($type='xml') { switch ($type) { - case 'xml': + case 'xml': header('Content-Type: application/xml; charset=utf-8'); $this->startXML(); break; - case 'json': + case 'json': header('Content-Type: application/json; charset=utf-8'); // Check for JSONP callback @@ -534,15 +536,15 @@ class TwitterapiAction extends Action print $callback . '('; } break; - case 'rss': + case 'rss': header("Content-Type: application/rss+xml; charset=utf-8"); $this->init_twitter_rss(); break; - case 'atom': + case 'atom': header('Content-Type: application/atom+xml; charset=utf-8'); $this->init_twitter_atom(); break; - default: + default: $this->client_error(_('Not a supported data format.')); break; } @@ -553,10 +555,10 @@ class TwitterapiAction extends Action function end_document($type='xml') { switch ($type) { - case 'xml': + case 'xml': $this->endXML(); break; - case 'json': + case 'json': // Check for JSONP callback $callback = $this->arg('callback'); @@ -564,13 +566,13 @@ class TwitterapiAction extends Action print ')'; } break; - case 'rss': + case 'rss': $this->end_twitter_rss(); break; - case 'atom': + case 'atom': $this->end_twitter_rss(); break; - default: + default: $this->client_error(_('Not a supported data format.')); break; } @@ -657,13 +659,13 @@ class TwitterapiAction extends Action { $profile_array = $this->twitter_user_array($profile, true); switch ($content_type) { - case 'xml': + case 'xml': $this->show_twitter_xml_user($profile_array); break; - case 'json': + case 'json': $this->show_json_objects($profile_array); break; - default: + default: $this->client_error(_('Not a supported data format.')); return; } @@ -672,8 +674,8 @@ class TwitterapiAction extends Action function get_user($id, $apidata=null) { - if (!$id) { - + if (empty($id)) { + // Twitter supports these other ways of passing the user ID if (is_numeric($this->arg('id'))) { return User::staticGet($this->arg('id')); @@ -681,7 +683,7 @@ class TwitterapiAction extends Action $nickname = common_canonical_nickname($this->arg('id')); return User::staticGet('nickname', $nickname); } else if ($this->arg('user_id')) { - // This is to ensure that a non-numeric user_id still + // This is to ensure that a non-numeric user_id still // overrides screen_name even if it doesn't get used if (is_numeric($this->arg('user_id'))) { return User::staticGet('id', $this->arg('user_id')); @@ -693,7 +695,7 @@ class TwitterapiAction extends Action // Fall back to trying the currently authenticated user return $apidata['user']; } - + } else if (is_numeric($id)) { return User::staticGet($id); } else { @@ -720,13 +722,13 @@ class TwitterapiAction extends Action { $source_name = _($source); switch ($source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'api': + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'api': break; - default: + default: $ns = Notice_source::staticGet($source); if ($ns) { $source_name = '<a href="' . $ns->url . '">' . $ns->name . '</a>'; @@ -736,4 +738,49 @@ class TwitterapiAction extends Action return $source_name; } + /** + * Returns query argument or default value if not found. Certain + * parameters used throughout the API are lightly scrubbed and + * bounds checked. This overrides Action::arg(). + * + * @param string $key requested argument + * @param string $def default value to return if $key is not provided + * + * @return var $var + */ + function arg($key, $def=null) + { + + // XXX: Do even more input validation/scrubbing? + + if (array_key_exists($key, $this->args)) { + switch($key) { + case 'page': + $page = (int)$this->args['page']; + return ($page < 1) ? 1 : $page; + case 'count': + $count = (int)$this->args['count']; + if ($count < 1) { + return 20; + } elseif ($count > 200) { + return 200; + } else { + return $count; + } + case 'since_id': + $since_id = (int)$this->args['since_id']; + return ($since_id < 1) ? 0 : $since_id; + case 'max_id': + $max_id = (int)$this->args['max_id']; + return ($max_id < 1) ? 0 : $max_id; + case 'since': + return strtotime($this->args['since']); + default: + return parent::arg($key, $def); + } + } else { + return $def; + } + } + } |