From f8af2a0fc7d07589fe8bb9f42452f474fa946c24 Mon Sep 17 00:00:00 2001 From: Ben Adida <ben@adida.net> Date: Sat, 6 Nov 2010 13:35:17 -0700 Subject: [PATCH] improved the CSV upload process to confirm what an upload looks like --- helios/election_urls.py | 1 + helios/models.py | 18 +++++++++++ helios/templates/voters_upload_confirm.html | 26 ++++++++++++++++ helios/views.py | 34 +++++++++++++++++---- 4 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 helios/templates/voters_upload_confirm.html diff --git a/helios/election_urls.py b/helios/election_urls.py index f63ff58..4b76876 100644 --- a/helios/election_urls.py +++ b/helios/election_urls.py @@ -68,6 +68,7 @@ urlpatterns = patterns('', # managing voters (r'^/voters/$', voter_list), (r'^/voters/upload$', voters_upload), + (r'^/voters/upload-cancel$', voters_upload_cancel), (r'^/voters/list$', voters_list_pretty), (r'^/voters/email$', voters_email), (r'^/voters/(?P<voter_uuid>[^/]+)$', one_voter), diff --git a/helios/models.py b/helios/models.py index 5763eba..5135118 100644 --- a/helios/models.py +++ b/helios/models.py @@ -448,6 +448,24 @@ class VoterFile(models.Model): processing_finished_at = models.DateTimeField(auto_now_add=False, null=True) num_voters = models.IntegerField(null=True) + def itervoters(self): + reader = unicode_csv_reader(open(self.voter_file.path, "rU")) + + for voter_fields in reader: + # bad line + if len(voter_fields) < 1: + continue + + return_dict = {'voter_id': voter_fields[0]} + + if len(voter_fields) > 1: + return_dict['email'] = voter_fields[1] + + if len(voter_fields) > 2: + return_dict['name'] = voter_fields[2] + + yield return_dict + def process(self): self.processing_started_at = datetime.datetime.utcnow() self.save() diff --git a/helios/templates/voters_upload_confirm.html b/helios/templates/voters_upload_confirm.html new file mode 100644 index 0000000..18d5e09 --- /dev/null +++ b/helios/templates/voters_upload_confirm.html @@ -0,0 +1,26 @@ +{% extends TEMPLATE_BASE %} + +{% block content %} + <h2 class="title">{{election.name}} — Bulk Upload Voters — Confirm<span style="font-size:0.7em;">[<a href="{% url helios.views.one_election_view election.uuid %}">back to election</a>]</span></h2> + +<p> +You have uploaded a file of voters. The first few rows of this file are: +</p> + +<table> +<tr><th>Voter Login</th><th>Email Address</th><th>Name</th></tr> +{% for v in voters %} +<tr><td>{{v.voter_id}}</td><td>{{v.email}}</td><td>{{v.name}}</td></tr> +{% endfor %} +</table> + +<p></p> +<form method="post" action="" id="upload_form"> + Does this look right to you? + <input type="hidden" name="confirm_p" value="1" /> + <input type="submit" value="Yes, let's go" /> +</form> + +<a href="{% url helios.views.voters_upload_cancel election.uuid %}">no, let me upload a different file</a> + +{% endblock %} diff --git a/helios/views.py b/helios/views.py index c15635b..da59a9f 100644 --- a/helios/views.py +++ b/helios/views.py @@ -941,14 +941,36 @@ def voters_upload(request, election): return render_template(request, 'voters_upload', {'election': election}) if request.method == "POST": - # we store the file away for future processing - voters_file = request.FILES['voters_file'] - voter_file_obj = election.add_voters_file(voters_file) + if bool(request.POST.get('confirm_p', 0)): + # launch the background task to parse that file + tasks.voter_file_process.delay(voter_file_id = request.session['voter_file_id']) + del request.session['voter_file_id'] - # launch the background task to parse that file - tasks.voter_file_process.delay(voter_file_id = voter_file_obj.id) + return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid])) + else: + # we need to confirm + voters_file = request.FILES['voters_file'] + voter_file_obj = election.add_voters_file(voters_file) - return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid])) + request.session['voter_file_id'] = voter_file_obj.id + + # import the first few lines to check + voters = [v for v in voter_file_obj.itervoters()][:5] + + return render_template(request, 'voters_upload_confirm', {'election': election, 'voters': voters}) + +@election_admin() +def voters_upload_cancel(request, election): + """ + cancel upload of CSV file + """ + voter_file_id = request.session.get('voter_file_id', None) + if voter_file_id: + vf = VoterFile.objects.get(id = voter_file_id) + vf.delete() + del request.session['voter_file_id'] + + return HttpResponseRedirect(reverse(one_election_view, args=[election.uuid])) @election_admin(frozen=True) def voters_email(request, election): -- GitLab