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. """ user = users.get_current_user() if not user: self.redirect(users.create_login_url(self.request.uri)) return exploration = Exploration.get(exploration_id) if not exploration.is_editable_by(user): raise self.UnauthorizedUserException( '%s does not have the credentials to edit this exploration.', user) if not state_id: return handler(self, user, exploration, **kwargs) state = State.get(state_id, exploration) return handler(self, user, exploration, state, **kwargs)
def test_create_and_get_state(self): """Test creation and retrieval of states.""" id_1 = "123" name_1 = "State 1" state_1 = State.create(self.exploration, name_1, state_id=id_1) fetched_state_1 = State.get(id_1, parent=self.exploration.key) self.assertEqual(fetched_state_1, state_1) fetched_state_by_name_1 = State.get_by_name(name_1, self.exploration) self.assertEqual(fetched_state_by_name_1, state_1) # Test the failure cases. id_2 = "fake_id" name_2 = "fake_name" with self.assertRaises(Exception): State.get(id_2, parent=self.exploration.key) fetched_state_by_name_2 = State.get_by_name(name_2, self.exploration, strict=False) self.assertIsNone(fetched_state_by_name_2) with self.assertRaises(Exception): State.get_by_name(name_2, self.exploration, strict=True) # The default behavior is to fail noisily. with self.assertRaises(Exception): State.get_by_name(name_2, self.exploration)
def post(self, exploration_id, state_id): """Handles feedback interactions with readers.""" values = {'error': []} exploration = Exploration.get(exploration_id) state = State.get(state_id, parent=exploration.key) old_state = state payload = json.loads(self.request.get('payload')) # The 0-based index of the last content block already on the page. block_number = payload.get('block_number') + 1 # The reader's answer. answer = payload.get('answer') # The answer handler (submit, click, etc.) handler = payload.get('handler') params = payload.get('params', {}) # Add the reader's answer to the parameter list. params['answer'] = answer dest_id, feedback, rule, recorded_answer = state.transition( answer, params, handler) 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() assert dest_id html_output, widget_output = '', [] # TODO(sll): The following is a special-case for multiple choice input, # in which the choice text must be displayed instead of the choice # number. We might need to find a way to do this more generically. if state.widget.widget_id == 'interactive-MultipleChoiceInput': answer = state.widget.params['choices'][int(answer)] # Append reader's answer. values['reader_html'] = feconf.JINJA_ENV.get_template( 'reader/reader_response.html').render({'response': answer}) if dest_id == feconf.END_DEST: # This leads to a FINISHED state. if feedback: html_output, widget_output = self._append_feedback( feedback, html_output, widget_output, block_number, params) EventHandler.record_exploration_completed(exploration_id) else: state = State.get(dest_id, parent=exploration.key) EventHandler.record_state_hit(exploration_id, dest_id) if feedback: html_output, widget_output = self._append_feedback( feedback, html_output, widget_output, block_number, params) # Populate new parameters. params = get_params(state, existing_params=params) # Append text for the new state only if the new and old states # differ. if old_state.id != state.id: state_html, state_widgets = parse_content_into_html( 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 if state.widget.widget_id in DEFAULT_ANSWERS: values['default_answer'] = DEFAULT_ANSWERS[state.widget.widget_id] values.update({ 'exploration_id': exploration.id, 'state_id': state.id, 'oppia_html': html_output, 'widgets': widget_output, 'block_number': block_number, 'params': params, 'finished': (dest_id == feconf.END_DEST), }) if dest_id != feconf.END_DEST: if state.widget.sticky and ( state.widget.widget_id == old_state.widget.widget_id): values['interactive_widget_html'] = '' values['sticky_interactive_widget'] = True else: values['interactive_widget_html'] = ( InteractiveWidget.get_raw_code( state.widget.widget_id, params=utils.parse_dict_with_params( state.widget.params, params) ) ) else: values['interactive_widget_html'] = '' self.render_json(values)