]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Make a richer StatusNet profile from a user's Facebook profile
authorZach Copley <zach@status.net>
Tue, 9 Nov 2010 23:14:50 +0000 (23:14 +0000)
committerZach Copley <zach@status.net>
Tue, 9 Nov 2010 23:14:50 +0000 (23:14 +0000)
plugins/FacebookSSO/FacebookSSOPlugin.php
plugins/FacebookSSO/actions/facebookfinishlogin.php
plugins/FacebookSSO/lib/facebookclient.php

index a094f2957fff4b0ffa24c94788048352cc5f8d20..32b6a29106570f9b1a101e74a5ca1c5d1dd6dd71 100644 (file)
@@ -3,7 +3,8 @@
  * StatusNet - the distributed open-source microblogging tool
  * Copyright (C) 2010, StatusNet, Inc.
  *
- * A plugin for single-sign-in (SSO) with Facebook
+ * A plugin for integrating Facebook with StatusNet. Includes single-sign-on
+ * and publishing notices to Facebook using Facebook's Graph API.
  *
  * PHP version 5
  *
@@ -35,14 +36,7 @@ if (!defined('STATUSNET')) {
 define("FACEBOOK_SERVICE", 2);
 
 /**
- * Main class for Facebook single-sign-on plugin
- *
- *
- * Simple plugins can be implemented as a single module. Others are more complex
- * and require additional modules; these should use their own directory, like
- * 'local/plugins/{$name}/'. All files related to the plugin, including images,
- * JavaScript, CSS, external libraries or PHP modules should go in the plugin
- * directory.
+ * Main class for Facebook plugin
  *
  * @category  Plugin
  * @package   StatusNet
@@ -62,8 +56,7 @@ class FacebookSSOPlugin extends Plugin
     /**
      * Initializer for this plugin
      *
-     * Plugins overload this method to do any initialization they need,
-     * like connecting to remote servers or creating paths or so on.
+     * Gets an instance of the Facebook API client object
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
@@ -78,33 +71,9 @@ class FacebookSSOPlugin extends Plugin
         return true;
     }
 
-    /**
-     * Cleanup for this plugin
-     *
-     * Plugins overload this method to do any cleanup they need,
-     * like disconnecting from remote servers or deleting temp files or so on.
-     *
-     * @return boolean hook value; true means continue processing, false means stop.
-     */
-    function cleanup()
-    {
-        return true;
-    }
-
     /**
      * Load related modules when needed
      *
-     * Most non-trivial plugins will require extra modules to do their work. Typically
-     * these include data classes, action classes, widget classes, or external libraries.
-     *
-     * This method receives a class name and loads the PHP file related to that class. By
-     * tradition, action classes typically have files named for the action, all lower-case.
-     * Data classes are in files with the data class name, initial letter capitalized.
-     *
-     * Note that this method will be called for *all* overloaded classes, not just ones
-     * in this plugin! So, make sure to return true by default to let other plugins, and
-     * the core code, get a chance.
-     *
      * @param string $cls Name of the class to be loaded
      *
      * @return boolean hook value; true means continue processing, false means stop.
@@ -118,12 +87,9 @@ class FacebookSSOPlugin extends Plugin
 
         switch ($cls)
         {
-        case 'Facebook': // New JavaScript SDK
+        case 'Facebook': // Facebook PHP SDK
             include_once $dir . '/extlib/facebook.php';
             return false;
-        case 'FacebookRestClient': // Old REST lib
-            include_once $dir . '/extlib/facebookapi_php5_restlib.php';
-            return false;
         case 'FacebookloginAction':
         case 'FacebookfinishloginAction':
         case 'FacebookadminpanelAction':
@@ -153,10 +119,8 @@ class FacebookSSOPlugin extends Plugin
         );
 
         if (in_array(get_class($action), $needy)) {
-            common_debug("needs scripts!");
             return true;
         } else {
-            common_debug("doesn't need scripts!");
             return false;
         }
     }
@@ -164,11 +128,6 @@ class FacebookSSOPlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * This event handler lets the plugin map URLs on the site to actions (and
-     * thus an action handler class). Note that the action handler class for an
-     * action will be named 'FoobarAction', where action = 'foobar'. The class
-     * must be loaded in the onAutoload() method.
-     *
      * @param Net_URL_Mapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
@@ -281,6 +240,11 @@ class FacebookSSOPlugin extends Plugin
 
     /*
      * Is there a Facebook application for the plugin to use?
+     *
+     * Checks to see if a Facebook application ID and secret
+     * have been configured and a valid Facebook API client
+     * object exists.
+     *
      */
     function hasApplication()
     {
@@ -298,6 +262,12 @@ class FacebookSSOPlugin extends Plugin
         return false;
     }
 
+    /*
+     * Output a Facebook div for the Facebook JavaSsript SDK to use
+     *
+     * @param Action $action the current action
+     *
+     */
     function onStartShowHeader($action)
     {
         // output <div id="fb-root"></div> as close to <body> as possible
@@ -305,6 +275,12 @@ class FacebookSSOPlugin extends Plugin
         return true;
     }
 
+    /*
+     * Load the Facebook JavaScript SDK on pages that need them.
+     *
+     * @param Action $action the current action
+     *
+     */
     function onEndShowScripts($action)
     {
         if ($this->needsScripts($action)) {
@@ -324,7 +300,7 @@ $('#facebook_button').bind('click', function(event) {
         } else {
             // NOP (user cancelled login)
         }
-    }, {perms:'read_stream,publish_stream,offline_access,user_status,user_location,user_website'});
+    }, {perms:'read_stream,publish_stream,offline_access,user_status,user_location,user_website,email'});
 });
 ENDOFSCRIPT;
 
@@ -341,7 +317,7 @@ ENDOFSCRIPT;
     /*
      * Log the user out of Facebook, per the Facebook authentication guide
      *
-     * @param Action action the action
+     * @param Action action the current action
      */
     function onEndLogout($action)
     {
@@ -381,10 +357,10 @@ ENDOFSCRIPT;
     }
 
     /*
-     * Add fbml namespace so Facebook's JavaScript SDK can parse and render
-     * XFBML tags (e.g: <fb:login-button>)
+     * Add fbml namespace to our HTML, so Facebook's JavaScript SDK can parse
+     * and render XFBML tags
      *
-     * @param Action    $action   current action
+     * @param Action    $action   the current action
      * @param array     $attrs    array of attributes for the HTML tag
      *
      * @return nothing
@@ -432,6 +408,30 @@ ENDOFSCRIPT;
         return true;
     }
 
+    /*
+     * Use SSL for Facebook stuff
+     *
+     * @param string $action name
+     * @param boolean $ssl outval to force SSL
+     * @return mixed hook return value
+     */
+    function onSensitiveAction($action, &$ssl)
+    {
+        $sensitive = array(
+            'facebookadminpanel',
+            'facebooksettings',
+            'facebooklogin',
+            'facebookfinishlogin'
+        );
+
+        if (in_array($action, $sensitive)) {
+            $ssl = true;
+            return false;
+        } else {
+            return true;
+        }
+    }
+
     /*
      * Add version info for this plugin
      *
index 16f7cff500aed8504b5b632519b2b1d5f4c46aec..e61f3515479b70b556b56ac4004e60b1d285ceba 100644 (file)
@@ -33,7 +33,6 @@ if (!defined('STATUSNET')) {
 
 class FacebookfinishloginAction extends Action
 {
-
     private $facebook = null; // Facebook client
     private $fbuid    = null; // Facebook user ID
     private $fbuser   = null; // Facebook user object (JSON)
@@ -341,12 +340,14 @@ class FacebookfinishloginAction extends Action
         }
 
         $args = array(
-            'nickname' => $nickname,
-            'fullname' => $this->fbuser['firstname'] . ' ' . $this->fbuser['lastname'],
-            // XXX: Figure out how to get email
-            'homepage' => $this->fbuser['link'],
-            'bio'      => $this->fbuser['about'],
-            'location' => $this->fbuser['location']['name']
+            'nickname'        => $nickname,
+            'fullname'        => $this->fbuser['first_name']
+                . ' ' . $this->fbuser['last_name'],
+            'email'           => $this->fbuser['email'],
+            'email_confirmed' => true,
+            'homepage'        => $this->fbuser['website'],
+            'bio'             => $this->fbuser['about'],
+            'location'        => $this->fbuser['location']['name']
         );
 
         if (!empty($invite)) {
@@ -362,6 +363,8 @@ class FacebookfinishloginAction extends Action
             return;
         }
 
+        $this->setAvatar($user);
+
         common_set_user($user);
         common_real_login(true);
 
@@ -384,6 +387,68 @@ class FacebookfinishloginAction extends Action
         );
     }
 
+    /*
+     * Attempt to download the user's Facebook picture and create a
+     * StatusNet avatar for the new user.
+     */
+    function setAvatar($user)
+    {
+        $picUrl = sprintf(
+            'http://graph.facebook.com/%s/picture?type=large',
+            $this->fbuid
+        );
+
+        // fetch the picture from Facebook
+        $client = new HTTPClient();
+
+        common_debug("status = $status - " . $finalUrl , __FILE__);
+
+        // fetch the actual picture
+        $response = $client->get($picUrl);
+
+        if ($response->isOk()) {
+
+            $finalUrl = $client->getUrl();
+            $filename = 'facebook-' . substr(strrchr($finalUrl, '/'), 1 );
+
+            common_debug("Filename = " . $filename, __FILE__);
+
+            $ok = file_put_contents(
+                Avatar::path($filename),
+                $response->getBody()
+            );
+
+            if (!$ok) {
+                common_log(
+                    LOG_WARNING,
+                    sprintf(
+                        'Couldn\'t save Facebook avatar %s',
+                        $tmp
+                    ),
+                    __FILE__
+                );
+
+            } else {
+
+                $profile = $user->getProfile();
+
+                if ($profile->setOriginal($filename)) {
+                    common_log(
+                        LOG_INFO,
+                        sprintf(
+                            'Saved avatar for %s (%d) from Facebook profile %s, filename = %s',
+                             $user->nickname,
+                             $user->id,
+                             $this->fbuid,
+                             $picture
+                        ),
+                        __FILE__
+                    );
+                }
+            }
+        }
+    }
+
     function connectNewUser()
     {
         $nickname = $this->trimmed('nickname');
@@ -437,7 +502,6 @@ class FacebookfinishloginAction extends Action
             __FILE__
         );
 
-        // Return to Facebook connection settings tab
         common_redirect(common_local_url('facebookfinishlogin'), 303);
     }
 
index cf45c9ed95e8adfb456a7bf9faa2a98f3fd44bf9..6753243ed0878dd683b118ab0c0116c54cb2a7d2 100644 (file)
@@ -47,7 +47,6 @@ class Facebookclient
     protected $flink         = null; // Foreign_link StatusNet -> Facebook
     protected $notice        = null; // The user's notice
     protected $user          = null; // Sender of the notice
-    //protected $oldRestClient = null; // Old REST API client
 
     function __construct($notice)
     {
@@ -382,7 +381,7 @@ class Facebookclient
         $code   = $e->getCode();
 
         // The Facebook PHP SDK seems to always set the code attribute
-        // of the Exception to 0; they put the real error code it in
+        // of the Exception to 0; they put the real error code in
         // the message. Gar!
         if ($code == 0) {
             preg_match('/^\(#(?<code>\d+)\)/', $errmsg, $matches);
@@ -554,7 +553,6 @@ class Facebookclient
      */
     function formatAttachments()
     {
-
         $attachments = $this->notice->attachments();
 
         $fbattachment          = array();