Commits

Mike Bayer committed ebaa786

initial rev

  • Participants

Comments (0)

Files changed (5)

+syntax:regexp
+^build/
+^dist/
+^docs/build/output
+.pyc$
+.orig$
+.egg-info
+.coverage
+==========
+tracvatar
+==========
+
+Adds a filter to trac views that allows Gravatar icons to be rendered
+in templates.
+
+This basically works by intercepting outgoing templates, looking for authors
+in the data dictionary being passed to genshi, and adding a
+collection of gravatar hashes to it. 
+
+To install, just use ``python setup.py bdist_egg`` to create an egg file which
+then goes into the Trac ``plugins/`` folder, or just ``python setup.py install``
+to plug it in entirely.
+
+
+
+#!/usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+import os
+
+from setuptools import setup
+
+setup(
+    name = 'tracvatar',
+    version = '1.0',
+    packages = ['tracvatar'],
+    package_data = {'tracvatar': ['htdocs/*.js']},
+
+    author = 'Mike Bayer',
+    author_email = 'mike_mp@zzzcomputing.com',
+    description = 'Add gravatar icons to various points around trac',
+    long_description = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read(),
+    license = 'BSD',
+    keywords = 'trac plugin gravatar',
+    url = 'http://bitbucket.org/zzzeek/tracvatar',
+    classifiers = [
+        'Framework :: Trac',
+        'Development Status :: 4 - Beta',
+        'Environment :: Web Environment',
+        'License :: OSI Approved :: BSD License',
+        'Natural Language :: English',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+    ],
+
+    install_requires = ['Trac'],
+
+    entry_points = {
+        'trac.plugins': [
+            'tracvatar.web_ui = tracvatar.web_ui',
+        ],
+    },
+)
+
+

File tracvatar/__init__.py

Empty file added.

File tracvatar/web_ui.py

+from trac.core import Component, implements
+from trac.web.api import ITemplateStreamFilter
+from genshi.filters.transform import Transformer
+from genshi.builder import tag
+import itertools
+import textwrap
+import re
+
+class GravatarModule(Component):
+    implements(ITemplateStreamFilter)
+
+    def filter_stream(self, req, method, filename, stream, data):
+        filter_ = []
+        if req.path_info.startswith("/ticket"):
+            filter_ = self._ticket_filter(data)
+        elif req.path_info.startswith("/timeline"):
+            filter_ = self._timeline_filter(data)
+
+        for f in filter_:
+            stream |= f
+        return stream
+
+    def _crap(self):
+        if tracvatar_data:
+            hashes = self._get_hashes([t[2] for t in tracvatar_data])
+            for t in tracvatar_data:
+                if t[2] in hashes:
+                    t[3] = hashes[t[2]]
+
+        def f(stream):
+            stream = iter(stream)
+            elem = next(stream)
+            yield elem
+
+            for elem in tag.script(
+                "\njQuery(document).ready(function($) {\n    " + 
+                "\n    ".join(self._js_calls(page, tracvatar_data)) + 
+                "\n}"
+                ,type="text/javascript"
+            ).generate():
+                yield elem
+
+            for elem in stream:
+                yield elem
+
+    def _node_attrs(self, node):
+        """given a genshi node in a stream, return a dictionary of the 
+        'attrs' portion."""
+
+        return dict([(str(qname), value) for qname, value in node[1][1]])
+
+    def _ticket_filter(self, data):
+        tracvatar_data = {}
+        if 'ticket' in data:
+            tracvatar_data['reporter'] = [data['ticket'].values['reporter'], None]
+        if 'changes' in data:
+            for change in data['changes']:
+                tracvatar_data[('change', change['cnum'])] = [change['author'], None]
+        self._get_hashes(tracvatar_data)
+
+        def find_change(stream):
+            stream = iter(stream)
+            start_tag = next(stream)
+            attrs = self._node_attrs(start_tag)
+            change = re.match(r'trac\-change\-(\d+)', attrs["id"])
+            if not change:
+                return itertools.chain([start_tag], stream)
+            else:
+                change = change.group(1)
+
+            elm = tag.img(src="foo_%s.png" % change)
+            stream = Transformer('//h3[@class="change"]').prepend(elm.generate())(stream)
+            return itertools.chain([start_tag], stream)
+
+        return \
+            Transformer('//div[@id="ticket"]').prepend(tag.img(src="foo.png").generate()),\
+            Transformer('//div[@id="changelog"]/div[@class="change"]').filter(find_change)
+
+    def _get_hashes(self, tracvatar_data):
+        authors = sorted(set([t[0] for t in tracvatar_data.values()]))
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute(
+            "select sid, value from session_attribute where name=%%s and sid in (%s)" % (
+                ",".join(["%s" for author in authors])
+            ), ("email",) + tuple(authors)
+        )
+        hashes = {}
+        for sid, value in cursor.fetchall():
+            hashes[sid] = value
+        for values in tracvatar_data.values():
+            if values[0] in hashes:
+                values[1] = hashes[values[0]]