Twitter-compatible API: /statuses/public_timeline.xml sorta works

darcs-hash:20080715031812-ca946-10a94dd3cd96039ad76adc36f0f23d7402768fbe.gz
This commit is contained in:
zach 2008-07-14 23:18:12 -04:00
parent b3ea8b9a01
commit efd14edf5c
9 changed files with 156 additions and 23 deletions

View File

@ -19,9 +19,9 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
# This naming convention looks real sick require_once(INSTALLDIR.'/lib/twitterapi.php');
class ApiaccountAction extends Action {
class ApiaccountAction extends TwitterapiAction {
function verify_credentials($args, $apidata) { function verify_credentials($args, $apidata) {
parent::handle($args); parent::handle($args);

View File

@ -19,8 +19,9 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
# This naming convention looks real sick require_once(INSTALLDIR.'/lib/twitterapi.php');
class ApiblocksAction extends Action {
class ApiblocksAction extends TwitterapiAction {
function create($args, $apidata) { function create($args, $apidata) {
parent::handle($args); parent::handle($args);

View File

@ -19,7 +19,9 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
class Apidirect_messagesAction extends Action { require_once(INSTALLDIR.'/lib/twitterapi.php');
class Apidirect_messagesAction extends TwitterapiAction {
function direct_messages($args, $apidata) { function direct_messages($args, $apidata) {
parent::handle($args); parent::handle($args);

View File

@ -19,8 +19,9 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
# This naming convention looks real sick require_once(INSTALLDIR.'/lib/twitterapi.php');
class ApifavoritesAction extends Action {
class ApifavoritesAction extends TwitterapiAction {
function favorites($args, $apidata) { function favorites($args, $apidata) {
parent::handle($args); parent::handle($args);

View File

@ -19,8 +19,9 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
# This naming convention looks real sick require_once(INSTALLDIR.'/lib/twitterapi.php');
class ApifriendshipsAction extends Action {
class ApifriendshipsAction extends TwitterapiAction {
function create($args, $apidata) { function create($args, $apidata) {

View File

@ -19,8 +19,9 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
# This naming convention looks real sick require_once(INSTALLDIR.'/lib/twitterapi.php');
class ApihelpAction extends Action {
class ApihelpAction extends TwitterapiAction {
/* Returns the string "ok" in the requested format with a 200 OK HTTP status code. /* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
* URL:http://identi.ca/api/help/test.format * URL:http://identi.ca/api/help/test.format

View File

@ -19,8 +19,10 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/twitterapi.php');
# This naming convention looks real sick # This naming convention looks real sick
class ApinotificationsAction extends Action { class ApinotificationsAction extends TwitterapiAction {
function follow($args, $apidata) { function follow($args, $apidata) {

View File

@ -19,28 +19,66 @@
if (!defined('LACONICA')) { exit(1); } if (!defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/twitterapi.php');
/* XXX: Please don't freak out about all the ugly comments in this file. /* XXX: Please don't freak out about all the ugly comments in this file.
* They are mostly in here for reference while I develop the * They are mostly in here for reference while I work on the
* API. I'll fix things up to make them look better later. -- Zach * API. I'll fix things up to make them look better later. -- Zach
*/ */
class ApistatusesAction extends Action { class ApistatusesAction extends TwitterapiAction {
/* /*
Returns the 20 most recent statuses from non-protected users who have set a custom user icon. * Returns the 20 most recent statuses from non-protected users who have set a custom
Does not require authentication. * user icon. Does not require authentication.
*
URL: http://identi.ca/api/statuses/public_timeline.format * URL: http://identi.ca/api/statuses/public_timeline.format
*
Formats: xml, json, rss, atom * Formats: xml, json, rss, atom
*/ */
function public_timeline($args, $apidata) { function public_timeline($args, $apidata) {
parent::handle($args); parent::handle($args);
print "Public Timeline! requested content-type: " . $apidata['content-type'] . "\n"; if ($apidata['content-type'] == 'xml') {
header('Content-Type: application/xml; charset=utf-8');
$notice = DB_DataObject::factory('notice');
# FIXME: bad performance
$notice->whereAdd('EXISTS (SELECT user.id from user where user.id = notice.profile_id)');
$notice->orderBy('created DESC, notice.id DESC');
$notice->limit(20);
$cnt = $notice->find();
common_start_xml();
// XXX: To really live up to the spec we need to build a list
// of notices by users who have custom avatars
if ($cnt > 0) {
common_element_start('statuses', array('type' => 'array'));
for ($i = 0; $i < 20; $i++) {
if ($notice->fetch()) {
$this->show_xml_status($notice);
} else {
// shouldn't happen!
break;
}
}
common_element_end('statuses');
}
common_end_xml();
} elseif ($apidata['content-type'] == 'rss') {
common_server_error("API method under construction.", $code=501);
} elseif ($apidata['content-type'] == 'atom') {
common_server_error("API method under construction.", $code=501);
} elseif ($apidata['content-type'] == 'json') {
common_server_error("API method under construction.", $code=501);
}
exit(); exit();
} }
/* /*
Returns the 20 most recent statuses posted by the authenticating user and that user's friends. Returns the 20 most recent statuses posted by the authenticating user and that user's friends.
This is the equivalent of /home on the Web. This is the equivalent of /home on the Web.

87
lib/twitterapi.php Normal file
View File

@ -0,0 +1,87 @@
<?php
/*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, Controlez-Vous, 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 <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) { exit(1); }
class TwitterapiAction extends Action {
function handle($args) {
parent::handle($args);
}
/*
* Spits out a Laconica notice as a Twitter-compatible "status"
*/
function show_xml_status($notice) {
global $config;
$profile = $notice->getProfile();
common_element_start('status');
// XXX: twitter created_at date looks like this: Mon Jul 14 23:52:38 +0000 2008
common_element('created_at', NULL, common_exact_date($notice->created));
common_element('text', NULL, $notice->content);
common_element('source', NULL, 'Web'); # twitterific, twitterfox, etc.
common_element('truncated', NULL, 'false'); # how do we tell in Laconica?
common_element('in_reply_to_status_id', NULL, $notice->reply_to);
common_element('in_reply_to_user_id', NULL,'');
common_element('favorited', Null, ''); # feature for some day
common_element_start('user');
common_element('id', NULL, $notice->id);
common_element('name', NULL, $profile->getBestName());
common_element('screen_name', NULL, $profile->nickname);
common_element('location', NULL, $profile->location);
common_element('description', NULL, $profile->bio);
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
common_element('profile_image_url', NULL, ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE));
common_element('url', NULL, $profile->homepage);
common_element('protected', NULL, 'false'); # not supported yet
common_element('followers_count', NULL, $this->count_subscriptions($profile)); # where do I get this?
common_element_end('user');
common_element_end('status');
}
// XXX: Candidate for a general utility method somewhere?
function count_subscriptions($profile) {
$count = 0;
$sub = new Subscription();
$sub->subscribed = $profile->id;
if ($sub->find()) {
while ($sub->fetch()) {
if ($sub->token) {
$other = Remote_profile::staticGet('id', $sub->subscriber);
} else {
$other = User::staticGet('id', $sub->subscriber);
}
if (!$other) {
common_debug('Got a bad subscription: '.print_r($sub,TRUE));
continue;
}
$count++;
}
}
return $count;
}
}