]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/rsd.php
Use array_merge instead of array_replace (same effect, and array_merge works with...
[quix0rs-gnu-social.git] / actions / rsd.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2008-2010, StatusNet, Inc.
5  *
6  * Really Simple Discovery (RSD) for API access
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category API
24  * @package  StatusNet
25  * @author   Evan Prodromou <evan@status.net>
26  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
27  * @link     http://status.net/
28  *
29  */
30
31 if (!defined('STATUSNET')) {
32     exit(1);
33 }
34
35 /**
36  * RSD action class
37  *
38  * Really Simple Discovery (RSD) is a simple (to a fault, maybe)
39  * discovery tool for blog APIs.
40  *
41  * http://tales.phrasewise.com/rfc/rsd
42  *
43  * Anil Dash suggested that RSD be used for services that implement
44  * the Twitter API:
45  *
46  * http://dashes.com/anil/2009/12/the-twitter-api-is-finished.html
47  *
48  * It's in use now for WordPress.com blogs:
49  *
50  * http://matt.wordpress.com/xmlrpc.php?rsd
51  *
52  * I (evan@status.net) have tried to stay faithful to the premise of
53  * RSD, while adding information useful to StatusNet client developers.
54  * In particular:
55  *
56  * - There is a link from each user's profile page to their personal
57  *   RSD feed. A personal rsd.xml includes a 'blogID' element that is
58  *   their username.
59  * - There is a link from the public root to '/rsd.xml', a public RSD
60  *   feed. It's identical to the personal rsd except it doesn't include
61  *   a blogId.
62  * - I've added a setting to the API to indicate that OAuth support is
63  *   available.
64  *
65  * @category API
66  * @package  StatusNet
67  * @author   Evan Prodromou <evan@status.net>
68  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
69  * @link     http://status.net/
70  */
71 class RsdAction extends Action
72 {
73     /**
74      * Optional attribute for the personal rsd.xml file.
75      */
76     var $user = null;
77
78     /**
79      * Prepare the action for use.
80      *
81      * Check for a nickname; redirect if non-canonical; if
82      * not provided, assume public rsd.xml.
83      *
84      * @param array $args GET, POST, and URI arguments.
85      *
86      * @return boolean success flag
87      */
88     function prepare($args)
89     {
90         parent::prepare($args);
91
92         // optional argument
93
94         $nickname_arg = $this->arg('nickname');
95
96         if (empty($nickname_arg)) {
97             $this->user = null;
98         } else {
99             $nickname = common_canonical_nickname($nickname_arg);
100
101             // Permanent redirect on non-canonical nickname
102
103             if ($nickname_arg != $nickname) {
104                 common_redirect(common_local_url('rsd',
105                                                  array('nickname' => $nickname)),
106                                 301);
107                 return false;
108             }
109
110             $this->user = User::staticGet('nickname', $nickname);
111
112             if (empty($this->user)) {
113                 // TRANS: Client error.
114                 $this->clientError(_('No such user.'), 404);
115                 return false;
116             }
117         }
118
119         return true;
120     }
121
122     /**
123      * Action handler.
124      *
125      * Outputs the XML format for an RSD file. May include
126      * personal information if this is a personal file
127      * (based on whether $user attribute is set).
128      *
129      * @param array $args array of arguments
130      *
131      * @return nothing
132      */
133     function handle($args)
134     {
135         header('Content-Type: application/rsd+xml');
136
137         $this->startXML();
138
139         $rsdNS = 'http://archipelago.phrasewise.com/rsd';
140         $this->elementStart('rsd', array('version' => '1.0',
141                                          'xmlns' => $rsdNS));
142         $this->elementStart('service');
143         // TRANS: Engine name for RSD.
144         $this->element('engineName', null, _('StatusNet'));
145         $this->element('engineLink', null, 'http://status.net/');
146         $this->elementStart('apis');
147         if (Event::handle('StartRsdListApis', array($this, $this->user))) {
148
149             $blogID   = (empty($this->user)) ? '' : $this->user->nickname;
150             $apiAttrs = array('name' => 'Twitter',
151                               'preferred' => 'true',
152                               'apiLink' => $this->_apiRoot(),
153                               'blogID' => $blogID);
154
155             $this->elementStart('api', $apiAttrs);
156             $this->elementStart('settings');
157             $this->element('docs', null,
158                            'http://status.net/wiki/TwitterCompatibleAPI');
159             $this->element('setting', array('name' => 'OAuth'),
160                            'true');
161             $this->elementEnd('settings');
162             $this->elementEnd('api');
163
164             // Atom API
165
166             if (empty($this->user)) {
167                 $service = common_local_url('ApiAtomService');
168             } else {
169                 $service = common_local_url('ApiAtomService', array('id' => $this->user->nickname));
170             }
171
172             $this->element('api', array('name' => 'Atom',
173                                         'preferred' => 'false',
174                                         'apiLink' => $service,
175                                         'blogID' => $blogID));
176
177             Event::handle('EndRsdListApis', array($this, $this->user));
178         }
179         $this->elementEnd('apis');
180         $this->elementEnd('service');
181         $this->elementEnd('rsd');
182
183         $this->endXML();
184
185         return true;
186     }
187
188     /**
189      * Returns last-modified date for use in caching
190      *
191      * Per-user rsd.xml is dated to last change of user
192      * (in case of nickname change); public has no date.
193      *
194      * @return string date of last change of this page
195      */
196     function lastModified()
197     {
198         if (!empty($this->user)) {
199             return $this->user->modified;
200         } else {
201             return null;
202         }
203     }
204
205     /**
206      * Flag to indicate if this action is read-only
207      *
208      * It is; it doesn't change the DB.
209      *
210      * @param array $args ignored
211      *
212      * @return boolean true
213      */
214     function isReadOnly($args)
215     {
216         return true;
217     }
218
219     /**
220      * Return current site's API root
221      *
222      * Varies based on URL parameters, like if fancy URLs are
223      * turned on.
224      *
225      * @return string API root URI for this site
226      */
227     private function _apiRoot()
228     {
229         if (common_config('site', 'fancy')) {
230             return common_path('api/', true);
231         } else {
232             return common_path('index.php/api/', true);
233         }
234     }
235 }