Fixes an issue where the organization home page would throw a 505 when no projects...
[Melange.git] / app / django / contrib / formtools / preview.py
blob856343a0dfb68d244096476d92b64b8d32ef1726
1 """
2 Formtools Preview application.
3 """
5 import cPickle as pickle
7 from django.conf import settings
8 from django.http import Http404
9 from django.shortcuts import render_to_response
10 from django.template.context import RequestContext
11 from django.utils.hashcompat import md5_constructor
12 from django.contrib.formtools.utils import security_hash
14 AUTO_ID = 'formtools_%s' # Each form here uses this as its auto_id parameter.
16 class FormPreview(object):
17 preview_template = 'formtools/preview.html'
18 form_template = 'formtools/form.html'
20 # METHODS SUBCLASSES SHOULDN'T OVERRIDE ###################################
22 def __init__(self, form):
23 # form should be a Form class, not an instance.
24 self.form, self.state = form, {}
26 def __call__(self, request, *args, **kwargs):
27 stage = {'1': 'preview', '2': 'post'}.get(request.POST.get(self.unused_name('stage')), 'preview')
28 self.parse_params(*args, **kwargs)
29 try:
30 method = getattr(self, stage + '_' + request.method.lower())
31 except AttributeError:
32 raise Http404
33 return method(request)
35 def unused_name(self, name):
36 """
37 Given a first-choice name, adds an underscore to the name until it
38 reaches a name that isn't claimed by any field in the form.
40 This is calculated rather than being hard-coded so that no field names
41 are off-limits for use in the form.
42 """
43 while 1:
44 try:
45 f = self.form.base_fields[name]
46 except KeyError:
47 break # This field name isn't being used by the form.
48 name += '_'
49 return name
51 def preview_get(self, request):
52 "Displays the form"
53 f = self.form(auto_id=AUTO_ID)
54 return render_to_response(self.form_template,
55 {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state},
56 context_instance=RequestContext(request))
58 def preview_post(self, request):
59 "Validates the POST data. If valid, displays the preview page. Else, redisplays form."
60 f = self.form(request.POST, auto_id=AUTO_ID)
61 context = {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state}
62 if f.is_valid():
63 context['hash_field'] = self.unused_name('hash')
64 context['hash_value'] = self.security_hash(request, f)
65 return render_to_response(self.preview_template, context, context_instance=RequestContext(request))
66 else:
67 return render_to_response(self.form_template, context, context_instance=RequestContext(request))
69 def post_post(self, request):
70 "Validates the POST data. If valid, calls done(). Else, redisplays form."
71 f = self.form(request.POST, auto_id=AUTO_ID)
72 if f.is_valid():
73 if self.security_hash(request, f) != request.POST.get(self.unused_name('hash')):
74 return self.failed_hash(request) # Security hash failed.
75 return self.done(request, f.cleaned_data)
76 else:
77 return render_to_response(self.form_template,
78 {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state},
79 context_instance=RequestContext(request))
81 # METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ########################
83 def parse_params(self, *args, **kwargs):
84 """
85 Given captured args and kwargs from the URLconf, saves something in
86 self.state and/or raises Http404 if necessary.
88 For example, this URLconf captures a user_id variable:
90 (r'^contact/(?P<user_id>\d{1,6})/$', MyFormPreview(MyForm)),
92 In this case, the kwargs variable in parse_params would be
93 {'user_id': 32} for a request to '/contact/32/'. You can use that
94 user_id to make sure it's a valid user and/or save it for later, for
95 use in done().
96 """
97 pass
99 def security_hash(self, request, form):
101 Calculates the security hash for the given HttpRequest and Form instances.
103 Subclasses may want to take into account request-specific information,
104 such as the IP address.
106 return security_hash(request, form)
108 def failed_hash(self, request):
109 "Returns an HttpResponse in the case of an invalid security hash."
110 return self.preview_post(request)
112 # METHODS SUBCLASSES MUST OVERRIDE ########################################
114 def done(self, request, cleaned_data):
116 Does something with the cleaned_data and returns an
117 HttpResponseRedirect.
119 raise NotImplementedError('You must define a done() method on your %s subclass.' % self.__class__.__name__)