示例#1
0
    def _update_questionnaire_store_with_form_data(self, answers):
        survey_answer_ids = self._schema.get_answer_ids_for_block(
            self._current_location.block_id)

        for answer_id, answer_value in answers.items():

            # If answer is not answered then check for a schema specified default
            if answer_value is None:
                answer_value = self._schema.get_answer(answer_id).get(
                    'default')

            if answer_id in survey_answer_ids:
                if answer_value is not None:
                    answer = Answer(
                        answer_id=answer_id,
                        value=answer_value,
                        group_instance_id=get_group_instance_id(
                            self._schema, self._answer_store,
                            self._current_location),
                        group_instance=self._current_location.group_instance)

                    latest_answer_store_hash = self._answer_store.get_hash()
                    self._answer_store.add_or_update(answer)

                    if latest_answer_store_hash != self._answer_store.get_hash(
                    ) and self._schema.answer_dependencies[answer_id]:
                        self._remove_dependent_answers_from_completed_blocks(
                            answer_id)
                else:
                    self._remove_answer_from_questionnaire_store(answer_id)
def build_view_context_for_calculated_summary(metadata, schema, answer_store,
                                              schema_context, block_type,
                                              variables, current_location):
    block = schema.get_block(current_location.block_id)
    section_list = _build_calculated_summary_section_list(
        schema, block, current_location.group_id)

    context = build_view_context_for_summary(schema, section_list,
                                             answer_store, metadata,
                                             block_type, variables,
                                             schema_context)

    context['summary']['groups'] = [
        context['summary']['groups'][current_location.group_instance]
    ]
    schema_context['group_instance_id'] = get_group_instance_id(
        schema, answer_store, current_location)
    rendered_block = renderer.render(block, **schema_context)
    formatted_total = _get_formatted_total(context['summary'].get(
        'groups', []))

    context['summary'].update({
        'calculated_question':
        _get_calculated_question(rendered_block['calculation'], answer_store,
                                 schema, metadata,
                                 current_location.group_instance,
                                 formatted_total),
        'title':
        get_question_title(rendered_block, answer_store, schema, metadata,
                           current_location.group_instance) %
        dict(total=formatted_total),
    })
    return context
def get_form_for_location(schema, block_json, location, answer_store, metadata, disable_mandatory=False):  # pylint: disable=too-many-locals
    """
    Returns the form necessary for the location given a get request, plus any template arguments

    :param schema: schema
    :param block_json: The block json
    :param location: The location which this form is for
    :param answer_store: The current answer store
    :param metadata: metadata
    :param disable_mandatory: Make mandatory answers optional
    :return: form, template_args A tuple containing the form for this location and any additional template arguments
    """
    if disable_mandatory:
        block_json = disable_mandatory_answers(block_json)

    if location.block_id == 'household-composition':
        answer_ids = schema.get_answer_ids_for_block(location.block_id)
        answers = answer_store.filter(answer_ids, location.group_instance)

        data = deserialise_composition_answers(answers)

        return generate_household_composition_form(schema, block_json, data, metadata, location.group_instance)

    group_instance_id = get_group_instance_id(schema, answer_store, location)

    if schema.block_has_question_type(location.block_id, 'Relationship'):
        answer_ids = schema.get_answer_ids_for_block(location.block_id)
        group = schema.get_group(location.group_id)
        answers = answer_store.filter(answer_ids, location.group_instance)

        data = deserialise_relationship_answers(answers)

        # Relationship block only supports 1 question
        question = schema.get_question(block_json['questions'][0]['id'])

        answer_ids = []

        repeat_rule = group['routing_rules'][0]['repeat']
        if 'answer_ids' in repeat_rule:
            for answer_id in repeat_rule['answer_ids']:
                answer_ids.append(answer_id)
        if 'answer_id' in repeat_rule:
            answer_ids.append(repeat_rule['answer_id'])

        relationship_choices = build_relationship_choices(answer_ids, answer_store, location.group_instance, question.get('member_label'))

        form = generate_relationship_form(schema, block_json, relationship_choices, data, location.group_instance, group_instance_id)

        return form

    mapped_answers = get_mapped_answers(
        schema,
        answer_store,
        group_instance=location.group_instance,
        group_instance_id=group_instance_id,
        block_id=location.block_id,
    )

    return generate_form(schema, block_json, answer_store, metadata, location.group_instance, group_instance_id, data=mapped_answers)
示例#4
0
def post_form_for_location(schema,
                           block_json,
                           location,
                           answer_store,
                           metadata,
                           request_form,
                           disable_mandatory=False):
    """
    Returns the form necessary for the location given a post request, plus any template arguments

    :param block_json: The block json
    :param location: The location which this form is for
    :param answer_store: The current answer store
    :param metadata: metadata
    :param request_form: form, template_args A tuple containing the form for this location and any additional template arguments
    :param error_messages: The default error messages to use within the form
    :param disable_mandatory: Make mandatory answers optional
    """

    if disable_mandatory:
        block_json = disable_mandatory_answers(block_json)

    if location.block_id == 'household-composition':
        return generate_household_composition_form(schema, block_json,
                                                   request_form, metadata,
                                                   location.group_instance)

    group_instance_id = get_group_instance_id(schema, answer_store, location)

    if schema.block_has_question_type(location.block_id, 'Relationship'):
        group = schema.get_group(location.group_id)

        answer_ids = []

        repeat_rule = group['routing_rules'][0]['repeat']
        if 'answer_ids' in repeat_rule:
            for answer_id in repeat_rule['answer_ids']:
                answer_ids.append(answer_id)
        if 'answer_id' in repeat_rule:
            answer_ids.append(repeat_rule['answer_id'])

        relationship_choices = build_relationship_choices(
            answer_ids, answer_store, location.group_instance)
        form = generate_relationship_form(schema, block_json,
                                          relationship_choices, request_form,
                                          location.group_instance,
                                          group_instance_id)

        return form

    data = clear_other_text_field(request_form,
                                  schema.get_questions_for_block(block_json))
    return generate_form(schema,
                         block_json,
                         answer_store,
                         metadata,
                         location.group_instance,
                         group_instance_id,
                         formdata=data)
示例#5
0
def build_view_context_for_question(metadata, schema, answer_store,
                                    current_location, variables,
                                    rendered_block, form):  # noqa: C901, E501  pylint: disable=too-complex,line-too-long,too-many-locals

    context = {
        'variables': variables,
        'block': rendered_block,
        'csrf_token': form.csrf_token,
        'question_titles': {},
        'form': {
            'errors': form.errors,
            'question_errors': form.question_errors,
            'mapped_errors': form.map_errors(),
            'answer_errors': {},
            'data': {},
            'other_answer': {},
            'fields': {},
        },
    }

    answer_ids = []
    for question in rendered_block.get('questions'):
        if question.get('titles'):
            group_instance_id = get_group_instance_id(schema, answer_store,
                                                      current_location)
            context['question_titles'][question['id']] = get_title_from_titles(
                metadata, schema, answer_store, question['titles'],
                current_location.group_instance, group_instance_id)
        for answer in question['answers']:
            if current_location.block_id == 'household-composition':
                for repeated_form in form.household:
                    answer_ids.append(repeated_form.form[answer['id']].id)
            else:
                answer_ids.append(answer['id'])

            if answer['type'] in ('Checkbox', 'Radio'):
                options = answer['options']
                context['form']['other_answer'][answer['id']] = []
                for index in range(len(options)):
                    context['form']['other_answer'][answer['id']].append(
                        form.get_other_answer(answer['id'], index))

    for answer_id in answer_ids:
        context['form']['answer_errors'][answer_id] = form.answer_errors(
            answer_id)

        if hasattr(form, 'get_data'):
            context['form']['data'][answer_id] = form.get_data(answer_id)

        if answer_id in form:
            context['form']['fields'][answer_id] = form[answer_id]

    if current_location.block_id in ['household-composition']:
        context['form']['household'] = form.household

    return context
示例#6
0
    def __init__(self, group_schema, path, answer_store, metadata, schema, group_instance, schema_context):
        self.id = group_schema['id'] + '-' + str(group_instance)
        self.schema_context = schema_context

        location = Location(group_schema['id'], group_instance, group_schema['blocks'][0]['id'])
        self.group_instance_id = get_group_instance_id(schema, answer_store, location)

        self.title = self._get_title(group_schema, schema, answer_store, group_instance)

        self.blocks = self._build_blocks(group_schema, path, answer_store, metadata, schema, group_instance)
示例#7
0
    def _update_questionnaire_store_with_answer_data(self, answers):
        survey_answer_ids = self._schema.get_answer_ids_for_block(
            self._current_location.block_id)

        valid_answers = (answer for answer in answers
                         if answer.answer_id in survey_answer_ids)

        for answer in valid_answers:
            answer.group_instance_id = get_group_instance_id(
                self._schema, self._answer_store, self._current_location,
                answer.answer_instance)
            self._answer_store.add_or_update(answer)
示例#8
0
    def _evaluate_routing_rules(self, this_location, blocks, block, block_index, path):
        for rule in filter(is_goto_rule, block['routing_rules']):
            group_instance_id = get_group_instance_id(self.schema, self.answer_store, this_location)
            should_goto = evaluate_goto(rule['goto'],
                                        self.schema,
                                        self.metadata,
                                        self.answer_store,
                                        this_location.group_instance,
                                        group_instance_id=group_instance_id,
                                        routing_path=path)

            if should_goto:
                return self._follow_routing_rule(this_location, rule, blocks, block_index, path)
示例#9
0
def update_questionnaire_store_with_answer_data(questionnaire_store, location,
                                                answers, schema):

    survey_answer_ids = schema.get_answer_ids_for_block(location.block_id)

    for answer in [a for a in answers if a.answer_id in survey_answer_ids]:
        answer.group_instance_id = get_group_instance_id(
            schema, questionnaire_store.answer_store, location,
            answer.answer_instance)
        questionnaire_store.answer_store.add_or_update(answer)

    if location not in questionnaire_store.completed_blocks:
        questionnaire_store.completed_blocks.append(location)
示例#10
0
    def build_path(self):
        """
        Visits all the blocks from a location forwards and returns path
        taken given a list of answers.

        :param blocks: A list containing all block content in the survey
        :param this_location: The location to visit, represented as a dict
        :return: A list of locations followed through the survey
        """
        this_location = None

        blocks = []
        path = []
        block_index = 0
        first_groups = self._get_first_group_in_section()

        for group in self.schema.groups:
            first_block_in_group = self.schema.get_first_block_id_for_group(group['id'])
            if not this_location:
                this_location = Location(group['id'], 0, first_block_in_group)

            no_of_repeats = get_number_of_repeats(group, self.schema, path, self.answer_store)

            first_group_instance_index = None
            for group_instance in range(0, no_of_repeats):

                if 'skip_conditions' in group:
                    group_instance_id = get_group_instance_id(self.schema, self.answer_store, Location(group['id'], group_instance, first_block_in_group))

                    if evaluate_skip_conditions(group['skip_conditions'], self.schema, self.metadata,
                                                self.answer_store, group_instance, group_instance_id,
                                                routing_path=path):
                        continue

                group_blocks = list(self._build_blocks_for_group(group, group_instance))
                blocks += group_blocks

                if group_blocks and first_group_instance_index is None:
                    # get the group instance of the first instance of a block in this group that has not been skipped
                    first_group_instance_index = group_blocks[0]['group_instance']

            all_blocks_skipped = first_group_instance_index is None

            if not all_blocks_skipped:
                if group['id'] in first_groups:
                    this_location = Location(group['id'], first_group_instance_index, first_block_in_group)

                if blocks:
                    path, block_index = self._build_path_within_group(blocks, block_index, this_location, path)

        return path
示例#11
0
    def _generate_link_name(self, label_answer_ids, location):
        link_names = []

        group_instance_id = get_group_instance_id(self.schema,
                                                  self.answer_store, location)

        for answer_id in label_answer_ids:
            for answer in self.answer_store.filter(
                    answer_ids=[answer_id],
                    group_instance_id=group_instance_id).escaped():
                if answer['value']:
                    link_names.append(answer['value'])

        return ' '.join(link_names)
示例#12
0
def _get_schema_context(full_routing_path, location, metadata,
                        collection_metadata, answer_store, schema):
    answer_ids_on_path = get_answer_ids_on_routing_path(
        schema, full_routing_path)
    group_instance_id = get_group_instance_id(schema, answer_store,
                                              location) if location else None

    return build_schema_context(
        metadata=metadata,
        collection_metadata=collection_metadata,
        schema=schema,
        answer_store=answer_store,
        group_instance=location.group_instance if location else 0,
        group_instance_id=group_instance_id,
        answer_ids_on_path=answer_ids_on_path)
示例#13
0
def upgrade_to_2_add_group_instance_id(answer_store, schema):
    """ Answers should have a `group_instance_id` ready for more complex group repeat rules. """
    from app.questionnaire.location import Location
    from app.helpers.schema_helpers import get_group_instance_id

    for answer in answer_store:
        # Happily, parent_id's are patched on to the schema for each nested level, so we can
        # retrieve the block_id and group_id for the answer we're processing here.
        answer_schema = schema.get_answer(answer['answer_id'])
        question = schema.get_question(answer_schema['parent_id'])
        block_id = question['parent_id']
        block = schema.get_block(question['parent_id'])
        group_id = block['parent_id']

        location = Location(
            group_id=group_id,
            group_instance=answer['group_instance'],
            block_id=block_id,
        )
        # `get_group_instance_id` handles providing a consistent group_instance_id
        answer['group_instance_id'] = get_group_instance_id(schema, answer_store, location, answer['answer_instance'])
示例#14
0
def update_questionnaire_store_with_form_data(questionnaire_store, location,
                                              answer_dict, schema):

    survey_answer_ids = schema.get_answer_ids_for_block(location.block_id)

    for answer_id, answer_value in answer_dict.items():

        # If answer is not answered then check for a schema specified default
        if answer_value is None:
            answer_value = schema.get_answer(answer_id).get('default')

        if answer_id in survey_answer_ids or location.block_id == 'household-composition':
            if answer_value is not None:
                answer = Answer(answer_id=answer_id,
                                value=answer_value,
                                group_instance_id=get_group_instance_id(
                                    schema, questionnaire_store.answer_store,
                                    location),
                                group_instance=location.group_instance)

                latest_answer_store_hash = questionnaire_store.answer_store.get_hash(
                )
                questionnaire_store.answer_store.add_or_update(answer)
                if latest_answer_store_hash != questionnaire_store.answer_store.get_hash(
                ) and schema.answer_dependencies[answer_id]:
                    _remove_dependent_answers_from_completed_blocks(
                        answer_id, location.group_instance,
                        questionnaire_store, schema)
            else:
                _remove_answer_from_questionnaire_store(
                    answer_id,
                    questionnaire_store,
                    group_instance=location.group_instance)

    if location not in questionnaire_store.completed_blocks:
        questionnaire_store.completed_blocks.append(location)
示例#15
0
    def test_get_group_instance_id(self):
        questionnaire = {
            'sections': [{
                'id': 'section1',
                'groups': [
                    {
                        'id': 'group1',
                        'blocks': [
                            {
                                'id': 'block1',
                                'questions': [{
                                    'id': 'question1',
                                    'type': 'Question',
                                    'answers': [
                                        {
                                            'id': 'answer1',
                                            'type': 'TextArea'
                                        }
                                    ]
                                }]
                            }
                        ]
                    },
                    {
                        'id': 'group2',
                        'blocks': [
                            {
                                'id': 'block2',
                                'questions': [{
                                    'id': 'question2',
                                    'type': 'Question',
                                    'answers': [
                                        {
                                            'id': 'answer2',
                                            'type': 'TextArea'
                                        }
                                    ]
                                }]
                            }
                        ],
                        'routing_rules': [{
                            'repeat': {
                                'type': 'group',
                                'group_ids': ['group1']
                            }
                        }]
                    }
                ]
            }]
        }
        schema = QuestionnaireSchema(questionnaire)

        answer_1 = Answer(
            answer_id='answer1',
            group_instance_id='group1-aaa',
            group_instance=0,
            value=25,
        )
        answer_2 = Answer(
            answer_id='answer1',
            group_instance_id='group1-bbb',
            group_instance=1,
            value=65,
        )

        store = AnswerStore(None)
        store.add_or_update(answer_1)
        store.add_or_update(answer_2)

        location = Location('group2', 0, 'block2')
        self.assertEqual(get_group_instance_id(schema, store, location), 'group1-aaa')

        location = Location('group2', 1, 'block2')
        self.assertEqual(get_group_instance_id(schema, store, location), 'group1-bbb')