import os import re import pickle from StringIO import StringIO from trac.core import * from trac.perm import IPermissionRequestor from trac.util import sorted, escape from trac.wiki.formatter import wiki_to_oneliner from trac.web.chrome import ITemplateProvider, add_stylesheet class Poll(object): def __init__(self, base_dir, title, vote_defs): self.vote_defs = vote_defs self.title = title # Perhaps the Wiki page name should be included? self.key = ''.join(re.findall(r'(\w+)', title)).lower() self.store = os.path.join(base_dir, self.key + '.poll') self.load() def load(self): """ Load pickled representation of votes. """ self.votes = {} if os.path.isfile(self.store): poll = pickle.load(open(self.store, 'r')) assert self.title == poll['title'], \ 'Stored poll is not the same as this one.' self.votes = dict([(k, v) for k, v in poll['votes'].iteritems() if k in [d[0] for d in self.vote_defs]]) self.votes.update(dict([(k[0], []) for k in self.vote_defs if k[0] not in self.votes])) def save(self): data = {'title': self.title, 'votes': self.votes} pickle.dump(data, open(self.store, 'w')) def populate(self, req): """ Update poll based on HTTP request. """ if req.args.get('poll', '') == self.key: vote = req.args.get('vote', '') if not vote: return if vote not in self.votes: raise TracError('No such vote %s' % vote) username = req.authname or 'anonymous' 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): out = StringIO() can_vote = req.perm.has_permission('POLL_VOTE') if can_vote: out.write('
\n') return out.getvalue() try: from trac.wiki.macros import WikiMacroBase except ImportError: # TODO Remove this when ported to 0.10 from trac.wiki.api import IWikiMacroProvider class WikiMacroBase(Component): """Abstract base class for wiki macros.""" implements(IWikiMacroProvider) abstract = True def get_macros(self): """Yield the name of the macro based on the class name.""" name = self.__class__.__name__ if name.endswith('Macro'): name = name[:-5] yield name def get_macro_description(self, name): """Return the subclass's docstring.""" return inspect.getdoc(self.__class__) def render_macro(self, req, name, content): raise NotImplementedError class PollMacro(WikiMacroBase): """ Add a poll. Each argument must be separated by a semi-colon (;) or new-line (if used as a processor). The first argument is the title of the poll, which is also the identifier for each poll. Usage: `[[TicketPoll(