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