示例#1
0
    def post(self, exploration_id, state_id):
        """Handles feedback interactions with readers."""
        values = {}

        exploration = Exploration.get(exploration_id)
        old_state = exploration.get_state_by_id(state_id)

        # The reader's answer.
        answer = self.payload.get('answer')
        # The answer handler (submit, click, etc.)
        handler = self.payload.get('handler')
        # The 0-based index of the last content block already on the page.
        block_number = self.payload.get('block_number') + 1

        params = self.payload.get('params', {})
        params['answer'] = answer

        rule = old_state.classify(handler, answer, params)
        new_state_id = rule.dest
        feedback = rule.get_feedback_string()

        recorded_answer = answer
        # TODO(sll): This is a special case for multiple-choice input
        # which should really be handled generically.
        if old_state.widget.widget_id == 'interactive-MultipleChoiceInput':
            recorded_answer = old_state.widget.params['choices'][int(answer)]

        if recorded_answer is not None:
            recorded_answer = json.dumps(recorded_answer)
            EventHandler.record_rule_hit(
                exploration_id, state_id, rule, recorded_answer)
            # Add this answer to the state's 'unresolved answers' list.
            if recorded_answer not in old_state.unresolved_answers:
                old_state.unresolved_answers[recorded_answer] = 0
            old_state.unresolved_answers[recorded_answer] += 1
            # TODO(sll): Make this async?
            old_state.put()

        html_output, widget_output = '', []
        old_params = params

        if new_state_id == feconf.END_DEST:
            # This leads to a FINISHED state.
            new_state = None
            if feedback:
                html_output, widget_output = self._append_feedback(
                    feedback, html_output, widget_output, block_number,
                    old_params)
            EventHandler.record_exploration_completed(exploration_id)
        else:
            new_state = exploration.get_state_by_id(new_state_id)
            EventHandler.record_state_hit(exploration_id, new_state_id)

            if feedback:
                html_output, widget_output = self._append_feedback(
                    feedback, html_output, widget_output, block_number,
                    old_params)

            # Populate new parameters.
            params = get_params(new_state, existing_params=old_params)
            # Append text for the new state only if the new and old states
            # differ.
            if old_state.id != new_state.id:
                state_html, state_widgets = parse_content_into_html(
                    new_state.content, block_number, params)
                # Separate text for the new state and feedback for the old state
                # by an additional line.
                if state_html and feedback:
                    html_output += '<br>'
                html_output += state_html
                widget_output += state_widgets

        # Render the response in the customized html if
        # - the response is not rendered in the sticky interactive widget, and
        # - there is a static rendering html provided for that widget.
        sticky = (
            new_state_id != feconf.END_DEST and
            new_state.widget.sticky and
            new_state.widget.widget_id == old_state.widget.widget_id
        )
        custom_response = ''
        if not sticky:
            response_params = utils.parse_dict_with_params(
                old_state.widget.params, old_params)
            response_params['answer'] = old_params['answer']
            response_params['iframe_content'] = False
            custom_response = InteractiveWidget.get_raw_static_code(
                old_state.widget.widget_id, response_params)

            if custom_response:
                response_params['iframe_content'] = True
                values['response_iframe'] = (
                    InteractiveWidget.get_raw_static_code(
                        old_state.widget.widget_id, response_params)
                )

        # Append reader's answer.
        response = custom_response if custom_response else answer
        if sticky:
            response = ''
        values['reader_html'] = self.jinja2_env.get_template(
            'reader/reader_response.html').render({
                'response': response,
                'custom_response': bool(custom_response),
            })

        if new_state_id != feconf.END_DEST and new_state.widget.widget_id in DEFAULT_ANSWERS:
            values['default_answer'] = DEFAULT_ANSWERS[new_state.widget.widget_id]
        values['state_id'] = new_state_id
        values.update({
            'exploration_id': exploration_id,
            'oppia_html': html_output, 'widgets': widget_output,
            'block_number': block_number, 'params': params,
            'finished': (new_state_id == feconf.END_DEST),
        })

        if new_state_id != feconf.END_DEST:
            if sticky:
                values['interactive_widget_html'] = ''
                values['sticky_interactive_widget'] = True
            else:
                values['interactive_widget_html'] = (
                    InteractiveWidget.get_raw_code(
                        new_state.widget.widget_id,
                        params=utils.parse_dict_with_params(
                            new_state.widget.params, params)
                    )
                )
        else:
            values['interactive_widget_html'] = ''

        self.render_json(values)