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 fmt = macro.formatter 70 71 args = args.split(",") 72 args = map(unicode.strip, args) 73 74 if len(args) < 1: 75 return fmt.rawHTML('<pre>[[Vote: Insufficient macro arguments]]</pre>') 76 77 pageName = args[0] 78 voteName = pageName 79 candidates = ['1','2','3','4','5'] 80 src_litstar = '/wiki/modern/img/star_on.png' 81 src_unlitstar = '/wiki/modern/img/star_off.png' 82 83 form = macro.form 84 request = macro.request 85 if request.user.valid: 86 voter = request.user.name 87 else: 88 voter = '' 89 thisPage = fmt.page 90 votes = loadVotes(thisPage, voteName) 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(thisPage, voteName, votes) 99 except: # XXX 100 return fmt.rawHTML('<pre>[[Vote: failed to store vote]]</pre>') 101 102 # generate dictionary {candidate: numvotes} 103 results = countVotes(votes) 104 onestar = results.setdefault(candidates[0],0) 105 twostar = results.setdefault(candidates[1],0) 106 threestar = results.setdefault(candidates[2],0) 107 fourstar = results.setdefault(candidates[3],0) 108 fivestar = results.setdefault(candidates[4],0) 109 counts = (onestar+twostar+threestar+fourstar+fivestar) 110 111 if counts == 0: 112 average = 0 113 else: 114 average = (onestar*1+twostar*2+threestar*3+fourstar*4+fivestar*5)/counts 115 116 hasVoted = voter in votes 117 118 # spit out votes table (as part of a form if the user hasn't voted yet) 119 html = [] 120 121 if voter: 122 html.append(''' 123 <form method="get" name="%(formname)s" action="%(url)s#voteform">\n 124 <input type="hidden" name="voteName" value="%(voteName)s">\n 125 <input type="hidden" name="vote" value="0"> 126 ''' % { 127 'formname': voteName, 128 'url': thisPage.url(request), 129 'voteName': voteName, 130 } 131 ) 132 btnstar = '<input type="image" src="%(isrc)s" OnClick="document.%(form)s.vote.value=%(value)s">\n' 133 for i in range(1,6): 134 if i <= average: 135 html.append(btnstar % {'isrc':src_litstar, 'form':voteName, 'value': i}) 136 if i > average: 137 html.append(btnstar % {'isrc':src_unlitstar, 'form':voteName, 'value': i}) 138 if average == 0: 139 html.append(' No Rating') 140 #else: 141 # html.append(' %(avg)s ' % { 'avg': average }) 142 html.append('</form>') 143 else: 144 html.append('Please log in to vote.') 145 146 return fmt.rawHTML(''.join(html)) 147 148 # vim: tabstop=4 expandtab shiftwidth=4