Skip to content
This repository has been archived by the owner on Aug 20, 2018. It is now read-only.

Commit

Permalink
Manage preview-confirm step with Django Form
Browse files Browse the repository at this point in the history
  • Loading branch information
mjzffr committed Sep 28, 2014
1 parent 0d492af commit b8e400c
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 22 deletions.
15 changes: 15 additions & 0 deletions oneanddone/tasks/forms.py
Expand Up @@ -21,6 +21,21 @@ class Meta:
fields = ('text',)


class PreviewConfirmationForm(forms.Form):
""" Used to create a multi-step object-creation/update process, with a
chance to preview and cancel changes before committing them.
"""
submission_stages = ('fill', 'preview', 'confirm')
stage = forms.CharField(widget=forms.HiddenInput())

def clean(self):
cleaned_data = super(PreviewConfirmationForm, self).clean()
if cleaned_data.get('stage') not in self.submission_stages:
raise forms.ValidationError(_('Form data is missing or has been '
'tampered.'))
return cleaned_data


class TaskInvalidationCriterionForm(forms.Form):
criterion = forms.ModelChoiceField(queryset=
TaskInvalidationCriterion.objects.all())
Expand Down
4 changes: 2 additions & 2 deletions oneanddone/tasks/templates/tasks/confirmation.html
Expand Up @@ -17,13 +17,13 @@ <h1>{{ title }}</h1>
<form method="post">
{{ csrf() }}
{{ hiddenform([batch_form, task_form], [criterion_formset]) }}
<input type="hidden" name="stage" value="initial" />
{{ stage_form__fill }}
<button type="submit" class="button">{{ _('No, cancel import') }}</button>
</form>
<form method="post">
{{ csrf() }}
{{ hiddenform([batch_form, task_form], [criterion_formset]) }}
<input type="hidden" name="stage" value="confirm" />
{{ stage_form__confirm }}
<button type="submit" class="button">{{ _('Yes, import tasks') }}</button>
</form>
</div>
Expand Down
2 changes: 1 addition & 1 deletion oneanddone/tasks/templates/tasks/form.html
Expand Up @@ -47,7 +47,7 @@ <h4>{{ title }}</h4>
</div>
{% endif %}
{% if action == 'Import' %}
<input type="hidden" name="stage" value="preview" />
{{ stage_form__preview }}
{{ form_field(batch_form['description'], help_text=True) }}
{{ form_field(batch_form['query'], help_text=True) }}
<div class="subsection content-container">
Expand Down
39 changes: 20 additions & 19 deletions oneanddone/tasks/views.py
Expand Up @@ -17,7 +17,8 @@

from oneanddone.base.util import get_object_or_none, SortHeaders
from oneanddone.tasks.filters import ActivityFilterSet, TasksFilterSet
from oneanddone.tasks.forms import (FeedbackForm, TaskImportBatchForm,
from oneanddone.tasks.forms import (FeedbackForm, PreviewConfirmationForm,
TaskImportBatchForm,
TaskInvalidCriteriaFormSet, TaskForm)
from oneanddone.tasks.mixins import (APIRecordCreatorMixin,
APIOnlyCreatorMayDeleteMixin)
Expand Down Expand Up @@ -219,18 +220,24 @@ def get_forms(self):
kwargs = {'initial': None}
if self.request.method == 'POST':
kwargs['data'] = self.request.POST

batch_form = TaskImportBatchForm(instance=None,
prefix='batch', **kwargs)
batch_form = TaskImportBatchForm(instance=None, prefix='batch',
**kwargs)
criterion_formset = TaskInvalidCriteriaFormSet(prefix='criterion',
**kwargs)
kwargs['initial'] = {'end_date': date.today() + timedelta(days=30),
'repeatable': False}
task_form = TaskForm(instance=None, prefix='task', **kwargs)

return {'criterion_formset': criterion_formset,
'batch_form': batch_form,
'task_form': task_form}
forms = {'criterion_formset': criterion_formset,
'batch_form': batch_form,
'task_form': task_form}

# Create a hidden form for each possible PreviewConfirmationForm stage.
# These forms are used to signal what the next stage should be.
make_stage = lambda x: PreviewConfirmationForm(data={'stage': x})
stages = PreviewConfirmationForm.submission_stages
forms.update({'stage_form__' + s: make_stage(s) for s in stages})
return forms

def get_context_data(self, **kwargs):
ctx = super(ImportTasksView, self).get_context_data(**kwargs)
Expand All @@ -253,20 +260,20 @@ def forms_valid(self, forms):
return self.render_to_response(self.get_context_data(**ctx))

def forms_invalid(self, forms):
self.stage = 'initial'
self.stage = 'fill'
return self.render_to_response(self.get_context_data(**forms))

def get(self, request, *args, **kwargs):
# Assume this is a fresh start to the import process
self.stage = None
self.stage = 'fill'
forms = self.get_forms()
assert forms['criterion_formset'].total_form_count() == 1
return self.render_to_response(self.get_context_data(**forms))

def post(self, request, *args, **kwargs):
stage = self._update_stage()
self.stage = self.request.POST.get('stage', 'fill')
forms = self.get_forms()
if stage == 'initial':
if self.stage == 'fill':
return self.render_to_response(self.get_context_data(**forms))

if all([form.is_valid() for form in forms.values()]):
Expand All @@ -277,8 +284,8 @@ def post(self, request, *args, **kwargs):
def done(self, forms):
bugs = forms['batch_form'].cleaned_data['_fresh_bugs']
import_batch = forms['batch_form'].save(self.request.user)
criterion_objs = [criterion_form.cleaned_data['criterion'] for criterion_form in
forms['criterion_formset'].forms]
criterion_objs = [criterion_form.cleaned_data['criterion'] for
criterion_form in forms['criterion_formset'].forms]
for criterion in criterion_objs:
criterion.batches.add(import_batch)
criterion.save()
Expand All @@ -300,12 +307,6 @@ def done(self, forms):
messages.success(self.request, _('{num} tasks created.').format(num=str(len(bugs))))
return redirect('tasks.list')

def _update_stage(self):
self.stage = self.request.POST.get('stage')
if self.stage not in ['initial', 'preview', 'confirm']:
raise ValidationError(_('Form data is missing or has been tampered.'))
return self.stage


class CreateTaskView(LoginRequiredMixin, MyStaffUserRequiredMixin, generic.CreateView):
model = Task
Expand Down

0 comments on commit b8e400c

Please sign in to comment.