From 744f92b0650e3bcdd57109254aac2cb09e532521 Mon Sep 17 00:00:00 2001
From: Ben Adida <ben@adida.net>
Date: Sun, 3 Jul 2011 15:51:02 -0700
Subject: [PATCH] fixed emailing to be consistent, with templates

---
 auth/templates/login_box.html                 |  10 --
 auth/templates/perms_why.html                 |  21 ++++
 auth/views.py                                 |   5 +-
 helios/forms.py                               |   1 -
 helios/templates/combine_decryptions.html     |  24 +---
 .../{vote_body_nolinks.txt => info_body.txt}  |   2 +
 helios/templates/email/info_subject.txt       |   1 +
 helios/templates/email/result_subject.txt     |   2 +-
 helios/templates/email/vote_body.txt          |   2 +-
 helios/templates/email/vote_subject.txt       |   2 +-
 helios/templates/voters_email.html            |  40 ++++---
 helios/tests.py                               |  10 +-
 helios/views.py                               | 107 +++++++-----------
 13 files changed, 106 insertions(+), 121 deletions(-)
 create mode 100644 auth/templates/perms_why.html
 rename helios/templates/email/{vote_body_nolinks.txt => info_body.txt} (63%)
 create mode 100644 helios/templates/email/info_subject.txt

diff --git a/auth/templates/login_box.html b/auth/templates/login_box.html
index 3918f27..4ed3f81 100644
--- a/auth/templates/login_box.html
+++ b/auth/templates/login_box.html
@@ -3,16 +3,6 @@
 {% else %}
 {% for auth_system in enabled_auth_systems %}
 {% ifequal auth_system "password" %}
-<form method="post" action="{% url auth.auth_systems.password.password_login_view %}">
-<input type="hidden" name="election_uuid" value="{{election.uuid}}" />
-<input type="hidden" name="csrf_token" value="{{csrf_token}}" />
-<input type="hidden" name="return_url" value="{{return_url}}" />
-<table>
-    {{form.as_table}}
-</table>
-<input type="submit" value="log in" />
-<a style="font-size: 0.8em;" href="{% url auth.auth_systems.password.password_forgotten_view %}?return_url={{return_url|urlencode}}">forgot password?</a>
-</form>
 {% else %}
 <p>
     <a href="{{SECURE_URL_HOST}}{% url auth.views.start system_name=auth_system %}?return_url={{return_url}}" style="font-size: 1.4em;">
diff --git a/auth/templates/perms_why.html b/auth/templates/perms_why.html
new file mode 100644
index 0000000..179d103
--- /dev/null
+++ b/auth/templates/perms_why.html
@@ -0,0 +1,21 @@
+{% extends TEMPLATE_BASE %}
+
+{% block content %}
+<h1>Why we need your information</h1>
+
+<p>
+It looks like you declined to grant us permission to access your
+information. We understand and value your privacy. We ask for this
+information so we can contact you with your voting tracking number and
+when an election in which you participated has been tallied. We
+promise not to use this information for any other purpose. Without
+this information, we unfortunately cannot help you vote.
+</p>
+
+<form method="POST" action="">
+<input type="hidden" value="{{csrf_token}}" />
+<input type="submit" value="OK, I understand, let's do this login thing." /><br /><br />
+<a href="http://google.com">nope, get me out of here</a>.
+</form>
+
+{% endblock %}
diff --git a/auth/views.py b/auth/views.py
index 2469f9f..fda1dfc 100644
--- a/auth/views.py
+++ b/auth/views.py
@@ -40,13 +40,12 @@ def index(request):
   if auth.DEFAULT_AUTH_SYSTEM:
     default_auth_system_obj = AUTH_SYSTEMS[auth.DEFAULT_AUTH_SYSTEM]
 
-  form = password.LoginForm()
+  #form = password.LoginForm()
 
   return render_template(request,'index', {'return_url' : request.GET.get('return_url', '/'),
                                            'enabled_auth_systems' : auth.ENABLED_AUTH_SYSTEMS,
                                            'default_auth_system': auth.DEFAULT_AUTH_SYSTEM,
-                                           'default_auth_system_obj': default_auth_system_obj,
-                                           'form' : form})
+                                           'default_auth_system_obj': default_auth_system_obj})
 
 def login_box_raw(request, return_url='/', auth_systems = None):
   """
diff --git a/helios/forms.py b/helios/forms.py
index 4fcf514..acc7a58 100644
--- a/helios/forms.py
+++ b/helios/forms.py
@@ -29,7 +29,6 @@ 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')])
 
 class TallyNotificationEmailForm(forms.Form):
diff --git a/helios/templates/combine_decryptions.html b/helios/templates/combine_decryptions.html
index 35bbe72..e83e1f8 100644
--- a/helios/templates/combine_decryptions.html
+++ b/helios/templates/combine_decryptions.html
@@ -5,28 +5,12 @@
   <h2 class="title">{{election.name}} &mdash; 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 be released, and voters will be notified that of the availability of the tally.<br />The default message reads:
-</p>
+    You are about to release the tally for this election
+  </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">
+  <form method="POST" action="">
     <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
-    <table class="pretty">
-     {{email_form.as_table}}
-     </table>
-  <div>
-  <label for="">&nbsp;</label><input type="submit" value="Release Tally and Notify Voters" id="send_button" />
-  </div>
+    <input type="submit" value="release the tally!" />
   </form>
-  
 
 {% endblock %}
diff --git a/helios/templates/email/vote_body_nolinks.txt b/helios/templates/email/info_body.txt
similarity index 63%
rename from helios/templates/email/vote_body_nolinks.txt
rename to helios/templates/email/info_body.txt
index 43500ac..8a606ad 100644
--- a/helios/templates/email/vote_body_nolinks.txt
+++ b/helios/templates/email/info_body.txt
@@ -2,5 +2,7 @@ Dear {{voter.name}},
 
 {{custom_message|safe}}
 
+Election Link: {{election_url}}
+
 --
 Helios
diff --git a/helios/templates/email/info_subject.txt b/helios/templates/email/info_subject.txt
new file mode 100644
index 0000000..6b43baf
--- /dev/null
+++ b/helios/templates/email/info_subject.txt
@@ -0,0 +1 @@
+Additional Information: {{custom_subject|safe}}
diff --git a/helios/templates/email/result_subject.txt b/helios/templates/email/result_subject.txt
index a7929f1..c7ac9f4 100644
--- a/helios/templates/email/result_subject.txt
+++ b/helios/templates/email/result_subject.txt
@@ -1 +1 @@
-{{custom_subject|safe}}
+Tally Released - {{custom_subject|safe}}
diff --git a/helios/templates/email/vote_body.txt b/helios/templates/email/vote_body.txt
index b0c6875..c6f4422 100644
--- a/helios/templates/email/vote_body.txt
+++ b/helios/templates/email/vote_body.txt
@@ -2,7 +2,7 @@ Dear {{voter.name}},
 
 {{custom_message|safe}}
 
-Election URL:  {{election_url}}
+Election URL:  {{election_vote_url}}
 Election Fingerprint:  {{voter.election.hash}}
 {% ifequal voter.voter_type "password" %}
 Your voter ID: {{voter.voter_login_id}}
diff --git a/helios/templates/email/vote_subject.txt b/helios/templates/email/vote_subject.txt
index a7929f1..e048737 100644
--- a/helios/templates/email/vote_subject.txt
+++ b/helios/templates/email/vote_subject.txt
@@ -1 +1 @@
-{{custom_subject|safe}}
+Vote: {{custom_subject|safe}}
diff --git a/helios/templates/voters_email.html b/helios/templates/voters_email.html
index cb7a26e..1c6155b 100644
--- a/helios/templates/voters_email.html
+++ b/helios/templates/voters_email.html
@@ -1,17 +1,15 @@
 {% extends TEMPLATE_BASE %}
 
-{% block title %}Email Voters for {{election.name}}{% endblock %}
+{% block title %}Contact Voters for {{election.name}}{% endblock %}
 {% block content %}
 <script>
-var BATCH_SIZE = 25;
-
 var voter_id = null;
 {% if voter %}
 voter_id = '{{voter.voter_id}}';
 {% endif %}
 </script>
 
-  <h2 class="title">{{election.name}} &mdash; Email Voters <span style="font-size:0.7em;">[<a href="{% url helios.views.one_election_view election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Contact Voters <span style="font-size:0.7em;">[<a href="{% url helios.views.one_election_view election.uuid %}">back to election</a>]</span></h2>
 
 {% if voter %}  
   <p>
@@ -19,21 +17,31 @@ voter_id = '{{voter.voter_id}}';
   </p>
 {% endif %}
 
-  <p>
-    The email will <b><u>automatically</u></b> include a "Dear Voter" line, as well as a footer including<br />
-    the election URL, the login information, and a simple email signature.<br />
-    No need to include these in the body of your email below.
-  </p>
-  <p>
-    If the voter has already voted, the message will include a reminder of their smart ballot tracker.<br />
-  </p>
+<p>
+<b>Templates</b>:
+
+{% for template_option in templates %}
+{% if template_option.0 == template %}
+<b>{{template_option.1}}</b>
+{% else %}
+<a href="?template={{template_option.0}}">{{template_option.1}}</a>
+{% endif %}
+&nbsp;&nbsp;&nbsp;
+{% endfor %}
+
+<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>
 
-  <p>
-    The subject of the email is set by default below, but can be changed to your liking.
-  </p>
-  
   <form class="prettyform" action="" method="POST" id="email_form">
     <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
+    <input type="hidden" name="template" value="{{template}}" />
     <table class="pretty">
      {{email_form.as_table}}
      </table>
diff --git a/helios/tests.py b/helios/tests.py
index 7dcfe56..acce775 100644
--- a/helios/tests.py
+++ b/helios/tests.py
@@ -547,7 +547,7 @@ class ElectionBlackboxTests(WebTest):
         self.assertEquals(num_messages_after - num_messages_before, NUM_VOTERS)
 
         email_message = mail.outbox[num_messages_before]
-        self.assertEquals(email_message.subject, "your password")
+        assert "your password" in email_message.subject, "bad subject in email"
 
         # get the username and password
         username = re.search('voter ID: (.*)', email_message.body).group(1)
@@ -655,11 +655,11 @@ class ElectionBlackboxTests(WebTest):
         # combine decryptions
         response = self.client.post("/helios/elections/%s/combine_decryptions" % election_id, {
                 "csrf_token" : self.client.session['csrf_token'],
-                "subject" : "tally subject",
-                "body" : "tally body",
-                "send_to" : "all"
                 })
-        self.assertRedirects(response, "/helios/elections/%s/view" % election_id)
+
+        # after tallying, we now are supposed to see the email screen
+        # with the right template value of 'result'
+        self.assertRedirects(response, "/helios/elections/%s/voters/email?template=result" % election_id)
 
         # check that tally matches
         response = self.client.get("/helios/elections/%s/result" % election_id)
diff --git a/helios/views.py b/helios/views.py
index 4e551e6..5f7e7a5 100644
--- a/helios/views.py
+++ b/helios/views.py
@@ -1043,65 +1043,16 @@ def combine_decryptions(request, election):
 
   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': '&lt;YOUR MESSAGE HERE&gt;',
-      'voter': {'vote_hash' : '<SMART_TRACKER>',
-                'name': '<VOTER_NAME>'}
-      })
-
-  if request.method == "GET":
-    email_form = forms.TallyNotificationEmailForm(initial= {'subject': default_subject})
-  else:
+  if request.method == "POST":
     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
-        }
-
-      # if the user opted for notifying no one, then we skip this step
-      if email_form.cleaned_data['send_to'] != 'none':
-        # 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)
-      # and this is not configurable, this is ALWAYS sent
-      tasks.voters_notify.delay(election_id = election.id,
-                                notification_template = 'notification/result.txt',
-                                extra_vars = extra_vars)
+    election.combine_decryptions()
+    election.save()
 
-      return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid]))
+    return HttpResponseRedirect("%s?%s" % (reverse(voters_email, args=[election.uuid]), urllib.urlencode({'template': 'result'})))
 
   # 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})
-
+  return render_template(request, 'combine_decryptions', {'election': election})
 
 @election_admin(frozen=True)
 def one_election_set_result_and_proof(request, election):
@@ -1270,31 +1221,55 @@ def voters_upload_cancel(request, election):
 def voters_email(request, election):
   if not helios.VOTERS_EMAIL:
     return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid]))
-  
+  TEMPLATES = [
+    ('vote', 'Time to Vote'),
+    ('info', 'Additional Info'),
+    ('result', 'Election Result')
+    ]
+
+  template = request.REQUEST.get('template', 'vote')
+  if not template in [t[0] for t in TEMPLATES]:
+    raise Exception("bad template")
+
   voter_id = request.REQUEST.get('voter_id', None)
   if voter_id:
     voter = Voter.get_by_election_and_voter_id(election, voter_id)
   else:
     voter = None
   
+  election_url = get_election_url(election)
+  election_vote_url = get_election_govote_url(election)
+
+  default_subject = render_template_raw(None, 'email/%s_subject.txt' % template, {
+      'custom_subject': "&lt;SUBJECT&gt;"
+})
+  default_body = render_template_raw(None, 'email/%s_body.txt' % template, {
+      'election' : election,
+      'election_url' : election_url,
+      'election_vote_url' : election_vote_url,
+      'custom_subject' : default_subject,
+      'custom_message': '&lt;YOUR MESSAGE HERE&gt;',
+      'voter': {'vote_hash' : '<SMART_TRACKER>',
+                'name': '<VOTER_NAME>',
+                'voter_type' : election.voter_set.all()[0].voter_type,
+                'election' : election}
+      })
+
   if request.method == "GET":
-    email_form = forms.EmailVotersForm(initial={'subject': 'Vote in %s' % election.name})
+    email_form = forms.EmailVotersForm()
   else:
     email_form = forms.EmailVotersForm(request.POST)
     
     if email_form.is_valid():
       
       # the client knows to submit only once with a specific voter_id
-      subject_template = 'email/vote_subject.txt'
-      body_template = 'email/vote_body.txt'
+      subject_template = 'email/%s_subject.txt' % template
+      body_template = 'email/%s_body.txt' % template
 
-      if email_form.cleaned_data['suppress_election_links']:
-        body_template = 'email/vote_body_nolinks.txt'
-      
       extra_vars = {
         'custom_subject' : email_form.cleaned_data['subject'],
         'custom_message' : email_form.cleaned_data['body'],
-        'election_url' : get_election_govote_url(election),
+        'election_url' : election_url,
         'election' : election
         }
         
@@ -1317,7 +1292,13 @@ def voters_email(request, election):
       # this batch process is all async, so we can return a nice note
       return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid]))
     
-  return render_template(request, "voters_email", {'email_form': email_form, 'election': election, 'voter': voter})    
+  return render_template(request, "voters_email", {
+      'email_form': email_form, 'election': election,
+      'voter': voter,
+      'default_subject': default_subject,
+      'default_body' : default_body,
+      'template' : template,
+      'templates' : TEMPLATES})    
 
 # Individual Voters
 @election_view()
-- 
GitLab