diff --git a/eos/base/election.py b/eos/base/election.py
index 321f823..2f8cff6 100644
--- a/eos/base/election.py
+++ b/eos/base/election.py
@@ -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)
diff --git a/eosweb/core/static/nunjucks/booth/cast_prepoll.html b/eosweb/core/static/nunjucks/booth/cast_prepoll.html
new file mode 100644
index 0000000..269b2a2
--- /dev/null
+++ b/eosweb/core/static/nunjucks/booth/cast_prepoll.html
@@ -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 .
+#}
+
+{% block content %}
+
Your vote has not yet been cast.
+
+
+
Your vote has not yet been cast. Please follow the instructions to continue.
+
+
+ If you have not already done so, please make a note of your ballot fingerprint, {{ eosjs.eos.core.hashing.__all__.SHA256().update_obj(ballot).hash_as_b64() }} . Please retain a copy of your ballot fingerprint – you can use it to verify that your vote has been counted correctly. You may print this page as a receipt if you wish.
+
+ To continue, copy and paste the ballot below and provide it to the election administrator.
+
+
+ {# For some reason nunjucks doesn't like calling this the normal way #}
+ {% set ballot_deaudit = ballot.deaudit() %}
+
+
+{% endblock %}
+
+{% block buttons %}
+ Back
+{% endblock %}
diff --git a/eosweb/core/static/nunjucks/booth/review_prepoll.html b/eosweb/core/static/nunjucks/booth/review_prepoll.html
new file mode 100644
index 0000000..f2879d7
--- /dev/null
+++ b/eosweb/core/static/nunjucks/booth/review_prepoll.html
@@ -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 .
+#}
+
+{% block content %}
+ Your vote has not yet been cast. Your selections are shown below. Please review your selections and ensure you are happy with them before continuing.
+
+
+
Your vote has not yet been cast. Please follow the instructions to continue.
+
+
+ {% for question in election.questions.impl %}
+ {{ loop.index }}. {{ question.prompt }}
+ {% include templates[selection_model_view_map[election.questions.__getitem__(loop.index0)._name]["selections_review"]] %}
+ {% endfor %}
+
+ If you are happy with your selections, then make a note of your ballot fingerprint, {{ eosjs.eos.core.hashing.__all__.SHA256().update_obj(ballot).hash_as_b64() }} .
+ Click ‘Continue’, and you will be able to copy your pre-poll ballot to provide to the election administrator.
+{% endblock %}
+
+{% block buttons %}
+ Back
+ Continue
+{% endblock %}
+
+{% block after %}
+
+ If you would like to audit your ballot, click here . Auditing your ballot is an optional 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.
+{% endblock %}
diff --git a/eosweb/core/templates/election/view/booth.html b/eosweb/core/templates/election/view/booth.html
index 6fa0436..9bf85e7 100644
--- a/eosweb/core/templates/election/view/booth.html
+++ b/eosweb/core/templates/election/view/booth.html
@@ -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 ===
diff --git a/eosweb/core/templates/election/view/view.html b/eosweb/core/templates/election/view/view.html
index f6483b5..1d16fac 100644
--- a/eosweb/core/templates/election/view/view.html
+++ b/eosweb/core/templates/election/view/view.html
@@ -76,6 +76,8 @@
Voting booth
Voting in this {{ election.kind }} has not yet begun. If you would like to preview the voting booth, click here . Note that you will not be able to cast any ballots until voting opens.
+
+ If you are a registered pre-poll voter, you may access the pre-poll voting booth here .
{% elif election.workflow.get_task('eos.base.workflow.TaskCloseVoting').status == Status.EXITED %}
Voting booth