Re-implement Facebook service to use OAuth2 and Graph API. This allows
[hermes] / package / src / org / maemo / hermes / engine / facebook / provider.py
index c88ecaa..e693795 100644 (file)
@@ -1,8 +1,9 @@
-from facebook import Facebook, FacebookError
 import gnome.gconf
 import gtk, hildon
 import org.maemo.hermes.engine.provider
-import org.maemo.hermes.engine.facebook.service
+from org.maemo.hermes.engine.facebook.service import Service
+from org.maemo.hermes.engine.facebook.api import FacebookApi
+import oauth2
 
 class Provider(org.maemo.hermes.engine.provider.Provider):
     """Facebook provider for Hermes. 
@@ -19,21 +20,15 @@ class Provider(org.maemo.hermes.engine.provider.Provider):
         """Initialise the provider, and ensure the environment is going to work."""
 
         self._gc = gnome.gconf.client_get_default()
-        if (self._gc.get_string('/desktop/gnome/url-handlers/http/command') == 'epiphany %s'):
-            raise Exception('Browser in gconf invalid (see NB#136012). Installation error.')
 
-        key_app    = self._gc.get_string('/apps/maemo/hermes/facebook_app')
+        key_app    = self._gc.get_string('/apps/maemo/hermes/facebook_key')
         key_secret = self._gc.get_string('/apps/maemo/hermes/facebook_secret')
         if key_app is None or key_secret is None:
             raise Exception('No Facebook application keys found. Installation error.')
         
-        self.fb = Facebook(key_app, key_secret)
-        self.fb.desktop = True
-
-        if self.fb.session_key is None:
-            self.fb.session_key = self._gc.get_string('/apps/maemo/hermes/facebook_session_key')
-            self.fb.secret = self._gc.get_string('/apps/maemo/hermes/facebook_secret_key')
-            self.fb.uid = self._gc.get_string('/apps/maemo/hermes/facebook_uid')
+        access_token = self._gc.get_string('/apps/maemo/hermes/facebook_access_token')
+        self.oauth = oauth2.OAuth2(key_app, key_secret, access_token)
+        self.api = FacebookApi(self.oauth)
 
 
     # -----------------------------------------------------------------------
@@ -48,8 +43,7 @@ class Provider(org.maemo.hermes.engine.provider.Provider):
     def get_account_detail(self):
         """Return the email address associated with the user, if available."""
         
-        name = self._gc.get_string('/apps/maemo/hermes/facebook_user')
-        return name and name or _('Pending authorisation')
+        return self._gc.get_string('/apps/maemo/hermes/facebook_user')
     
     
     # -----------------------------------------------------------------------
@@ -65,79 +59,53 @@ class Provider(org.maemo.hermes.engine.provider.Provider):
         """Open the preferences for this provider as a child of the 'parent' widget."""
 
         dialog = gtk.Dialog(self.get_name(), parent)
-        dialog.add_button(_('Clear'), gtk.RESPONSE_OK)
         dialog.add_button(_('Disable'), gtk.RESPONSE_NO)
-        dialog.add_button(_('Enable'), gtk.RESPONSE_YES)
-        
-        dialog.vbox.add(gtk.Label(_('Note: authentication via web page')))
+        enable = dialog.add_button(_('Enable'), gtk.RESPONSE_YES)
+
+        button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT,
+                               hildon.BUTTON_ARRANGEMENT_VERTICAL)
+        self._handle_button(None, button, enable)
+        button.connect('clicked', self._handle_button, button, enable)
+        dialog.vbox.add(button)
         
         checkbox = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
         checkbox.set_label(_('Create birthday-only contacts'))
         checkbox.set_active(self._gc.get_bool('/apps/maemo/hermes/facebook_birthday_only'))
         dialog.vbox.add(checkbox)
-        dialog.vbox.add(gtk.Label(''))
+        dialog.vbox.add(gtk.Label(""))
         
-        while True:
-            dialog.show_all()
-            result = dialog.run()
-            dialog.hide()
-            if result == gtk.RESPONSE_CANCEL:
-                return None
-            elif result == gtk.RESPONSE_OK:
-                self._gc.unset('/apps/maemo/hermes/facebook_session_key')
-                self._gc.unset('/apps/maemo/hermes/facebook_secret_key')
-                self._gc.unset('/apps/maemo/hermes/facebook_uid')
-                self._gc.unset('/apps/maemo/hermes/facebook_user')
-            else:
-                break
+        dialog.show_all()
+        result = dialog.run()
+        dialog.hide()
+        if result == gtk.RESPONSE_CANCEL or result == gtk.RESPONSE_DELETE_EVENT:
+            return None
     
         self._gc.set_bool('/apps/maemo/hermes/facebook_birthday_only', checkbox.get_active())
         return result == gtk.RESPONSE_YES
+
+
+    # -----------------------------------------------------------------------
+    def _handle_button(self, e, button, enable):
+        """Ensure the button state is correct."""
+        
+        authenticated = self._gc.get_string('/apps/maemo/hermes/facebook_access_token') is not None
+        if e is not None:
+            if authenticated:
+                self._gc.unset('/apps/maemo/hermes/facebook_access_token')
+            else:
+                self.api.authenticate()
+                self._gc.set_string('/apps/maemo/hermes/facebook_access_token', self.oauth.get_access_token())
+                self._gc.set_string('/apps/maemo/hermes/facebook_user', self.api.get_user())
+        
+            authenticated = self._gc.get_string('/apps/maemo/hermes/facebook_access_token') is not None
         
+        button.set_title(authenticated and _("Clear authorisation") or _("Authorise"))
+        enable.set_sensitive(authenticated)
+
     
     # -----------------------------------------------------------------------
     def service(self, gui_callback):
         """Return a service instance."""
         
         self._gui = gui_callback
-        
-        # Check the available session is still valid...
-        while True:
-            try:
-                if self.fb.users.getLoggedInUser() and self.fb.session_key:
-                    break
-            except FacebookError:
-                pass
-            self._do_fb_login()
-
-        return org.maemo.hermes.engine.facebook.service.Service(self.fb)
-
-
-    # -----------------------------------------------------------------------
-    def _do_fb_login(self):
-        """Perform authentication against Facebook and store the result in gconf
-             for later use. Uses the 'need_auth' and 'block_for_auth' methods on
-             the callback class. The former allows a message to warn the user
-             about what is about to happen to be shown; the second is to wait
-             for the user to confirm they have logged in."""
-        self.fb.session_key = None
-        self.fb.secret = None
-        self.fb.uid = None
-        
-        if self._gui:
-            self._gui.need_auth()
-            
-        self.fb.auth.createToken()
-        self.fb.login()
-        
-        if self._gui:
-            self._gui.block_for_auth()
-          
-        session = self.fb.auth.getSession()
-        self._gc.set_string('/apps/maemo/hermes/facebook_session_key', session['session_key'])
-        self._gc.set_string('/apps/maemo/hermes/facebook_secret_key', session['secret'])
-        self._gc.set_string('/apps/maemo/hermes/facebook_uid', str(session['uid']))
-
-        info = self.fb.users.getInfo([self.fb.uid], ['name'])
-        self._gc.set_string('/apps/maemo/hermes/facebook_user', info[0]['name'])
-
+        return Service(self.get_id(), self.api, self._gc.get_bool('/apps/maemo/hermes/facebook_birthday_only'))