From 140689800b03ff704f6c70260c2b740ad41578c0 Mon Sep 17 00:00:00 2001 From: zach Date: Sun, 20 Jul 2008 03:09:05 -0400 Subject: [PATCH] Twitter-compatible API - Error handling that better matches Twitter's darcs-hash:20080720070905-ca946-dda57dd92210461361fd58b7a3244bf24c01e801.gz --- actions/api.php | 15 +++++++---- actions/twitapifriendships.php | 23 ++++++++++------ lib/twitterapi.php | 49 +++++++++++++++++++++++++++++++++- lib/util.php | 8 ------ 4 files changed, 73 insertions(+), 22 deletions(-) diff --git a/actions/api.php b/actions/api.php index a525703208..69fda2e224 100644 --- a/actions/api.php +++ b/actions/api.php @@ -45,9 +45,7 @@ class ApiAction extends Action { $this->api_method = $cmdext[0]; $this->content_type = strtolower($cmdext[1]); } - - # common_debug("apiaction = $this->api_action, method = $this->api_method, argument = $this->api_arg, ctype = $this->content_type"); - + # XXX Maybe check to see if the command actually exists first? if($this->requires_auth()) { if (!isset($_SERVER['PHP_AUTH_USER'])) { @@ -56,7 +54,7 @@ class ApiAction extends Action { header('WWW-Authenticate: Basic realm="Laconica API"'); # if the user hits cancel -- bam! - common_show_basic_auth_error(); + $this->show_basic_auth_error(); } else { $nickname = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; @@ -67,7 +65,7 @@ class ApiAction extends Action { $this->process_command(); } else { # basic authentication failed - common_show_basic_auth_error(); + $this->show_basic_auth_error(); } } } else { @@ -123,5 +121,12 @@ class ApiAction extends Action { return true; } } + + function show_basic_auth_error() { + header('HTTP/1.1 401 Unauthorized'); + header('Content-type: text/plain'); + print("Could not authenticate you."); # exactly what Twitter says - no \n + exit(); + } } diff --git a/actions/twitapifriendships.php b/actions/twitapifriendships.php index 0253cb8e57..90e890e35c 100644 --- a/actions/twitapifriendships.php +++ b/actions/twitapifriendships.php @@ -31,7 +31,7 @@ class TwitapifriendshipsAction extends TwitterapiAction { $other = $this->get_user($id); if (!$other) { - $this->client_error(_('No such user')); + $this->client_error(_('Could not follow user: User not found.'), 403, $apidata['content-type']); exit(); return; } @@ -39,7 +39,7 @@ class TwitapifriendshipsAction extends TwitterapiAction { $user = $apidata['user']; if ($user->isSubscribed($other)) { - $this->client_error(_('Already subscribed.')); + $this->client_error("Could not follow user: $other->nickname is already on your list.", 403, $apidata['content-type']); exit(); return; } @@ -55,7 +55,7 @@ class TwitapifriendshipsAction extends TwitterapiAction { $result = $sub->insert(); if (!$result) { - $this->server_error(_('Could not subscribe')); + $this->client_error("Could not follow user: $other->nickname.", 400, $apidata['content-type']); exit(); return; } @@ -101,7 +101,7 @@ class TwitapifriendshipsAction extends TwitterapiAction { $sub->delete(); $sub->query('COMMIT'); } else { - $this->client_error(_('Not subscribed')); + $this->client_error(_('You are not friends with the specified user.'), 403, $apidata['content-type']); exit(); } @@ -127,14 +127,21 @@ class TwitapifriendshipsAction extends TwitterapiAction { function exists($args, $apidata) { parent::handle($args); + + $user_a_id = $this->trimmed('user_a'); $user_b_id = $this->trimmed('user_b'); + $user_a = $this->get_profile($user_a_id); $user_b = $this->get_profile($user_b_id); + if($user_a) { print "got user a profile";} + if($user_b) { print "got user b profile";} + + if (!$user_a || !$user_b) { - $this->client_error(_('No such user')); - return; + $this->client_error(_('Two user ids or screen_names must be supplied.'), 400, $apidata['content-type']); + exit(); } if ($user_a->isSubscribed($user_b)) { @@ -151,20 +158,20 @@ class TwitapifriendshipsAction extends TwitterapiAction { break; case 'json': print json_encode($result); - print "\n"; break; default: print $result; break; } + exit(); } function get_profile($id) { if (is_numeric($id)) { return Profile::staticGet($id); } else { - $user = User::staticGet('nickname', $id); + $user = User::staticGet('nickname', $id); if ($user) { return $user->getProfile(); } else { diff --git a/lib/twitterapi.php b/lib/twitterapi.php index 06f491fb6e..12416bc367 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -280,7 +280,54 @@ class TwitterapiAction extends Action { break; } } - + + function client_error($msg, $code = 400, $content_type = 'json') { + + static $status = array(400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed'); + + $action = $this->trimmed('action'); + + common_debug("User error '$code' on '$action': $msg", __FILE__); + + if (!array_key_exists($code, $status)) { + $code = 400; + } + + $status_string = $status[$code]; + header('HTTP/1.1 '.$code.' '.$status_string); + + if ($content_type == 'xml') { + common_start_xml(); + common_element_start('hash'); + common_element('error', NULL, $msg); + common_element('request', NULL, $_SERVER['REQUEST_URI']); + common_element_end('hash'); + common_end_xml(); + } else { + $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']); + print(json_encode($error_array)); + } + + exit(); + } + function init_twitter_rss() { common_start_xml(); common_element_start('rss', array('version' => '2.0')); diff --git a/lib/util.php b/lib/util.php index 62f7abc9ee..36ccfe29a7 100644 --- a/lib/util.php +++ b/lib/util.php @@ -223,14 +223,6 @@ function common_show_header($pagetitle, $callable=NULL, $data=NULL, $headercall= common_element_start('div', array('id' => 'content')); } -# XXX: Refactor w/common_user_error() ? -function common_show_basic_auth_error() { - header('HTTP/1.1 401 Unauthorized'); - header('Content-type: text/plain'); - print("Could not authenticate you."); # exactly what Twitter says - no \n - exit(); -} - function common_show_footer() { global $xw, $config; common_element_end('div'); # content div