]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/FacebookBridge/FacebookBridgePlugin.php
Fix name of Facebook Bridge plugin
[quix0rs-gnu-social.git] / plugins / FacebookBridge / FacebookBridgePlugin.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2010, StatusNet, Inc.
5  *
6  * A plugin for integrating Facebook with StatusNet. Includes single-sign-on
7  * and publishing notices to Facebook using Facebook's Graph API.
8  *
9  * PHP version 5
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Affero General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Affero General Public License for more details.
20  *
21  * You should have received a copy of the GNU Affero General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  * @category  Pugin
25  * @package   StatusNet
26  * @author    Zach Copley <zach@status.net>
27  * @copyright 2010 StatusNet, Inc.
28  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
29  * @link      http://status.net/
30  */
31
32 if (!defined('STATUSNET')) {
33     exit(1);
34 }
35
36 define("FACEBOOK_SERVICE", 2);
37
38 /**
39  * Main class for Facebook Bridge plugin
40  *
41  * @category  Plugin
42  * @package   StatusNet
43  * @author    Zach Copley <zach@status.net>
44  * @copyright 2010 StatusNet, Inc.
45  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
46  * @link      http://status.net/
47  */
48 class FacebookBridgePlugin extends Plugin
49 {
50     public $appId    = null; // Facebook application ID
51     public $secret   = null; // Facebook application secret
52     public $facebook = null; // Facebook application instance
53     public $dir      = null; // Facebook plugin dir
54
55     /**
56      * Initializer for this plugin
57      *
58      * Gets an instance of the Facebook API client object
59      *
60      * @return boolean hook value; true means continue processing, false means stop.
61      */
62     function initialize()
63     {
64         $this->facebook = Facebookclient::getFacebook(
65             $this->appId,
66             $this->secret
67         );
68
69         return true;
70     }
71
72     /**
73      * Load related modules when needed
74      *
75      * @param string $cls Name of the class to be loaded
76      *
77      * @return boolean hook value; true means continue processing, false means stop.
78      */
79     function onAutoload($cls)
80     {
81
82         $dir = dirname(__FILE__);
83
84         //common_debug("class = " . $cls);
85
86         switch ($cls)
87         {
88         case 'Facebook': // Facebook PHP SDK
89             include_once $dir . '/extlib/facebook.php';
90             return false;
91         case 'FacebookloginAction':
92         case 'FacebookfinishloginAction':
93         case 'FacebookadminpanelAction':
94         case 'FacebooksettingsAction':
95         case 'FacebookdeauthorizeAction':
96             include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
97             return false;
98         case 'Facebookclient':
99         case 'FacebookQueueHandler':
100             include_once $dir . '/lib/' . strtolower($cls) . '.php';
101             return false;
102         case 'Notice_to_item':
103             include_once $dir . '/classes/' . $cls . '.php';
104             return false;
105         default:
106             return true;
107         }
108
109     }
110
111     /**
112      * Database schema setup
113      *
114      * We maintain a table mapping StatusNet notices to Facebook items
115      *
116      * @see Schema
117      * @see ColumnDef
118      *
119      * @return boolean hook value; true means continue processing, false means stop.
120      */
121     function onCheckSchema()
122     {
123         $schema = Schema::get();
124         $schema->ensureTable('notice_to_item', Notice_to_item::schemaDef());
125         return true;
126     }
127
128     /*
129      * Does this $action need the Facebook JavaScripts?
130      */
131     function needsScripts($action)
132     {
133         static $needy = array(
134             'FacebookloginAction',
135             'FacebookfinishloginAction',
136             'FacebookadminpanelAction',
137             'FacebooksettingsAction'
138         );
139
140         if (in_array(get_class($action), $needy)) {
141             return true;
142         } else {
143             return false;
144         }
145     }
146
147     /**
148      * Map URLs to actions
149      *
150      * @param Net_URL_Mapper $m path-to-action mapper
151      *
152      * @return boolean hook value; true means continue processing, false means stop.
153      */
154     function onRouterInitialized($m)
155     {
156         // Always add the admin panel route
157         $m->connect('admin/facebook', array('action' => 'facebookadminpanel'));
158
159         // Only add these routes if an application has been setup on
160         // Facebook for the plugin to use.
161         if ($this->hasApplication()) {
162
163             $m->connect(
164                 'main/facebooklogin',
165                 array('action' => 'facebooklogin')
166             );
167             $m->connect(
168                 'main/facebookfinishlogin',
169                 array('action' => 'facebookfinishlogin')
170             );
171             $m->connect(
172                 'settings/facebook',
173                 array('action' => 'facebooksettings')
174             );
175             $m->connect(
176                 'facebook/deauthorize',
177                 array('action' => 'facebookdeauthorize')
178             );
179
180         }
181
182         return true;
183     }
184
185     /*
186      * Add a login tab for Facebook, but only if there's a Facebook
187      * application defined for the plugin to use.
188      *
189      * @param Action &action the current action
190      *
191      * @return void
192      */
193     function onEndLoginGroupNav(&$action)
194     {
195         $action_name = $action->trimmed('action');
196
197         if ($this->hasApplication()) {
198
199             $action->menuItem(
200                 common_local_url('facebooklogin'),
201                 _m('MENU', 'Facebook'),
202                 // TRANS: Tooltip for menu item "Facebook".
203                 _m('Login or register using Facebook'),
204                'facebooklogin' === $action_name
205             );
206         }
207
208         return true;
209     }
210
211     /**
212      * Add a Facebook tab to the admin panels
213      *
214      * @param Widget $nav Admin panel nav
215      *
216      * @return boolean hook value
217      */
218     function onEndAdminPanelNav($nav)
219     {
220         if (AdminPanelAction::canAdmin('facebook')) {
221
222             $action_name = $nav->action->trimmed('action');
223
224             $nav->out->menuItem(
225                 common_local_url('facebookadminpanel'),
226                 // TRANS: Menu item.
227                 _m('MENU','Facebook'),
228                 // TRANS: Tooltip for menu item "Facebook".
229                 _m('Facebook integration configuration'),
230                 $action_name == 'facebookadminpanel',
231                 'nav_facebook_admin_panel'
232             );
233         }
234
235         return true;
236     }
237
238     /*
239      * Add a tab for user-level Facebook settings if the user
240      * has a link to Facebook
241      *
242      * @param Action &action the current action
243      *
244      * @return void
245      */
246     function onEndConnectSettingsNav(&$action)
247     {
248         if ($this->hasApplication()) {
249             $action_name = $action->trimmed('action');
250
251             // CurrentUserDesignAction stores the current user in $cur
252             $user = $action->getCurrentUser();
253
254             $flink = null;
255
256             if (!empty($user)) {
257                 $flink = Foreign_link::getByUserID(
258                     $user->id,
259                     FACEBOOK_SERVICE
260                 );
261             }
262
263             if (!empty($flink)) {
264
265                 $action->menuItem(
266                     common_local_url('facebooksettings'),
267                     // TRANS: Menu item tab.
268                     _m('MENU','Facebook'),
269                     // TRANS: Tooltip for menu item "Facebook".
270                     _m('Facebook settings'),
271                     $action_name === 'facebooksettings'
272                 );
273
274             }
275         }
276
277     }
278
279     /*
280      * Is there a Facebook application for the plugin to use?
281      *
282      * Checks to see if a Facebook application ID and secret
283      * have been configured and a valid Facebook API client
284      * object exists.
285      *
286      */
287     function hasApplication()
288     {
289         if (!empty($this->facebook)) {
290
291             $appId  = $this->facebook->getAppId();
292             $secret = $this->facebook->getApiSecret();
293
294             if (!empty($appId) && !empty($secret)) {
295                 return true;
296             }
297
298         }
299
300         return false;
301     }
302
303     /*
304      * Output a Facebook div for the Facebook JavaSsript SDK to use
305      *
306      * @param Action $action the current action
307      *
308      */
309     function onStartShowHeader($action)
310     {
311         // output <div id="fb-root"></div> as close to <body> as possible
312         $action->element('div', array('id' => 'fb-root'));
313         return true;
314     }
315
316     /*
317      * Load the Facebook JavaScript SDK on pages that need them.
318      *
319      * @param Action $action the current action
320      *
321      */
322     function onEndShowScripts($action)
323     {
324         if ($this->needsScripts($action)) {
325
326             $action->script('https://connect.facebook.net/en_US/all.js');
327
328             $script = <<<ENDOFSCRIPT
329 FB.init({appId: %1\$s, session: %2\$s, status: true, cookie: true, xfbml: true});
330
331 $('#facebook_button').bind('click', function(event) {
332
333     event.preventDefault();
334
335     FB.login(function(response) {
336         if (response.session && response.perms) {
337             window.location.href = '%3\$s';
338         } else {
339             // NOP (user cancelled login)
340         }
341     }, {perms:'read_stream,publish_stream,offline_access,user_status,user_location,user_website,email'});
342 });
343 ENDOFSCRIPT;
344
345             $action->inlineScript(
346                 sprintf($script,
347                     json_encode($this->facebook->getAppId()),
348                     json_encode($this->facebook->getSession()),
349                     common_local_url('facebookfinishlogin')
350                 )
351             );
352         }
353     }
354
355     /*
356      * Log the user out of Facebook, per the Facebook authentication guide
357      *
358      * @param Action action the current action
359      */
360     function onEndLogout($action)
361     {
362         if ($this->hasApplication()) {
363             $session = $this->facebook->getSession();
364             $fbuser  = null;
365             $fbuid   = null;
366
367             if ($session) {
368                 try {
369                     $fbuid  = $this->facebook->getUser();
370                     $fbuser = $this->facebook->api('/me');
371                  } catch (FacebookApiException $e) {
372                      common_log(LOG_ERROR, $e, __FILE__);
373                  }
374             }
375
376             if (!empty($fbuser)) {
377
378                 $logoutUrl = $this->facebook->getLogoutUrl(
379                     array('next' => common_local_url('public'))
380                 );
381
382                 common_log(
383                     LOG_INFO,
384                     sprintf(
385                         "Logging user out of Facebook (fbuid = %s)",
386                         $fbuid
387                     ),
388                     __FILE__
389                 );
390                 common_debug("LOGOUT URL = $logoutUrl");
391                 common_redirect($logoutUrl, 303);
392             }
393
394         }
395     }
396
397     /*
398      * Add fbml namespace to our HTML, so Facebook's JavaScript SDK can parse
399      * and render XFBML tags
400      *
401      * @param Action    $action   the current action
402      * @param array     $attrs    array of attributes for the HTML tag
403      *
404      * @return nothing
405      */
406     function onStartHtmlElement($action, $attrs) {
407
408         if ($this->needsScripts($action)) {
409             $attrs = array_merge(
410                 $attrs,
411                 array('xmlns:fb' => 'http://www.facebook.com/2008/fbml')
412             );
413         }
414
415         return true;
416     }
417
418     /**
419      * Add a Facebook queue item for each notice
420      *
421      * @param Notice $notice      the notice
422      * @param array  &$transports the list of transports (queues)
423      *
424      * @return boolean hook return
425      */
426     function onStartEnqueueNotice($notice, &$transports)
427     {
428         if (self::hasApplication() && $notice->isLocal()) {
429             array_push($transports, 'facebook');
430         }
431         return true;
432     }
433
434     /**
435      * Register Facebook notice queue handler
436      *
437      * @param QueueManager $manager
438      *
439      * @return boolean hook return
440      */
441     function onEndInitializeQueueManager($manager)
442     {
443         if (self::hasApplication()) {
444             $manager->connect('facebook', 'FacebookQueueHandler');
445         }
446         return true;
447     }
448
449     /*
450      * Use SSL for Facebook stuff
451      *
452      * @param string $action name
453      * @param boolean $ssl outval to force SSL
454      * @return mixed hook return value
455      */
456     function onSensitiveAction($action, &$ssl)
457     {
458         $sensitive = array(
459             'facebookadminpanel',
460             'facebooksettings',
461             'facebooklogin',
462             'facebookfinishlogin'
463         );
464
465         if (in_array($action, $sensitive)) {
466             $ssl = true;
467             return false;
468         } else {
469             return true;
470         }
471     }
472
473     /**
474      * If a notice gets deleted, remove the Notice_to_item mapping and
475      * delete the item on Facebook
476      *
477      * @param User   $user   The user doing the deleting
478      * @param Notice $notice The notice getting deleted
479      *
480      * @return boolean hook value
481      */
482     function onStartDeleteOwnNotice(User $user, Notice $notice)
483     {
484         $client = new Facebookclient($notice);
485         $client->streamRemove();
486         
487         return true;
488     }
489
490     /**
491      * Notify remote users when their notices get favorited.
492      *
493      * @param Profile or User $profile of local user doing the faving
494      * @param Notice $notice being favored
495      * @return hook return value
496      */
497     function onEndFavorNotice(Profile $profile, Notice $notice)
498     {
499         $client = new Facebookclient($notice);
500         $client->like();
501
502         return true;
503     }
504
505     /**
506      * Notify remote users when their notices get de-favorited.
507      *
508      * @param Profile $profile Profile person doing the de-faving
509      * @param Notice  $notice  Notice being favored
510      *
511      * @return hook return value
512      */
513     function onEndDisfavorNotice(Profile $profile, Notice $notice)
514     {
515         $client = new Facebookclient($notice);
516         $client->unLike();
517
518         return true;
519     }
520
521     /*
522      * Add version info for this plugin
523      *
524      * @param array &$versions    plugin version descriptions
525      */
526     function onPluginVersion(&$versions)
527     {
528         $versions[] = array(
529             'name' => 'Facebook Bridge',
530             'version' => STATUSNET_VERSION,
531             'author' => 'Craig Andrews, Zach Copley',
532             'homepage' => 'http://status.net/wiki/Plugin:FacebookBridge',
533             'rawdescription' =>
534             _m('A plugin for integrating StatusNet with Facebook.')
535         );
536
537         return true;
538     }
539 }