forked from stephrdev/django-formwizard
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Backported django.contrib.formtools.wizard. Compat. with Django 1.4+
- Loading branch information
Showing
30 changed files
with
1,419 additions
and
1,277 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
Stephan Jaekel <steph@rdev.info> | ||
Stephan Jaekel <steph@rdev.info>Jannis Leidel <jannis@leidel.info> | ||
|
Empty file.
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# empty models file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,21 @@ | ||
from django.core.exceptions import ImproperlyConfigured | ||
from django.utils.importlib import import_module | ||
|
||
try: | ||
from importlib import import_module | ||
except ImportError: | ||
from django.utils.importlib import import_module | ||
from formwizard.storage.base import BaseStorage | ||
from formwizard.storage.exceptions import (MissingStorageModule, | ||
MissingStorageClass, NoFileStorageConfigured) | ||
|
||
class MissingStorageModuleException(ImproperlyConfigured): | ||
pass | ||
|
||
class MissingStorageClassException(ImproperlyConfigured): | ||
pass | ||
|
||
def get_storage(path, *args, **kwargs): | ||
i = path.rfind('.') | ||
module, attr = path[:i], path[i+1:] | ||
try: | ||
mod = import_module(module) | ||
except ImportError, e: | ||
raise MissingStorageModuleException('Error loading storage %s: "%s"' % (module, e)) | ||
raise MissingStorageModule( | ||
'Error loading storage %s: "%s"' % (module, e)) | ||
try: | ||
storage_class = getattr(mod, attr) | ||
except AttributeError: | ||
raise MissingStorageClassException('Module "%s" does not define a storage named "%s"' % (module, attr)) | ||
raise MissingStorageClass( | ||
'Module "%s" does not define a storage named "%s"' % (module, attr)) | ||
return storage_class(*args, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,94 @@ | ||
class NoFileStorageException(Exception): | ||
pass | ||
from django.core.files.uploadedfile import UploadedFile | ||
from django.utils.functional import lazy_property | ||
from django.utils.encoding import smart_str | ||
|
||
from formwizard.storage.exceptions import NoFileStorageConfigured | ||
|
||
|
||
class BaseStorage(object): | ||
def __init__(self, prefix): | ||
self.prefix = 'formwizard_%s' % prefix | ||
step_key = 'step' | ||
step_data_key = 'step_data' | ||
step_files_key = 'step_files' | ||
extra_data_key = 'extra_data' | ||
|
||
def get_current_step(self): | ||
raise NotImplementedError() | ||
def __init__(self, prefix, request=None, file_storage=None): | ||
self.prefix = 'wizard_%s' % prefix | ||
self.request = request | ||
self.file_storage = file_storage | ||
|
||
def set_current_step(self, step): | ||
raise NotImplementedError() | ||
def init_data(self): | ||
self.data = { | ||
self.step_key: None, | ||
self.step_data_key: {}, | ||
self.step_files_key: {}, | ||
self.extra_data_key: {}, | ||
} | ||
|
||
def get_step_data(self, step): | ||
raise NotImplementedError() | ||
def reset(self): | ||
self.init_data() | ||
|
||
def _get_current_step(self): | ||
return self.data[self.step_key] | ||
|
||
def _set_current_step(self, step): | ||
self.data[self.step_key] = step | ||
|
||
current_step = lazy_property(_get_current_step, _set_current_step) | ||
|
||
def _get_extra_data(self): | ||
return self.data[self.extra_data_key] or {} | ||
|
||
def get_current_step_data(self): | ||
raise NotImplementedError() | ||
def _set_extra_data(self, extra_data): | ||
self.data[self.extra_data_key] = extra_data | ||
|
||
extra_data = lazy_property(_get_extra_data, _set_extra_data) | ||
|
||
def get_step_data(self, step): | ||
return self.data[self.step_data_key].get(step, None) | ||
|
||
def set_step_data(self, step, cleaned_data): | ||
raise NotImplementedError() | ||
self.data[self.step_data_key][step] = cleaned_data | ||
|
||
@property | ||
def current_step_data(self): | ||
return self.get_step_data(self.current_step) | ||
|
||
def get_step_files(self, step): | ||
raise NotImplementedError() | ||
wizard_files = self.data[self.step_files_key].get(step, {}) | ||
|
||
if wizard_files and not self.file_storage: | ||
raise NoFileStorageConfigured | ||
|
||
files = {} | ||
for field, field_dict in wizard_files.iteritems(): | ||
field_dict = dict((smart_str(k), v) | ||
for k, v in field_dict.iteritems()) | ||
tmp_name = field_dict.pop('tmp_name') | ||
files[field] = UploadedFile( | ||
file=self.file_storage.open(tmp_name), **field_dict) | ||
return files or None | ||
|
||
def set_step_files(self, step, files): | ||
raise NotImplementedError() | ||
if files and not self.file_storage: | ||
raise NoFileStorageConfigured | ||
|
||
def get_extra_context_data(self): | ||
raise NotImplementedError() | ||
if step not in self.data[self.step_files_key]: | ||
self.data[self.step_files_key][step] = {} | ||
|
||
def set_extra_context_data(self, extra_context): | ||
raise NotImplementedError() | ||
for field, field_file in (files or {}).iteritems(): | ||
tmp_filename = self.file_storage.save(field_file.name, field_file) | ||
file_dict = { | ||
'tmp_name': tmp_filename, | ||
'name': field_file.name, | ||
'content_type': field_file.content_type, | ||
'size': field_file.size, | ||
'charset': field_file.charset | ||
} | ||
self.data[self.step_files_key][step][field] = file_dict | ||
|
||
def reset(self): | ||
raise NotImplementedError() | ||
@property | ||
def current_step_files(self): | ||
return self.get_step_files(self.current_step) | ||
|
||
def update_response(self, response): | ||
raise NotImplementedError() | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,129 +1,32 @@ | ||
import hmac | ||
|
||
from django.conf import settings | ||
from django.core.exceptions import SuspiciousOperation | ||
from django.utils.hashcompat import sha_constructor | ||
from django.core.signing import BadSignature | ||
from django.utils import simplejson as json | ||
from formwizard.storage.base import BaseStorage, NoFileStorageException | ||
from django.core.files.uploadedfile import UploadedFile | ||
from django.core.files import File | ||
|
||
sha_hmac = sha_constructor | ||
|
||
class CookieStorage(BaseStorage): | ||
step_cookie_key = 'step' | ||
step_data_cookie_key = 'step_data' | ||
step_files_cookie_key = 'step_files' | ||
extra_context_cookie_key = 'extra_context' | ||
|
||
def __init__(self, prefix, request, file_storage, *args, **kwargs): | ||
super(CookieStorage, self).__init__(prefix) | ||
self.file_storage = file_storage | ||
self.request = request | ||
self.cookie_data = self.load_cookie_data() | ||
if self.cookie_data is None: | ||
self.init_storage() | ||
|
||
def init_storage(self): | ||
self.cookie_data = { | ||
self.step_cookie_key: None, | ||
self.step_data_cookie_key: {}, | ||
self.step_files_cookie_key: {}, | ||
self.extra_context_cookie_key: {}, | ||
} | ||
return True | ||
|
||
def get_current_step(self): | ||
return self.cookie_data[self.step_cookie_key] | ||
|
||
def set_current_step(self, step): | ||
self.cookie_data[self.step_cookie_key] = step | ||
return True | ||
|
||
def get_step_data(self, step): | ||
return self.cookie_data[self.step_data_cookie_key].get(step, None) | ||
|
||
def get_current_step_data(self): | ||
return self.get_step_data(self.get_current_step()) | ||
|
||
def set_step_data(self, step, cleaned_data): | ||
self.cookie_data[self.step_data_cookie_key][step] = cleaned_data | ||
return True | ||
|
||
|
||
def set_step_files(self, step, files): | ||
if files and not self.file_storage: | ||
raise NoFileStorageException | ||
|
||
if not self.cookie_data[self.step_files_cookie_key].has_key(step): | ||
self.cookie_data[self.step_files_cookie_key][step] = {} | ||
|
||
for field, field_file in (files or {}).items(): | ||
tmp_filename = self.file_storage.save(field_file.name, field_file) | ||
file_dict = { | ||
'tmp_name': tmp_filename, | ||
'name': field_file.name, | ||
'content_type': field_file.content_type, | ||
'size': field_file.size, | ||
'charset': field_file.charset | ||
} | ||
self.cookie_data[self.step_files_cookie_key][step][field] = file_dict | ||
from formwizard import storage | ||
|
||
return True | ||
|
||
def get_current_step_files(self): | ||
return self.get_step_files(self.get_current_step()) | ||
class CookieStorage(storage.BaseStorage): | ||
encoder = json.JSONEncoder(separators=(',', ':')) | ||
|
||
def get_step_files(self, step): | ||
session_files = self.cookie_data[self.step_files_cookie_key].get(step, {}) | ||
def __init__(self, *args, **kwargs): | ||
super(CookieStorage, self).__init__(*args, **kwargs) | ||
self.data = self.load_data() | ||
if self.data is None: | ||
self.init_data() | ||
|
||
if session_files and not self.file_storage: | ||
raise NoFileStorageException | ||
|
||
files = {} | ||
for field, field_dict in session_files.items(): | ||
files[field] = UploadedFile( | ||
file=self.file_storage.open(field_dict['tmp_name']), | ||
name=field_dict['name'], | ||
content_type=field_dict['content_type'], | ||
size=field_dict['size'], | ||
charset=field_dict['charset'], | ||
) | ||
return files or None | ||
|
||
def get_extra_context_data(self): | ||
return self.cookie_data[self.extra_context_cookie_key] or {} | ||
|
||
def set_extra_context_data(self, extra_context): | ||
self.cookie_data[self.extra_context_cookie_key] = extra_context | ||
return True | ||
|
||
def reset(self): | ||
return self.init_storage() | ||
def load_data(self): | ||
try: | ||
data = self.request.get_signed_cookie(self.prefix) | ||
except KeyError: | ||
data = None | ||
except BadSignature: | ||
raise SuspiciousOperation('FormWizard cookie manipulated') | ||
if data is None: | ||
return None | ||
return json.loads(data, cls=json.JSONDecoder) | ||
|
||
def update_response(self, response): | ||
if len(self.cookie_data) > 0: | ||
response.set_cookie(self.prefix, self.create_cookie_data(self.cookie_data)) | ||
if self.data: | ||
response.set_signed_cookie(self.prefix, self.encoder.encode(self.data)) | ||
else: | ||
response.delete_cookie(self.prefix) | ||
return response | ||
|
||
def load_cookie_data(self): | ||
data = self.request.COOKIES.get(self.prefix, None) | ||
if data is None: | ||
return None | ||
|
||
bits = data.split('$', 1) | ||
if len(bits) == 2: | ||
if bits[0] == self.get_cookie_hash(bits[1]): | ||
return json.loads(bits[1], cls=json.JSONDecoder) | ||
|
||
raise SuspiciousOperation('FormWizard cookie manipulated') | ||
|
||
def get_cookie_hash(self, data): | ||
return hmac.new('%s$%s' % (settings.SECRET_KEY, self.prefix), data, sha_hmac).hexdigest() | ||
|
||
def create_cookie_data(self, data): | ||
encoder = json.JSONEncoder(separators=(',', ':')) | ||
encoded_data = encoder.encode(data) | ||
return '%s$%s' % (self.get_cookie_hash(encoded_data), encoded_data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from django.core.exceptions import ImproperlyConfigured | ||
|
||
class MissingStorageModule(ImproperlyConfigured): | ||
pass | ||
|
||
class MissingStorageClass(ImproperlyConfigured): | ||
pass | ||
|
||
class NoFileStorageConfigured(ImproperlyConfigured): | ||
pass |
Oops, something went wrong.