Newer
Older
from django.conf import settings
from django.utils.text import mark_safe
from django.core.files.storage import get_storage_class
from opentech.apply.stream_forms.blocks import FormFieldBlock
from opentech.apply.utils.blocks import MustIncludeFieldBlock
from opentech.apply.stream_forms.blocks import UploadableMediaBlock
from opentech.apply.stream_forms.files import StreamFieldFile
__all__ = ['AccessFormData']
submission_storage = get_storage_class(getattr(settings, 'PRIVATE_FILE_STORAGE', None))()
class AccessFormData:
"""Mixin for interacting with form data from streamfields
requires:
- form_data > jsonfield containing the submitted data
- form_fields > streamfield containing the original form fields
"""
@property
def raw_data(self):
# Returns the data mapped by field id instead of the data stored using the must include
# values
data = self.form_data.copy()
for field_name, field_id in self.must_include.items():
if field_id not in data:
response = data[field_name]
data[field_id] = response
@classmethod
def stream_file(cls, file):
Fredrik Jonsson
committed
if 'path' in file:
file['filename'] = file['name']
file['name'] = file['path']
if isinstance(file, StreamFieldFile):
return StreamFieldFile(file, name=file.name, storage=submission_storage)
return StreamFieldFile(None, name=file['name'], filename=file.get('filename'), storage=submission_storage)
@classmethod
def process_file(cls, file):
try:
return cls.stream_file(file)
except TypeError:
return [cls.stream_file(f) for f in file]
@classmethod
def from_db(cls, db, field_names, values):
instance = super().from_db(db, field_names, values)
if 'form_data' in field_names:
# When the form_data is loaded from the DB deserialise it
instance.form_data = cls.deserialised_data(instance.form_data, instance.form_fields)
return instance
@classmethod
def deserialised_data(cls, data, form_fields):
# Converts the file dicts into actual file objects
data = data.copy()
for field in form_fields:
if isinstance(field.block, UploadableMediaBlock):
file = data.get(field.id, [])
data[field.id] = cls.process_file(file)
def get_definitive_id(self, id):
if id in self.must_include:
return self.must_include[id]
return id
def field(self, id):
definitive_id = self.get_definitive_id(id)
return self.raw_fields[definitive_id]
def data(self, id):
definitive_id = self.get_definitive_id(id)
return self.raw_data[definitive_id]
except KeyError as e:
# We have most likely progressed application forms so the data isnt in form_data
return None
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
@property
def question_field_ids(self):
for field_id, field in self.fields.items():
if isinstance(field.block, FormFieldBlock):
yield field_id
@property
def raw_fields(self):
# Field ids to field class mapping - similar to raw_data
return {
field.id: field
for field in self.form_fields
}
@property
def fields(self):
# ALl fields on the application
fields = self.raw_fields.copy()
for field_name, field_id in self.must_include.items():
response = fields.pop(field_id)
fields[field_name] = response
return fields
@property
def must_include(self):
return {
field.block.name: field.id
for field in self.form_fields
if isinstance(field.block, MustIncludeFieldBlock)
}
def render_answer(self, field_id, include_question=False):
field = self.field(field_id)
data = self.data(field_id)
return field.render(context={'data': data, 'include_question': include_question})
def render_answers(self):
# Returns a list of the rendered answers
return [
self.render_answer(field_id, include_question=True)
for field_id in self.question_field_ids
if field_id not in self.must_include
]
def output_answers(self):
# Returns a safe string of the rendered answers
return mark_safe(''.join(self.render_answers()))