]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/twitapistatuses.php
correct some SQL and add some spaces
[quix0rs-gnu-social.git] / actions / twitapistatuses.php
1 <?php
2 /*
3  * Laconica - a distributed open-source microblogging tool
4  * Copyright (C) 2008, Controlez-Vous, Inc.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 if (!defined('LACONICA')) { exit(1); }
21
22 require_once(INSTALLDIR.'/lib/twitterapi.php');
23
24 /* XXX: Please don't freak out about all the ugly comments in this file.
25  * They are mostly in here for reference while I work on the
26  * API. I'll fix things up later to make them look better later. -- Zach
27  */
28 class TwitapistatusesAction extends TwitterapiAction {
29
30         function is_readonly() {
31
32                 static $write_methods = array(  'update',
33                                                                                 'destroy');
34
35                 $cmdtext = explode('.', $this->arg('method'));
36
37                 if (in_array($cmdtext[0], $write_methods)) {
38                         return false;
39                 }
40
41                 return true;
42         }
43
44         function public_timeline($args, $apidata) {
45                 parent::handle($args);
46
47                 $sitename = common_config('site', 'name');
48                 $siteserver = common_config('site', 'server');
49                 $title = sprintf(_("%s public timeline"), $sitename);
50                 $id = "tag:$siteserver:Statuses";
51                 $link = common_root_url();
52                 $subtitle = sprintf(_("%s updates from everyone!"), $sitename);
53
54                 // Number of public statuses to return by default -- Twitter sends 20
55                 $MAX_PUBSTATUSES = 20;
56
57                 // FIXME: To really live up to the spec we need to build a list
58                 // of notices by users who have custom avatars, so fix this SQL -- Zach
59
60                 $notice = Notice::publicStream(0, $MAX_PUBSTATUSES);
61                 
62                 if ($notice) {
63
64                         switch($apidata['content-type']) {
65                                 case 'xml':
66                                         $this->show_xml_timeline($notice);
67                                         break;
68                                 case 'rss':
69                                         $this->show_rss_timeline($notice, $title, $id, $link, $subtitle);
70                                         break;
71                                 case 'atom':
72                                         $this->show_atom_timeline($notice, $title, $id, $link, $subtitle);
73                                         break;
74                                 case 'json':
75                                         $this->show_json_timeline($notice);
76                                         break;
77                                 default:
78                                         common_user_error(_('API method not found!'), $code = 404);
79                                         break;
80                         }
81
82                 } else {
83                         common_server_error(_('Couldn\'t find any statuses.'), $code = 503);
84                 }
85
86                 exit();
87         }
88
89         function show_xml_timeline($notice) {
90
91                 $this->init_document('xml');
92                 common_element_start('statuses', array('type' => 'array'));
93
94                 if (is_array($notice)) {
95                         foreach ($notice as $n) {
96                                 $twitter_status = $this->twitter_status_array($n);
97                                 $this->show_twitter_xml_status($twitter_status);
98                         }
99                 } else {
100                         while ($notice->fetch()) {
101                                 $twitter_status = $this->twitter_status_array($notice);
102                                 $this->show_twitter_xml_status($twitter_status);
103                         }
104                 }
105
106                 common_element_end('statuses');
107                 $this->end_document('xml');
108         }
109
110         function show_rss_timeline($notice, $title, $id, $link, $subtitle) {
111
112                 $this->init_document('rss');
113
114                 common_element_start('channel');
115                 common_element('title', NULL, $title);
116                 common_element('link', NULL, $link);
117                 common_element('description', NULL, $subtitle);
118                 common_element('language', NULL, 'en-us');
119                 common_element('ttl', NULL, '40');
120
121
122                 if (is_array($notice)) {
123                         foreach ($notice as $n) {
124                                 $entry = $this->twitter_rss_entry_array($n);
125                                 $this->show_twitter_rss_item($entry);
126                         }
127                 } else {
128                         while ($notice->fetch()) {
129                                 $entry = $this->twitter_rss_entry_array($notice);
130                                 $this->show_twitter_rss_item($entry);
131                         }
132                 }
133
134                 common_element_end('channel');
135                 $this->end_twitter_rss();
136         }
137
138         function show_atom_timeline($notice, $title, $id, $link, $subtitle=NULL) {
139
140                 $this->init_document('atom');
141
142                 common_element('title', NULL, $title);
143                 common_element('id', NULL, $id);
144                 common_element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), NULL);
145                 common_element('subtitle', NULL, $subtitle);
146
147                 if (is_array($notice)) {
148                         foreach ($notice as $n) {
149                                 $entry = $this->twitter_rss_entry_array($n);
150                                 $this->show_twitter_atom_entry($entry);
151                         }
152                 } else {
153                         while ($notice->fetch()) {
154                                 $entry = $this->twitter_rss_entry_array($notice);
155                                 $this->show_twitter_atom_entry($entry);
156                         }
157                 }
158
159                 $this->end_document('atom');
160
161         }
162
163         function show_json_timeline($notice) {
164
165                 $this->init_document('json');
166
167                 $statuses = array();
168
169                 if (is_array($notice)) {
170                         foreach ($notice as $n) {
171                                 $twitter_status = $this->twitter_status_array($n);
172                                 array_push($statuses, $twitter_status);
173                         }
174                 } else {
175                         while ($notice->fetch()) {
176                                 $twitter_status = $this->twitter_status_array($notice);
177                                 array_push($statuses, $twitter_status);
178                         }
179                 }
180
181                 $this->show_twitter_json_statuses($statuses);
182
183                 $this->end_document('json');
184         }
185
186         /*
187         Returns the 20 most recent statuses posted by the authenticating user and that user's friends.
188         This is the equivalent of /home on the Web.
189
190         URL: http://server/api/statuses/friends_timeline.format
191
192         Parameters:
193
194             * since.  Optional.  Narrows the returned results to just those statuses created after the specified
195                         HTTP-formatted date.  The same behavior is available by setting an If-Modified-Since header in
196                         your HTTP request.
197                         Ex: http://server/api/statuses/friends_timeline.rss?since=Tue%2C+27+Mar+2007+22%3A55%3A48+GMT
198             * since_id.  Optional.  Returns only statuses with an ID greater than (that is, more recent than)
199                         the specified ID.  Ex: http://server/api/statuses/friends_timeline.xml?since_id=12345
200             * count.  Optional.  Specifies the number of statuses to retrieve. May not be greater than 200.
201                         Ex: http://server/api/statuses/friends_timeline.xml?count=5
202             * page. Optional. Ex: http://server/api/statuses/friends_timeline.rss?page=3
203
204         Formats: xml, json, rss, atom
205         */
206         function friends_timeline($args, $apidata) {
207                 parent::handle($args);
208
209                 $since = $this->arg('since');
210                 $since_id = $this->arg('since_id');
211                 $count = $this->arg('count');
212                 $page = $this->arg('page');
213
214                 if (!$page) {
215                         $page = 1;
216                 }
217
218                 if (!$count) {
219                         $count = 20;
220                 }
221
222                 $user = $this->get_user($id, $apidata);
223                 $profile = $user->getProfile();
224
225                 $sitename = common_config('site', 'name');
226                 $siteserver = common_config('site', 'server');
227
228                 $title = sprintf(_("%s and friends"), $user->nickname);
229                 $id = "tag:$siteserver:friends:".$user->id;
230                 $link = common_local_url('all', array('nickname' => $user->nickname));
231                 $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename);
232
233                 $notice = $user->noticesWithFriends(($page-1)*20, $count);
234
235                 switch($apidata['content-type']) {
236                  case 'xml':
237                         $this->show_xml_timeline($notice);
238                         break;
239                  case 'rss':
240                         $this->show_rss_timeline($notice, $title, $id, $link, $subtitle);
241                         break;
242                  case 'atom':
243                         $this->show_atom_timeline($notice, $title, $id, $link, $subtitle);
244                         break;
245                  case 'json':
246                         $this->show_json_timeline($notice);
247                         break;
248                  default:
249                         common_user_error(_('API method not found!'), $code = 404);
250                 }
251
252                 exit();
253         }
254
255         /*
256                 Returns the 20 most recent statuses posted from the authenticating user. It's also possible to
257         request another user's timeline via the id parameter below. This is the equivalent of the Web
258         /archive page for your own user, or the profile page for a third party.
259
260                 URL: http://server/api/statuses/user_timeline.format
261
262                 Formats: xml, json, rss, atom
263
264                 Parameters:
265
266                     * id. Optional. Specifies the ID or screen name of the user for whom to return the
267             friends_timeline. Ex: http://server/api/statuses/user_timeline/12345.xml or
268             http://server/api/statuses/user_timeline/bob.json.
269                         * count. Optional. Specifies the number of
270             statuses to retrieve. May not be greater than 200. Ex:
271             http://server/api/statuses/user_timeline.xml?count=5
272                         * since. Optional. Narrows the returned
273             results to just those statuses created after the specified HTTP-formatted date. The same
274             behavior is available by setting an If-Modified-Since header in your HTTP request. Ex:
275             http://server/api/statuses/user_timeline.rss?since=Tue%2C+27+Mar+2007+22%3A55%3A48+GMT
276                         * since_id. Optional. Returns only statuses with an ID greater than (that is, more recent than)
277             the specified ID. Ex: http://server/api/statuses/user_timeline.xml?since_id=12345 * page.
278             Optional. Ex: http://server/api/statuses/friends_timeline.rss?page=3
279         */
280         function user_timeline($args, $apidata) {
281                 parent::handle($args);
282
283                 $user = null;
284
285                 // function was called with an argument /statuses/user_timeline/api_arg.format
286                 if (isset($apidata['api_arg'])) {
287
288                         if (is_numeric($apidata['api_arg'])) {
289                                 $user = User::staticGet($apidata['api_arg']);
290                         } else {
291                                 $nickname = common_canonical_nickname($apidata['api_arg']);
292                                 $user = User::staticGet('nickname', $nickname);
293                         }
294                 } else {
295
296                         // if no user was specified, then we'll use the authenticated user
297                         $user = $apidata['user'];
298                 }
299
300                 if (!$user) {
301                         // Set the user to be the auth user if asked-for can't be found
302                         // honestly! This is what Twitter does, I swear --Zach
303                         $user = $apidata['user'];
304                 }
305
306                 $profile = $user->getProfile();
307
308                 if (!$profile) {
309                         common_server_error(_('User has no profile.'));
310                         exit();
311                 }
312
313                 $count = $this->arg('count');
314                 $since = $this->arg('since');
315                 $since_id = $this->arg('since_id');
316                 $page = $this->arg('page');
317
318                 if (!$page) {
319                         $page = 1;
320                 }
321
322                 if (!$count) {
323                         $count = 20;
324                 }
325
326                 $sitename = common_config('site', 'name');
327                 $siteserver = common_config('site', 'server');
328
329                 $title = sprintf(_("%s timeline"), $user->nickname);
330                 $id = "tag:$siteserver:user:".$user->id;
331                 $link = common_local_url('showstream', array('nickname' => $user->nickname));
332                 $subtitle = sprintf(_('Updates from %1$s on %2$s!'), $user->nickname, $sitename);
333
334                 # XXX: since
335                 # XXX: since_id
336
337                 $notice = $user->getNotices((($page-1)*20), $count);
338
339                 switch($apidata['content-type']) {
340                  case 'xml':
341                         $this->show_xml_timeline($notice);
342                         break;
343                  case 'rss':
344                         $this->show_rss_timeline($notice, $title, $id, $link, $subtitle);
345                         break;
346                  case 'atom':
347                         $this->show_atom_timeline($notice, $title, $id, $link, $subtitle);
348                         break;
349                  case 'json':
350                         $this->show_json_timeline($notice);
351                         break;
352                  default:
353                         common_user_error(_('API method not found!'), $code = 404);
354                 }
355
356                 exit();
357         }
358
359         function update($args, $apidata) {
360
361                 parent::handle($args);
362
363                 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
364                         $this->client_error(_('This method requires a POST.'), 400, $apidata['content-type']);
365                         exit();
366                 }
367
368                 $user = $apidata['user'];
369                 $status = $this->trimmed('status');
370                 $source = $this->trimmed('source');
371                 $in_reply_to_status_id = intval($this->trimmed('in_reply_to_status_id'));
372
373                 if (!$source) {
374                         $source = 'api';
375                 }
376
377                 if (!$status) {
378
379                         // XXX: Note: In this case, Twitter simply returns '200 OK'
380                         // No error is given, but the status is not posted to the
381                         // user's timeline.  Seems bad.  Shouldn't we throw an
382                         // errror? -- Zach
383                         exit();
384
385                 } else if (mb_strlen($status) > 140) {
386
387                         // XXX: Twitter truncates anything over 140, flags the status
388                     // as "truncated."  Sending this error may screw up some clients
389                     // that assume Twitter will truncate for them.  Should we just
390                     // truncate too? -- Zach
391                         $this->client_error(_('That\'s too long. Max notice size is 140 chars.'), $code = 406, $apidata['content-type']);
392                         exit();
393                 }
394
395                 $reply_to = NULL;
396
397                 if ($in_reply_to_status_id) {
398                                                 
399                         // check whether notice actually exists
400                         $reply = Notice::staticGet($in_reply_to_status_id);
401                         
402                         if ($reply) {
403                                 $reply_to = $in_reply_to_status_id;
404                         } else {
405                                 $this->client_error(_('Not found'), $code = 404, $apidata['content-type']);
406                                 exit();
407                         }
408                 }
409                         
410                 $notice = Notice::saveNew($user->id, $status, $source, 1, $reply_to);
411
412                 if (is_string($notice)) {
413                         $this->server_error($notice);
414                         exit();
415                 }
416
417                 common_broadcast_notice($notice);
418
419                 // FIXME: Bad Hack
420                 // I should be able to just sent this notice off for display,
421                 // but $notice->created does not contain a string at this
422                 // point and I don't know how to convert it to one here. So
423                 // I'm forced to have DBObject pull the notice back out of the
424                 // DB before printing. --Zach
425                 $apidata['api_arg'] = $notice->id;
426                 $this->show($args, $apidata);
427
428                 exit();
429         }
430
431         /*
432                 Returns the 20 most recent @replies (status updates prefixed with @username) for the authenticating user.
433                 URL: http://server/api/statuses/replies.format
434
435                 Formats: xml, json, rss, atom
436
437                 Parameters:
438
439                 * page. Optional. Retrieves the 20 next most recent replies. Ex: http://server/api/statuses/replies.xml?page=3
440                 * since. Optional. Narrows the returned results to just those replies created after the specified HTTP-formatted date. The
441         same behavior is available by setting an If-Modified-Since header in your HTTP request. Ex:
442         http://server/api/statuses/replies.xml?since=Tue%2C+27+Mar+2007+22%3A55%3A48+GMT
443                 * since_id. Optional. Returns only statuses with an ID greater than (that is, more recent than) the specified
444                 ID. Ex: http://server/api/statuses/replies.xml?since_id=12345
445         */
446         function replies($args, $apidata) {
447
448                 parent::handle($args);
449
450                 $since = $this->arg('since');
451
452                 $count = $this->arg('count');
453                 $page = $this->arg('page');
454
455                 $user = $apidata['user'];
456                 $profile = $user->getProfile();
457
458                 $sitename = common_config('site', 'name');
459                 $siteserver = common_config('site', 'server');
460
461                 $title = sprintf(_('%1$s / Updates replying to %2$s'), $sitename, $user->nickname);
462                 $id = "tag:$siteserver:replies:".$user->id;
463                 $link = common_local_url('replies', array('nickname' => $user->nickname));
464                 $subtitle = "gar";
465                 $subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), $sitename, $user->nickname, $profile->getBestName());
466
467                 if (!$page) {
468                         $page = 1;
469                 }
470
471                 if (!$count) {
472                         $count = 20;
473                 }
474
475                 $notice = $user->getReplies((($page-1)*20), $count);
476                 $notices = array();
477
478                 while ($notice->fetch()) {
479                         $notices[] = clone($notice);
480                 }
481
482                 switch($apidata['content-type']) {
483                  case 'xml':
484                         $this->show_xml_timeline($notices);
485                         break;
486                  case 'rss':
487                         $this->show_rss_timeline($notices, $title, $id, $link, $subtitle);
488                         break;
489                  case 'atom':
490                         $this->show_atom_timeline($notices, $title, $id, $link, $subtitle);
491                         break;
492                  case 'json':
493                         $this->show_json_timeline($notices);
494                         break;
495                  default:
496                         common_user_error(_('API method not found!'), $code = 404);
497                 }
498
499
500                 exit();
501
502
503         }
504
505         function show($args, $apidata) {
506                 parent::handle($args);
507                 
508                 $notice_id = $apidata['api_arg'];               
509                 $notice = Notice::staticGet($notice_id);
510
511                 if ($notice) {
512                         if ($apidata['content-type'] == 'xml') { 
513                                 $this->show_single_xml_status($notice);
514                         } elseif ($apidata['content-type'] == 'json') {
515                                 $this->show_single_json_status($notice);
516                         }
517                 } else {
518                         // XXX: Twitter just sets a 404 header and doens't bother to return an err msg
519                         $this->client_error(_('No status with that ID found.'), 404, $apidata['content-type']);
520                 }
521                 
522                 exit();
523         }
524
525
526         /*
527                 Destroys the status specified by the required ID parameter. The authenticating user must be
528         the author of the specified status.
529
530                  URL: http://server/api/statuses/destroy/id.format
531
532                  Formats: xml, json
533
534                  Parameters:
535
536                  * id. Required. The ID of the status to destroy. Ex:
537                 http://server/api/statuses/destroy/12345.json or
538                 http://server/api/statuses/destroy/23456.xml
539
540         */
541         function destroy($args, $apidata) {
542         
543                 parent::handle($args);
544
545                 common_debug($_SERVER['REQUEST_METHOD']);
546                 
547                 // Check for RESTfulness  
548                 if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
549                         // XXX: Twitter just prints the err msg, no XML / JSON.
550                         $this->client_error(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']);
551                         exit();
552                 } 
553                 
554                 $user = $apidata['user'];                               
555                 $notice_id = $apidata['api_arg'];               
556                 $notice = Notice::staticGet($notice_id);
557                 
558                 if (!$notice) {
559                         $this->client_error(_('No status found with that ID.'), 404, $apidata['content-type']);
560                         exit();
561                 }
562                                 
563                 if ($user->id == $notice->profile_id) {
564                         $replies = new Reply;
565                         $replies->get('notice_id', $notice_id);
566                         common_dequeue_notice($notice);
567                         $replies->delete();
568                         $notice->delete();
569                         
570                         if ($apidata['content-type'] == 'xml') { 
571                                 $this->show_single_xml_status($notice);
572                         } elseif ($apidata['content-type'] == 'json') {
573                                 $this->show_single_json_status($notice);
574                         }       
575                 } else {
576                         $this->client_error(_('You may not delete another user\'s status.'), 403, $apidata['content-type']);
577                 }
578                 
579                 exit();
580         }
581
582         # User Methods
583
584         /*
585                 Returns up to 100 of the authenticating user's friends who have most recently updated, each with current status inline.
586         It's also possible to request another user's recent friends list via the id parameter below.
587
588                  URL: http://server/api/statuses/friends.format
589
590                  Formats: xml, json
591
592                  Parameters:
593
594                  * id. Optional. The ID or screen name of the user for whom to request a list of friends. Ex:
595                 http://server/api/statuses/friends/12345.json
596                         or
597                         http://server/api/statuses/friends/bob.xml
598                  * page. Optional. Retrieves the next 100 friends. Ex: http://server/api/statuses/friends.xml?page=2
599                  * lite. Optional. Prevents the inline inclusion of current status. Must be set to a value of true. Ex:
600                 http://server/api/statuses/friends.xml?lite=true
601                  * since. Optional. Narrows the returned results to just those friendships created after the specified
602                         HTTP-formatted date. The same behavior is available by setting an If-Modified-Since header in your HTTP
603                         request. Ex: http://server/api/statuses/friends.xml?since=Tue%2C+27+Mar+2007+22%3A55%3A48+GMT
604         */
605         function friends($args, $apidata) {
606                 parent::handle($args);
607                 return $this->subscriptions($apidata, 'subscribed', 'subscriber');
608         }
609
610         /*
611                 Returns the authenticating user's followers, each with current status inline. They are ordered by the
612                 order in which they joined Twitter (this is going to be changed).
613
614                 URL: http://server/api/statuses/followers.format
615                 Formats: xml, json
616
617                 Parameters:
618
619                     * id. Optional. The ID or screen name of the user for whom to request a list of followers. Ex:
620                 http://server/api/statuses/followers/12345.json
621                                 or
622                                 http://server/api/statuses/followers/bob.xml
623                     * page. Optional. Retrieves the next 100 followers. Ex: http://server/api/statuses/followers.xml?page=2
624                     * lite. Optional. Prevents the inline inclusion of current status. Must be set to a value of true.
625                                 Ex: http://server/api/statuses/followers.xml?lite=true
626         */
627         function followers($args, $apidata) {
628                 parent::handle($args);
629
630                 return $this->subscriptions($apidata, 'subscriber', 'subscribed');
631         }
632
633         function subscriptions($apidata, $other_attr, $user_attr) {
634
635                 $user = $this->get_subs_user($apidata);
636
637                 # XXX: id
638                 # XXX: lite
639
640                 $page = $this->trimmed('page');
641
642                 if (!$page || !is_numeric($page)) {
643                         $page = 1;
644                 }
645
646                 $profile = $user->getProfile();
647
648                 if (!$profile) {
649                         common_server_error(_('User has no profile.'));
650                         return;
651                 }
652
653                 $sub = new Subscription();
654                 $sub->$user_attr = $profile->id;
655                 $sub->orderBy('created DESC');
656                 $sub->limit(($page-1)*100, 100);
657
658                 $others = array();
659
660                 if ($sub->find()) {
661                         while ($sub->fetch()) {
662                                 $others[] = Profile::staticGet($sub->$other_attr);
663                         }
664                 } else {
665                         // user has no followers
666                 }
667
668                 $type = $apidata['content-type'];
669
670                 $this->init_document($type);
671                 $this->show_profiles($others, $type);
672                 $this->end_document($type);
673                 exit();
674         }
675
676         function get_subs_user($apidata) {
677
678                 // function was called with an argument /statuses/user_timeline/api_arg.format
679                 if (isset($apidata['api_arg'])) {
680
681                         if (is_numeric($apidata['api_arg'])) {
682                                 $user = User::staticGet($apidata['api_arg']);
683                         } else {
684                                 $nickname = common_canonical_nickname($apidata['api_arg']);
685                                 $user = User::staticGet('nickname', $nickname);
686                         }
687                 } else {
688
689                         // if no user was specified, then we'll use the authenticated user
690                         $user = $apidata['user'];
691                 }
692
693                 if (!$user) {
694                         // Set the user to be the auth user if asked-for can't be found
695                         // honestly! This is what Twitter does, I swear --Zach
696                         $user = $apidata['user'];
697                 }
698
699                 return $user;
700         }
701
702         function show_profiles($profiles, $type) {
703                 switch ($type) {
704                  case 'xml':
705                         common_element_start('users', array('type' => 'array'));
706                         foreach ($profiles as $profile) {
707                                 $this->show_profile($profile);
708                         }
709                         common_element_end('users');
710                         break;
711                  case 'json':
712                         $arrays = array();
713                         foreach ($profiles as $profile) {
714                                 $arrays[] = $this->twitter_user_array($profile, true);
715                         }
716                         print json_encode($arrays);
717                         break;
718                  default:
719                         $this->client_error(_('unsupported file type'));
720                         exit();
721                 }
722         }
723
724         /*
725         Returns a list of the users currently featured on the site with their current statuses inline.
726         URL: http://server/api/statuses/featured.format
727
728         Formats: xml, json
729         */
730         function featured($args, $apidata) {
731                 parent::handle($args);
732                 common_server_error(_('API method under construction.'), $code=501);
733         }
734
735         function get_user($id, $apidata) {
736                 if (!$id) {
737                         return $apidata['user'];
738                 } else if (is_numeric($id)) {
739                         return User::staticGet($id);
740                 } else {
741                         return User::staticGet('nickname', $id);
742                 }
743         }
744 }
745