1 #format python 2 # -*- coding: iso-8859-1 -*- 3 ''' 4 MoinMoin - VotingStars Macro 5 Author: Travis Bailey 6 Date: February 2006 7 8 Purpose: 9 This macro allows ratings of items using stars (based on Vote macro) 10 Usage: 11 [[VotingStars(UniqueName)]] 12 e.g. 1. NiceShop [[VotingStars(shop1)]] 13 1. EvenNicerShop [[VotingStars(shop2)]] 14 Tested: 15 Firefox 1.5 MoinMoin 1.5.1 Python 2.3 16 17 I basically just slapped this together from the Vote1_3.py script and the 18 RatingStars.py script. I wanted to get the benefits of both. I wanted a 19 Utility to only allow Registered users to submit, allow them to change 20 their vote, and to average the results. 21 22 So basically it uses the Vote1_3.py code to track one vote per user. 23 It averages the total stars given and then displays the number of average 24 number of rated stars. 25 26 You can have multiple VotingStars on one page (so long as the UniqueNames are unique) 27 Changing the UniqueName creates a new vote. 28 Make sure not to conflict with any Vote names you are using 29 30 VotingStars data is stored in data_dir/pages/pagename/votes 31 (i.e. alongside the attachments directory for a page). 32 33 You can customise the appearance by defining the following CSS styles: 34 table.votestars 35 36 ''' 37 import os, pickle 38 from MoinMoin import wikiutil 39 from MoinMoin.util import filesys 40 41 def makeFilename(thisPage, voteName): 42 votesDir = thisPage.getPagePath("votes") 43 if not os.path.exists(votesDir): 44 filesys.makeDirs(votesDir) 45 voteName = wikiutil.quoteWikinameFS(voteName) + '.pik' 46 return os.path.join(votesDir, voteName) 47 48 def loadVotes(thisPage, voteName): 49 votesFile = makeFilename(thisPage, voteName) 50 try: 51 f = open(votesFile, 'r') 52 return pickle.load(f) 53 except: # XXX 54 return {} 55 56 def saveVotes(thisPage, voteName, votes): 57 votesFile = makeFilename(thisPage, voteName) 58 f = open(votesFile, 'w') 59 pickle.dump(votes, f) 60 61 def countVotes(votes): 62 results = {} 63 for v in votes.values(): 64 results.setdefault(v, 0) 65 results[v] += 1 66 return results 67 68 def execute(macro, args): 69 args = args.split(",") 70 args = map(unicode.strip, args) 71 72 if len(args) < 1: 73 return macro.formatter.rawHTML('<pre>[[Vote: Insufficient macro arguments]]</pre>') 74 75 pageName = args[0] 76 voteName = pageName 77 candidates = ['1','2','3','4','5'] 78 src_litstar = '/wiki/modern/img/star_on.png' 79 src_unlitstar = '/wiki/modern/img/star_off.png' 80 81 form = macro.form 82 request = macro.request 83 if request.user.valid: 84 voter = request.user.name 85 else: 86 voter = '' 87 thisPage = macro.formatter.page 88 votes = loadVotes(thisPage, voteName) 89 90 # votes are stored in a dictionary as {user: candidate} to avoid duplicate votes 91 # (a voter could switch their vote but this UI doesn't expose that facility) 92 if form.has_key('vote') and form.has_key('voteName') and voter: 93 if form['voteName'][0] == voteName: 94 votes[voter] = form['vote'][0] 95 try: 96 saveVotes(thisPage, voteName, votes) 97 except: # XXX 98 return macro.formatter.rawHTML('<a id="voteform"><pre>[[Vote: failed to store vote]]</pre>') 99 100 # generate dictionary {candidate: numvotes} 101 results = countVotes(votes) 102 onestar = results.setdefault(candidates[0],0) 103 twostar = results.setdefault(candidates[1],0) 104 threestar = results.setdefault(candidates[2],0) 105 fourstar = results.setdefault(candidates[3],0) 106 fivestar = results.setdefault(candidates[4],0) 107 counts = (onestar+twostar+threestar+fourstar+fivestar) 108 109 if counts == 0: 110 average = 0 111 else: 112 average = (onestar*1+twostar*2+threestar*3+fourstar*4+fivestar*5)/counts 113 114 hasVoted = voter in votes 115 116 # spit out votes table (as part of a form if the user hasn't voted yet) 117 html = '<a id="voteform"><table class="votestars"><tr><td>' 118 119 if voter: 120 html += ''' 121 <form method="get" name="%(formname)s" action="%(url)s#voteform">\n 122 <input type="hidden" name="voteName" value="%(voteName)s">\n 123 <input type="hidden" name="vote" value="0"> 124 ''' % { 125 'formname': voteName, 126 'url': thisPage.url(request), 127 'voteName': voteName, 128 } 129 btnstar = '<input type="image" src="%(isrc)s" OnClick="document.%(form)s.vote.value=%(value)s">\n' 130 for i in range(1,6): 131 if i <= average: 132 html += btnstar % {'isrc':src_litstar, 'form':voteName, 'value': i} 133 if i > average: 134 html += btnstar % {'isrc':src_unlitstar, 'form':voteName, 'value': i} 135 if average == 0: 136 html += ' No Rating' 137 #else: 138 # html += ' %(avg)s ' % { 'avg': average } 139 html += '</form></td></tr></table></a>' 140 else: 141 html += 'You must be logged in to Rate.</td></tr></table></a>' 142 143 return macro.formatter.rawHTML(html) 144