diff options
Diffstat (limited to 'actions/rsd.php')
-rw-r--r-- | actions/rsd.php | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/actions/rsd.php b/actions/rsd.php new file mode 100644 index 000000000..f88bf2e9a --- /dev/null +++ b/actions/rsd.php @@ -0,0 +1,226 @@ +<?php +/** + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2008-2010, StatusNet, Inc. + * + * Really Simple Discovery (RSD) for API access + * + * PHP version 5 + * + * 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/>. + * + * @category API + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * RSD action class + * + * Really Simple Discovery (RSD) is a simple (to a fault, maybe) + * discovery tool for blog APIs. + * + * http://tales.phrasewise.com/rfc/rsd + * + * Anil Dash suggested that RSD be used for services that implement + * the Twitter API: + * + * http://dashes.com/anil/2009/12/the-twitter-api-is-finished.html + * + * It's in use now for WordPress.com blogs: + * + * http://matt.wordpress.com/xmlrpc.php?rsd + * + * I (evan@status.net) have tried to stay faithful to the premise of + * RSD, while adding information useful to StatusNet client developers. + * In particular: + * + * - There is a link from each user's profile page to their personal + * RSD feed. A personal rsd.xml includes a 'blogID' element that is + * their username. + * - There is a link from the public root to '/rsd.xml', a public RSD + * feed. It's identical to the personal rsd except it doesn't include + * a blogId. + * - I've added a setting to the API to indicate that OAuth support is + * available. + * + * @category API + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ + +class RsdAction extends Action +{ + /** + * Optional attribute for the personal rsd.xml file. + */ + + var $user = null; + + /** + * Prepare the action for use. + * + * Check for a nickname; redirect if non-canonical; if + * not provided, assume public rsd.xml. + * + * @param array $args GET, POST, and URI arguments. + * + * @return boolean success flag + */ + + function prepare($args) + { + parent::prepare($args); + + // optional argument + + $nickname_arg = $this->arg('nickname'); + + if (empty($nickname_arg)) { + $this->user = null; + } else { + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $nickname) { + common_redirect(common_local_url('rsd', + array('nickname' => $nickname)), + 301); + return false; + } + + $this->user = User::staticGet('nickname', $nickname); + + if (empty($this->user)) { + $this->clientError(_('No such user.'), 404); + return false; + } + } + + return true; + } + + /** + * Action handler. + * + * Outputs the XML format for an RSD file. May include + * personal information if this is a personal file + * (based on whether $user attribute is set). + * + * @param array $args array of arguments + * + * @return nothing + */ + + function handle($args) + { + header('Content-Type: application/rsd+xml'); + + $this->startXML(); + + $rsdNS = 'http://archipelago.phrasewise.com/rsd'; + $this->elementStart('rsd', array('version' => '1.0', + 'xmlns' => $rsdNS)); + $this->elementStart('service'); + $this->element('engineName', null, _('StatusNet')); + $this->element('engineLink', null, 'http://status.net/'); + $this->elementStart('apis'); + if (Event::handle('StartRsdListApis', array($this, $this->user))) { + + $blogID = (empty($this->user)) ? '' : $this->user->nickname; + $apiAttrs = array('name' => 'Twitter', + 'preferred' => 'true', + 'apiLink' => $this->_apiRoot(), + 'blogID' => $blogID); + + $this->elementStart('api', $apiAttrs); + $this->elementStart('settings'); + $this->element('docs', null, + 'http://status.net/wiki/TwitterCompatibleAPI'); + $this->element('setting', array('name' => 'OAuth'), + 'true'); + $this->elementEnd('settings'); + $this->elementEnd('api'); + Event::handle('EndRsdListApis', array($this, $this->user)); + } + $this->elementEnd('apis'); + $this->elementEnd('service'); + $this->elementEnd('rsd'); + + $this->endXML(); + + return true; + } + + /** + * Returns last-modified date for use in caching + * + * Per-user rsd.xml is dated to last change of user + * (in case of nickname change); public has no date. + * + * @return string date of last change of this page + */ + + function lastModified() + { + if (!empty($this->user)) { + return $this->user->modified; + } else { + return null; + } + } + + /** + * Flag to indicate if this action is read-only + * + * It is; it doesn't change the DB. + * + * @param array $args ignored + * + * @return boolean true + */ + + function isReadOnly($args) + { + return true; + } + + /** + * Return current site's API root + * + * Varies based on URL parameters, like if fancy URLs are + * turned on. + * + * @return string API root URI for this site + */ + + private function _apiRoot() + { + if (common_config('site', 'fancy')) { + return common_path('api/', true); + } else { + return common_path('index.php/api/', true); + } + } +} |