]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - _darcs/pristine/lib/twitterapi.php
move opening brace of class declaration to next line
[quix0rs-gnu-social.git] / _darcs / pristine / lib / twitterapi.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 class TwitterapiAction extends Action
23 {
24
25     var $auth_user;
26
27     function handle($args)
28     {
29         parent::handle($args);
30     }
31
32     function twitter_user_array($profile, $get_notice=false)
33     {
34
35         $twitter_user = array();
36
37         $twitter_user['name'] = $profile->getBestName();
38         $twitter_user['followers_count'] = $this->count_subscriptions($profile);
39         $twitter_user['screen_name'] = $profile->nickname;
40         $twitter_user['description'] = ($profile->bio) ? $profile->bio : null;
41         $twitter_user['location'] = ($profile->location) ? $profile->location : null;
42         $twitter_user['id'] = intval($profile->id);
43
44         $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
45
46         $twitter_user['profile_image_url'] = ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE);
47         $twitter_user['protected'] = 'false'; # not supported by Laconica yet
48         $twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
49
50         if ($get_notice) {
51             $notice = $profile->getCurrentNotice();
52             if ($notice) {
53                 # don't get user!
54                 $twitter_user['status'] = $this->twitter_status_array($notice, false);
55             }
56         }
57
58         return $twitter_user;
59     }
60
61     function twitter_status_array($notice, $include_user=true)
62     {
63
64         $profile = $notice->getProfile();
65
66         $twitter_status = array();
67         $twitter_status['text'] = $notice->content;
68         $twitter_status['truncated'] = 'false'; # Not possible on Laconica
69         $twitter_status['created_at'] = $this->date_twitter($notice->created);
70         $twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ? intval($notice->reply_to) : null;
71         $twitter_status['source'] = $this->source_link($notice->source);
72         $twitter_status['id'] = intval($notice->id);
73         $twitter_status['in_reply_to_user_id'] = ($notice->reply_to) ? $this->replier_by_reply(intval($notice->reply_to)) : null;
74
75         if (isset($this->auth_user)) {
76             $twitter_status['favorited'] = ($this->auth_user->hasFave($notice)) ? 'true' : 'false';
77         } else {
78             $twitter_status['favorited'] = 'false';
79         }
80
81         if ($include_user) {
82             # Don't get notice (recursive!)
83             $twitter_user = $this->twitter_user_array($profile, false);
84             $twitter_status['user'] = $twitter_user;
85         }
86
87         return $twitter_status;
88     }
89
90     function twitter_rss_entry_array($notice)
91     {
92
93         $profile = $notice->getProfile();
94
95         $server = common_config('site', 'server');
96         $entry = array();
97
98         # We trim() to avoid extraneous whitespace in the output
99
100         $entry['content'] = common_xml_safe_str(trim($notice->rendered));
101         $entry['title'] = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content));
102         $entry['link'] = common_local_url('shownotice', array('notice' => $notice->id));
103         $entry['published'] = common_date_iso8601($notice->created);
104         $entry['id'] = "tag:$server,2008:$entry[link]";
105         $entry['updated'] = $entry['published'];
106
107         # RSS Item specific
108         $entry['description'] = $entry['content'];
109         $entry['pubDate'] = common_date_rfc2822($notice->created);
110         $entry['guid'] = $entry['link'];
111
112         return $entry;
113     }
114
115     function twitter_rss_dmsg_array($message)
116     {
117
118         $server = common_config('site', 'server');
119         $entry = array();
120
121         $entry['title'] = sprintf('Message from %s to %s',
122             $message->getFrom()->nickname, $message->getTo()->nickname);
123
124         $entry['content'] = common_xml_safe_str(trim($message->content));
125         $entry['link'] = common_local_url('showmessage', array('message' => $message->id));
126         $entry['published'] = common_date_iso8601($message->created);
127         $entry['id'] = "tag:$server,2008:$entry[link]";
128         $entry['updated'] = $entry['published'];
129
130         # RSS Item specific
131         $entry['description'] = $entry['content'];
132         $entry['pubDate'] = common_date_rfc2822($message->created);
133         $entry['guid'] = $entry['link'];
134
135         return $entry;
136     }
137
138     function twitter_dmsg_array($message)
139     {
140
141         $twitter_dm = array();
142
143         $from_profile = $message->getFrom();
144         $to_profile = $message->getTo();
145
146         $twitter_dm['id'] = $message->id;
147         $twitter_dm['sender_id'] = $message->from_profile;
148         $twitter_dm['text'] = trim($message->content);
149         $twitter_dm['recipient_id'] = $message->to_profile;
150         $twitter_dm['created_at'] = $this->date_twitter($message->created);
151         $twitter_dm['sender_screen_name'] = $from_profile->nickname;
152         $twitter_dm['recipient_screen_name'] = $to_profile->nickname;
153         $twitter_dm['sender'] = $this->twitter_user_array($from_profile, false);
154         $twitter_dm['recipient'] = $this->twitter_user_array($to_profile, false);
155
156         return $twitter_dm;
157     }
158
159     function show_twitter_xml_status($twitter_status)
160     {
161         common_element_start('status');
162         foreach($twitter_status as $element => $value) {
163             switch ($element) {
164             case 'user':
165                 $this->show_twitter_xml_user($twitter_status['user']);
166                 break;
167             case 'text':
168                 common_element($element, null, common_xml_safe_str($value));
169                 break;
170             default:
171                 common_element($element, null, $value);
172             }
173         }
174         common_element_end('status');
175     }
176
177     function show_twitter_xml_user($twitter_user, $role='user')
178     {
179         common_element_start($role);
180         foreach($twitter_user as $element => $value) {
181             if ($element == 'status') {
182                 $this->show_twitter_xml_status($twitter_user['status']);
183             } else {
184                 common_element($element, null, $value);
185             }
186         }
187         common_element_end($role);
188     }
189
190     function show_twitter_rss_item($entry)
191     {
192         common_element_start('item');
193         common_element('title', null, $entry['title']);
194         common_element('description', null, $entry['description']);
195         common_element('pubDate', null, $entry['pubDate']);
196         common_element('guid', null, $entry['guid']);
197         common_element('link', null, $entry['link']);
198         common_element_end('item');
199     }
200
201     function show_twitter_atom_entry($entry)
202     {
203         common_element_start('entry');
204         common_element('title', null, $entry['title']);
205         common_element('content', array('type' => 'html'), $entry['content']);
206         common_element('id', null, $entry['id']);
207         common_element('published', null, $entry['published']);
208         common_element('updated', null, $entry['updated']);
209         common_element('link', array('href' => $entry['link'], 'rel' => 'alternate', 'type' => 'text/html'), null);
210         common_element_end('entry');
211     }
212
213     function show_json_objects($objects)
214     {
215         print(json_encode($objects));
216     }
217
218     function show_single_xml_status($notice)
219     {
220         $this->init_document('xml');
221         $twitter_status = $this->twitter_status_array($notice);
222         $this->show_twitter_xml_status($twitter_status);
223         $this->end_document('xml');
224     }
225
226     function show_single_json_status($notice)
227     {
228         $this->init_document('json');
229         $status = $this->twitter_status_array($notice);
230         $this->show_json_objects($status);
231         $this->end_document('json');
232     }
233
234     function show_single_xml_dmsg($message)
235     {
236         $this->init_document('xml');
237         $dmsg = $this->twitter_dmsg_array($message);
238         $this->show_twitter_xml_dmsg($dmsg);
239         $this->end_document('xml');
240     }
241
242     function show_single_json_dmsg($message)
243     {
244         $this->init_document('json');
245         $dmsg = $this->twitter_dmsg_array($message);
246         $this->show_json_objects($dmsg);
247         $this->end_document('json');
248     }
249
250     function show_twitter_xml_dmsg($twitter_dm)
251     {
252         common_element_start('direct_message');
253         foreach($twitter_dm as $element => $value) {
254             switch ($element) {
255             case 'sender':
256             case 'recipient':
257                 $this->show_twitter_xml_user($value, $element);
258                 break;
259             case 'text':
260                 common_element($element, null, common_xml_safe_str($value));
261                 break;
262             default:
263                 common_element($element, null, $value);
264             }
265         }
266         common_element_end('direct_message');
267     }
268
269     function show_xml_timeline($notice)
270     {
271
272         $this->init_document('xml');
273         common_element_start('statuses', array('type' => 'array'));
274
275         if (is_array($notice)) {
276             foreach ($notice as $n) {
277                 $twitter_status = $this->twitter_status_array($n);
278                 $this->show_twitter_xml_status($twitter_status);
279             }
280         } else {
281             while ($notice->fetch()) {
282                 $twitter_status = $this->twitter_status_array($notice);
283                 $this->show_twitter_xml_status($twitter_status);
284             }
285         }
286
287         common_element_end('statuses');
288         $this->end_document('xml');
289     }
290
291     function show_rss_timeline($notice, $title, $link, $subtitle, $suplink=null)
292     {
293
294         $this->init_document('rss');
295
296         common_element_start('channel');
297         common_element('title', null, $title);
298         common_element('link', null, $link);
299         if (!is_null($suplink)) {
300             # For FriendFeed's SUP protocol
301             common_element('link', array('xmlns' => 'http://www.w3.org/2005/Atom',
302                                          'rel' => 'http://api.friendfeed.com/2008/03#sup',
303                                          'href' => $suplink,
304                                          'type' => 'application/json'));
305         }
306         common_element('description', null, $subtitle);
307         common_element('language', null, 'en-us');
308         common_element('ttl', null, '40');
309
310         if (is_array($notice)) {
311             foreach ($notice as $n) {
312                 $entry = $this->twitter_rss_entry_array($n);
313                 $this->show_twitter_rss_item($entry);
314             }
315         } else {
316             while ($notice->fetch()) {
317                 $entry = $this->twitter_rss_entry_array($notice);
318                 $this->show_twitter_rss_item($entry);
319             }
320         }
321
322         common_element_end('channel');
323         $this->end_twitter_rss();
324     }
325
326     function show_atom_timeline($notice, $title, $id, $link, $subtitle=null, $suplink=null)
327     {
328
329         $this->init_document('atom');
330
331         common_element('title', null, $title);
332         common_element('id', null, $id);
333         common_element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null);
334         if (!is_null($suplink)) {
335             # For FriendFeed's SUP protocol
336             common_element('link', array('rel' => 'http://api.friendfeed.com/2008/03#sup',
337                                          'href' => $suplink,
338                                          'type' => 'application/json'));
339         }
340         common_element('subtitle', null, $subtitle);
341
342         if (is_array($notice)) {
343             foreach ($notice as $n) {
344                 $entry = $this->twitter_rss_entry_array($n);
345                 $this->show_twitter_atom_entry($entry);
346             }
347         } else {
348             while ($notice->fetch()) {
349                 $entry = $this->twitter_rss_entry_array($notice);
350                 $this->show_twitter_atom_entry($entry);
351             }
352         }
353
354         $this->end_document('atom');
355
356     }
357
358     function show_json_timeline($notice)
359     {
360
361         $this->init_document('json');
362
363         $statuses = array();
364
365         if (is_array($notice)) {
366             foreach ($notice as $n) {
367                 $twitter_status = $this->twitter_status_array($n);
368                 array_push($statuses, $twitter_status);
369             }
370         } else {
371             while ($notice->fetch()) {
372                 $twitter_status = $this->twitter_status_array($notice);
373                 array_push($statuses, $twitter_status);
374             }
375         }
376
377         $this->show_json_objects($statuses);
378
379         $this->end_document('json');
380     }
381
382     // Anyone know what date format this is?
383     // Twitter's dates look like this: "Mon Jul 14 23:52:38 +0000 2008" -- Zach
384     function date_twitter($dt)
385     {
386         $t = strtotime($dt);
387         return date("D M d G:i:s O Y", $t);
388     }
389
390     function replier_by_reply($reply_id)
391     {
392         $notice = Notice::staticGet($reply_id);
393         if ($notice) {
394             $profile = $notice->getProfile();
395             if ($profile) {
396                 return intval($profile->id);
397             } else {
398                 common_debug('Can\'t find a profile for notice: ' . $notice->id, __FILE__);
399             }
400         } else {
401             common_debug("Can't get notice: $reply_id", __FILE__);
402         }
403         return null;
404     }
405
406     // XXX: Candidate for a general utility method somewhere?
407     function count_subscriptions($profile)
408     {
409
410         $count = 0;
411         $sub = new Subscription();
412         $sub->subscribed = $profile->id;
413
414         $count = $sub->find();
415
416         if ($count > 0) {
417             return $count - 1;
418         } else {
419             return 0;
420         }
421     }
422
423     function init_document($type='xml')
424     {
425         switch ($type) {
426          case 'xml':
427             header('Content-Type: application/xml; charset=utf-8');
428             common_start_xml();
429             break;
430          case 'json':
431             header('Content-Type: application/json; charset=utf-8');
432
433             // Check for JSONP callback
434             $callback = $this->arg('callback');
435             if ($callback) {
436                 print $callback . '(';
437             }
438             break;
439          case 'rss':
440             header("Content-Type: application/rss+xml; charset=utf-8");
441             $this->init_twitter_rss();
442             break;
443          case 'atom':
444             header('Content-Type: application/atom+xml; charset=utf-8');
445             $this->init_twitter_atom();
446             break;
447          default:
448             $this->client_error(_('Not a supported data format.'));
449             break;
450         }
451
452         return;
453     }
454
455     function end_document($type='xml')
456     {
457         switch ($type) {
458          case 'xml':
459             common_end_xml();
460             break;
461          case 'json':
462
463             // Check for JSONP callback
464             $callback = $this->arg('callback');
465             if ($callback) {
466                 print ')';
467             }
468             break;
469          case 'rss':
470             $this->end_twitter_rss();
471             break;
472          case 'atom':
473             $this->end_twitter_rss();
474             break;
475          default:
476             $this->client_error(_('Not a supported data format.'));
477             break;
478         }
479         return;
480     }
481
482     function client_error($msg, $code = 400, $content_type = 'json')
483     {
484
485         static $status = array(400 => 'Bad Request',
486                                401 => 'Unauthorized',
487                                402 => 'Payment Required',
488                                403 => 'Forbidden',
489                                404 => 'Not Found',
490                                405 => 'Method Not Allowed',
491                                406 => 'Not Acceptable',
492                                407 => 'Proxy Authentication Required',
493                                408 => 'Request Timeout',
494                                409 => 'Conflict',
495                                410 => 'Gone',
496                                411 => 'Length Required',
497                                412 => 'Precondition Failed',
498                                413 => 'Request Entity Too Large',
499                                414 => 'Request-URI Too Long',
500                                415 => 'Unsupported Media Type',
501                                416 => 'Requested Range Not Satisfiable',
502                                417 => 'Expectation Failed');
503
504         $action = $this->trimmed('action');
505
506         common_debug("User error '$code' on '$action': $msg", __FILE__);
507
508         if (!array_key_exists($code, $status)) {
509             $code = 400;
510         }
511
512         $status_string = $status[$code];
513         header('HTTP/1.1 '.$code.' '.$status_string);
514
515         if ($content_type == 'xml') {
516             $this->init_document('xml');
517             common_element_start('hash');
518             common_element('error', null, $msg);
519             common_element('request', null, $_SERVER['REQUEST_URI']);
520             common_element_end('hash');
521             $this->end_document('xml');
522         } else {
523             $this->init_document('json');
524             $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
525             print(json_encode($error_array));
526             $this->end_document('json');
527         }
528
529     }
530
531     function init_twitter_rss()
532     {
533         common_start_xml();
534         common_element_start('rss', array('version' => '2.0'));
535     }
536
537     function end_twitter_rss()
538     {
539         common_element_end('rss');
540         common_end_xml();
541     }
542
543     function init_twitter_atom()
544     {
545         common_start_xml();
546         common_element_start('feed', array('xmlns' => 'http://www.w3.org/2005/Atom', 'xml:lang' => 'en-US'));
547     }
548
549     function end_twitter_atom()
550     {
551         common_end_xml();
552         common_element_end('feed');
553     }
554
555     function show_profile($profile, $content_type='xml', $notice=null)
556     {
557         $profile_array = $this->twitter_user_array($profile, true);
558         switch ($content_type) {
559          case 'xml':
560             $this->show_twitter_xml_user($profile_array);
561             break;
562          case 'json':
563             $this->show_json_objects($profile_array);
564             break;
565          default:
566             $this->client_error(_('Not a supported data format.'));
567             return;
568         }
569         return;
570     }
571
572     function get_user($id, $apidata=null)
573     {
574         if (!$id) {
575             return $apidata['user'];
576         } else if (is_numeric($id)) {
577             return User::staticGet($id);
578         } else {
579             $nickname = common_canonical_nickname($id);
580             return User::staticGet('nickname', $nickname);
581         }
582     }
583
584     function get_profile($id)
585     {
586         if (is_numeric($id)) {
587             return Profile::staticGet($id);
588         } else {
589             $user = User::staticGet('nickname', $id);
590             if ($user) {
591                 return $user->getProfile();
592             } else {
593                 return null;
594             }
595         }
596     }
597
598     function source_link($source)
599     {
600         $source_name = _($source);
601         switch ($source) {
602          case 'web':
603          case 'xmpp':
604          case 'mail':
605          case 'omb':
606          case 'api':
607             break;
608          default:
609             $ns = Notice_source::staticGet($source);
610             if ($ns) {
611                 $source_name = '<a href="' . $ns->url . '">' . $ns->name . '</a>';
612             }
613             break;
614         }
615         return $source_name;
616     }
617
618     function show_extended_profile($user, $apidata)
619     {
620
621         $this->auth_user = $apidata['user'];
622
623         $profile = $user->getProfile();
624
625         if (!$profile) {
626             common_server_error(_('User has no profile.'));
627             return;
628         }
629
630         $twitter_user = $this->twitter_user_array($profile, true);
631
632         // Add in extended user fields offered up by this method
633         $twitter_user['created_at'] = $this->date_twitter($profile->created);
634
635         $subbed = DB_DataObject::factory('subscription');
636         $subbed->subscriber = $profile->id;
637         $subbed_count = (int) $subbed->count() - 1;
638
639         $notices = DB_DataObject::factory('notice');
640         $notices->profile_id = $profile->id;
641         $notice_count = (int) $notices->count();
642
643         $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
644         $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
645
646         // Other fields Twitter sends...
647         $twitter_user['profile_background_color'] = '';
648         $twitter_user['profile_text_color'] = '';
649         $twitter_user['profile_link_color'] = '';
650         $twitter_user['profile_sidebar_fill_color'] = '';
651
652         $faves = DB_DataObject::factory('fave');
653         $faves->user_id = $user->id;
654         $faves_count = (int) $faves->count();
655         $twitter_user['favourites_count'] = $faves_count;
656
657         $timezone = 'UTC';
658
659         if ($user->timezone) {
660             $timezone = $user->timezone;
661         }
662
663         $t = new DateTime;
664         $t->setTimezone(new DateTimeZone($timezone));
665         $twitter_user['utc_offset'] = $t->format('Z');
666         $twitter_user['time_zone'] = $timezone;
667
668         $following = 'false';
669
670         if (isset($this->auth_user)) {
671             if ($this->auth_user->isSubscribed($profile)) {
672                 $following = 'true';
673             }
674
675             // Not implemented yet
676             $twitter_user['notifications'] = 'false';
677         }
678
679         $twitter_user['following'] = $following;
680
681         if ($apidata['content-type'] == 'xml') {
682             $this->init_document('xml');
683             $this->show_twitter_xml_user($twitter_user);
684             $this->end_document('xml');
685         } elseif ($apidata['content-type'] == 'json') {
686             $this->init_document('json');
687             $this->show_json_objects($twitter_user);
688             $this->end_document('json');
689         }
690
691     }
692
693 }