Author: humbedooh
Date: Tue Mar 24 11:36:26 2015
New Revision: 1668848
URL: http://svn.apache.org/r1668848
Log:
- Add checksums to issues
- Add feature for cuing monitors before an election starts
- Send checksums to monitors when an election has been closed.
Modified:
steve/trunk/pysteve/lib/election.py
steve/trunk/pysteve/www/cgi-bin/rest_admin.py
steve/trunk/pysteve/www/htdocs/admin/edit_election.html
steve/trunk/pysteve/www/htdocs/css/steve_interactive.css
steve/trunk/pysteve/www/htdocs/js/steve_rest.js
Modified: steve/trunk/pysteve/lib/election.py
URL:
http://svn.apache.org/viewvc/steve/trunk/pysteve/lib/election.py?rev=1668848&r1=1668847&r2=1668848&view=diff
==============================================================================
--- steve/trunk/pysteve/lib/election.py (original)
+++ steve/trunk/pysteve/lib/election.py Tue Mar 24 11:36:26 2015
@@ -69,10 +69,13 @@ def getIssue(electionID, issueID):
issuepath = os.path.join(homedir, "issues", electionID, issueID) + ".json"
issuedata = None
if os.path.isfile(issuepath):
+ ihash = ""
with open(issuepath, "r") as f:
data = f.read()
+ ihash = hashlib.sha224(data).hexdigest()
f.close()
issuedata = json.loads(data)
+ issuedata['hash'] = ihash
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)
@@ -144,6 +147,15 @@ def vote(electionID, issueID, voterID, v
else:
raise Exception("No such election")
+def getVotes(electionID, issueID):
+ issuepath = os.path.join(homedir, "issues", electionID, issueID) +
".json.votes"
+ if os.path.isfile(issuepath):
+ with open(issuepath, "r") as f:
+ votes = json.loads(f.read())
+ f.close()
+ return votes
+ else:
+ return {}
def invalidate(issueData, vote):
"Tries to invalidate a vote, returns why if succeeded, None otherwise"
@@ -316,4 +328,18 @@ def stv(candidates, votes, numseats, shu
winnernames.append(candidates[i]['name'])
# Return the data
- return winners, winnernames, debug
\ No newline at end of file
+ return winners, winnernames, debug
+
+def getHash(electionID):
+ basedata = getBasedata(electionID)
+ issues = listIssues(electionID)
+ ihash = ""
+ output = []
+ for issue in issues:
+ issuedata = getIssue(electionID, issue)
+ votes = getVotes(electionID, issue)
+ ihash += issuedata['hash']
+ output.append("Issue #%s: %s\n- Checksum: %s\n- Votes cast: %u\n" %
(issue, issuedata['title'], issuedata['hash'], len(votes)))
+ tothash = hashlib.sha224(ihash).hexdigest()
+ output.insert(0, ("The following data shows the state of the election data
on disk. If any of these checksums change, especially the main checksum, then
the election has been edited (rigged?) after invites were sent out.\n\nMain
Election Checksum : %s\n\n" % tothash))
+ return tothash, "\n".join(output)
Modified: steve/trunk/pysteve/www/cgi-bin/rest_admin.py
URL:
http://svn.apache.org/viewvc/steve/trunk/pysteve/www/cgi-bin/rest_admin.py?rev=1668848&r1=1668847&r2=1668848&view=diff
==============================================================================
--- steve/trunk/pysteve/www/cgi-bin/rest_admin.py (original)
+++ steve/trunk/pysteve/www/cgi-bin/rest_admin.py Tue Mar 24 11:36:26 2015
@@ -411,6 +411,20 @@ else:
else:
response.respond(404, {'message': 'No such election or
issue'})
+ # Send issue hash to monitors
+ elif action == "debug" and electionID:
+ if election.exists(electionID):
+ basedata = election.getBasedata(electionID)
+ if karma >= 4 or ('owner' in basedata and basedata['owner'] ==
whoami):
+ ehash, debug = election.getHash(electionID)
+ for email in basedata['monitors']:
+ voter.email(email, "Monitoring update for election
#%s" % electionID, debug)
+ response.respond(200, {'message': "Debug sent to
monitors", 'hash': ehash, 'debug': debug})
+ else:
+ response.respond(403, {'message': "You do not have karma
to do this"})
+ else:
+ response.respond(404, {'message': 'No such election'})
+
# Get a temp voter ID for peeking
elif action == "temp" and electionID:
if electionID and election.exists(electionID):
@@ -499,6 +513,9 @@ else:
if reopen:
response.respond(200, {'message': "Election
reopened"})
else:
+ ehash, debug = election.getHash(electionID)
+ for email in basedata['monitors']:
+ voter.email(email, "Monitoring update for
election #%s: Election closed!" % electionID, debug)
response.respond(200, {'message': "Election
closed"})
except Exception as err:
response.respond(500, {'message': "Could not close
election: %s" % err})
Modified: steve/trunk/pysteve/www/htdocs/admin/edit_election.html
URL:
http://svn.apache.org/viewvc/steve/trunk/pysteve/www/htdocs/admin/edit_election.html?rev=1668848&r1=1668847&r2=1668848&view=diff
==============================================================================
--- steve/trunk/pysteve/www/htdocs/admin/edit_election.html (original)
+++ steve/trunk/pysteve/www/htdocs/admin/edit_election.html Tue Mar 24 11:36:26
2015
@@ -25,37 +25,43 @@
<img style="vertical-align: middle;"
src="/images/icon_invite.png"/>
Invite people
</a>
-
+
<a
href="javascript:void(location.href='add_issue.html'+document.location.search);"
class="btn-green" title="Click to add an issue to this election">
<img style="vertical-align: middle;" src="/images/icon_add.png"/>
Add an issue
</a>
-
+
<a id="closea"
href="javascript:void(location.href='close.html'+document.location.search);"
class="btn-red" title="Click to close this election, preventing
further voting">
<img style="vertical-align: middle;"
src="/images/icon_close.png"/>
<span id="closex">Close election</span>
</a>
-
+
<a
href="javascript:void(location.href='edit_basedata.html'+document.location.search);"
class="btn" title="Edit base data (title etc)">
<img style="vertical-align: middle;" src="/images/icon_edit.png"/>
- Edit election base data
+ Edit base data
</a>
-
+
<a href="javascript:void(peekAtElection());"
class="btn-purple" title="Take a sneek peek at this election as
viewed by voters">
<img style="vertical-align: middle;" src="/images/icon_view.png"/>
View election
</a>
-
+
<a
href="javascript:void(location.href='tally.html'+document.location.search);"
class="btn-black" title="Do a preliminary tally of all votes">
<img style="vertical-align: middle;" src="/images/icon_view.png"/>
Tally votes
</a>
+
+ <a href="javascript:void(primeMonitors());"
+ class="btn-orange" title="Sends the election checksum to monitors.
Use this right before you invite people to the election.">
+ <img style="vertical-align: middle;"
src="/images/icon_invite.png"/>
+ Cue monitors
+ </a>
<br/>
</fieldset>
<form>
Modified: steve/trunk/pysteve/www/htdocs/css/steve_interactive.css
URL:
http://svn.apache.org/viewvc/steve/trunk/pysteve/www/htdocs/css/steve_interactive.css?rev=1668848&r1=1668847&r2=1668848&view=diff
==============================================================================
--- steve/trunk/pysteve/www/htdocs/css/steve_interactive.css (original)
+++ steve/trunk/pysteve/www/htdocs/css/steve_interactive.css Tue Mar 24
11:36:26 2015
@@ -78,6 +78,28 @@ p {
transition: 0.3s ease;
}
+.btn-orange {
+ background: #C17E3F !important;
+ border: #C18E3F solid 1px;
+ border-radius: 3px;
+ color: #fff !important;
+ display: inline-block;
+ font-weight: bold;
+ font-size: 14px;
+ padding: 4px 8px;
+ text-decoration: none;
+ text-align: center;
+ min-width: 30px;
+ position: relative;
+ transition: color .1s ease;
+ cursor: pointer;
+ margin-left: 10px;
+}
+.btn-orange:hover {
+ background: #D19E3F !important;
+ transition: 0.3s ease;
+}
+
.btn-black {
background: #888888 !important;
border: #aaaaaa solid 1px;
Modified: steve/trunk/pysteve/www/htdocs/js/steve_rest.js
URL:
http://svn.apache.org/viewvc/steve/trunk/pysteve/www/htdocs/js/steve_rest.js?rev=1668848&r1=1668847&r2=1668848&view=diff
==============================================================================
--- steve/trunk/pysteve/www/htdocs/js/steve_rest.js (original)
+++ steve/trunk/pysteve/www/htdocs/js/steve_rest.js Tue Mar 24 11:36:26 2015
@@ -432,6 +432,7 @@ function renderEditBasedata(code, respon
obj.appendChild(keyvaluepair("id", "Election ID:", "text",
election, true))
obj.appendChild(keyvaluepair("type", "Open election?:", "text",
response.base_data.open, true))
obj.appendChild(keyvaluepair("etitle", "Election title:",
"text", response.base_data.title))
+ obj.appendChild(keyvaluepair("etitle", "Monitors:", "text",
response.base_data.monitors.join(", "), true))
obj.appendChild(document.createElement('hr'))
//obj.appendChild(keyvaluepair("description",
"Description/statement:", "textarea", edit_i.description))
@@ -939,4 +940,22 @@ function displayIssueYNA(code, response,
obj.appendChild(outer)
}
+}
+
+
+
+function primeMonitorsCallback(code, response, election) {
+ alert(response.message)
+}
+function primeMonitors() {
+ var l = document.location.search.substr(1).split('/');
+ var election = l[0]
+
+
+ postREST("/steve/admin/debug/" + election, {
+
+ },
+ undefined,
+ primeMonitorsCallback,
+ election)
}
\ No newline at end of file