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