Laid the ground work for client-side input validation by setting up a fn that's triggered before the form is submitted. The vote start and end date time is now being validated both server side and client side and now includes UTC offsets

This commit is contained in:
vince0656 2018-06-13 13:01:55 +01:00
parent a0863e4ade
commit 6dcafb2e9a
4 changed files with 157 additions and 37 deletions

View file

@ -1,5 +1,7 @@
from datetime import datetime
from django.utils.dateparse import parse_datetime
from allauthdemo.polls.models import Event
from allauthdemo.polls.models import Poll
from allauthdemo.polls.models import PollOption
@ -54,11 +56,29 @@ class CreateNewEventModelAdaptor:
self.identifier = self.form_data.pop('identifier-input')[0]
# Extract start and end times as string and convert to datetime
# The UTC offset comes with a colon i.e. '+01:00' which needs to be removed
starts_at = self.form_data.pop('vote-start-input')[0]
self.starts_at = datetime.strptime(starts_at, '%Y-%m-%d %H:%M')
starts_at_offset_index = starts_at.find('+')
if starts_at_offset_index != -1:
starts_at_time = starts_at[0: starts_at_offset_index-1].replace(' ', 'T')
starts_at_offset = starts_at[starts_at_offset_index:].replace(':', '')
starts_at = starts_at_time + starts_at_offset
self.starts_at = parse_datetime(starts_at)
else:
self.starts_at = datetime.strptime(starts_at, '%Y-%m-%d %H:%M')
ends_at = self.form_data.pop('vote-end-input')[0]
self.ends_at = datetime.strptime(ends_at, '%Y-%m-%d %H:%M')
ends_at_offset_index = ends_at.find('+')
if ends_at_offset_index != -1:
ends_at_time = ends_at[0:ends_at_offset_index-1].replace(' ', 'T')
ends_at_offset = ends_at[ends_at_offset_index:].replace(':', '')
ends_at = ends_at_time + ends_at_offset
self.ends_at = parse_datetime(ends_at)
else:
self.ends_at = datetime.strptime(ends_at, '%Y-%m-%d %H:%M')
# Extract the list of organisers
organisers_list = self.form_data.pop('organiser-email-input')

View file

@ -302,7 +302,7 @@ def create_event(request):
# TODO: Based on whether validation was successful within update model and whether
# TODO: data was actually persisted, either perform a redirect (success) or flag an error
return HttpResponseRedirect("/event")
return HttpResponseRedirect("/event/")
elif request.method == "GET":
#form = EventForm()
#organiser_formset = OrganiserFormSet(prefix="formset_organiser", initial=[{'email': request.user.email }])

View file

@ -22,7 +22,7 @@
<div class="form-group"> <!-- Excluded class(missing %s): { if election_form.name.errors }has-error{ endif } -->
<label for="name-input" class="col-sm-3 col-md-2 control-label">Name:</label> <!-- This text can be a template variable -->
<div class="col-sm-9 col-md-10">
<input type="text" class="form-control" id="name-input" placeholder="Example: My poll" name="name-input" maxlength="255">
<input type="text" class="form-control input-control" id="name-input" placeholder="Example: My poll" name="name-input" maxlength="255">
<span id="name-input-help-block" class="help-block">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
A short and clear name.
@ -34,7 +34,7 @@
<div class="form-group"> <!-- Excluded class(missing %s): { if election_form.slug.errors }has-error{ endif } -->
<label for="identifier-input" class="col-sm-3 col-md-2 control-label">Identifier:</label> <!-- This text can be a template variable -->
<div class="col-sm-9 col-md-10">
<input type="text" class="form-control" id="identifier-input" placeholder="Example: My-poll" name="identifier-input" maxlength="255">
<input type="text" class="form-control input-control" id="identifier-input" placeholder="Example: My-poll" name="identifier-input" maxlength="255">
<span id="identifier-input-help-block" class="help-block">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
Used in the election URL, it must only consist of letters, numbers, underscores or hyphens; no whitespace is permitted.
@ -47,7 +47,7 @@
<label for="vote-start-input" class="col-sm-3 col-md-2 control-label">Voting starts at:</label>
<div class="col-sm-9 col-md-10">
<div class="input-group date">
<input type="text" class="form-control" data-date-format="YYYY-MM-DD H:mm" id="vote-start-input" name="vote-start-input">
<input type="text" class="form-control input-control" data-date-format="YYYY-MM-DD H:mm Z" id="vote-start-input" name="vote-start-input">
<span class="input-group-addon btn">
<i class="fa fa-calendar" aria-hidden="true"></i>
/
@ -56,7 +56,7 @@
</div>
<span id="vote-start-input-help-block" class="help-block">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
Date and time when registered voters can commence voting.
Date and time when registered voters can commence voting. This includes the UTC offset starting with '+'.
</span>
</div>
</div>
@ -65,7 +65,7 @@
<label for="vote-end-input" class="col-sm-3 col-md-2 control-label">Voting ends at:</label>
<div class="col-sm-9 col-md-10">
<div class="input-group date">
<input type="text" class="form-control" data-date-format="YYYY-MM-DD H:mm" id="vote-end-input" name="vote-end-input">
<input type="text" class="form-control input-control" data-date-format="YYYY-MM-DD H:mm Z" id="vote-end-input" name="vote-end-input">
<span class="input-group-addon btn">
<i class="fa fa-calendar" aria-hidden="true"></i>
/
@ -74,7 +74,7 @@
</div>
<span id="vote-end-input-help-block" class="help-block">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
Date and time when registered voters can no longer vote.
Date and time when registered voters can no longer vote. This includes the UTC offset starting with '+'.
</span>
</div>
</div>
@ -82,7 +82,7 @@
<div class="form-group">
<label for="question-input" class="col-sm-3 col-md-2 control-label">Question / Statement:</label> <!-- This text can be a template variable -->
<div class="col-sm-9 col-md-10">
<input type="text" class="form-control" id="question-input" placeholder="Example: Elections for the European Parliament" name="question-input" maxlength="200">
<input type="text" class="form-control input-control" id="question-input" placeholder="Example: Elections for the European Parliament" name="question-input" maxlength="200">
<span id="question-input-help-block" class="help-block">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
Question / Statement that will be put forward to voters along with the below options.
@ -115,7 +115,7 @@
<td>
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: Candidate 1" id="option-name-input" name="option-name-input" maxlength="200">
<input type="text" class="form-control input-sm input-control" placeholder="Example: Candidate 1" id="option-name-input" name="option-name-input" maxlength="200">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -136,7 +136,7 @@
<td>
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: Candidate 2" id="option-name-input" name="option-name-input" maxlength="200">
<input type="text" class="form-control input-sm input-control" placeholder="Example: Candidate 2" id="option-name-input" name="option-name-input" maxlength="200">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -157,7 +157,7 @@
<td>
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: Candidate X" id="option-name-input" name="option-name-input" maxlength="200">
<input type="text" class="form-control input-sm input-control" placeholder="Example: Candidate X" id="option-name-input" name="option-name-input" maxlength="200">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -190,12 +190,12 @@
<div class="row">
<div class="col-xs-6">
<label class="sr-only" for="minimum-input">Minimum</label>
<input type="number" class="form-control" id="minimum-input" placeholder="Minimum" value="" name="minimum-input" min="0"> <!-- TODO: Max should be set to the number of options -->
<input type="number" class="form-control input-control" id="minimum-input" placeholder="Minimum" value="" name="minimum-input" min="0"> <!-- TODO: Max should be set to the number of options -->
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
<div class="col-xs-6">
<label class="sr-only" for="maximum-input">Maximum</label>
<input type="number" class="form-control" id="maximum-input" placeholder="Maximum" value="" name="maximum-input" min="1"> <!-- TODO: Max should be set to the number of options -->
<input type="number" class="form-control input-control" id="maximum-input" placeholder="Maximum" value="" name="maximum-input" min="1"> <!-- TODO: Max should be set to the number of options -->
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</div>
@ -231,7 +231,7 @@
<!-- Email -->
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: organiser@example.com" id="organiser-email-input" name="organiser-email-input" value="{{ user_email }}" maxlength="255">
<input type="text" class="form-control input-sm input-control" placeholder="Example: organiser@example.com" id="organiser-email-input" name="organiser-email-input" value="{{ user_email }}" maxlength="255">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -252,7 +252,7 @@
<!-- Email -->
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: organiser@example.com" id="organiser-email-input" name="organiser-email-input" maxlength="255">
<input type="text" class="form-control input-sm input-control" placeholder="Example: organiser@example.com" id="organiser-email-input" name="organiser-email-input" maxlength="255">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -272,7 +272,7 @@
<!-- Email -->
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: organiser@example.com" id="organiser-email-input" name="organiser-email-input" maxlength="255">
<input type="text" class="form-control input-sm input-control" placeholder="Example: organiser@example.com" id="organiser-email-input" name="organiser-email-input" maxlength="255">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -322,7 +322,7 @@
<!-- Email -->
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: trustee@example.com" id="trustee-email-input" name="trustee-email-input" value="{{ user_email }}" maxlength="255">
<input type="text" class="form-control input-sm input-control" placeholder="Example: trustee@example.com" id="trustee-email-input" name="trustee-email-input" value="{{ user_email }}" maxlength="255">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -343,7 +343,7 @@
<!-- Email -->
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: trustee@example.com" id="trustee-email-input" name="trustee-email-input" maxlength="255">
<input type="text" class="form-control input-sm input-control" placeholder="Example: trustee@example.com" id="trustee-email-input" name="trustee-email-input" maxlength="255">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -363,7 +363,7 @@
<!-- Email -->
<div> <!-- Has error conditional class removed -->
<!-- TODO: Add an invisible screen reader label to associate with this and other inputs -->
<input type="text" class="form-control input-sm" placeholder="Example: trustee@example.com" id="trustee-email-input" name="trustee-email-input" maxlength="255">
<input type="text" class="form-control input-sm input-control" placeholder="Example: trustee@example.com" id="trustee-email-input" name="trustee-email-input" maxlength="255">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
</div>
</td>
@ -392,7 +392,7 @@
<div class="form-group">
<label for="voters-list-input" class="col-sm-3 col-md-2 control-label">Voters List:</label> <!-- This text can be a template variable -->
<div class="col-sm-9 col-md-10">
<textarea class="form-control" id="voters-list-input" placeholder="alice@example.com, bob@example.com..." name="voters-list-input" rows="4"></textarea>
<textarea class="form-control input-control" id="voters-list-input" placeholder="alice@example.com, bob@example.com..." name="voters-list-input" rows="4"></textarea>
<span id="voters-list-input-help-block" class="help-block">
<!-- Error handling / input validation has been removed temporarily and would be placed here -->
Manually enter email addresses separated with commas. Alternatively, you can also upload a CSV file:
@ -422,7 +422,7 @@
</div>
<hr>
<input class="btn btn-success" type="submit" value="Create Event" id="submit-event-create" disabled/>
<input class="btn btn-danger" type="button" value="Cancel" onclick="location.href='{% url 'polls:index' %}'" />
<input class="btn btn-danger" type="button" value="Cancel" id="cancel-event-create" onclick="location.href='{% url 'polls:index' %}'" />
</form>
</div>
</div>