Implement pre-poll voting

This commit is contained in:
RunasSudo 2017-12-11 17:04:57 +10:30
parent 2d3e474725
commit ffe9af3bd9
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
5 changed files with 138 additions and 25 deletions

View File

@ -47,10 +47,11 @@ class Ballot(EmbeddedObject):
return Ballot(encrypted_answers=encrypted_answers_deaudit, election_id=self.election_id, election_hash=self.election_hash)
class Vote(EmbeddedObject):
_ver = StringField(default='0.4')
_ver = StringField(default='0.5')
ballot = EmbeddedObjectField()
cast_at = DateTimeField()
comment = StringField()
cast_ip = StringField(is_protected=True)
cast_fingerprint = BlobField(is_protected=True)

View File

@ -0,0 +1,41 @@
{% extends templates['booth/base.html'] %}
{#
Eos - Verifiable elections
Copyright © 2017 RunasSudo (Yingtong Li)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% block content %}
<p>Your vote has <span class="superem">not</span> yet been cast.</p>
<div class="ui negative message">
<p>Your vote has <span class="superem">not</span> yet been cast. Please follow the instructions to continue.</p>
</div>
<p>If you have not already done so, please make a note of your ballot fingerprint, <span class="hash">{{ eosjs.eos.core.hashing.__all__.SHA256().update_obj(ballot).hash_as_b64() }}</span>. Please retain a copy of your ballot fingerprint – you can use it to verify that your vote has been counted correctly. You may <a href="#" onclick="window.print();return false;">print this page</a> as a receipt if you wish.</p>
<p>To continue, copy and paste the ballot below and provide it to the election administrator.</p>
<div class="ui form">
{# For some reason nunjucks doesn't like calling this the normal way #}
{% set ballot_deaudit = ballot.deaudit() %}
<textarea>{{ ballot_deaudit.to_json(ballot_deaudit.serialise_and_wrap(ballot_deaudit)) }}</textarea>
</div>
{% endblock %}
{% block buttons %}
<button class="ui left floated button" onclick="prevTemplate();">Back</a>
{% endblock %}

View File

@ -0,0 +1,45 @@
{% extends templates['booth/base.html'] %}
{#
Eos - Verifiable elections
Copyright © 2017 RunasSudo (Yingtong Li)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% block content %}
<p>Your vote has <span class="superem">not</span> yet been cast. Your selections are shown below. Please review your selections and ensure you are happy with them before continuing.</p>
<div class="ui negative message">
<p>Your vote has <span class="superem">not</span> yet been cast. Please follow the instructions to continue.</p>
</div>
{% for question in election.questions.impl %}
<h2>{{ loop.index }}. {{ question.prompt }}</h2>
{% include templates[selection_model_view_map[election.questions.__getitem__(loop.index0)._name]["selections_review"]] %}
{% endfor %}
<p>If you are happy with your selections, then make a note of your ballot fingerprint, <span class="hash">{{ eosjs.eos.core.hashing.__all__.SHA256().update_obj(ballot).hash_as_b64() }}</span>.</p>
<p>Click ‘Continue’, and you will be able to copy your pre-poll ballot to provide to the election administrator.</p>
{% endblock %}
{% block buttons %}
<button class="ui left floated button" onclick="prevTemplate();">Back</button>
<button class="ui right floated primary button" onclick="nextTemplate(2);">Continue</button>
{% endblock %}
{% block after %}
<div style="clear: both; margin-bottom: 1em;"></div>
<p><small>If you would like to audit your ballot, <a href="#" onclick="nextTemplate(1);">click here</a>. Auditing your ballot is an <b>optional</b> step you can take to check that your vote has been prepared correctly. You do not need to audit your ballot in order to cast a vote.</small></p>
{% endblock %}

View File

@ -214,30 +214,54 @@
}
});
templates['booth/encrypt.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/review.html', {ballot: booth.ballot});
}
});
templates['booth/review.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/audit.html', {ballot: booth.ballot});
}
});
templates['booth/audit.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/cast.html', {ballot: booth.ballot});
}
});
templates['booth/cast.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/complete.html', {voter: booth.voter, vote: booth.vote});
}
});
templates['booth/complete.html'] = null;
if (location.search.indexOf('?prepoll') >= 0) {
// Pre-poll
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/review_prepoll.html', {ballot: booth.ballot});
}
});
templates['booth/review_prepoll.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/audit.html', {ballot: booth.ballot});
}
});
templates['booth/audit.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/cast_prepoll.html', {ballot: booth.ballot});
}
});
templates['booth/cast_prepoll.html'] = null;
} else {
// Real voting booth
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/review.html', {ballot: booth.ballot});
}
});
templates['booth/review.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/audit.html', {ballot: booth.ballot});
}
});
templates['booth/audit.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/cast.html', {ballot: booth.ballot});
}
});
templates['booth/cast.html'] = null;
boothTasks.append({
activate: function(fromLeft) {
showTemplate('booth/complete.html', {voter: booth.voter, vote: booth.vote});
}
});
templates['booth/complete.html'] = null;
}
// === END BOOTH TASKS ===

View File

@ -76,6 +76,8 @@
<h2>Voting booth</h2>
<p>Voting in this {{ election.kind }} has not yet begun. If you would like to preview the voting booth, <a href="{{ url_for('election_booth', election_id=election._id) }}">click here</a>. Note that you will not be able to cast any ballots until voting opens.</p>
<p><small>If you are a registered pre-poll voter, you may access the pre-poll voting booth <a href="{{ url_for('election_booth', election_id=election._id) }}?prepoll">here</a>.</small></p>
{% elif election.workflow.get_task('eos.base.workflow.TaskCloseVoting').status == Status.EXITED %}
<h2>Voting booth</h2>