diff --git a/helios/forms.py b/helios/forms.py index de3f435c926dc11760e917961c03969f75c20ae3..21cff19c54965daf73600d2f969166688e99a5c8 100644 --- a/helios/forms.py +++ b/helios/forms.py @@ -25,4 +25,5 @@ class ElectionTimesForm(forms.Form): class EmailVotersForm(forms.Form): subject = forms.CharField(max_length=80) 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')]) diff --git a/helios/tasks.py b/helios/tasks.py index c0f189a21733f98f5629f3acb16b94553bb109e1..461150f96992ab226f202193b9f5cc444e53e0d2 100644 --- a/helios/tasks.py +++ b/helios/tasks.py @@ -36,9 +36,22 @@ def cast_vote_verify_and_store(cast_vote_id, status_update_message=None, **kwarg logger.error("Failed to verify and store %d" % cast_vote_id) @task() -def voters_email(election_id, subject_template, body_template, extra_vars={}): +def voters_email(election_id, subject_template, body_template, extra_vars={}, + voter_constraints_include=None, voter_constraints_exclude=None): + """ + voter_constraints_include are conditions on including voters + voter_constraints_exclude are conditions on excluding voters + """ election = Election.objects.get(id = election_id) - for voter in election.voter_set.all(): + + # select the right list of voters + voters = election.voter_set.all() + if voter_constraints_include: + voters = voters.filter(**voter_constraints_include) + if voter_constraints_exclude: + voters = voters.exclude(**voter_constraints_exclude) + + for voter in voters: single_voter_email.delay(voter.uuid, subject_template, body_template, extra_vars) @task() diff --git a/helios/templates/email/vote_body.txt b/helios/templates/email/vote_body.txt index 4e2afd3eb5b6f26b990247c4de4426d2ed346430..7672da0dc2c703c53b4f09580251deea950cd89c 100644 --- a/helios/templates/email/vote_body.txt +++ b/helios/templates/email/vote_body.txt @@ -10,7 +10,7 @@ Your password: {{voter.user.info.password}} {% else %} Log in with your {{voter.voter_type}} account. {% endifequal %}{% if voter.vote_hash %} -We have a vote recorded for you already, with smart tracker: +We have recorded your vote with smart tracker: {{voter.vote_hash}} diff --git a/helios/templates/email/vote_body_nolinks.txt b/helios/templates/email/vote_body_nolinks.txt new file mode 100644 index 0000000000000000000000000000000000000000..43500ac230ad509c7fd8e9c75d670ff427b9083e --- /dev/null +++ b/helios/templates/email/vote_body_nolinks.txt @@ -0,0 +1,6 @@ +Dear {{voter.name}}, + +{{custom_message|safe}} + +-- +Helios diff --git a/helios/views.py b/helios/views.py index b26b17132d3cabf0ae66c1f556d3764c43eefd2b..e486fa32ee4d2150ca6e9146bac6f787670dc0fb 100644 --- a/helios/views.py +++ b/helios/views.py @@ -943,7 +943,7 @@ def voters_email(request, election): voter = Voter.get_by_election_and_voter_id(election, voter_id) if request.method == "GET": - email_form = forms.EmailVotersForm({'subject': 'Vote in %s' % election.name, 'body':' '}) + email_form = forms.EmailVotersForm(initial={'subject': 'Vote in %s' % election.name}) else: email_form = forms.EmailVotersForm(request.POST) @@ -952,6 +952,9 @@ def voters_email(request, election): # the client knows to submit only once with a specific voter_id subject_template = 'email/vote_subject.txt' body_template = 'email/vote_body.txt' + + if email_form.cleaned_data['suppress_election_links']: + body_template = 'email/vote_body_nolinks.txt' extra_vars = { 'custom_subject' : email_form.cleaned_data['subject'], @@ -960,11 +963,21 @@ def voters_email(request, election): 'election' : election } + voter_constraints_include = None + voter_constraints_exclude = None + + # exclude those who have not voted + if email_form.cleaned_data['send_to'] == 'voted': + voter_constraints_exclude = {'vote_hash' : None} + + # include only those who have not voted + if email_form.cleaned_data['send_to'] == 'not-voted': + voter_constraints_include = {'vote_hash': None} if voter: tasks.single_voter_email.delay(voter_uuid = voter.uuid, subject_template = subject_template, body_template = body_template, extra_vars = extra_vars) else: - tasks.voters_email.delay(election_id = election.id, subject_template = subject_template, body_template = body_template, extra_vars = extra_vars) + tasks.voters_email.delay(election_id = election.id, subject_template = subject_template, body_template = body_template, extra_vars = extra_vars, voter_constraints_include = voter_constraints_include, voter_constraints_exclude = voter_constraints_exclude) # this batch process is all async, so we can return a nice note return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid]))