]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Facebook/FacebookPlugin.php
some formatting changes to make inblobs work
[quix0rs-gnu-social.git] / plugins / Facebook / FacebookPlugin.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * Plugin to add a StatusNet Facebook application
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Plugin
23  * @package   StatusNet
24  * @author    Zach Copley <zach@status.net>
25  * @copyright 2009 StatusNet, Inc.
26  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
27  * @link      http://status.net/
28  */
29
30 if (!defined('STATUSNET')) {
31     exit(1);
32 }
33
34 define("FACEBOOK_CONNECT_SERVICE", 3);
35
36 require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php';
37
38 /**
39  * Facebook plugin to add a StatusNet Facebook application
40  *
41  * @category Plugin
42  * @package  StatusNet
43  * @author   Zach Copley <zach@status.net>
44  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
45  * @link     http://status.net/
46  */
47
48 class FacebookPlugin extends Plugin
49 {
50
51     /**
52      * Add Facebook app actions to the router table
53      *
54      * Hook for RouterInitialized event.
55      *
56      * @param Net_URL_Mapper &$m path-to-action mapper
57      *
58      * @return boolean hook return
59      */
60
61     function onStartInitializeRouter($m)
62     {
63
64         // Facebook App stuff
65
66         $m->connect('facebook/app', array('action' => 'facebookhome'));
67         $m->connect('facebook/app/index.php', array('action' => 'facebookhome'));
68         $m->connect('facebook/app/settings.php',
69                     array('action' => 'facebooksettings'));
70         $m->connect('facebook/app/invite.php', array('action' => 'facebookinvite'));
71         $m->connect('facebook/app/remove', array('action' => 'facebookremove'));
72
73         // Facebook Connect stuff
74
75         $m->connect('main/facebookconnect', array('action' => 'FBConnectAuth'));
76         $m->connect('main/facebooklogin', array('action' => 'FBConnectLogin'));
77         $m->connect('settings/facebook', array('action' => 'FBConnectSettings'));
78         $m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver'));
79
80         return true;
81     }
82
83     /**
84      * Automatically load the actions and libraries used by the Facebook app
85      *
86      * @param Class $cls the class
87      *
88      * @return boolean hook return
89      *
90      */
91
92     function onAutoload($cls)
93     {
94         switch ($cls) {
95         case 'FacebookAction':
96         case 'FacebookhomeAction':
97         case 'FacebookinviteAction':
98         case 'FacebookremoveAction':
99         case 'FacebooksettingsAction':
100             include_once INSTALLDIR . '/plugins/Facebook/' .
101               strtolower(mb_substr($cls, 0, -6)) . '.php';
102             return false;
103         case 'FBConnectAuthAction':
104         case 'FBConnectLoginAction':
105         case 'FBConnectSettingsAction':
106         case 'FBC_XDReceiverAction':
107             include_once INSTALLDIR . '/plugins/Facebook/' .
108               mb_substr($cls, 0, -6) . '.php';
109             return false;
110         case 'FBCLoginGroupNav':
111             include_once INSTALLDIR . '/plugins/Facebook/FBCLoginGroupNav.php';
112             return false;
113         case 'FBCSettingsNav':
114             include_once INSTALLDIR . '/plugins/Facebook/FBCSettingsNav.php';
115             return false;
116         default:
117             return true;
118         }
119     }
120
121     /**
122      * Override normal HTML output to force the content type to
123      * text/html and add in xmlns:fb
124      *
125      * @param Action $action the current action
126      *
127      * @return void
128      */
129
130     function onStartShowHTML($action)
131     {
132
133         if ($this->reqFbScripts($action)) {
134
135             // XXX: Horrible hack to make Safari, FF2, and Chrome work with
136             // Facebook Connect. These browser cannot use Facebook's
137             // DOM parsing routines unless the mime type of the page is
138             // text/html even though Facebook Connect uses XHTML.  This is
139             // A bug in Facebook Connect, and this is a temporary solution
140             // until they fix their JavaScript libs.
141
142             header('Content-Type: text/html');
143
144             $action->extraHeaders();
145
146             $action->startXML('html');
147
148             $language = $action->getLanguage();
149
150             $action->elementStart('html',
151                 array('xmlns'  => 'http://www.w3.org/1999/xhtml',
152                       'xmlns:fb' => 'http://www.facebook.com/2008/fbml',
153                       'xml:lang' => $language,
154                       'lang'     => $language));
155
156             return false;
157
158         } else {
159
160             return true;
161         }
162     }
163
164     /**
165      * Add in the Facebook Connect JavaScript stuff
166      *
167      * Note: this script needs to appear in the <body>
168      *
169      * @param Action $action the current action
170      *
171      * @return void
172      *
173      */
174
175     function onEndShowScripts($action)
176     {
177         if ($this->reqFbScripts($action)) {
178
179             $apikey      = common_config('facebook', 'apikey');
180             $plugin_path = common_path('plugins/Facebook');
181
182             $login_url  = common_local_url('FBConnectAuth');
183             $logout_url = common_local_url('logout');
184
185             // XXX: Facebook says we don't need this FB_RequireFeatures(),
186             // but we actually do, for IE and Safari. Gar.
187
188             $js .= '    $(document).ready(function () {';
189             $js .= '         FB_RequireFeatures(';
190             $js .= '             ["XFBML"], function() {';
191             $js .= '                 FB.init("%1$s", "../xd_receiver.html");';
192             $js .= '             }';
193             $js .= '         );';
194             $js .= '    });';
195
196             $js .= '    function goto_login() {';
197             $js .= '        window.location = "%2$s";';
198             $js .= '    }';
199
200             // The below function alters the logout link so that it logs the user out
201             // of Facebook Connect as well as the site.  However, for some pages
202             // (FB Connect Settings) we need to output the FB Connect scripts (to
203             // show an existing FB connection even if the user isn't authenticated
204             // with Facebook connect) but NOT alter the logout link. And the only
205             // way to reliably do that is with the FB Connect .js libs.  Crazy.
206
207             $js .= '    FB.ensureInit(function() {';
208             $js .= '        FB.Connect.ifUserConnected(';
209             $js .= '            function() { ';
210             $js .= '                $(\'#nav_logout a\').attr(\'href\', \'#\');';
211             $js .= '                $(\'#nav_logout a\').click(function() {';
212             $js .= '                   FB.Connect.logoutAndRedirect(\'%3$s\');';
213             $js .= '                   return false;';
214             $js .= '                })';
215             $js .= '            },';
216             $js .= '            function() {';
217             $js .= '                return false;';
218             $js .= '            }';
219             $js .= '        );';
220             $js .= '     });';
221
222             $js = sprintf($js, $apikey, $login_url, $logout_url);
223
224             // Compress the bugger down a bit
225
226             $js = str_replace('  ', '', $js);
227
228             $action->inlineScript($js);
229         }
230
231     }
232
233     /**
234      * Add in an additional Facebook Connect script that's supposed to
235      * appear as close as possible to </body>
236      *
237      * @param Action $action the current action
238      *
239      * @return void
240      *
241      */
242
243     function onEndShowFooter($action)
244     {
245         if ($this->reqFbScripts($action)) {
246             $action->script('http://static.ak.connect.facebook.com' .
247                             '/js/api_lib/v0.4/FeatureLoader.js.php');
248         }
249     }
250
251     /**
252      * Output Facebook Connect specific CSS link
253      *
254      * @param Action $action the current action
255      *
256      * @return void
257      *
258      */
259
260     function onEndShowStatusNetStyles($action)
261     {
262         if ($this->reqFbScripts($action)) {
263             $action->cssLink('plugins/Facebook/FBConnect.css');
264         }
265     }
266
267     /**
268      * Does the Action we're plugged into require the FB Scripts?  We only
269      * want to output FB namespace, scripts, CSS, etc. on the pages that
270      * really need them.
271      *
272      * @param Action $action the current action
273      *
274      * @return boolean true
275      */
276
277     function reqFbScripts($action)
278     {
279
280         // If you're logged in w/FB Connect, you always need the FB stuff
281
282         $fbuid = $this->loggedIn();
283
284         if (!empty($fbuid)) {
285             return true;
286         }
287
288         // List of actions that require FB stuff
289
290         $needy = array('FBConnectLoginAction',
291                        'FBConnectauthAction',
292                        'FBConnectSettingsAction');
293
294         if (in_array(get_class($action), $needy)) {
295             return true;
296         }
297
298         return false;
299
300     }
301
302     /**
303      * Is the user currently logged in with FB Connect?
304      *
305      * @return mixed $fbuid the Facebook ID of the logged in user, or null
306      */
307
308     function loggedIn()
309     {
310         $user = common_current_user();
311
312         if (!empty($user)) {
313
314             $flink = Foreign_link::getByUserId($user->id,
315                 FACEBOOK_CONNECT_SERVICE);
316             $fbuid = 0;
317
318             if (!empty($flink)) {
319
320                 try {
321
322                     $facebook = getFacebook();
323                     $fbuid    = $facebook->get_loggedin_user();
324
325                 } catch (Exception $e) {
326                     common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
327                         'Problem getting Facebook user: ' .
328                             $e->getMessage());
329                 }
330
331                 if ($fbuid > 0) {
332                     return $fbuid;
333                 }
334             }
335         }
336
337         return null;
338     }
339
340     /**
341      * Add in a Facebook Connect avatar to the primary nav menu
342      *
343      * @param Action $action the current action
344      *
345      * @return void
346      *
347      */
348
349     function onStartPrimaryNav($action)
350     {
351         $user = common_current_user();
352
353         $connect = 'FBConnectSettings';
354         if (common_config('xmpp', 'enabled')) {
355             $connect = 'imsettings';
356         } else if (common_config('sms', 'enabled')) {
357             $connect = 'smssettings';
358         } else if (common_config('twitter', 'enabled')) {
359             $connect = 'twittersettings';
360         }
361
362         if (!empty($user)) {
363
364             $fbuid = $this->loggedIn();
365
366             if (!empty($fbuid)) {
367
368                 /* Default FB silhouette pic for FB users who haven't
369                    uploaded a profile pic yet. */
370
371                 $silhouetteUrl =
372                     'http://static.ak.fbcdn.net/pics/q_silhouette.gif';
373
374                 $url = $this->getProfilePicURL($fbuid);
375
376                 $action->elementStart('li', array('id' => 'nav_fb'));
377
378                 $action->element('img', array('id' => 'fbc_profile-pic',
379                     'src' => (!empty($url)) ? $url : $silhouetteUrl,
380                     'alt' => 'Facebook Connect User',
381                     'width' => '16'), '');
382
383                 $iconurl =  common_path('plugins/Facebook/fbfavicon.ico');
384                 $action->element('img', array('id' => 'fb_favicon',
385                     'src' => $iconurl));
386
387                 $action->elementEnd('li');
388
389             }
390         }
391
392         return true;
393     }
394
395     /*
396      * Add a login tab for Facebook Connect
397      *
398      * @param Action &action the current action
399      *
400      * @return void
401      */
402
403     function onEndLoginGroupNav(&$action)
404     {
405
406         $action_name = $action->trimmed('action');
407
408         $action->menuItem(common_local_url('FBConnectLogin'),
409                                            _m('Facebook'),
410                                            _m('Login or register using Facebook'),
411                                            'FBConnectLogin' === $action_name);
412
413         return true;
414     }
415
416     /*
417      * Add a tab for managing Facebook Connect settings
418      *
419      * @param Action &action the current action
420      *
421      * @return void
422      */
423
424     function onEndConnectSettingsNav(&$action)
425     {
426         $action_name = $action->trimmed('action');
427
428         $action->menuItem(common_local_url('FBConnectSettings'),
429                           _m('Facebook'),
430                           _m('Facebook Connect Settings'),
431                           $action_name === 'FBConnectSettings');
432
433         return true;
434     }
435
436     /**
437      * Have the logout process do some Facebook Connect cookie cleanup
438      *
439      * @param Action $action the current action
440      *
441      * @return void
442      */
443
444     function onStartLogout($action)
445     {
446         $action->logout();
447         $fbuid = $this->loggedIn();
448
449         if (!empty($fbuid)) {
450             try {
451                 $facebook = getFacebook();
452                 $facebook->expire_session();
453             } catch (Exception $e) {
454                 common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
455                            'Could\'t logout of Facebook: ' .
456                            $e->getMessage());
457             }
458         }
459
460         return true;
461     }
462
463     /**
464      * Get the URL of the user's Facebook avatar
465      *
466      * @param int $fbuid the Facebook user ID
467      *
468      * @return string $url the url for the user's Facebook avatar
469      */
470
471     function getProfilePicURL($fbuid)
472     {
473         $facebook = getFacebook();
474         $url      = null;
475
476         try {
477
478             $fqry = 'SELECT pic_square FROM user WHERE uid = %s';
479
480             $result = $facebook->api_client->fql_query(sprintf($fqry, $fbuid));
481
482             if (!empty($result)) {
483                 $url = $result[0]['pic_square'];
484             }
485
486         } catch (Exception $e) {
487             common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
488                        "Facebook client failure requesting profile pic!");
489         }
490
491         return $url;
492     }
493
494     /**
495      * Add a Facebook queue item for each notice
496      *
497      * @param Notice $notice      the notice
498      * @param array  &$transports the list of transports (queues)
499      *
500      * @return boolean hook return
501      */
502
503     function onStartEnqueueNotice($notice, &$transports)
504     {
505         array_push($transports, 'facebook');
506         return true;
507     }
508
509     /**
510      * broadcast the message when not using queuehandler
511      *
512      * @param Notice &$notice the notice
513      * @param array  $queue   destination queue
514      *
515      * @return boolean hook return
516      */
517
518     function onUnqueueHandleNotice(&$notice, $queue)
519     {
520         if (($queue == 'facebook') && ($this->_isLocal($notice))) {
521             facebookBroadcastNotice($notice);
522             return false;
523         }
524         return true;
525     }
526
527     /**
528      * Determine whether the notice was locally created
529      *
530      * @param Notice $notice the notice
531      *
532      * @return boolean locality
533      */
534
535     function _isLocal($notice)
536     {
537         return ($notice->is_local == Notice::LOCAL_PUBLIC ||
538                 $notice->is_local == Notice::LOCAL_NONPUBLIC);
539     }
540
541     /**
542      * Add Facebook queuehandler to the list of daemons to start
543      *
544      * @param array $daemons the list fo daemons to run
545      *
546      * @return boolean hook return
547      *
548      */
549
550     function onGetValidDaemons($daemons)
551     {
552         array_push($daemons, INSTALLDIR .
553                    '/plugins/Facebook/facebookqueuehandler.php');
554         return true;
555     }
556
557 }