From ef0ce78087f998aa3c969ac4cac0a2c6cfedd64a Mon Sep 17 00:00:00 2001 From: Ben Adida <ben@adida.net> Date: Wed, 17 Nov 2010 05:47:36 -0800 Subject: [PATCH] reworked the last 'combine decryptions' step and added ability to customize email message to voters --- helios/forms.py | 5 ++ helios/templates/combine_decryptions.html | 36 ++++++++++ helios/templates/election_view.html | 2 +- helios/templates/email/result_body.txt | 15 +++-- helios/templates/email/result_subject.txt | 2 +- helios/views.py | 80 +++++++++++++++++------ 6 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 helios/templates/combine_decryptions.html diff --git a/helios/forms.py b/helios/forms.py index 21cff19..c15e5e0 100644 --- a/helios/forms.py +++ b/helios/forms.py @@ -27,3 +27,8 @@ class EmailVotersForm(forms.Form): body = forms.CharField(max_length=2000, widget=forms.Textarea) suppress_election_links = forms.BooleanField(label = "Suppress links?", required=False) send_to = forms.ChoiceField(label="Send To", choices= [('all', 'all voters'), ('voted', 'voters who have cast a ballot'), ('not-voted', 'voters who have not yet cast a ballot')]) + +class TallyNotificationEmailForm(forms.Form): + subject = forms.CharField(max_length=80) + body = forms.CharField(max_length=2000, widget=forms.Textarea) + send_to = forms.ChoiceField(label="Send To", choices= [('all', 'all voters'), ('voted', 'only voters who cast a ballot')]) diff --git a/helios/templates/combine_decryptions.html b/helios/templates/combine_decryptions.html new file mode 100644 index 0000000..efb9f85 --- /dev/null +++ b/helios/templates/combine_decryptions.html @@ -0,0 +1,36 @@ +{% extends TEMPLATE_BASE %} + +{% block title %}Combine Decryptions and Release Tally — {{election.name}}{% endblock %} +{% block content %} + <h2 class="title">{{election.name}} — Combine Decryptions and Release Tally <span style="font-size:0.7em;">[<a href="{% url helios.views.one_election_view election.uuid %}">cancel</a>]</span></h2> + + <p> + The tally for this election will now be computed and displayed on the main election page. + </p> + + <p> +In addition, voters will be notified that of the availability of the tally. The default message reads: +</p> + +<pre style="margin:10px; border: 1px solid #888; padding:20px"> +Subject: {{default_subject}} + +{{default_body|safe}} +</pre> + +<p> +You may tweak the subject and add a custom message using the form below. +</p> + + <form class="prettyform" action="" method="POST" id="email_form"> + <input type="hidden" name="csrf_token" value="{{csrf_token}}" /> + <table class="pretty"> + {{email_form.as_table}} + </table> + <div> + <label for=""> </label><input type="submit" value="Release Tally and Notify Voters" id="send_button" /> + </div> + </form> + + +{% endblock %} diff --git a/helios/templates/election_view.html b/helios/templates/election_view.html index aa0563e..6434fe6 100644 --- a/helios/templates/election_view.html +++ b/helios/templates/election_view.html @@ -109,7 +109,7 @@ trustees will be asked to provide their share of the decryption. {% else %} {% if election.ready_for_decryption_combination %} -<a onclick="return confirm('Ready for the tally? Voters will be notified immediately.');" href="{% url helios.views.combine_decryptions election.uuid %}">combine trustee decryptions and release results</a><br /> +<a href="{% url helios.views.combine_decryptions election.uuid %}">combine trustee decryptions and release results</a><br /> The decryption shares from the trustees are combined and the tally is decrypted.<br /> Once you do this, the tally will be immediately available for all to see, and all voters will be notified that the tally is ready. diff --git a/helios/templates/email/result_body.txt b/helios/templates/email/result_body.txt index c578bfe..2c1d7f0 100644 --- a/helios/templates/email/result_body.txt +++ b/helios/templates/email/result_body.txt @@ -1,12 +1,19 @@ Dear {{voter.name}}, -The tally has been computed for +The tally for {{election.name}} has been computed and released: - {{voter.election.name}} + {{election_url}} -Check out the results at: +{{custom_message|safe}} - {{election_url}} +{% if voter.vote_hash %}You smart ballot tracker in this election was: + + {{voter.vote_hash}} +If you believe this tracker to be in error, please contact us. +{% else %} +It appears you did not cast a vote in this election. +Please contact us if you believe you did. +{% endif %} -- Helios diff --git a/helios/templates/email/result_subject.txt b/helios/templates/email/result_subject.txt index 2e1baa9..a7929f1 100644 --- a/helios/templates/email/result_subject.txt +++ b/helios/templates/email/result_subject.txt @@ -1 +1 @@ -Tally computed for {{voter.election.name}} +{{custom_subject|safe}} diff --git a/helios/views.py b/helios/views.py index 56440fd..6e2e5d3 100644 --- a/helios/views.py +++ b/helios/views.py @@ -851,26 +851,68 @@ def trustee_upload_decryption(request, election, trustee_uuid): @election_admin(frozen=True) def combine_decryptions(request, election): - election.combine_decryptions() - election.save() + """ + combine trustee decryptions + """ + + election_url = get_election_url(election) + + default_subject = 'Tally released for %s' % election.name + default_body = render_template_raw(None, 'email/result_body.txt', { + 'election' : election, + 'election_url' : election_url, + 'custom_subject' : default_subject, + 'custom_message': '<YOUR MESSAGE HERE>', + 'voter': {'vote_hash' : '<SMART_TRACKER>', + 'name': '<VOTER_NAME>'} + }) + + if request.method == "GET": + email_form = forms.TallyNotificationEmailForm(initial= {'subject': default_subject}) + else: + check_csrf(request) + + email_form = forms.TallyNotificationEmailForm(request.POST) + + if email_form.is_valid(): + election.combine_decryptions() + election.save() + + # notify voters! + extra_vars = { + 'custom_subject' : email_form.cleaned_data['subject'], + 'custom_message' : email_form.cleaned_data['body'], + 'election_url' : election_url, + 'election' : election + } + + # exclude those who have not voted + if email_form.cleaned_data['send_to'] == 'voted': + voter_constraints_exclude = {'vote_hash' : None} + else: + voter_constraints_exclude = {} + + # full-length email + tasks.voters_email.delay(election_id = election.id, + subject_template = 'email/result_subject.txt', + body_template = 'email/result_body.txt', + extra_vars = extra_vars, + voter_constraints_exclude = voter_constraints_exclude) + + # rapid short-message notification + # this inherently only applies to those who have voted (for the most part) + tasks.voters_notify.delay(election_id = election.id, + notification_template = 'notification/result.txt', + extra_vars = extra_vars) + + return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid])) + + # if just viewing the form or the form is not valid + return render_template(request, 'combine_decryptions', {'election': election, + 'email_form' : email_form, + 'default_subject': default_subject, + 'default_body': default_body}) - # notify voters! - extra_vars = { - 'election_url' : get_election_url(election) - } - - # full-length email - tasks.voters_email.delay(election_id = election.id, - subject_template = 'email/result_subject.txt', - body_template = 'email/result_body.txt', - extra_vars = extra_vars) - - # rapid short-message notification - tasks.voters_notify.delay(election_id = election.id, - notification_template = 'notification/result.txt', - extra_vars = extra_vars) - - return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid])) @election_admin(frozen=True) def one_election_set_result_and_proof(request, election): -- GitLab