Ralph Bean avatar Ralph Bean committed 3ff58cf

Add libravatar as an alternative backend.

Comments (0)

Files changed (3)

 tracvatar
 ==========
 
-Adds `Gravatar <http://www.gravatar.com/>`_ icons to Trac.
+Adds avatar icons provided by either `Gravatar <http://www.gravatar.com/>`_  or
+`Libravatar <http://libravatar.org>`_ to Trac.
 
 Credit goes to the `HackergotchiPlugin <http://trac-hacks.org/wiki/HackergotchiPlugin>`_ for 
 some general ideas.
 
-Currently, only Gravatar is supported, but the more open-ended plugin
-system of Hackergotchi can be re-implemented here if other avatar
-engines are desired.
-
 Ideally, Trac itself would just include support for author avatars
 as a built in, since this is an extremely common and desirable feature.
 
 For now, the approach of the plugin is to filter specific Trac views,
 gather all the authors found in the "data" hash being passed to 
-Genshi, then using Genshi filters to insert additional Gravatar nodes.
+Genshi, then using Genshi filters to insert additional avatar nodes.
 
 Currently supported views are:
 
 * Issue change display (i.e. comments, attachments)
 * Source browser listing (tested for svn and hg so far)
 * Individual changeset page (tested for svn and hg so far)
-* User prefs page (includes link to "change your avatar" at gravatar.com)
+* User prefs page (includes link to "change your avatar" at
+  gravatar.com/libravatar.org)
 
 Installation
 ============
     browser_lineitem_size = 20
     browser_changeset_size = 40
     prefs_form_size = 40
-    gravatar_default = default
+    avatar_default = default
+    backend = libravatar
 
 
 

tracvatar/htdocs/tracvatar.css

   margin:3px 10px 0px 0px;
 }
 
-td.tracvatar.prefs-gravatar {
+td.tracvatar.prefs-avatar {
   vertical-align:middle;
   white-space:nowrap;
-}
+}

tracvatar/web_ui.py

 import hashlib
 import re
 
+
 class AvatarModule(Component):
     implements(ITemplateStreamFilter, ITemplateProvider)
 
     browser_lineitem_size = Option("tracvatar", "browser_lineitem_size", default="20")
     browser_changeset_size = Option("tracvatar", "browser_changeset_size", default="40")
     prefs_form_size = Option("tracvatar", "prefs_form_size", default="40")
+    default = Option('tracvatar', 'avatar_default', default='default',
+                            doc="The default value to pass along to avatar to "
+                            "use if the email address does not match.")
+    backend = Option('tracvatar', 'backend', default='gravatar',
+                            doc="The name of the avatar service to use as a "
+                            "backend.  Currently gravatar and libravatar "
+                            "are supported.")
 
-    default = Option('tracvatar', 'gravatar_default', default='default',
-                            doc="The default value to pass along to gravatar to "
-                            "use if the email address does not match.")
+    # A mapping of possible backends to their peculiarities
+    backends = {
+        "gravatar": {
+            "url": "gravatar.com",
+            "base": "http://www.gravatar.com/avatar/",
+            "base_ssl": "https://gravatar.com/avatar/",
+        },
+        "libravatar": {
+            "url": "libravatar.org",
+            "base": "http://cdn.libravatar.org/avatar/",
+            "base_ssl": "https://seccdn.libravatar.org/avatar/",
+        },
+    }
 
     def filter_stream(self, req, method, filename, stream, data):
         filter_ = []
 
     def _footer(self):
         return Transformer('//div[@id="footer"]/p[@class="left"]').append(tag.p(
-            "Gravatar support by ",
+            "%s support by " % self.backend.title(),
             tag.a("Tracvatar %s" % tracvatar.__version__,
                     href="https://bitbucket.org/zzzeek/tracvatar"),
             class_="left",
 
     def _generate_avatar(self, context, author, class_, size):
         author_data = context['author_data']
-        email_hash = author_data.get(author, None) or self._gravatar(author)
+        email_hash = author_data.get(author, None) or self._avatar_slug(author)
         if context['is_https']:
-            href = "https://gravatar.com/avatar/" + email_hash
+            href = self.backends[self.backend]['base_ssl'] + email_hash
         else:
-            href = "http://www.gravatar.com/avatar/" + email_hash
+            href = self.backends[self.backend]['base'] + email_hash
         href += "?size=%s" % size
         # for some reason sizing doesn't work if you pass "default=default"
         if self.default != 'default':
             tag.tr(
                 tag.th(
                     tag.label(
-                        "Gravatar:",
-                        for_="gravatar"
+                        self.backend.title() + ":",
+                        for_="avatar"
                     )
                 ),
                 tag.td(
                     self._generate_avatar(
                          context,
                          email,
-                         "prefs-gravatar",
+                         "prefs-avatar",
                          self.prefs_form_size
                     ),
                     " Change your avatar at ",
                     tag.a(
-                        "gravatar.com",
-                        href="http://gravatar.com"
+                        self.backends[self.backend]['url'],
+                        href="http://" + self.backends[self.backend]['url'],
                     ),
-                    class_="tracvatar prefs-gravatar",
+                    class_="tracvatar prefs-avatar",
                 ),
                 class_="field"
             )
     # from trac source
     _long_author_re = re.compile(r'.*<([^@]+)@([^@]+)>\s*|([^@]+)@([^@]+)')
 
-    def _gravatar(self, email):
+    def _avatar_slug(self, email):
         if email is None:
             email = ''
         return hashlib.md5(email.lower()).hexdigest()
                 ), ("email",) + tuple(lookup_authors)
             )
             for sid, email in cursor.fetchall():
-                author_data[sid] = self._gravatar(email)
+                author_data[sid] = self._avatar_slug(email)
 
         for author in email_authors:
             author_info = self._long_author_re.match(author)
                     continue
                 author_data[name] = \
                     author_data[author] = \
-                    self._gravatar("%s@%s" % (name, host))
+                    self._avatar_slug("%s@%s" % (name, host))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.