You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@steve.apache.org by hu...@apache.org on 2015/03/22 15:09:43 UTC

svn commit: r1668375 - in /steve/trunk/pytest/www/cgi-bin: lib/election.py rest_admin.py rest_voter.py

Author: humbedooh
Date: Sun Mar 22 14:09:42 2015
New Revision: 1668375

URL: http://svn.apache.org/r1668375
Log:
refactor: put election tools into election.py and let rest_voter pull from there, for easier overview of what happens.

Added:
    steve/trunk/pytest/www/cgi-bin/lib/election.py
Modified:
    steve/trunk/pytest/www/cgi-bin/rest_admin.py
    steve/trunk/pytest/www/cgi-bin/rest_voter.py

Added: steve/trunk/pytest/www/cgi-bin/lib/election.py
URL: http://svn.apache.org/viewvc/steve/trunk/pytest/www/cgi-bin/lib/election.py?rev=1668375&view=auto
==============================================================================
--- steve/trunk/pytest/www/cgi-bin/lib/election.py (added)
+++ steve/trunk/pytest/www/cgi-bin/lib/election.py Sun Mar 22 14:09:42 2015
@@ -0,0 +1,72 @@
+import hashlib, json, random, os, sys, time
+from __main__ import homedir, config
+from os import listdir
+
+
+def exists(election):
+    elpath = os.path.join(homedir, "issues", election)
+    return os.path.isdir(elpath)
+
+def getBasedata(election, hideHash = False):
+    elpath = os.path.join(homedir, "issues", election)
+    if os.path.isdir(elpath):
+        with open(elpath + "/basedata.json", "r") as f:
+            data = f.read()
+            f.close()
+            basedata = json.loads(data)
+            if hideHash and 'hash' in basedata:
+                del basedata['hash']
+            basedata['id'] = election
+            return basedata
+    return None
+    
+def getIssue(electionID, issueID):
+    issuepath = os.path.join(homedir, "issues", electionID, issueID) + ".json"
+    issuedata = None
+    if os.path.isfile(issuepath):
+        with open(issuepath, "r") as f:
+            data = f.read()
+            f.close()
+            issuedata = json.loads(data)
+        issuedata['id'] = issueID
+        issuedata['APIURL'] = "https://%s/steve/voter/view/%s/%s" % (config.get("general", "rooturl"), electionID, issueID)
+        issuedata['prettyURL'] = "https://%s/steve/ballot?%s/%s" % (config.get("general", "rooturl"), electionID, issueID)
+    return issuedata
+    
+def listIssues(election):
+    issues = []
+    elpath = os.path.join(homedir, "issues", election)
+    if os.path.isdir(elpath):
+        issues = [ f.strip(".json") for f in os.listdir(elpath) if os.path.isfile(os.path.join(elpath,f)) and f != "basedata.json" and f != "voters.json" and f.endswith(".json")]
+    return issues
+
+def vote(electionID, issueID, voterID, vote):
+    votes = {}
+    basedata = getBasedata(electionID)
+    if basedata:
+        issuepath = os.path.join(homedir, "issues", electionID, issueID) + ".json"
+        if os.path.isfile(issuepath + ".votes"):
+            with open(issuepath + ".votes", "r") as f:
+                votes = json.loads(f.read())
+                f.close()
+        votes[voterID] = vote
+        with open(issuepath + ".votes", "w") as f:
+            f.write(json.dumps(votes))
+            f.close()
+        votehash = hashlib.sha224(basedata['hash'] + issueID + voterID + vote).hexdigest()
+        return votehash
+    else:
+        raise Exception("No such election")
+
+
+def invalidate(issueData, vote):
+    letters = ['y','n','a']
+    if issueData['type'].find("stv") == 0:
+        letters = [chr(i) for i in range(ord('a'),ord('a') + len(issueData['candidates']))]
+    for char in letters:
+        if vote.count(char) > 1:
+            return "Duplicate letters found"
+    for char in vote:
+        if not char in letters:
+            return "Invalid characters in vote. Accepted are: %s" % ", ".join(letters)
+    return None
\ No newline at end of file

Modified: steve/trunk/pytest/www/cgi-bin/rest_admin.py
URL: http://svn.apache.org/viewvc/steve/trunk/pytest/www/cgi-bin/rest_admin.py?rev=1668375&r1=1668374&r2=1668375&view=diff
==============================================================================
--- steve/trunk/pytest/www/cgi-bin/rest_admin.py (original)
+++ steve/trunk/pytest/www/cgi-bin/rest_admin.py Sun Mar 22 14:09:42 2015
@@ -43,7 +43,7 @@ form = cgi.FieldStorage();
 
 whoami = os.environ['REMOTE_USER'] if 'REMOTE_USER' in os.environ else None
 
-from lib import response, voter
+from lib import response, voter, election
 
 if not whoami:
     response.respond(403, {'message': 'Could not verify your identity: No auth scheme found'})

Modified: steve/trunk/pytest/www/cgi-bin/rest_voter.py
URL: http://svn.apache.org/viewvc/steve/trunk/pytest/www/cgi-bin/rest_voter.py?rev=1668375&r1=1668374&r2=1668375&view=diff
==============================================================================
--- steve/trunk/pytest/www/cgi-bin/rest_voter.py (original)
+++ steve/trunk/pytest/www/cgi-bin/rest_voter.py Sun Mar 22 14:09:42 2015
@@ -41,7 +41,7 @@ homedir = config.get("general", "homedir
 pathinfo = os.environ['PATH_INFO'] if 'PATH_INFO' in os.environ else None
 form = cgi.FieldStorage();
 
-from lib import response, voter
+from lib import response, voter, election
 
 
 whoami = os.environ['REMOTE_USER'] if 'REMOTE_USER' in os.environ else None
@@ -55,37 +55,29 @@ if pathinfo:
     if l[0] == "":
         l.pop(0)
     action = l[0]
-    election = l[1] if len(l) > 1 else None
-    issue = l[2]  if len(l) > 2 else None
-    voterid = form.getvalue('uid')
+    electionID = l[1] if len(l) > 1 else None
+    issueID = l[2]  if len(l) > 2 else None
+    voterID = form.getvalue('uid')
     
-    if not voterid and karma < 3 and (action != "request" and action != "peek"):
+    if not voterID and karma < 3 and (action != "request" and action != "peek"):
         response.respond(403, {'message': "Voter UID missing"})
     
     elif action == "view":
         # View a list of issues for an election
-        if election and not issue:
+        if electionID and not issueID:
             js = []
-            elpath = os.path.join(homedir, "issues", election)
-            if os.path.isdir(elpath):
-                basedata = {}
+            if election.exists(electionID):
                 try:
-                    with open(elpath + "/basedata.json", "r") as f:
-                        basedata = json.loads(f.read())
-                        f.close()
-                    if karma < 3 and not voter.get(election, basedata, voterid):
+                    basedata = election.getBasedata(electionID)
+                    if not basedata:
+                        raise Exception("Could not load base data")
+                    if karma < 3 and not voter.get(electionID, basedata, voterID):
                         raise Exception("Invalid voter ID presented")
-                    issues = [ f for f in listdir(elpath) if os.path.isfile(os.path.join(elpath,f)) and f != "basedata.json" and f != "voters.json" and f.endswith(".json")]
-                    for issue in issues:
+                    for issueID in election.listIssues(electionID):
                         try:
-                            with open(elpath + "/" + issue, "r") as f:
-                                entry = json.loads(f.read())
-                                f.close()
-                                entry['id'] = issue.strip(".json")
-                                entry['APIURL'] = "https://%s/steve/voter/view/%s/%s" % (os.environ['SERVER_NAME'], election, issue.strip(".json"))
-                                entry['prettyURL'] = "https://%s/steve/ballot?%s/%s" % (os.environ['SERVER_NAME'], election, issue.strip(".json"))
-                                entry['hasVoted'] = voter.hasVoted(election, issue, voterid)
-                                js.append(entry)
+                            entry = election.getIssue(electionID, issueID)
+                            entry['hasVoted'] = voter.hasVoted(electionID, issueID, voterID)
+                            js.append(entry)
                         except Exception as err:
                             response.respond(500, {'message': 'Could not load issues: %s' % err})
                 except Exception as err:
@@ -97,45 +89,31 @@ if pathinfo:
                 response.respond(404, {'message': 'No such election'})
                 
         # View a speficic issue
-        elif election and issue:
+        elif electionID and issueID:
             js = []
-            elpath = os.path.join(homedir, "issues", election)
-            issuepath = os.path.join(homedir, "issues", election, issue)
-            if os.path.isfile(issuepath + ".json"):
-                basedata = {}
+            issuedata = election.getIssue(electionID, issueID)
+            if issuedata:
                 try:
-                    with open(elpath + "/basedata.json", "r") as f:
-                        basedata = json.loads(f.read())
-                        f.close()
-                    if karma < 3 and not voter.get(election, basedata, voterid):
+                    basedata = election.getBasedata(electionID)
+                    if karma < 3 and not voter.get(electionID, basedata, voterID):
                         raise Exception("Invalid voter ID presented")
-                    with open(issuepath + ".json", "r") as f:
-                        entry = json.loads(f.read())
-                        f.close()
-                        entry['id'] = issue.strip(".json")
-                        entry['APIURL'] = "https://%s/steve/voter/view/%s/%s" % (os.environ['SERVER_NAME'], election, issue)
-                        entry['prettyURL'] = "https://%s/steve/ballot?%s/%s" % (os.environ['SERVER_NAME'], election, issue)
-                        response.respond(200, {'issue': entry})
+                    entry = election.getIssue(electionID, issueID)
+                    response.respond(200, {'issue': entry})
                 except Exception as err:
                     response.respond(500, {'message': "Could not load issue: %s" % err})
             else:
                 response.respond(404, {'message': 'No such issue'})
         else:
             response.respond(404, {'message': 'No election ID supplied'})
-    elif action == "vote" and election and issue and voterid:
+            
+            
+            
+    elif action == "vote" and electionID and issueID and voterID:
         try:
-            elpath = os.path.join(homedir, "issues", election)
-            issuepath = os.path.join(homedir, "issues", election, issue) + ".json"
-            if os.path.isdir(elpath) and os.path.isfile(issuepath):
-                basedata = {}
-                issuedata = {}
-                with open(elpath + "/basedata.json", "r") as f:
-                    basedata = json.loads(f.read())
-                    f.close()
-                with open(issuepath, "r") as f:
-                    issuedata = json.loads(f.read())
-                    f.close()
-                email = voter.get(election, basedata, voterid)
+            basedata = election.getBasedata(electionID)
+            issuedata = election.getIssue(electionID, issueID)
+            if basedata and issuedata:
+                email = voter.get(electionID, basedata, voterID)
                 if not email:
                     response.respond(403, {'message': 'Could not save vote: Invalid voter ID presented'})
                 else:
@@ -143,54 +121,28 @@ if pathinfo:
                     if not vote:
                         response.respond(500, {'message': 'Please specify a vote'})
                     else:
-                        double = False
-                        invalid = False
-                        letters = ['y','n','a']
-                        if issuedata['type'].find("stv") == 0:
-                            letters = [chr(i) for i in range(ord('a'),ord('a') + len(issuedata['candidates']))]
-                        for char in letters:
-                            if vote.count(char) > 1:
-                                double = True
-                                break
-                        for char in vote:
-                            if not char in letters:
-                                invalid = True
-                                break
-                        if double:
-                            response.respond(500, {'message': "Vote contains duplicate characters"})
-                        elif invalid:
-                            response.respond(500, {'message': "Vote contains invalid characters. Accepted are: %s" % ", ".join(letters)})
+                        invalid = election.invalidate(issuedata, vote)
+                        if invalid:
+                            response.respond(500, {'message': invalid})
                         else:
-                            votes = {}
-                            if os.path.isfile(issuepath + ".votes"):
-                                with open(issuepath + ".votes", "r") as f:
-                                    votes = json.loads(f.read())
-                                    f.close()
-                            votes[voterid] = vote
-                            with open(issuepath + ".votes", "w") as f:
-                                f.write(json.dumps(votes))
-                                f.close()
-                            votehash = hashlib.sha224(basedata['hash'] + voterid + vote + email).hexdigest()
-                            voter.email(email, "Vote registered: %s (%s)" % (issue, issuedata['title']), "This is a receipt that your vote was registered for issue #%s:\n\nElection: %s (%s)\nIssue: %s (%s)\nVote cryptohash: %s" % (issue, basedata['title'], election, issuedata['title'], issue, votehash))
+                            votehash = election.vote(electionID, issueID, voterID, vote)
+                            voter.email(email, "Vote registered: %s (%s)" % (issueID, issuedata['title']), "This is a receipt that your vote was registered for issue #%s:\n\nElection: %s (%s)\nIssue: %s (%s)\nVote cryptohash: %s" % (issueID, basedata['title'], electionID, issuedata['title'], issueID, votehash))
                             response.respond(200, {'message': 'Vote saved!'})
-                            
             else:
                 response.respond(404, {'message': 'Could not save vote: No such election or issue'})
                     
         except Exception as err:
             response.respond(500, {'message': 'Could not save vote: %s' % err})
+            
+            
     elif action == "request" and election:
         email = form.getvalue('email')
         if not email or len(email) > 300 or not re.match(r"([^@]+@[^@]+)", email):
             response.respond(400, {'message': 'Could not request voter ID: Invalid email address specified'})
         else:
             try:
-                elpath = os.path.join(homedir, "issues", election)
-                if os.path.isdir(elpath):
-                    basedata = {}
-                    with open(elpath + "/basedata.json", "r") as f:
-                        basedata = json.loads(f.read())
-                        f.close()
+                basedata = election.getBasedata(electionID)
+                if basedata:
                     if 'open' in basedata and basedata['open'] == "true":
                         uid, xhash = voter.add(election, basedata, email)
                         voter.email(email, "Your voter link for %s" % basedata['title'], "Your personal vote link is: %s/election.html?%s/%s\nDo not share this link with anyone." % (config.get("general", "rooturl"), election, uid))
@@ -206,13 +158,8 @@ if pathinfo:
         try:
             elpath = os.path.join(homedir, "issues", election)
             if os.path.isdir(elpath):
-                basedata = {}
-                with open(elpath + "/basedata.json", "r") as f:
-                    basedata = json.loads(f.read())
-                    f.close()
+                basedata = election.getBasedata(electionID, hideHash=True)
                 if 'open' in basedata and basedata['open'] == "true":
-                    if 'hash' in basedata:
-                        del basedata['hash']
                     response.respond(200, { 'base_data': basedata } )
                 else:
                     response.respond(403, {'message': 'This election is not open to the public'})