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