Attachment 'Vote.py'
Download 1 #format python
2 '''
3 Simple Vote macro for MoinMoin.
4 Author: Martin Stone <martins@evos.net>
5 Hacked by: John Cocula (john@cocula.com)
6
7 Usage:
8 [[Vote(pageName, voteTitle, candidate1, ...)]]
9
10 E.g:
11 [[Vote(MyBlog, Do polls work?, yes)]]
12
13 Just like Martin's Vote macro, except you must specify the name of the
14 page on which to vote "appears." Without this information, when a user
15 votes from an included page, after pressing the Vote button they are
16 returned to the included page, not the main page. Also different is
17 that the current number of votes is hidden until the user has voted.
18 Lastly, it is possible to have a poll that only has one choice, which
19 is kind of funny. The remainder of the description is Martin's:
20
21 You can have multiple votes on one page (so long as the titles are unique).
22 You can add candidates after a vote has started, but note that renaming
23 candidates will lose the votes (and not allow users to recast their votes).
24 Changing the vote title creates a new vote.
25
26 Vote data is stored in data_dir/pages/pagename/votes
27 (i.e. alongside the attachments directory for a page).
28
29 You can customise the appearance by defining the following CSS styles:
30 table.vote
31 td.votelogin (for "must login" message)
32 '''
33
34 from MoinMoin import user, webapi, wikiutil, config
35 import os
36 import pickle
37 import string
38
39
40 def getVotesDir(macro):
41 """ Get directory where votes on this page are stored.
42 """
43 pagename = macro.formatter.page.page_name
44 return os.path.join(config.data_dir, "pages", pagename, "votes")
45
46
47 def makeFilename(voteName):
48 voteName = string.translate(voteName, string.maketrans('\\/:*?"<>|', 'xxxxxxxxx'), string.whitespace) # any I've missed?
49 return voteName+".pik"
50
51
52 def loadVotes(macro,voteName):
53 try:
54 f = open(os.path.join(getVotesDir(macro), makeFilename(voteName)), 'r')
55 return pickle.load(f)
56 except:
57 return {}
58
59
60 def saveVotes(macro,voteName, votes):
61 votesDir = getVotesDir(macro)
62 if not os.path.isdir(votesDir):
63 os.makedirs(votesDir) #need mode?
64
65 f = open(os.path.join(votesDir, makeFilename(voteName)), 'w')
66 pickle.dump(votes, f)
67
68
69 def countVotes(votes):
70 results = {}
71 for v in votes.values():
72 results.setdefault(v, 0)
73 results[v] = results[v] + 1
74
75 return results
76
77
78 def execute(macro, args):
79 args = string.split(args, ",")
80 args = map(string.strip, args)
81
82 if len(args) < 3: return macro.formatter.rawHTML('<pre>[[Vote: Insufficient macro arguments]]</pre>')
83
84 pageName = args[0]
85 voteName = args[1]
86 candidates = args[2:]
87
88 form = macro.form
89 votes = loadVotes(macro,voteName)
90 voter = macro.request.user.name
91
92 # votes are stored in a dictionary as {user: candidate} to avoid duplicate votes
93 # (a voter could switch their vote but this UI doesn't expose that facility)
94 if form.has_key('vote') and form.has_key('voteName') and voter:
95 if form['voteName'][0] == voteName:
96 votes[voter] = form['vote'][0]
97 try:
98 saveVotes(macro, voteName, votes)
99 except:
100 return macro.formatter.rawHTML('<a id="voteform"><pre>[[Vote: failed to store vote]]</pre>')
101
102 # generate dictionary {candidate: numvotes}
103 results = countVotes(votes)
104
105 hasVoted = voter in votes
106
107 # spit out votes table (as part of a form if the user hasn't voted yet)
108 html = ''
109 if not hasVoted:
110 voteButton = '<td><INPUT type="radio" name="vote" value="%s">vote</td>'
111 html += '''
112 <form method="get" action="%(scriptname)s/%(pageName)s#voteform">\n
113 <input type="hidden" name="voteName" value="%(voteName)s">
114 ''' % {'scriptname': r'/cgi-bin/moin.cgi', 'pageName': pageName, 'voteName': voteName}
115 else:
116 voteButton = ''
117
118 html += '<a id="voteform"><table class="vote"><tr><th colspan="2">%s</th></tr>' % voteName
119
120 for candidate in candidates:
121 button = voteButton and (voteButton % candidate)
122 if not hasVoted:
123 button = '<td><INPUT type="radio" name="vote" value="%s">%s</td>' % (candidate, candidate)
124 count = ''
125 else:
126 button = candidate
127 count = results.setdefault(candidate, 0)
128 html += '<tr><td>%s</td><td>%s</td></tr>\n' % (button, count)
129
130 if not voter and not hasVoted:
131 html += '<tr><td colspan="3" class="votelogin">You need to login to vote</td></tr>'
132
133 html += '</table>\n'
134
135 if not hasVoted:
136 html += '<input type="submit" value="Vote">\n</form>\n'
137
138 return macro.formatter.rawHTML(html)
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.