new service - Gravatar
authorFredrik Wendt <fredrik@wendt.se>
Sat, 5 Jun 2010 21:31:26 +0000 (23:31 +0200)
committerFredrik Wendt <fredrik@wendt.se>
Sat, 5 Jun 2010 21:31:26 +0000 (23:31 +0200)
Signed-off-by: Fredrik Wendt <fredrik@wendt.se>

package/src/org/maemo/hermes/engine/gravatar/__init__.py [new file with mode: 0644]
package/src/org/maemo/hermes/engine/gravatar/provider.py [new file with mode: 0644]
package/src/org/maemo/hermes/engine/gravatar/service.py [new file with mode: 0644]

diff --git a/package/src/org/maemo/hermes/engine/gravatar/__init__.py b/package/src/org/maemo/hermes/engine/gravatar/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/package/src/org/maemo/hermes/engine/gravatar/provider.py b/package/src/org/maemo/hermes/engine/gravatar/provider.py
new file mode 100644 (file)
index 0000000..224954d
--- /dev/null
@@ -0,0 +1,47 @@
+import gnome.gconf
+import org.maemo.hermes.engine.provider
+import org.maemo.hermes.engine.gravatar.service
+
+class Provider(org.maemo.hermes.engine.provider.Provider):
+    """Gravatar provider for Hermes. 
+
+       Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
+       Released under the Artistic Licence."""
+
+
+    # -----------------------------------------------------------------------
+    def __init__(self):
+        self._gconf = gnome.gconf.client_get_default()
+
+
+    # -----------------------------------------------------------------------
+    def get_name(self):
+        """Return the display name of this service. An icon, of with the lower-case,
+           all-alphabetic version of this name is expected to be provided."""
+           
+        return 'Gravatar'
+    
+    
+    # -----------------------------------------------------------------------
+    def has_preferences(self):
+        """Whether or not this provider has any preferences. If it does not,
+           open_preferences must NOT be called; as the behaviour is undetermined."""
+           
+        return False
+    
+    
+    # -----------------------------------------------------------------------
+    def open_preferences(self, parent):
+        """Open the preferences for this provider as a child of the 'parent' widget."""
+
+        print "Err, open preferences. OK. Err, right. Hmm."
+
+    
+    # -----------------------------------------------------------------------
+    def service(self, gui_callback):
+        """Return the service backend"""
+
+        self._api_email = self._gconf.get_string('/apps/maemo/hermes/gravatar_api_email')
+        self._api_key = self._gconf.get_string('/apps/maemo/hermes/gravatar_api_key')
+
+        return org.maemo.hermes.engine.gravatar.service.Service()
diff --git a/package/src/org/maemo/hermes/engine/gravatar/service.py b/package/src/org/maemo/hermes/engine/gravatar/service.py
new file mode 100644 (file)
index 0000000..bc48b11
--- /dev/null
@@ -0,0 +1,145 @@
+import urllib, hashlib, xmlrpclib
+import org.maemo.hermes.engine.service
+
+class Service(org.maemo.hermes.engine.service.Service):
+    """Gravatar backend for Hermes.
+       
+       Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
+       Released under the Artistic Licence."""
+       
+    _image_url_base = "http://www.gravatar.com/avatar.php?"
+       
+    # -----------------------------------------------------------------------
+    def __init__(self, api_email, api_key):
+        """Initialise the Gravatar service
+        
+        api_email is the email address to use when talking to the backend.
+        api_key is the "secrect" key used when talking to the backend
+        """
+        self._api_email = api_email
+        self._api_key = api_key
+        if self._api_key is None or self._api_email is None:
+            raise Exception('No Gravatar application keys found. Installation error.')
+         
+        self._address_to_contact = {}
+        self._hash_to_address = {}
+        self._hash_has_gravatar = {}
+        self._empty_cache = True
+        
+        self._friends_by_contact = {}
+        self._contacts_by_friend = {}
+        
+        self._api_url = 'https://secure.gravatar.com/xmlrpc?user=' + hashlib.md5(self._api_email).hexdigest()
+   
+
+    # -----------------------------------------------------------------------
+    def get_name(self):
+        return "Gravatar"
+    
+    
+    # -----------------------------------------------------------------------
+    def pre_process_contact(self, contact):
+        """Extracts addresses from the contact."""
+        for address in contact.get_emails():
+            self._address_to_contact[address] = contact
+    
+    
+    # -----------------------------------------------------------------------
+    def process_contact(self, contact):
+        """On first call (with a contact missing a photo), go get data from Gravatar's servers."""
+        
+        if not self._has_photo(contact):
+            for address in contact.get_emails():
+                hash = self._get_hash_for_address(address)
+                if (self._hash_has_gravatar.has_key(hash) and self._hash_has_gravatar[hash]):
+                    friend = self._create_friend(contact.get_name())
+                    friend.set_photo_url(self._get_url_for_email_hash(hash))
+                    self._register_match(contact, friend)
+
+
+    # -----------------------------------------------------------------------
+    def process_friends(self):
+        self._lookup_addresses()
+
+    
+    # -----------------------------------------------------------------------
+    def get_friends(self):
+        return self._contacts_by_friend.keys()
+
+    
+    def get_contacts_with_match(self):
+        """Returns a dict with Contact objects as keys and Friend objects as values"""
+        return self._friends_by_contact
+    
+
+    def get_unmatched_friends(self):
+        """Will always return None - Gravatar only reacts on e-mail address input."""
+        return None
+    
+    
+
+
+    # -----------------------------------------------------------------------
+    def _register_match(self, contact, friend):
+        self._friends_by_contact[contact] = friend
+        self._contacts_by_friend[friend] = contact
+        
+    # -----------------------------------------------------------------------
+    # FIXME
+    def _has_photo(self, contact):
+        return False
+    
+        
+    # -----------------------------------------------------------------------
+
+    def _lookup_addresses(self):
+        """Constructs hashes for address_to_contact, makes call to the Gravatar.com service and updates
+        self._hash_has_gravatar"""
+        
+        addresses = self._address_to_contact.keys()
+        if len(addresses) == 0:
+            self._set_hash_information({})
+        else:
+            args = { "apikey" : self._api_key}
+            hashes = self._construct_hashes(addresses)
+            args["hashes"] = list(hashes)
+            url = self._api_url
+            self._set_hash_information(self._get_hash_info_from_server(args, url))
+            
+
+    # -----------------------------------------------------------------------
+    def _get_hash_info_from_server(self, args, url):
+        """Makes the actual XML-RPC call - override this for testing"""
+        
+        service = xmlrpclib.ServerProxy(url)
+        return service.grav.exists(args)
+
+
+    # -----------------------------------------------------------------------
+    def _set_hash_information(self, hash_info):
+        self._hash_has_gravatar = hash_info
+        self._empty_cache = False
+        
+
+    # -----------------------------------------------------------------------
+    def _get_url_for_email_hash(self, hash, default="404", size="128"):
+        """Assembles the URL to a gravatar, based on a hash of an e-mail address"""
+    
+        return self._image_url_base + urllib.urlencode({'gravatar_id':hash, 'd':default, 'size':size})
+    
+    
+    # -----------------------------------------------------------------------
+    def _construct_hashes(self, addresses):
+        """Creates hashes for all addresses specified, returning a set of hashes"""
+    
+        result = set()
+        for address in addresses:
+            hash = self._get_hash_for_address(address)
+            self._hash_to_address[hash] = address
+            result.add(hash)
+    
+        return result
+
+    # -----------------------------------------------------------------------
+    def _get_hash_for_address(self, address):
+        return hashlib.md5(address.lower()).hexdigest()