summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2012-12-24 22:55:11 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2012-12-29 21:58:12 +0100
commitd4ea02b9929eca32887efe773a8e6a717590b055 (patch)
treef860316c11f81816c6e60e6efb6a0fcf8dc635cb
parent052271168bc8f46c64451340d39682d5efdef9b6 (diff)
Removed the legacy form wizard.
-rw-r--r--django/contrib/formtools/tests/__init__.py253
-rw-r--r--django/contrib/formtools/tests/forms.py29
-rw-r--r--django/contrib/formtools/tests/urls.py8
-rw-r--r--django/contrib/formtools/wizard/__init__.py1
-rw-r--r--django/contrib/formtools/wizard/legacy.py270
5 files changed, 2 insertions, 559 deletions
diff --git a/django/contrib/formtools/tests/__init__.py b/django/contrib/formtools/tests/__init__.py
index aa7d5ff7d4..8caefd0e67 100644
--- a/django/contrib/formtools/tests/__init__.py
+++ b/django/contrib/formtools/tests/__init__.py
@@ -10,7 +10,6 @@ import warnings
from django import http
from django.conf import settings
from django.contrib.formtools import preview, utils
-from django.contrib.formtools.wizard import FormWizard
from django.test import TestCase
from django.test.html import parse_html
from django.test.utils import override_settings
@@ -187,255 +186,3 @@ class FormHmacTests(unittest.TestCase):
hash1 = utils.form_hmac(f1)
hash2 = utils.form_hmac(f2)
self.assertEqual(hash1, hash2)
-
-
-#
-# FormWizard tests
-#
-
-class TestWizardClass(FormWizard):
-
- def get_template(self, step):
- return 'forms/wizard.html'
-
- def done(self, request, cleaned_data):
- return http.HttpResponse(success_string)
-
-
-class DummyRequest(http.HttpRequest):
-
- def __init__(self, POST=None):
- super(DummyRequest, self).__init__()
- self.method = POST and "POST" or "GET"
- if POST is not None:
- self.POST.update(POST)
- self._dont_enforce_csrf_checks = True
-
-
-@override_settings(
- SECRET_KEY="123",
- TEMPLATE_DIRS=(
- os.path.join(os.path.dirname(upath(__file__)), 'templates'),
- ),
-)
-class WizardTests(TestCase):
- urls = 'django.contrib.formtools.tests.urls'
- wizard_step_data = (
- {
- '0-name': 'Pony',
- '0-thirsty': '2',
- },
- {
- '1-address1': '123 Main St',
- '1-address2': 'Djangoland',
- },
- {
- '2-random_crap': 'blah blah',
- }
- )
-
- def setUp(self):
- super(WizardTests, self).setUp()
- self.save_warnings_state()
- warnings.filterwarnings('ignore', category=DeprecationWarning,
- module='django.contrib.formtools.wizard')
-
- def tearDown(self):
- super(WizardTests, self).tearDown()
- self.restore_warnings_state()
-
- def test_step_starts_at_zero(self):
- """
- step should be zero for the first form
- """
- response = self.client.get('/wizard1/')
- self.assertEqual(0, response.context['step0'])
-
- def test_step_increments(self):
- """
- step should be incremented when we go to the next page
- """
- response = self.client.post('/wizard1/', {"0-field":"test", "wizard_step":"0"})
- self.assertEqual(1, response.context['step0'])
-
- def test_bad_hash(self):
- """
- Form should not advance if the hash is missing or bad
- """
- response = self.client.post('/wizard1/',
- {"0-field":"test",
- "1-field":"test2",
- "wizard_step": "1"})
- self.assertEqual(0, response.context['step0'])
-
- def test_good_hash(self):
- """
- Form should advance if the hash is present and good, as calculated using
- current method.
- """
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": {
- 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
- }[pickle.HIGHEST_PROTOCOL],
- "wizard_step": "1"}
- response = self.client.post('/wizard1/', data)
- self.assertEqual(2, response.context['step0'])
-
- def test_11726(self):
- """
- Regression test for ticket #11726.
- Wizard should not raise Http404 when steps are added dynamically.
- """
- reached = [False]
- that = self
-
- class WizardWithProcessStep(TestWizardClass):
- def process_step(self, request, form, step):
- if step == 0:
- if self.num_steps() < 2:
- self.form_list.append(WizardPageTwoForm)
- if step == 1:
- that.assertTrue(isinstance(form, WizardPageTwoForm))
- reached[0] = True
-
- wizard = WizardWithProcessStep([WizardPageOneForm])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": {
- 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
- }[pickle.HIGHEST_PROTOCOL],
- "wizard_step": "1"}
- wizard(DummyRequest(POST=data))
- self.assertTrue(reached[0])
-
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": {
- 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
- }[pickle.HIGHEST_PROTOCOL],
- "hash_1": {
- 2: "1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
- 3: "c33142ef9d01b1beae238adf22c3c6c57328f51a",
- }[pickle.HIGHEST_PROTOCOL],
- "wizard_step": "2"}
- self.assertRaises(http.Http404, wizard, DummyRequest(POST=data))
-
- def test_14498(self):
- """
- Regression test for ticket #14498. All previous steps' forms should be
- validated.
- """
- reached = [False]
- that = self
-
- class WizardWithProcessStep(TestWizardClass):
- def process_step(self, request, form, step):
- that.assertTrue(form.is_valid())
- reached[0] = True
-
- wizard = WizardWithProcessStep([WizardPageOneForm,
- WizardPageTwoForm,
- WizardPageThreeForm])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": {
- 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
- }[pickle.HIGHEST_PROTOCOL],
- "wizard_step": "1"}
- wizard(DummyRequest(POST=data))
- self.assertTrue(reached[0])
-
- def test_14576(self):
- """
- Regression test for ticket #14576.
-
- The form of the last step is not passed to the done method.
- """
- reached = [False]
- that = self
-
- class Wizard(TestWizardClass):
- def done(self, request, form_list):
- reached[0] = True
- that.assertTrue(len(form_list) == 2)
-
- wizard = Wizard([WizardPageOneForm,
- WizardPageTwoForm])
-
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": {
- 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
- }[pickle.HIGHEST_PROTOCOL],
- "wizard_step": "1"}
- wizard(DummyRequest(POST=data))
- self.assertTrue(reached[0])
-
- def test_15075(self):
- """
- Regression test for ticket #15075. Allow modifying wizard's form_list
- in process_step.
- """
- reached = [False]
- that = self
-
- class WizardWithProcessStep(TestWizardClass):
- def process_step(self, request, form, step):
- if step == 0:
- self.form_list[1] = WizardPageTwoAlternativeForm
- if step == 1:
- that.assertTrue(isinstance(form, WizardPageTwoAlternativeForm))
- reached[0] = True
-
- wizard = WizardWithProcessStep([WizardPageOneForm,
- WizardPageTwoForm,
- WizardPageThreeForm])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": {
- 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
- }[pickle.HIGHEST_PROTOCOL],
- "wizard_step": "1"}
- wizard(DummyRequest(POST=data))
- self.assertTrue(reached[0])
-
- def grab_field_data(self, response):
- """
- Pull the appropriate field data from the context to pass to the next wizard step
- """
- previous_fields = parse_html(response.context['previous_fields'])
- fields = {'wizard_step': response.context['step0']}
-
- for input_field in previous_fields:
- input_attrs = dict(input_field.attributes)
- fields[input_attrs["name"]] = input_attrs["value"]
-
- return fields
-
- def check_wizard_step(self, response, step_no):
- """
- Helper function to test each step of the wizard
- - Make sure the call succeeded
- - Make sure response is the proper step number
- - return the result from the post for the next step
- """
- step_count = len(self.wizard_step_data)
-
- self.assertContains(response, 'Step %d of %d' % (step_no, step_count))
-
- data = self.grab_field_data(response)
- data.update(self.wizard_step_data[step_no - 1])
-
- return self.client.post('/wizard2/', data)
-
- def test_9473(self):
- response = self.client.get('/wizard2/')
- for step_no in range(1, len(self.wizard_step_data) + 1):
- response = self.check_wizard_step(response, step_no)
diff --git a/django/contrib/formtools/tests/forms.py b/django/contrib/formtools/tests/forms.py
index 1ed2ab48bb..6f3ce4b0bd 100644
--- a/django/contrib/formtools/tests/forms.py
+++ b/django/contrib/formtools/tests/forms.py
@@ -1,21 +1,4 @@
from django import forms
-from django.contrib.formtools.wizard import FormWizard
-from django.http import HttpResponse
-
-class Page1(forms.Form):
- name = forms.CharField(max_length=100)
- thirsty = forms.NullBooleanField()
-
-class Page2(forms.Form):
- address1 = forms.CharField(max_length=100)
- address2 = forms.CharField(max_length=100)
-
-class Page3(forms.Form):
- random_crap = forms.CharField(max_length=100)
-
-class ContactWizard(FormWizard):
- def done(self, request, form_list):
- return HttpResponse("")
class TestForm(forms.Form):
field1 = forms.CharField()
@@ -30,15 +13,3 @@ class HashTestForm(forms.Form):
class HashTestBlankForm(forms.Form):
name = forms.CharField(required=False)
bio = forms.CharField(required=False)
-
-class WizardPageOneForm(forms.Form):
- field = forms.CharField()
-
-class WizardPageTwoForm(forms.Form):
- field = forms.CharField()
-
-class WizardPageTwoAlternativeForm(forms.Form):
- field = forms.CharField()
-
-class WizardPageThreeForm(forms.Form):
- field = forms.CharField()
diff --git a/django/contrib/formtools/tests/urls.py b/django/contrib/formtools/tests/urls.py
index 99bf7eaefa..739095d69f 100644
--- a/django/contrib/formtools/tests/urls.py
+++ b/django/contrib/formtools/tests/urls.py
@@ -5,15 +5,11 @@ This is a URLconf to be loaded by tests.py. Add any URLs needed for tests only.
from __future__ import absolute_import
from django.conf.urls import patterns, url
-from django.contrib.formtools.tests import TestFormPreview, TestWizardClass
+from django.contrib.formtools.tests import TestFormPreview
-from django.contrib.formtools.tests.forms import (ContactWizard, Page1, Page2,
- Page3, TestForm, WizardPageOneForm, WizardPageTwoForm, WizardPageThreeForm)
+from django.contrib.formtools.tests.forms import TestForm
urlpatterns = patterns('',
url(r'^preview/', TestFormPreview(TestForm)),
- url(r'^wizard1/$', TestWizardClass(
- [WizardPageOneForm, WizardPageTwoForm, WizardPageThreeForm])),
- url(r'^wizard2/$', ContactWizard([Page1, Page2, Page3])),
)
diff --git a/django/contrib/formtools/wizard/__init__.py b/django/contrib/formtools/wizard/__init__.py
index 8e51a3170d..e69de29bb2 100644
--- a/django/contrib/formtools/wizard/__init__.py
+++ b/django/contrib/formtools/wizard/__init__.py
@@ -1 +0,0 @@
-from django.contrib.formtools.wizard.legacy import FormWizard
diff --git a/django/contrib/formtools/wizard/legacy.py b/django/contrib/formtools/wizard/legacy.py
deleted file mode 100644
index d07e959de0..0000000000
--- a/django/contrib/formtools/wizard/legacy.py
+++ /dev/null
@@ -1,270 +0,0 @@
-"""
-FormWizard class -- implements a multi-page form, validating between each
-step and storing the form's state as HTML hidden fields so that no state is
-stored on the server side.
-"""
-from django.forms import HiddenInput
-from django.http import Http404
-from django.shortcuts import render_to_response
-from django.template.context import RequestContext
-from django.utils.crypto import constant_time_compare
-from django.utils.translation import ugettext_lazy as _
-from django.utils.decorators import method_decorator
-from django.views.decorators.csrf import csrf_protect
-
-from django.contrib.formtools.utils import form_hmac
-
-class FormWizard(object):
- # The HTML (and POST data) field name for the "step" variable.
- step_field_name="wizard_step"
-
- # METHODS SUBCLASSES SHOULDN'T OVERRIDE ###################################
-
- def __init__(self, form_list, initial=None):
- """
- Start a new wizard with a list of forms.
-
- form_list should be a list of Form classes (not instances).
- """
- self.form_list = form_list[:]
- self.initial = initial or {}
-
- # Dictionary of extra template context variables.
- self.extra_context = {}
-
- # A zero-based counter keeping track of which step we're in.
- self.step = 0
-
- import warnings
- warnings.warn(
- 'Old-style form wizards have been deprecated; use the class-based '
- 'views in django.contrib.formtools.wizard.views instead.',
- DeprecationWarning)
-
- def __repr__(self):
- return "step: %d\nform_list: %s\ninitial_data: %s" % (self.step, self.form_list, self.initial)
-
- def get_form(self, step, data=None):
- "Helper method that returns the Form instance for the given step."
- # Sanity check.
- if step >= self.num_steps():
- raise Http404('Step %s does not exist' % step)
- return self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None))
-
- def num_steps(self):
- "Helper method that returns the number of steps."
- # You might think we should just set "self.num_steps = len(form_list)"
- # in __init__(), but this calculation needs to be dynamic, because some
- # hook methods might alter self.form_list.
- return len(self.form_list)
-
- def _check_security_hash(self, token, request, form):
- expected = self.security_hash(request, form)
- return constant_time_compare(token, expected)
-
- @method_decorator(csrf_protect)
- def __call__(self, request, *args, **kwargs):
- """
- Main method that does all the hard work, conforming to the Django view
- interface.
- """
- if 'extra_context' in kwargs:
- self.extra_context.update(kwargs['extra_context'])
- current_step = self.get_current_or_first_step(request, *args, **kwargs)
- self.parse_params(request, *args, **kwargs)
-
- # Validate and process all the previous forms before instantiating the
- # current step's form in case self.process_step makes changes to
- # self.form_list.
-
- # If any of them fails validation, that must mean the validator relied
- # on some other input, such as an external Web site.
-
- # It is also possible that alidation might fail under certain attack
- # situations: an attacker might be able to bypass previous stages, and
- # generate correct security hashes for all the skipped stages by virtue
- # of:
- # 1) having filled out an identical form which doesn't have the
- # validation (and does something different at the end),
- # 2) or having filled out a previous version of the same form which
- # had some validation missing,
- # 3) or previously having filled out the form when they had more
- # privileges than they do now.
- #
- # Since the hashes only take into account values, and not other other
- # validation the form might do, we must re-do validation now for
- # security reasons.
- previous_form_list = []
- for i in range(current_step):
- f = self.get_form(i, request.POST)
- if not self._check_security_hash(request.POST.get("hash_%d" % i, ''),
- request, f):
- return self.render_hash_failure(request, i)
-
- if not f.is_valid():
- return self.render_revalidation_failure(request, i, f)
- else:
- self.process_step(request, f, i)
- previous_form_list.append(f)
-
- # Process the current step. If it's valid, go to the next step or call
- # done(), depending on whether any steps remain.
- if request.method == 'POST':
- form = self.get_form(current_step, request.POST)
- else:
- form = self.get_form(current_step)
-
- if form.is_valid():
- self.process_step(request, form, current_step)
- next_step = current_step + 1
-
- if next_step == self.num_steps():
- return self.done(request, previous_form_list + [form])
- else:
- form = self.get_form(next_step)
- self.step = current_step = next_step
-
- return self.render(form, request, current_step)
-
- def render(self, form, request, step, context=None):
- "Renders the given Form object, returning an HttpResponse."
- old_data = request.POST
- prev_fields = []
- if old_data:
- hidden = HiddenInput()
- # Collect all data from previous steps and render it as HTML hidden fields.
- for i in range(step):
- old_form = self.get_form(i, old_data)
- hash_name = 'hash_%s' % i
- prev_fields.extend([bf.as_hidden() for bf in old_form])
- prev_fields.append(hidden.render(hash_name, old_data.get(hash_name, self.security_hash(request, old_form))))
- return self.render_template(request, form, ''.join(prev_fields), step, context)
-
- # METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ########################
-
- def prefix_for_step(self, step):
- "Given the step, returns a Form prefix to use."
- return str(step)
-
- def render_hash_failure(self, request, step):
- """
- Hook for rendering a template if a hash check failed.
-
- step is the step that failed. Any previous step is guaranteed to be
- valid.
-
- This default implementation simply renders the form for the given step,
- but subclasses may want to display an error message, etc.
- """
- return self.render(self.get_form(step), request, step, context={'wizard_error': _('We apologize, but your form has expired. Please continue filling out the form from this page.')})
-
- def render_revalidation_failure(self, request, step, form):
- """
- Hook for rendering a template if final revalidation failed.
-
- It is highly unlikely that this point would ever be reached, but See
- the comment in __call__() for an explanation.
- """
- return self.render(form, request, step)
-
- def security_hash(self, request, form):
- """
- Calculates the security hash for the given HttpRequest and Form instances.
-
- Subclasses may want to take into account request-specific information,
- such as the IP address.
- """
- return form_hmac(form)
-
- def get_current_or_first_step(self, request, *args, **kwargs):
- """
- Given the request object and whatever *args and **kwargs were passed to
- __call__(), returns the current step (which is zero-based).
-
- Note that the result should not be trusted. It may even be a completely
- invalid number. It's not the job of this method to validate it.
- """
- if not request.POST:
- return 0
- try:
- step = int(request.POST.get(self.step_field_name, 0))
- except ValueError:
- return 0
- return step
-
- def parse_params(self, request, *args, **kwargs):
- """
- Hook for setting some state, given the request object and whatever
- *args and **kwargs were passed to __call__(), sets some state.
-
- This is called at the beginning of __call__().
- """
- pass
-
- def get_template(self, step):
- """
- Hook for specifying the name of the template to use for a given step.
-
- Note that this can return a tuple of template names if you'd like to
- use the template system's select_template() hook.
- """
- return 'forms/wizard.html'
-
- def render_template(self, request, form, previous_fields, step, context=None):
- """
- Renders the template for the given step, returning an HttpResponse object.
-
- Override this method if you want to add a custom context, return a
- different MIME type, etc. If you only need to override the template
- name, use get_template() instead.
-
- The template will be rendered with the following context:
- step_field -- The name of the hidden field containing the step.
- step0 -- The current step (zero-based).
- step -- The current step (one-based).
- step_count -- The total number of steps.
- form -- The Form instance for the current step (either empty
- or with errors).
- previous_fields -- A string representing every previous data field,
- plus hashes for completed forms, all in the form of
- hidden fields. Note that you'll need to run this
- through the "safe" template filter, to prevent
- auto-escaping, because it's raw HTML.
- """
- context = context or {}
- context.update(self.extra_context)
- return render_to_response(self.get_template(step), dict(context,
- step_field=self.step_field_name,
- step0=step,
- step=step + 1,
- step_count=self.num_steps(),
- form=form,
- previous_fields=previous_fields
- ), context_instance=RequestContext(request))
-
- def process_step(self, request, form, step):
- """
- Hook for modifying the FormWizard's internal state, given a fully
- validated Form object. The Form is guaranteed to have clean, valid
- data.
-
- This method should *not* modify any of that data. Rather, it might want
- to set self.extra_context or dynamically alter self.form_list, based on
- previously submitted forms.
-
- Note that this method is called every time a page is rendered for *all*
- submitted steps.
- """
- pass
-
- # METHODS SUBCLASSES MUST OVERRIDE ########################################
-
- def done(self, request, form_list):
- """
- Hook for doing something with the validated data. This is responsible
- for the final processing.
-
- form_list is a list of Form instances, each containing clean, valid
- data.
- """
- raise NotImplementedError("Your %s class has not defined a done() method, which is required." % self.__class__.__name__)