Example #1
0
    def test_get_all_explorations(self):
        """Test get_all_explorations()."""

        exploration = Exploration.get(
            exp_services.create_new(self.owner_id, "A title", "A category", "A exploration_id")
        )
        self.assertItemsEqual([e.id for e in exp_services.get_all_explorations()], [exploration.id])

        exploration2 = Exploration.get(
            exp_services.create_new(self.owner_id, "A new title", "A category", "A new exploration_id")
        )
        self.assertItemsEqual([e.id for e in exp_services.get_all_explorations()], [exploration.id, exploration2.id])
Example #2
0
    def test_creation_and_deletion_of_individual_explorations(self):
        """Test the create_new() and delete() methods."""
        exploration = Exploration.get(
            exp_services.create_new(self.owner_id, "A title", "A category", "A exploration_id")
        )
        exploration.put()

        retrieved_exploration = Exploration.get("A exploration_id")
        self.assertEqual(exploration.id, retrieved_exploration.id)
        self.assertEqual(exploration.title, retrieved_exploration.title)

        exploration.delete()
        with self.assertRaises(Exception):
            retrieved_exploration = Exploration.get("A exploration_id")
Example #3
0
def get_exploration_stats(event_name, exploration_id):
    """Retrieves statistics for the given event name and exploration id."""

    if event_name == STATS_ENUMS.exploration_visited:
        event_id = get_event_id(event_name, exploration_id)
        return Counter.get_value_by_id(event_id)

    if event_name == STATS_ENUMS.exploration_completed:
        event_id = get_event_id(event_name, exploration_id)
        return Counter.get_value_by_id(event_id)

    if event_name == STATS_ENUMS.rule_hit:
        result = {}

        exploration = Exploration.get(exploration_id)
        for state_id in exploration.state_ids:
            state = exploration.get_state_by_id(state_id)
            result[state.id] = {
                'name': state.name,
                'rules': {}
            }
            for handler in state.widget.handlers:
                for rule in handler.rules:
                    rule_name = create_rule_name(rule)
                    event_id = get_event_id(
                        event_name, '.'.join(
                            [exploration_id, state.id, rule_name]))

                    journal = Journal.get(event_id, strict=False)
                    result[state.id]['rules'][rule_name] = {
                        'answers': collections.Counter(
                            journal.values).most_common(10) if journal else [],
                    }

        return result

    if event_name == STATS_ENUMS.state_hit:
        result = {}

        exploration = Exploration.get(exploration_id)
        for state_id in exploration.state_ids:
            state = exploration.get_state_by_id(state_id)
            event_id = get_event_id(
                event_name, '.'.join([exploration_id, state.id]))

            result[state.id] = {
                'name': state.name,
                'count': Counter.get_value_by_id(event_id),
            }
        return result
Example #4
0
    def test_incomplete_and_default_flags(self):

        exp = Exploration.get(exp_services.create_new(
            '*****@*****.**', 'exploration', 'category', 'eid'))

        state_id = exp.init_state_id

        # Hit the default once, and do an incomplete twice. The result should
        # be classified as incomplete.

        for i in range(3):
            EventHandler.record_state_hit('eid', state_id)

        EventHandler.record_rule_hit(
            'eid', state_id, Rule(name='Default', dest=state_id),
            extra_info='1')

        states = stats_services.get_top_ten_improvable_states([exp])
        self.assertEquals(len(states), 1)
        self.assertEquals(states[0]['rank'], 2)
        self.assertEquals(states[0]['type'], 'incomplete')

        # Now hit the default two more times. The result should be classified
        # as default.

        for i in range(2):
            EventHandler.record_state_hit('eid', state_id)
            EventHandler.record_rule_hit(
                'eid', state_id, Rule(name='Default', dest=state_id),
                extra_info='1')

        states = stats_services.get_top_ten_improvable_states([exp])
        self.assertEquals(len(states), 1)
        self.assertEquals(states[0]['rank'], 3)
        self.assertEquals(states[0]['type'], 'default')
Example #5
0
def get_or_create_param(exploration_id, param_name, obj_type=None):
    """Returns a ParamChange instance corresponding to the given inputs.

    If the parameter does not exist in the given exploration, it is added to
    the list of exploration parameters.

    If the obj_type is not specified it is taken to be 'UnicodeString'.

    If the obj_type does not match the obj_type for the parameter in the
    exploration, an Exception is raised.
    """
    exploration = Exploration.get(exploration_id)

    for param in exploration.parameters:
        if param.name == param_name:
            if obj_type and param.obj_type != obj_type:
                raise Exception(
                    'Parameter %s has wrong obj_type: was %s, expected %s'
                    % (param_name, obj_type, param.obj_type))
            return ParamChange(name=param.name, obj_type=param.obj_type)

    # The parameter was not found, so add it.
    if not obj_type:
        obj_type = 'UnicodeString'
    exploration.parameters.append(
        Parameter(name=param_name, obj_type=obj_type))
    exploration.put()
    return ParamChange(name=param_name, obj_type=obj_type)
Example #6
0
def load_demos():
    """Initializes the demo explorations."""
    for index, exploration in enumerate(feconf.DEMO_EXPLORATIONS):
        if len(exploration) == 3:
            (exp_filename, title, category) = exploration
            image_filename = None
        elif len(exploration) == 4:
            (exp_filename, title, category, image_filename) = exploration
        else:
            raise Exception('Invalid demo exploration: %s' % exploration)

        image_id = None
        if image_filename:
            image_filepath = os.path.join(
                feconf.SAMPLE_IMAGES_DIR, image_filename)
            image_id = Image.create(utils.get_file_contents(
                image_filepath, raw_bytes=True))

        yaml_content = utils.get_sample_exploration_yaml(exp_filename)
        exploration_id = create_from_yaml(
            yaml_content, None, title, category, exploration_id=str(index),
            image_id=image_id)

        exploration = Exploration.get(exploration_id)
        exploration.is_public = True
        exploration.put()
Example #7
0
    def test_get_top_ten_improvable_states(self):
        exp = Exploration.get(exp_services.create_new(
            '*****@*****.**', 'exploration', 'category', 'eid'))

        state_id = exp.init_state_id

        EventHandler.record_rule_hit(
            'eid', state_id, Rule(name='Default', dest=state_id),
            extra_info='1')
        EventHandler.record_rule_hit(
            'eid', state_id, Rule(name='Default', dest=state_id),
            extra_info='2')
        EventHandler.record_rule_hit(
            'eid', state_id, Rule(name='Default', dest=state_id),
            extra_info='1')

        EventHandler.record_state_hit('eid', state_id)
        EventHandler.record_state_hit('eid', state_id)
        EventHandler.record_state_hit('eid', state_id)
        EventHandler.record_state_hit('eid', state_id)
        EventHandler.record_state_hit('eid', state_id)

        states = stats_services.get_top_ten_improvable_states([exp])
        self.assertEquals(len(states), 1)
        self.assertEquals(states[0]['exp_id'], 'eid')
        self.assertEquals(states[0]['type'], 'default')
        self.assertEquals(states[0]['rank'], 3)
        self.assertEquals(states[0]['state_id'], exp.init_state_id)
Example #8
0
def create_from_yaml(
    yaml_content, user_id, title, category, exploration_id=None,
        image_id=None):
    """Creates an exploration from a YAML text string."""
    exploration_dict = utils.dict_from_yaml(yaml_content)
    init_state_name = exploration_dict['states'][0]['name']

    exploration = Exploration.get(create_new(
        user_id, title, category, exploration_id=exploration_id,
        init_state_name=init_state_name, image_id=image_id))

    init_state = State.get_by_name(init_state_name, exploration)

    try:
        exploration.parameters = [Parameter(
            name=param['name'], obj_type=param['obj_type'],
            values=param['values']
        ) for param in exploration_dict['parameters']]

        state_list = []
        for state_description in exploration_dict['states']:
            state_name = state_description['name']
            state = (init_state if state_name == init_state_name
                     else exploration.add_state(state_name))
            state_list.append({'state': state, 'desc': state_description})

        for index, state in enumerate(state_list):
            modify_using_dict(exploration.id, state['state'].id, state['desc'])
    except Exception:
        exploration.delete()
        raise

    return exploration.id
Example #9
0
    def test_get_public_explorations(self):
        exploration = Exploration.get(
            exp_services.create_new(self.owner_id, "A title", "A category", "A exploration_id")
        )
        self.assertEqual(exp_services.get_public_explorations(), [])

        exploration.is_public = True
        exploration.put()
        self.assertEqual([e.id for e in exp_services.get_public_explorations()], [exploration.id])
Example #10
0
def export_state_to_dict(exploration_id, state_id):
    """Gets a Python dict representation of the state."""
    exploration = Exploration.get(exploration_id)
    state = exploration.get_state_by_id(state_id)

    state_dict = export_state_internals_to_dict(exploration_id, state_id)
    state_dict.update({'id': state.id, 'name': state.name,
                       'unresolved_answers': state.unresolved_answers})
    return state_dict
Example #11
0
    def setUp(self):
        """Loads the default widgets and creates a sample exploration."""
        super(StateModelUnitTests, self).setUp()
        InteractiveWidget.load_default_widgets()

        self.user_id = '*****@*****.**'

        self.exploration = Exploration.get(exp_services.create_new(
            self.user_id, 'A title', 'A category', 'A exploration_id'))
Example #12
0
    def get(self):
        """Handles GET requests."""
        if not Exploration.get('0', strict=False):
            admin.reload_demos()

        self.values.update({
            'gallery_login_url': users.create_login_url('/gallery'),
        })
        self.render_template('pages/index.html')
Example #13
0
def delete_demos():
    """Deletes the demo explorations."""
    explorations_to_delete = []
    for int_id in range(len(feconf.DEMO_EXPLORATIONS)):
        exploration = Exploration.get(str(int_id), strict=False)
        if not exploration:
            # This exploration does not exist, so it cannot be deleted.
            logging.info('No exploration with id %s found.' % int_id)
        else:
            explorations_to_delete.append(exploration)

    for exploration in explorations_to_delete:
        exploration.delete()
Example #14
0
    def test_two_state_default_hit(self):
        SECOND_STATE = 'State 2'

        exp = Exploration.get(exp_services.create_new(
            '*****@*****.**', 'exploration', 'category', 'eid'))

        second_state = exp.add_state(SECOND_STATE)

        state_1_id = exp.init_state_id
        state_2_id = second_state.id

        # Hit the default rule of state 1 once, and the default rule of state 2
        # twice.
        EventHandler.record_state_hit('eid', state_1_id)
        EventHandler.record_rule_hit(
            'eid', state_1_id, Rule(name='Default', dest=state_1_id),
            extra_info='1')

        for i in range(2):
            EventHandler.record_state_hit('eid', state_2_id)
            EventHandler.record_rule_hit(
                'eid', state_2_id, Rule(name='Default', dest=state_2_id),
                extra_info='1')

        states = stats_services.get_top_ten_improvable_states([exp])
        self.assertEquals(len(states), 2)
        self.assertEquals(states[0]['rank'], 2)
        self.assertEquals(states[0]['type'], 'default')
        self.assertEquals(states[0]['state_id'], state_2_id)
        self.assertEquals(states[1]['rank'], 1)
        self.assertEquals(states[1]['type'], 'default')
        self.assertEquals(states[1]['state_id'], state_1_id)

        # Hit the default rule of state 1 two more times.

        for i in range(2):
            EventHandler.record_state_hit('eid', state_1_id)
            EventHandler.record_rule_hit(
                'eid', state_1_id, Rule(name='Default', dest=state_1_id),
                extra_info='1')

        states = stats_services.get_top_ten_improvable_states([exp])
        self.assertEquals(len(states), 2)
        self.assertEquals(states[0]['rank'], 3)
        self.assertEquals(states[0]['type'], 'default')
        self.assertEquals(states[0]['state_id'], state_1_id)
        self.assertEquals(states[1]['rank'], 2)
        self.assertEquals(states[1]['type'], 'default')
        self.assertEquals(states[1]['state_id'], state_2_id)
Example #15
0
def export_to_yaml(exploration_id):
    """Returns a YAML version of the exploration."""
    exploration = Exploration.get(exploration_id)

    params = [{
        'name': param.name, 'obj_type': param.obj_type, 'values': param.values
    } for param in exploration.parameters]

    states_list = [export_state_internals_to_dict(
        exploration_id, state_id, human_readable_dests=True)
        for state_id in exploration.state_ids]

    return utils.yaml_from_dict({
        'parameters': params, 'states': states_list
    })
Example #16
0
    def test_no_improvement_flag_hit(self):

        exp = Exploration.get(exp_services.create_new(
            '*****@*****.**', 'exploration', 'category', 'eid'))

        init_state = exp.init_state
        init_state.widget.handlers[0].rules = [
            Rule(name='NotDefault', dest=init_state.id),
            Rule(name='Default', dest=init_state.id),
        ]
        init_state.put()

        EventHandler.record_rule_hit(
            'eid', init_state.id, Rule(name='NotDefault', dest=init_state.id),
            extra_info='1')
        EventHandler.record_state_hit('eid', init_state.id)

        states = stats_services.get_top_ten_improvable_states([exp])
        self.assertEquals(len(states), 0)
Example #17
0
    def post(self):
        """Handles POST requests."""

        exploration_id = self.payload.get('exploration_id')

        forked_exploration = Exploration.get(exploration_id)
        if not forked_exploration.is_demo:
            raise self.InvalidInputException('Exploration cannot be forked.')

        # Get the demo exploration as a YAML file, so that new states can be
        # created.
        yaml_content = exp_services.export_to_yaml(forked_exploration.id)
        title = 'Copy of %s' % forked_exploration.title
        category = forked_exploration.category

        new_exploration_id = exp_services.create_from_yaml(
            yaml_content, self.user_id, title, category)

        self.render_json({'explorationId': new_exploration_id})
Example #18
0
    def test_export_to_yaml(self):
        """Test the export_to_yaml() method."""
        exploration = Exploration.get(
            exp_services.create_new(self.owner_id, "A title", "A category", "A different exploration_id")
        )
        exploration.add_state("New state")
        yaml_content = exp_services.export_to_yaml(exploration.id)
        self.assertEqual(
            yaml_content,
            """parameters: []
states:
- content: []
  name: '[untitled state]'
  param_changes: []
  widget:
    handlers:
    - name: submit
      rules:
      - dest: '[untitled state]'
        feedback: []
        inputs: {}
        name: Default
        param_changes: []
    params: {}
    sticky: false
    widget_id: interactive-Continue
- content: []
  name: New state
  param_changes: []
  widget:
    handlers:
    - name: submit
      rules:
      - dest: New state
        feedback: []
        inputs: {}
        name: Default
        param_changes: []
    params: {}
    sticky: false
    widget_id: interactive-Continue
""",
        )
Example #19
0
def export_state_internals_to_dict(
        exploration_id, state_id, human_readable_dests=False):
    """Gets a Python dict of the internals of the state."""

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

    state_dict = copy.deepcopy(state.to_dict(exclude=['unresolved_answers']))
    # Remove the computed 'classifier' property.
    for handler in state_dict['widget']['handlers']:
        del handler['classifier']

    if human_readable_dests:
        # Change the dest ids to human-readable names.
        for handler in state_dict['widget']['handlers']:
            for rule in handler['rules']:
                if rule['dest'] != feconf.END_DEST:
                    dest_state = exploration.get_state_by_id(rule['dest'])
                    rule['dest'] = dest_state.name
    return state_dict
Example #20
0
def modify_using_dict(exploration_id, state_id, sdict):
    """Modifies the properties of a state using values from a dict."""
    exploration = Exploration.get(exploration_id)
    state = exploration.get_state_by_id(state_id)

    state.content = [
        Content(type=item['type'], value=item['value'])
        for item in sdict['content']
    ]

    state.param_changes = []
    for pc in sdict['param_changes']:
        instance = get_or_create_param(
            exploration_id, pc['name'], obj_type=pc['obj_type'])
        instance.values = pc['values']
        state.param_changes.append(instance)

    wdict = sdict['widget']
    state.widget = WidgetInstance(
        widget_id=wdict['widget_id'], sticky=wdict['sticky'],
        params=wdict['params'], handlers=[])

    # Augment the list of parameters in state.widget with the default widget
    # params.
    for wp in InteractiveWidget.get(wdict['widget_id']).params:
        if wp.name not in wdict['params']:
            state.widget.params[wp.name] = wp.value

    for handler in wdict['handlers']:
        handler_rules = [Rule(
            name=rule['name'],
            inputs=rule['inputs'],
            dest=State._get_id_from_name(rule['dest'], exploration),
            feedback=rule['feedback']
        ) for rule in handler['rules']]

        state.widget.handlers.append(AnswerHandlerInstance(
            name=handler['name'], rules=handler_rules))

    state.put()
    return state
Example #21
0
    def test_get_editable_explorations(self):
        exploration = Exploration.get(
            exp_services.create_new(self.owner_id, "A title", "A category", "A exploration_id")
        )
        exploration.add_editor(self.editor_id)
        exploration.put()

        def get_editable_ids(user_id):
            return [e.id for e in exp_services.get_editable_explorations(user_id)]

        self.assertEqual(get_editable_ids(self.owner_id), [exploration.id])
        self.assertEqual(get_editable_ids(self.viewer_id), [])
        self.assertEqual(get_editable_ids(None), [])

        # Set the exploration's status to published.
        exploration.is_public = True
        exploration.put()

        self.assertEqual(get_editable_ids(self.owner_id), [exploration.id])
        self.assertEqual(get_editable_ids(self.viewer_id), [])
        self.assertEqual(get_editable_ids(None), [])
Example #22
0
    def test_editor(self, exploration_id, state_id=None, **kwargs):
        """Gets the user and exploration id if the user can edit it.

        Args:
            self: the handler instance
            exploration_id: the exploration id
            state_id: the state id, if it exists
            **kwargs: any other arguments passed to the handler

        Returns:
            The user and exploration instance, if the user is authorized to edit
            this exploration. Also, the state instance, if one is supplied.

        Raises:
            self.NotLoggedInException: if there is no current user.
            self.UnauthorizedUserException: if the user exists but does not have
                the right credentials.
        """
        if not self.user_id:
            self.redirect(users.create_login_url(self.request.uri))
            return

        try:
            exploration = Exploration.get(exploration_id)
        except:
            raise self.PageNotFoundException

        if (not users.is_current_user_admin() and
                not exploration.is_editable_by(self.user_id)):
            raise self.UnauthorizedUserException(
                '%s does not have the credentials to edit this exploration.',
                self.user_id)

        if not state_id:
            return handler(self, exploration, **kwargs)
        try:
            state = exploration.get_state_by_id(state_id)
        except:
            raise self.PageNotFoundException
        return handler(self, exploration, state, **kwargs)
Example #23
0
    def get(self, exploration_id):
        """Populates the data on the individual exploration page."""
        # TODO(sll): Maybe this should send a complete state machine to the
        # frontend, and all interaction would happen client-side?
        try:
            exploration = Exploration.get(exploration_id)
        except Exception as e:
            raise self.PageNotFoundException(e)

        init_state = exploration.init_state
        # TODO: get params from exploration specification instead
        params = self._get_exploration_params(exploration)
        params = get_params(init_state, params)
        init_html, init_widgets = parse_content_into_html(
            init_state.content, 0, params)
        interactive_widget_html = InteractiveWidget.get_raw_code(
            init_state.widget.widget_id,
            params=utils.parse_dict_with_params(
                init_state.widget.params, params)
        )

        self.values.update({
            'block_number': 0,
            'interactive_widget_html': interactive_widget_html,
            'interactive_params': init_state.widget.params,
            'oppia_html': init_html,
            'params': params,
            'state_id': exploration.init_state_id,
            'title': exploration.title,
            'widgets': init_widgets,
        })
        if init_state.widget.widget_id in DEFAULT_ANSWERS:
            self.values['default_answer'] = (
                DEFAULT_ANSWERS[init_state.widget.widget_id])
        self.render_json(self.values)

        EventHandler.record_exploration_visited(exploration_id)
        EventHandler.record_state_hit(exploration_id, exploration.init_state_id)
Example #24
0
    def test_exploration_class(self):
        """Test the Exploration model class."""
        exploration = ExplorationModel(id='The exploration hash id')

        # A new exploration should have a default title property.
        self.assertEqual(exploration.title, 'New exploration')

        # A new exploration should have a default is_public property.
        self.assertEqual(exploration.is_public, False)

        state = State(id='The state hash id')
        state.put()

        # The 'state_ids' property must be a list of strings.
        with self.assertRaises(SyntaxError):
            exploration.state_ids = 'A string'
            exploration.put()
        with self.assertRaises(ValidationError):
            exploration.state_ids = [state]
            exploration.put()
        exploration.state_ids = [state.id]

        # An Exploration must have a category.
        with self.assertRaises(ValidationError):
            exploration.put()
        exploration.category = 'The category'

        # The 'parameters' property must be a list of Parameter objects.
        with self.assertRaises(ValidationError):
            exploration.parameters = 'A string'
            exploration.put()
        exploration.parameters = []
        parameter = Parameter(name='theParameter', obj_type='Int')
        with self.assertRaises(AttributeError):
            exploration.parameters = [parameter.key]
        exploration.parameters = [parameter]

        # The 'is_public' property must be a boolean.
        with self.assertRaises(ValidationError):
            exploration.is_public = 'true'
            exploration.put()
        exploration.is_public = True

        # The 'image_id' property must be a string.
        # TODO: This fails now because of the behaviour of CharField
        image = Image(id='The image')
        with self.assertRaises(ValidationError):
            exploration.image_id = image
            exploration.put()
        exploration.image_id = 'A string'

        exploration.editor_ids = ['A user id']

        # Put and retrieve the exploration.
        exploration.put()

        retrieved_exploration = Exploration.get('The exploration hash id')
        self.assertEqual(retrieved_exploration.category, 'The category')
        self.assertEqual(retrieved_exploration.title, 'New exploration')
        self.assertEqual(retrieved_exploration.state_ids, [state.id])
        self.assertEqual(retrieved_exploration.parameters, [parameter])
        self.assertEqual(retrieved_exploration.is_public, True)
        self.assertEqual(retrieved_exploration.image_id, 'A string')
        self.assertEqual(retrieved_exploration.editor_ids, ['A user id'])
Example #25
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)