Skip to content

Blocks

hypha.apply.utils.blocks

RichTextFieldBlock

Bases: TextFieldBlock

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

field_class class-attribute instance-attribute

field_class = CharField

required class-attribute instance-attribute

required = BooleanBlock(label=gettext_lazy('Required'), required=False)

default_value class-attribute instance-attribute

default_value = TextBlock(required=False, label=gettext_lazy('Default value'))

word_limit class-attribute instance-attribute

word_limit = IntegerBlock(default=1000, label=gettext_lazy('Word limit'))

widget class-attribute instance-attribute

Meta

label class-attribute instance-attribute
label = gettext_lazy('Rich text field')
icon class-attribute instance-attribute
icon = 'form'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = {
        "label": struct_value["field_label"],
        "help_text": conditional_escape(struct_value["help_text"]),
        "required": struct_value.get("required", False),
    }
    if "default_value" in struct_value:
        kwargs["initial"] = struct_value["default_value"]
    form_widget = self.get_widget(struct_value)
    if form_widget is not None:
        kwargs["widget"] = form_widget
    return kwargs

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return bleach_value(str(data))

render

render(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def render(self, value, context):
    data = context.get("data")
    data = self.prepare_data(value, data, context.get("serialize", False))

    context.update(data=data or self.no_response())

    if context.get("serialize"):
        if not data:
            return self.serialize_no_response(value, context)
        return self.serialize(value, context)

    return super().render(value, context)

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/utils/blocks.py
def get_searchable_content(self, value, data):
    return bleach.clean(data or "", tags=[], strip=True)

no_response

no_response()
Source code in hypha/apply/utils/blocks.py
def no_response(self):
    return "<p>-</p>"

MarkdownTextFieldBlock

Bases: TextFieldBlock

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

field_class class-attribute instance-attribute

field_class = CharField

required class-attribute instance-attribute

required = BooleanBlock(label=gettext_lazy('Required'), required=False)

default_value class-attribute instance-attribute

default_value = TextBlock(required=False, label=gettext_lazy('Default value'))

word_limit class-attribute instance-attribute

word_limit = IntegerBlock(default=1000, label=gettext_lazy('Word limit'))

widget class-attribute instance-attribute

widget = PagedownWidget()

template class-attribute instance-attribute

template = ''

Meta

label class-attribute instance-attribute
label = gettext_lazy('Markdown text field')
icon class-attribute instance-attribute
icon = 'form'
template class-attribute instance-attribute
template = 'stream_forms/render_markdown_field.html'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = {
        "label": struct_value["field_label"],
        "help_text": conditional_escape(struct_value["help_text"]),
        "required": struct_value.get("required", False),
    }
    if "default_value" in struct_value:
        kwargs["initial"] = struct_value["default_value"]
    form_widget = self.get_widget(struct_value)
    if form_widget is not None:
        kwargs["widget"] = form_widget
    return kwargs

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return bleach_value(str(data))

render

render(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def render(self, value, context):
    data = context.get("data")
    data = self.prepare_data(value, data, context.get("serialize", False))

    context.update(data=data or self.no_response())

    if context.get("serialize"):
        if not data:
            return self.serialize_no_response(value, context)
        return self.serialize(value, context)

    return super().render(value, context)

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/utils/blocks.py
def get_searchable_content(self, value, data):
    return bleach.clean(data or "", tags=[], strip=True)

no_response

no_response()
Source code in hypha/apply/utils/blocks.py
def no_response(self):
    return "<p>-</p>"

CustomFormFieldsBlock

CustomFormFieldsBlock(*args, **kwargs)

Bases: StreamBlock

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    # The space before " Required" is to make the group sort first. Ugly but easy, and it works.
    child_blocks = [
        (block.name, block(group=_(" Required"))) for block in self.required_blocks
    ]
    child_blocks += [
        (block.name, block(group=_("Custom"))) for block in self.single_blocks
    ]
    self.required_block_names = [block.name for block in self.required_blocks]
    self.single_block_names = [
        block.name for block in self.single_blocks
    ] + self.required_block_names

    super().__init__(child_blocks, *args, **kwargs)

rich_text class-attribute instance-attribute

rich_text = RichTextFieldBlock(group=gettext_lazy('Fields'))

markdown_text class-attribute instance-attribute

markdown_text = MarkdownTextFieldBlock(group=gettext_lazy('Fields'))

required_blocks class-attribute instance-attribute

required_blocks = []

single_blocks class-attribute instance-attribute

single_blocks = []

required_block_names instance-attribute

required_block_names = [name for block in required_blocks]

single_block_names instance-attribute

single_block_names = [name for block in single_blocks] + required_block_names

clean

clean(value)
Source code in hypha/apply/utils/blocks.py
def clean(self, value):
    try:
        value = super().clean(value)
    except ValidationError as e:
        error_dict = e.params or {}
    else:
        error_dict = {}

    block_types = [block.block_type for block in value]
    missing = set(self.required_block_names) - set(block_types)

    duplicates = [
        name
        for name in find_duplicates(block_types)
        if name in self.single_block_names
    ]

    all_errors = []
    if missing:
        all_errors.append(
            "You are missing the following required fields: {}".format(
                ", ".join(prettify_names(missing))
            )
        )

    if duplicates:
        all_errors.append(
            "The following fields must be included only once: {}".format(
                ", ".join(prettify_names(duplicates))
            )
        )
        for i, block_name in enumerate(block_types):
            if block_name in duplicates:
                self.add_error_to_child(error_dict, i, "info", "Duplicate field")

    for block in value:
        if hasattr(block.block, "child_blocks"):
            for child_block_name, child_block in block.block.child_blocks.items():
                if child_block.required and not block.value[child_block_name]:
                    all_errors.append(
                        "{} cannot be empty for {}".format(
                            child_block.label, block.block.label
                        )
                    )
                if (
                    isinstance(child_block, ListBlock)
                    and child_block.child_block.required
                ):
                    for child_value in block.value[child_block_name]:
                        if not child_value:
                            all_errors.append(
                                "{} cannot be empty for {}".format(
                                    child_block.label, block.block.label
                                )
                            )

    if all_errors or error_dict:
        error_dict["__all__"] = all_errors
        raise ValidationError(all_errors, params=error_dict)

    return value

add_error_to_child

add_error_to_child(errors, child_number, field, message)
Source code in hypha/apply/utils/blocks.py
def add_error_to_child(self, errors, child_number, field, message):
    new_error = ErrorList([message])
    try:
        errors[child_number].data[0].params[field] = new_error
    except KeyError:
        errors[child_number] = ErrorList(
            [ValidationError("Error", params={field: new_error})]
        )

to_python

to_python(value)

This allows historic data to still be accessible even if a custom field type is removed from the code in the future.

Source code in hypha/apply/utils/blocks.py
def to_python(self, value):
    """
    This allows historic data to still be accessible even
    if a custom field type is removed from the code in the future.
    """
    # If the data type is missing, fallback to a CharField
    for child_data in value:
        if child_data["type"] not in self.child_blocks:
            child_data["type"] = "char"

    return StreamValue(self, value, is_lazy=True)

SingleIncludeStatic

SingleIncludeStatic(*args, description='', **kwargs)

Bases: StaticBlock

Helper block which displays additional information about the must include block and helps display the error in a noticeable way.

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, description="", **kwargs):
    self.description = description
    super().__init__(*args, **kwargs)

description instance-attribute

description = description

Meta

admin_text class-attribute instance-attribute
admin_text = 'Must be included in the form only once.'

render_form

render_form(*args, **kwargs)
Source code in hypha/apply/utils/blocks.py
def render_form(self, *args, **kwargs):
    errors = kwargs.pop("errors")
    if errors:
        # Pretend the error is a readonly input so that we get nice formatting
        # Issue discussed here: https://github.com/wagtail/wagtail/issues/4122
        error_message = (
            '<div class="error"><input readonly placeholder="{}"></div>'.format(
                errors[0]
            )
        )
    else:
        error_message = ""
    form = super().render_form(*args, **kwargs)
    form = "<br>".join([self.description, form]) + error_message
    return mark_safe(form)

deconstruct

deconstruct()
Source code in hypha/apply/utils/blocks.py
def deconstruct(self):
    return ("wagtail.blocks.static_block.StaticBlock", (), {})

SingleIncludeMixin

SingleIncludeMixin(*args, **kwargs)
Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    info_name = (
        f"{self._meta_class.label} Field"
        if self._meta_class.label
        else f"{self.name.title()} Field"
    )
    child_blocks = [
        ("info", SingleIncludeStatic(label=info_name, description=self.description))
    ]
    super().__init__(child_blocks, *args, **kwargs)

SingleIncludeBlock

SingleIncludeBlock(*args, **kwargs)

Bases: SingleIncludeMixin, OptionalFormFieldBlock

A block that is only allowed to be included once in the form, but is optional

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    info_name = (
        f"{self._meta_class.label} Field"
        if self._meta_class.label
        else f"{self.name.title()} Field"
    )
    child_blocks = [
        ("info", SingleIncludeStatic(label=info_name, description=self.description))
    ]
    super().__init__(child_blocks, *args, **kwargs)

MustIncludeFieldBlock

MustIncludeFieldBlock(*args, **kwargs)

Bases: SingleIncludeMixin, FormFieldBlock

Any block inheriting from this will need to be included in the application forms This data will also be available to query on the submission object

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    info_name = (
        f"{self._meta_class.label} Field"
        if self._meta_class.label
        else f"{self.name.title()} Field"
    )
    child_blocks = [
        ("info", SingleIncludeStatic(label=info_name, description=self.description))
    ]
    super().__init__(child_blocks, *args, **kwargs)

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

field_class class-attribute instance-attribute

field_class = CharField

widget class-attribute instance-attribute

widget = None

Meta

template class-attribute instance-attribute
template = 'stream_forms/render_field.html'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return bleach_value(str(data))

render

render(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def render(self, value, context):
    data = context.get("data")
    data = self.prepare_data(value, data, context.get("serialize", False))

    context.update(data=data or self.no_response())

    if context.get("serialize"):
        if not data:
            return self.serialize_no_response(value, context)
        return self.serialize(value, context)

    return super().render(value, context)

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/stream_forms/blocks.py
def get_searchable_content(self, value, data):
    return str(data)

no_response

no_response()
Source code in hypha/apply/stream_forms/blocks.py
def no_response(self):
    return "-"

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/utils/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = super().get_field_kwargs(struct_value)
    kwargs["required"] = True
    return kwargs

find_duplicates

find_duplicates(items)
Source code in hypha/apply/utils/blocks.py
def find_duplicates(items):
    counted = Counter(items)
    duplicates = [name for name, count in counted.items() if count > 1]
    return duplicates

prettify_names

prettify_names(sequence)
Source code in hypha/apply/utils/blocks.py
def prettify_names(sequence):
    return [nice_field_name(item) for item in sequence]

nice_field_name

nice_field_name(name)
Source code in hypha/apply/utils/blocks.py
def nice_field_name(name):
    return name.title().replace("_", " ")

show_admin_form_error_messages

show_admin_form_error_messages(request, form)
Source code in hypha/apply/utils/blocks.py
def show_admin_form_error_messages(request, form):
    for err in form.errors.values():
        if isinstance(err, list):
            for form_field_error in err:
                messages.error(request, form_field_error)
        else:
            messages.error(request, err.as_text())