예제 #1
0
    def test_interstitial_post_blocks(self):
        survey = load_schema_file("0_star_wars.json")
        navigator = Navigator(survey)

        answers = {
            "ca3ce3a3-ae44-4e30-8f85-5b6a7a2fb23c": "Light Side"
        }

        self.assertFalse('summary' in navigator.get_location_path(answers))
class QuestionnaireManager(object):
    '''
    This class represents a user journey through a survey. It models the request/response process of the web application
    '''
    def __init__(self, schema, json=None):
        self._json = json
        self._schema = schema
        self.state = None

        self.navigator = Navigator(self._json)

    def validate(self, location, post_data):

        answers = get_answers(current_user)

        if location in self.navigator.get_location_path(answers):

            self.build_state(location, post_data)

            if self.state:
                self._conditional_display(self.state)
                is_valid = self.state.schema_item.validate(self.state)
                # Todo, this doesn't feel right, validation is casting the user values to their type.

                return is_valid

            else:
                # Item has node, but is not in schema: must be introduction, thank you or summary
                return True
        else:
            # Not a validation location, so can't be valid
            return False

    def validate_all_answers(self):

        answers = get_answers(current_user)

        for location in self.navigator.get_location_path(answers):
            is_valid = self.validate(location, get_answers(current_user))

            if not is_valid:
                logger.debug("Failed validation with current location %s", location)
                return False, location

        return True, None

    def process_incoming_answers(self, location, post_data):
        logger.debug("Processing post data for %s", location)

        is_valid = self.validate(location, post_data)
        # run the validator to update the validation_store
        if is_valid:

            # Store answers in QuestionnaireStore
            questionnaire_store = get_questionnaire_store(current_user.user_id, current_user.user_ik)

            for answer in self.get_state_answers(location):
                questionnaire_store.answers[answer.id] = answer.value

            if location not in questionnaire_store.completed_blocks:
                questionnaire_store.completed_blocks.append(location)

            questionnaire_store.save()

        return is_valid

    def get_rendering_context(self, location, is_valid=True):

        if is_valid:
            if location == 'summary':
                return self.get_summary_rendering_context()
            else:
                # apply page answers?
                self.build_state(location, get_answers(current_user))

        if self.state:
            self._plumbing_preprocessing()
            self._conditional_display(self.state)

        # look up the preprocessor and then build the view data
        return build_questionnaire_model(self._json, self.state)

    def get_summary_rendering_context(self):
        schema_template_context = get_schema_template_context(self, self._schema)
        rendered_questionnaire_schema_json = render_template_string(json.dumps(self._json), **schema_template_context)

        # look up the preprocessor and then build the view data
        return build_summary_model(json.loads(rendered_questionnaire_schema_json))

    def build_state(self, item_id, answers):
        # Build the state from the answers
        self.state = None
        if self._schema.item_exists(item_id):
            schema_item = self._schema.get_item_by_id(item_id)
            self.state = schema_item.construct_state()
            self.state.update_state(answers)

    def get_state_answers(self, item_id):
        # get the answers from the state
        if self._schema.item_exists(item_id):
            return self.state.get_answers()

        return []

    def _plumbing_preprocessing(self):
        # Run the current state through the plumbing preprocessor
        plumbing_template_preprocessor = PlumbingPreprocessor()
        plumbing_template_preprocessor.plumb_current_state(self, self.state, self._schema)

    def _conditional_display(self, item):
        # Process any conditional display rules

        if item.schema_item:

            item.skipped = False

            if hasattr(item.schema_item, 'skip_condition') and item.schema_item.skip_condition:
                rule = item.schema_item.skip_condition.__dict__
                rule['when'] = rule['when'].__dict__
                answer = get_answers(current_user).get(rule['when']['id'])

                item.skipped = evaluate_rule(rule, answer)

            for child in item.children:
                self._conditional_display(child)

    def get_schema_item_by_id(self, item_id):
        return self._schema.get_item_by_id(item_id)

    def get_schema(self):
        return self._schema