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