﻿id,summary,reporter,owner,description,type,status,priority,component,severity,resolution,keywords,cc,release
10703,[PATCH] support of fully anonymous polls,falkb,rjollos,"This patch adds the ability to make fully anonymous polls, simply by the use of pattern {{{ (*) }}} at the end of the poll question:

{{{
#!diff
Index: pollmacro/trunk/tracpoll/tracpoll.py
===================================================================
--- pollmacro/trunk/tracpoll/tracpoll.py	(revision 11672)
+++ pollmacro/trunk/tracpoll/tracpoll.py	(working copy)
@@ -1,3 +1,4 @@
+import hashlib
 import os
 import re
 import pickle
@@ -49,7 +50,7 @@
         finally:
             fd.close()
 
-    def populate(self, req):
+    def populate(self, req, isAnonymousPoll):
         """""" Update poll based on HTTP request. """"""
         if req.args.get('poll', '') == self.key:
             vote = req.args.get('vote', '')
@@ -58,13 +59,15 @@
             if vote not in self.votes:
                 raise TracError('No such vote %s' % vote)
             username = req.authname or 'anonymous'
+            if isAnonymousPoll:
+                username = hashlib.sha1(username).hexdigest()
             for v, voters in self.votes.items():
                 if username in voters:
                     self.votes[v].remove(username)
             self.votes[vote] = self.votes[vote] + [username]
             self.save()
 
-    def render(self, env, req):
+    def render(self, env, req, isAnonymousPoll):
         out = StringIO()
         can_vote = req.perm.has_permission('POLL_VOTE')
         if can_vote:
@@ -76,6 +79,8 @@
                   ' <ul>\n'
                   % escape(self.title))
         username = req.authname or 'anonymous'
+        if isAnonymousPoll:
+            username = hashlib.sha1(username).hexdigest()
         for id, style, vote in self.vote_defs:
             hid = escape(str(id))
             out.write('<li%s>\n' % (style and ' class=""%s""' % style or ''))
@@ -90,12 +95,15 @@
             else:
                 out.write(vote)
             if self.votes[id]:
-                out.write(' <span class=""voters"">(<span class=""voter"">' +
-                          '</span>, <span class=""voter"">'.join(self.votes[id]) +
-                          '</span>)</span>')
+                if isAnonymousPoll:
+                    out.write(' <span class=""voters"">(%s)</span>' % len(self.votes[id]))
+                else:
+                    out.write(' <span class=""voters"">(<span class=""voter"">' +
+                              '</span>, <span class=""voter"">'.join(self.votes[id]) +
+                              '</span>)</span>')
             out.write('</li>\n')
         if can_vote:
             out.write('<input type=""submit"" value=""Vote""/>')
         else:
             out.write(""<br/><i>You don't have permission to vote. You may need to login.</i>"")
         out.write(' </ul>\n</fieldset>\n')
@@ -128,6 +136,7 @@
                       'Path where poll pickle dumps should be stored.')
 
     def expand_macro(self, formatter, name, content):
+        isAnonymousPoll = False
         req = formatter.req
         if not content:
             return system_message(""A title must be provided as the first argument to the poll macro"")
@@ -136,9 +145,11 @@
         if len(content) < 2:
             return system_message(""One or more options must be provided to vote on."")
         title = content.pop(0)
-        return self.render_poll(req, title, content)
+        if title.endswith('(*)'):
+            isAnonymousPoll = True
+        return self.render_poll(req, title, content, isAnonymousPoll)
 
-    def render_poll(self, req, title, votes):
+    def render_poll(self, req, title, votes, isAnonymousPoll):
         add_stylesheet(req, 'poll/css/poll.css')
         if not req.perm.has_permission('POLL_VIEW'):
             return ''
@@ -184,8 +195,8 @@
 
         poll = Poll(self.base_dir, title, all_votes)
         if req.perm.has_permission('POLL_VOTE'):
-            poll.populate(req)
-        return poll.render(self.env, req)
+            poll.populate(req, isAnonymousPoll)
+        return poll.render(self.env, req, isAnonymousPoll)
 
     # IPermissionRequestor methods
     def get_permission_actions(self):
}}}
",enhancement,assigned,high,PollMacro,normal,,,,
