diff --git a/oneanddone/tasks/forms.py b/oneanddone/tasks/forms.py
index caac6b68..13275eeb 100644
--- a/oneanddone/tasks/forms.py
+++ b/oneanddone/tasks/forms.py
@@ -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())
diff --git a/oneanddone/tasks/templates/tasks/confirmation.html b/oneanddone/tasks/templates/tasks/confirmation.html
index fbd56114..5d1e01e2 100644
--- a/oneanddone/tasks/templates/tasks/confirmation.html
+++ b/oneanddone/tasks/templates/tasks/confirmation.html
@@ -17,13 +17,13 @@
{{ title }}
diff --git a/oneanddone/tasks/templates/tasks/form.html b/oneanddone/tasks/templates/tasks/form.html
index 749b4353..9f6c3b71 100644
--- a/oneanddone/tasks/templates/tasks/form.html
+++ b/oneanddone/tasks/templates/tasks/form.html
@@ -47,7 +47,7 @@ {{ title }}
{% endif %}
{% if action == 'Import' %}
-
+ {{ stage_form__preview }}
{{ form_field(batch_form['description'], help_text=True) }}
{{ form_field(batch_form['query'], help_text=True) }}
diff --git a/oneanddone/tasks/views.py b/oneanddone/tasks/views.py
index b0d613c0..72c817d2 100644
--- a/oneanddone/tasks/views.py
+++ b/oneanddone/tasks/views.py
@@ -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)
@@ -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)
@@ -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()]):
@@ -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()
@@ -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