Bases: BaseStreamForm
, AccessFormData
, Model
stream_file_class
class-attribute
instance-attribute
storage_class
class-attribute
instance-attribute
question_field_ids
property
question_text_field_ids
property
first_group_question_text_field_ids
property
first_group_question_text_field_ids
group_toggle_blocks
property
first_group_normal_text_blocks
property
first_group_normal_text_blocks
wagtail_reference_index_ignore
class-attribute
instance-attribute
wagtail_reference_index_ignore = True
submission
class-attribute
instance-attribute
submission = ForeignKey('funds.ApplicationSubmission', related_name='revisions', on_delete=CASCADE)
timestamp
class-attribute
instance-attribute
timestamp = DateTimeField(auto_now=True)
author
class-attribute
instance-attribute
author = ForeignKey(AUTH_USER_MODEL, on_delete=SET_NULL, null=True)
is_draft
class-attribute
instance-attribute
is_draft = BooleanField(default=False)
ordering = ['-timestamp']
stream_file
classmethod
stream_file(instance, field, file)
Source code in hypha/apply/funds/models/mixins.py
| @classmethod
def stream_file(cls, instance, field, file):
if not file:
return []
if isinstance(file, cls.stream_file_class):
return file
if isinstance(file, File):
return cls.stream_file_class(
instance, field, file, name=file.name, storage=cls.storage_class()
)
if isinstance(file, PlaceholderUploadedFile):
return cls.stream_file_class(
instance,
field,
None,
name=file.file_id,
filename=file.name,
storage=cls.storage_class(),
)
# This fixes a backwards compatibility issue with #507
# Once every application has been re-saved it should be possible to remove it
if "path" in file:
file["filename"] = file["name"]
file["name"] = file["path"]
return cls.stream_file_class(
instance,
field,
None,
name=file["name"],
filename=file.get("filename"),
storage=cls.storage_class(),
)
|
process_file
classmethod
process_file(instance, field, file)
Source code in hypha/apply/funds/models/mixins.py
| @classmethod
def process_file(cls, instance, field, file):
if isinstance(file, list):
return [cls.stream_file(instance, field, f) for f in file]
else:
return cls.stream_file(instance, field, file)
|
process_file_data
Source code in hypha/apply/funds/models/mixins.py
| def process_file_data(self, data):
for field in self.form_fields:
if isinstance(field.block, UploadableMediaBlock):
file = self.process_file(self, field, data.get(field.id, []))
try:
file.save()
except (AttributeError, FileNotFoundError):
try:
for f in file:
f.save()
except FileNotFoundError:
pass
self.form_data[field.id] = file
|
Source code in hypha/apply/funds/models/mixins.py
| def extract_files(self):
files = {}
for field in self.form_fields:
if isinstance(field.block, UploadableMediaBlock):
files[field.id] = self.data(field.id) or []
self.form_data.pop(field.id, None)
return files
|
from_db
classmethod
from_db(db, field_names, values)
Source code in hypha/apply/stream_forms/models.py
| @classmethod
def from_db(cls, db, field_names, values):
instance = super().from_db(db, field_names, values)
if "form_data" in field_names:
instance.form_data = cls.deserialize_form_data(
instance, instance.form_data, instance.form_fields
)
return instance
|
deserialised_data
classmethod
deserialised_data(instance, data, form_fields)
Source code in hypha/apply/funds/models/mixins.py
| @classmethod
def deserialised_data(cls, instance, data, form_fields):
# Converts the file dicts into actual file objects
data = data.copy()
# PERFORMANCE NOTE:
# Do not attempt to iterate over form_fields - that will fully instantiate the form_fields
# including any sub queries that they do
for i, field_data in enumerate(form_fields.raw_data):
block = form_fields.stream_block.child_blocks[field_data["type"]]
if isinstance(block, UploadableMediaBlock):
field_id = field_data.get("id")
if field_id:
field = form_fields[i]
file = data.get(field_id, [])
data[field_id] = cls.process_file(instance, field, file)
return data
|
get_definitive_id
Source code in hypha/apply/funds/models/mixins.py
| def get_definitive_id(self, id):
if id in self.named_blocks:
return self.named_blocks[id]
return id
|
field
Source code in hypha/apply/funds/models/mixins.py
| def field(self, id):
definitive_id = self.get_definitive_id(id)
try:
return self.raw_fields[definitive_id]
except KeyError:
raise UnusedFieldException(id) from None
|
data
Source code in hypha/apply/funds/models/mixins.py
| def data(self, id):
definitive_id = self.get_definitive_id(id)
try:
return self.raw_data[definitive_id]
except KeyError:
# We have most likely progressed application forms so the data isn't in form_data
return None
|
get_serialize_multi_inputs_answer(field)
Source code in hypha/apply/funds/models/mixins.py
| def get_serialize_multi_inputs_answer(self, field):
number_of_inputs = field.value.get("number_of_inputs")
answers = [self.data(field.id + "_" + str(i)) for i in range(number_of_inputs)]
data = ", ".join(filter(None, answers))
return data
|
serialize
Source code in hypha/apply/funds/models/mixins.py
| def serialize(self, field_id):
field = self.field(field_id)
if isinstance(field.block, MultiInputCharFieldBlock):
data = self.get_serialize_multi_inputs_answer(field)
else:
data = self.data(field_id)
return field.render(
context={
"serialize": True,
"data": data,
}
)
|
get_multi_inputs_answer(field, include_question=False)
Source code in hypha/apply/funds/models/mixins.py
| def get_multi_inputs_answer(self, field, include_question=False):
number_of_inputs = field.value.get("number_of_inputs")
answers = [self.data(field.id + "_" + str(i)) for i in range(number_of_inputs)]
render_data = [
field.render(
context={
"data": answer,
"include_question": include_question if i == 0 else False,
}
)
for i, answer in enumerate(filter(None, answers))
]
return "".join(render_data).replace("</section>", "") + "</section>"
|
render_answer
render_answer(field_id, include_question=False)
Source code in hypha/apply/funds/models/mixins.py
| def render_answer(self, field_id, include_question=False):
try:
field = self.field(field_id)
except UnusedFieldException:
return "-"
if isinstance(field.block, MultiInputCharFieldBlock):
render_data = self.get_multi_inputs_answer(field, include_question)
return render_data
else:
data = self.data(field_id)
# Some migrated content have empty address.
if not data:
return field.render(
context={"data": "", "include_question": include_question}
)
return field.render(
context={"data": data, "include_question": include_question}
)
|
render_answers
Source code in hypha/apply/funds/models/mixins.py
| 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.normal_blocks
]
|
render_first_group_text_answers
render_first_group_text_answers()
Source code in hypha/apply/funds/models/mixins.py
| def render_first_group_text_answers(self):
return [
self.render_answer(field_id, include_question=True)
for field_id in self.first_group_normal_text_blocks
]
|
render_text_blocks_answers
render_text_blocks_answers()
Source code in hypha/apply/funds/models/mixins.py
| def render_text_blocks_answers(self):
# Returns a list of the rendered answers of type text
return [
self.render_answer(field_id, include_question=True)
for field_id in self.question_text_field_ids
if field_id not in self.named_blocks
]
|
output_answers
Source code in hypha/apply/funds/models/mixins.py
| def output_answers(self):
# Returns a safe string of the rendered answers
return mark_safe("".join(self.render_answers()))
|
output_text_answers
Source code in hypha/apply/funds/models/mixins.py
| def output_text_answers(self):
return mark_safe("".join(self.render_text_blocks_answers()))
|
output_first_group_text_answers
output_first_group_text_answers()
Source code in hypha/apply/funds/models/mixins.py
| def output_first_group_text_answers(self):
return mark_safe("".join(self.render_first_group_text_answers()))
|
get_answer_from_label
get_answer_from_label(label)
Source code in hypha/apply/funds/models/mixins.py
| def get_answer_from_label(self, label):
for field_id in self.question_text_field_ids:
if field_id not in self.named_blocks:
question_field = self.serialize(field_id)
if label.lower() in question_field["question"].lower():
if isinstance(question_field["answer"], str):
answer = question_field["answer"]
else:
answer = ",".join(question_field["answer"])
if answer and not answer == "N":
return answer
return None
|
deserialize_form_data(instance, form_data, form_fields)
Source code in hypha/apply/stream_forms/models.py
| @classmethod
def deserialize_form_data(cls, instance, form_data, form_fields):
data = form_data.copy()
# PERFORMANCE NOTE:
# Do not attempt to iterate over form_fields - that will fully instantiate the form_fields
# including any sub queries that they do
for _i, field_data in enumerate(form_fields.raw_data):
block = form_fields.stream_block.child_blocks[field_data["type"]]
field_id = field_data.get("id")
try:
value = data[field_id]
except KeyError:
pass
else:
data[field_id] = block.decode(value)
return data
|
get_defined_fields
Source code in hypha/apply/stream_forms/models.py
| def get_defined_fields(self):
return self.form_fields
|
get_form_fields(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
| def get_form_fields(self, draft=False, form_data=None, user=None):
if form_data is None:
form_data = {}
form_fields = OrderedDict()
field_blocks = self.get_defined_fields()
group_counter = 1
is_in_group = False
# If true option 1 is selected
grouped_fields_visible = False
for struct_child in field_blocks:
block = struct_child.block
struct_value = struct_child.value
if isinstance(block, FormFieldBlock):
field_from_block = block.get_field(struct_value)
disabled_help_text = _(
"You are logged in so this information is fetched from your user account."
)
if isinstance(block, FullNameBlock) and user and user.is_authenticated:
if user.full_name:
field_from_block.disabled = True
field_from_block.initial = user.full_name
field_from_block.help_text = disabled_help_text
else:
field_from_block.help_text = _(
"You are logged in but your user account does not have a "
"full name. We'll update your user account with the name you provide here."
)
if isinstance(block, EmailBlock) and user and user.is_authenticated:
field_from_block.disabled = True
field_from_block.initial = user.email
field_from_block.help_text = disabled_help_text
if draft and not issubclass(
block.__class__, ApplicationMustIncludeFieldBlock
):
field_from_block.required = False
field_from_block.help_link = struct_value.get("help_link")
field_from_block.group_number = group_counter if is_in_group else 1
if isinstance(block, GroupToggleBlock) and not is_in_group:
field_from_block.group_number = 1
field_from_block.grouper_for = group_counter + 1
group_counter += 1
is_in_group = True
grouped_fields_visible = (
form_data.get(struct_child.id) == field_from_block.choices[0][0]
)
if isinstance(block, TextFieldBlock):
field_from_block.word_limit = struct_value.get("word_limit")
if isinstance(block, MultiInputCharFieldBlock):
number_of_inputs = struct_value.get("number_of_inputs")
for index in range(number_of_inputs):
form_fields[struct_child.id + "_" + str(index)] = (
field_from_block
)
field_from_block.multi_input_id = struct_child.id
field_from_block.add_button_text = struct_value.get(
"add_button_text"
)
if (
index == number_of_inputs - 1
): # Add button after last input field
field_from_block.multi_input_add_button = True
# Index for field until which fields will be visible to applicant.
# Initially only the first field with id UUID_0 will be visible.
field_from_block.visibility_index = 0
field_from_block.max_index = index
if index != 0:
field_from_block.multi_input_field = True
field_from_block.required = False
field_from_block.initial = None
field_from_block = copy.copy(field_from_block)
else:
if is_in_group and not isinstance(block, GroupToggleBlock):
field_from_block.required_when_visible = (
field_from_block.required
)
field_from_block.required = (
field_from_block.required & grouped_fields_visible
)
field_from_block.visible = grouped_fields_visible
form_fields[struct_child.id] = field_from_block
elif isinstance(block, GroupToggleEndBlock):
# Group toggle end block is used only to group fields and not used in actual form.
# Todo: Use streamblock to create nested form field blocks, a more elegant method to group form fields.
is_in_group = False
else:
field_wrapper = BlockFieldWrapper(struct_child)
field_wrapper.group_number = group_counter if is_in_group else 1
form_fields[struct_child.id] = field_wrapper
return form_fields
|
get_form_class(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
| def get_form_class(self, draft=False, form_data=None, user=None):
return type(
"WagtailStreamForm",
(self.submission_form_class,),
self.get_form_fields(draft, form_data, user),
)
|
get_compare_url_to_latest
get_compare_url_to_latest()
Source code in hypha/apply/funds/models/application_revisions.py
| def get_compare_url_to_latest(self):
return reverse(
"funds:submissions:revisions:compare",
kwargs={
"submission_pk": self.submission.id,
"to": self.submission.live_revision.id,
"from": self.id,
},
)
|
get_absolute_url
Source code in hypha/apply/funds/models/application_revisions.py
| def get_absolute_url(self):
# Compares against the previous revision
previous_revision = self.submission.revisions.filter(id__lt=self.id).first()
return reverse(
"funds:submissions:revisions:compare",
kwargs={
"submission_pk": self.submission.id,
"to": self.id,
"from": previous_revision.id,
},
)
|