Exemple #1
0
    def get(self):
        """Handles GET requests."""
        query_string = utils.unescape_encoded_uri_component(
            self.request.get('q'))

        # Remove all punctuation from the query string, and replace it with
        # spaces. See http://stackoverflow.com/a/266162 and
        # http://stackoverflow.com/a/11693937
        remove_punctuation_map = dict(
            (ord(char), None) for char in string.punctuation)
        query_string = query_string.translate(remove_punctuation_map)

        if self.request.get('category'):
            query_string += ' category=%s' % self.request.get('category')
        if self.request.get('language_code'):
            query_string += ' language_code=%s' % self.request.get(
                'language_code')
        search_cursor = self.request.get('cursor', None)

        explorations_list, new_search_cursor = get_matching_exploration_dicts(
            query_string, search_cursor)

        self.values.update({
            'explorations_list': explorations_list,
            'search_cursor': new_search_cursor,
        })

        self.render_json(self.values)
Exemple #2
0
    def get(self):
        """Handles GET requests."""
        query_string = utils.unescape_encoded_uri_component(
            self.request.get('q'))

        # Remove all punctuation from the query string, and replace it with
        # spaces. See http://stackoverflow.com/a/266162 and
        # http://stackoverflow.com/a/11693937
        remove_punctuation_map = dict(
            (ord(char), None) for char in string.punctuation)
        query_string = query_string.translate(remove_punctuation_map)

        if self.request.get('category'):
            query_string += ' category=%s' % self.request.get('category')
        if self.request.get('language_code'):
            query_string += ' language_code=%s' % self.request.get(
                'language_code')
        search_cursor = self.request.get('cursor', None)

        activity_list, new_search_cursor = get_matching_activity_dicts(
            query_string, search_cursor)

        self.values.update({
            'activity_list': activity_list,
            'search_cursor': new_search_cursor,
        })

        self.render_json(self.values)
Exemple #3
0
    def get(self, exploration_id, escaped_state_name):
        """Handles GET requests."""
        current_exploration = exp_fetchers.get_exploration_by_id(
            exploration_id)

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in current_exploration.states:
            logging.exception('Could not find state: %s' % state_name)
            logging.exception('Available states: %s' % (
                list(current_exploration.states.keys())))
            raise self.PageNotFoundException

        # TODO(#11475): Return visualizations info based on Apache Beam job.
        self.render_json({'visualizations_info': []})
Exemple #4
0
    def get(self):
        """Handles GET requests."""
        query_string = utils.unescape_encoded_uri_component(
            self.request.get('q'))

        # Remove all punctuation from the query string, and replace it with
        # spaces. See http://stackoverflow.com/a/266162 and
        # http://stackoverflow.com/a/11693937
        remove_punctuation_map = dict(
            (ord(char), None) for char in string.punctuation)
        query_string = query_string.translate(remove_punctuation_map)

        # If there is a category parameter, it should be in the following form:
        #     category=("Algebra" OR "Math")
        category_string = self.request.get('category', '')
        if category_string and (
                not category_string.startswith('("') or
                not category_string.endswith('")')):
            raise self.InvalidInputException('Invalid search query.')
        # The 2 and -2 account for the '("" and '")' characters at the
        # beginning and end.
        categories = (
            category_string[2:-2].split('" OR "') if category_string else [])

        # If there is a language code parameter, it should be in the following
        # form:
        #     language_code=("en" OR "hi")
        language_code_string = self.request.get('language_code', '')
        if language_code_string and (
                not language_code_string.startswith('("') or
                not language_code_string.endswith('")')):
            raise self.InvalidInputException('Invalid search query.')
        # The 2 and -2 account for the '("" and '")' characters at the
        # beginning and end.
        language_codes = (
            language_code_string[2:-2].split('" OR "')
            if language_code_string else [])

        # TODO(#11314): Change 'cursor' to 'offset' here and in the frontend.
        search_offset = self.request.get('cursor', None)

        activity_list, new_search_offset = get_matching_activity_dicts(
            query_string, categories, language_codes, search_offset)

        self.values.update({
            'activity_list': activity_list,
            'search_cursor': new_search_offset,
        })

        self.render_json(self.values)
Exemple #5
0
    def test_editor(self, exploration_id, escaped_state_name=None, **kwargs):
        """Gets the user and exploration id if the user can edit it.

        Args:
            self: the handler instance
            exploration_id: the exploration id
            escaped_state_name: the URL-escaped state name, if it exists
            **kwargs: any other arguments passed to the handler

        Returns:
            The relevant handler, if the user is authorized to edit this
            exploration.

        Raises:
            self.PageNotFoundException: if no such exploration or state exists.
            self.UnauthorizedUserException: if the user exists but does not
                have the right credentials.
        """
        if not self.user_id:
            self.redirect(
                current_user_services.create_login_url(self.request.uri))
            return

        if self.username in config_domain.BANNED_USERNAMES.value:
            raise self.UnauthorizedUserException(
                'You do not have the credentials to access this page.')

        try:
            exploration = exp_services.get_exploration_by_id(exploration_id)
        except:
            raise self.PageNotFoundException

        if not rights_manager.Actor(self.user_id).can_edit(
                feconf.ACTIVITY_TYPE_EXPLORATION, exploration_id):
            raise self.UnauthorizedUserException(
                'You do not have the credentials to edit this exploration.',
                self.user_id)

        if not escaped_state_name:
            return handler(self, exploration_id, **kwargs)

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in exploration.states:
            logging.error('Could not find state: %s' % state_name)
            logging.error('Available states: %s' % exploration.states.keys())
            raise self.PageNotFoundException

        return handler(self, exploration_id, state_name, **kwargs)
Exemple #6
0
    def test_editor(self, exploration_id, escaped_state_name=None, **kwargs):
        """Gets the user and exploration id if the user can edit it.

        Args:
            self: the handler instance
            exploration_id: the exploration id
            escaped_state_name: the URL-escaped state name, if it exists
            **kwargs: any other arguments passed to the handler

        Returns:
            The relevant handler, if the user is authorized to edit this
            exploration.

        Raises:
            self.PageNotFoundException: if no such exploration or state exists.
            self.UnauthorizedUserException: if the user exists but does not
                have the right credentials.
        """
        if not self.user_id:
            self.redirect(current_user_services.create_login_url(
                self.request.uri))
            return

        if self.username in config_domain.BANNED_USERNAMES.value:
            raise self.UnauthorizedUserException(
                'You do not have the credentials to access this page.')

        try:
            exploration = exp_services.get_exploration_by_id(exploration_id)
        except:
            raise self.PageNotFoundException

        if not rights_manager.Actor(self.user_id).can_edit(
                feconf.ACTIVITY_TYPE_EXPLORATION, exploration_id):
            raise self.UnauthorizedUserException(
                'You do not have the credentials to edit this exploration.',
                self.user_id)

        if not escaped_state_name:
            return handler(self, exploration_id, **kwargs)

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in exploration.states:
            logging.error('Could not find state: %s' % state_name)
            logging.error('Available states: %s' % exploration.states.keys())
            raise self.PageNotFoundException

        return handler(self, exploration_id, state_name, **kwargs)
Exemple #7
0
    def get(self, exploration_id, escaped_state_name):
        """Handles GET requests."""
        current_exploration = exp_fetchers.get_exploration_by_id(
            exploration_id)

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in current_exploration.states:
            logging.error('Could not find state: %s' % state_name)
            logging.error('Available states: %s' % (
                list(current_exploration.states.keys())))
            raise self.PageNotFoundException

        self.render_json({
            'visualizations_info': stats_services.get_visualizations_info(
                current_exploration.id, state_name,
                current_exploration.states[state_name].interaction.id),
        })
Exemple #8
0
    def get(self, exploration_id, escaped_state_name):
        """Handles GET requests."""
        try:
            exploration = exp_services.get_exploration_by_id(exploration_id)
        except:
            raise self.PageNotFoundException

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in exploration.states:
            logging.error('Could not find state: %s' % state_name)
            logging.error('Available states: %s' % exploration.states.keys())
            raise self.PageNotFoundException

        self.render_json({
            'rules_stats':
            stats_services.get_state_rules_stats(exploration_id, state_name)
        })
Exemple #9
0
    def get(self, exploration_id, escaped_state_name):
        """Handles GET requests."""
        try:
            exploration = exp_services.get_exploration_by_id(exploration_id)
        except:
            raise self.PageNotFoundException

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in exploration.states:
            logging.error('Could not find state: %s' % state_name)
            logging.error('Available states: %s' % exploration.states.keys())
            raise self.PageNotFoundException

        self.render_json({
            'rules_stats': stats_services.get_state_rules_stats(
                exploration_id, state_name)
        })
Exemple #10
0
    def get(self, exploration_id, escaped_state_name):
        """Handles GET requests."""
        try:
            exploration = exp_services.get_exploration_by_id(exploration_id)
        except:
            raise self.PageNotFoundException

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in exploration.states:
            # If trying to access a non-existing state, there is no training
            # data associated with it.
            self.render_json({'unhandled_answers': []})
            return

        state = exploration.states[state_name]

        # TODO(bhenning): Answers should be bound to a particular exploration
        # version or interaction ID.

        # TODO(bhenning): If the top 100 answers have already been classified,
        # then this handler will always return an empty list.

        # TODO(bhenning): This entire function will not work as expected until
        # the answers storage backend stores answers in a non-lossy way.
        # Currently, answers are stored as HTML strings and they are not able
        # to be converted back to the original objects they started as, so the
        # normalization calls in this function will not work correctly on those
        # strings. Once this happens, this handler should also be tested.

        # The total number of possible answers is 100 because it requests the
        # top 50 answers matched to the default rule and the top 50 answers
        # matched to the classifier individually.

        # TODO(sll): Functionality for retrieving untrained answers was removed
        # in PR 3489 due to infeasibility of the calculation approach. It needs
        # to be reinstated in the future so that the training interface can
        # function.
        submitted_answers = []

        interaction = state.interaction
        unhandled_answers = []
        if feconf.SHOW_TRAINABLE_UNRESOLVED_ANSWERS and interaction.id:
            interaction_instance = (
                interaction_registry.Registry.get_interaction_by_id(
                    interaction.id))

            try:
                # Normalize the answers.
                for answer in submitted_answers:
                    answer['answer'] = interaction_instance.normalize_answer(
                        answer['answer'])

                trained_answers = set()
                for answer_group in interaction.answer_groups:
                    trained_answers.update(
                        interaction_instance.normalize_answer(trained)
                        for trained in answer_group['training_data'])

                # Include all the answers which have been confirmed to be
                # associated with the default outcome.
                trained_answers.update(
                    set(
                        interaction_instance.normalize_answer(confirmed)
                        for confirmed in
                        interaction.confirmed_unclassified_answers))

                unhandled_answers = [
                    answer for answer in submitted_answers
                    if answer['answer'] not in trained_answers
                ]
            except Exception as e:
                logging.warning(
                    'Error loading untrained answers for interaction %s: %s.' %
                    (interaction.id, e))

        self.render_json({'unhandled_answers': unhandled_answers})
Exemple #11
0
    def get(self, exploration_id, escaped_state_name):
        """Handles GET requests."""
        try:
            exploration = exp_services.get_exploration_by_id(exploration_id)
        except:
            raise self.PageNotFoundException

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in exploration.states:
            # If trying to access a non-existing state, there is no training
            # data associated with it.
            self.render_json({'unhandled_answers': []})
            return

        state = exploration.states[state_name]

        # TODO(bhenning): Answers should be bound to a particular exploration
        # version or interaction ID.

        # TODO(bhenning): If the top 100 answers have already been classified,
        # then this handler will always return an empty list.

        # TODO(bhenning): This entire function will not work as expected until
        # the answers storage backend stores answers in a non-lossy way.
        # Currently, answers are stored as HTML strings and they are not able
        # to be converted back to the original objects they started as, so the
        # normalization calls in this function will not work correctly on those
        # strings. Once this happens, this handler should also be tested.

        # The total number of possible answers is 100 because it requests the
        # top 50 answers matched to the default rule and the top 50 answers
        # matched to the classifier individually.
        answers = stats_services.get_top_state_rule_answers(
            exploration_id, state_name, [
                exp_domain.DEFAULT_RULESPEC_STR,
                exp_domain.CLASSIFIER_RULESPEC_STR])[
                    :self.NUMBER_OF_TOP_ANSWERS_PER_RULE]

        interaction = state.interaction
        unhandled_answers = []
        if feconf.SHOW_TRAINABLE_UNRESOLVED_ANSWERS and interaction.id:
            interaction_instance = (
                interaction_registry.Registry.get_interaction_by_id(
                    interaction.id))

            try:
                # Normalize the answers.
                for answer in answers:
                    answer['value'] = interaction_instance.normalize_answer(
                        answer['value'])

                trained_answers = set()
                for answer_group in interaction.answer_groups:
                    for rule_spec in answer_group.rule_specs:
                        if (rule_spec.rule_type ==
                                exp_domain.CLASSIFIER_RULESPEC_STR):
                            trained_answers.update(
                                interaction_instance.normalize_answer(trained)
                                for trained
                                in rule_spec.inputs['training_data'])

                # Include all the answers which have been confirmed to be
                # associated with the default outcome.
                trained_answers.update(set(
                    interaction_instance.normalize_answer(confirmed)
                    for confirmed
                    in interaction.confirmed_unclassified_answers))

                unhandled_answers = [
                    answer for answer in answers
                    if answer['value'] not in trained_answers
                ]
            except Exception as e:
                logging.warning(
                    'Error loading untrained answers for interaction %s: %s.' %
                    (interaction.id, e))

        self.render_json({
            'unhandled_answers': unhandled_answers
        })
Exemple #12
0
    def get(self, exploration_id, escaped_state_name):
        """Handles GET requests."""
        try:
            exploration = exp_services.get_exploration_by_id(exploration_id)
        except:
            raise self.PageNotFoundException

        state_name = utils.unescape_encoded_uri_component(escaped_state_name)
        if state_name not in exploration.states:
            # If trying to access a non-existing state, there is no training
            # data associated with it.
            self.render_json({'unhandled_answers': []})
            return

        state = exploration.states[state_name]

        # TODO(bhenning): Answers should be bound to a particular exploration
        # version or interaction ID.

        # TODO(bhenning): If the top 100 answers have already been classified,
        # then this handler will always return an empty list.

        # TODO(bhenning): This entire function will not work as expected until
        # the answers storage backend stores answers in a non-lossy way.
        # Currently, answers are stored as HTML strings and they are not able
        # to be converted back to the original objects they started as, so the
        # normalization calls in this function will not work correctly on those
        # strings. Once this happens, this handler should also be tested.

        # The total number of possible answers is 100 because it requests the
        # top 50 answers matched to the default rule and the top 50 answers
        # matched to a fuzzy rule individually.
        answers = stats_services.get_top_state_rule_answers(
            exploration_id, state_name,
            [exp_domain.DEFAULT_RULESPEC_STR, rule_domain.FUZZY_RULE_TYPE],
            self.NUMBER_OF_TOP_ANSWERS_PER_RULE)

        interaction = state.interaction
        unhandled_answers = []
        if feconf.SHOW_TRAINABLE_UNRESOLVED_ANSWERS and interaction.id:
            interaction_instance = (
                interaction_registry.Registry.get_interaction_by_id(
                    interaction.id))

            try:
                # Normalize the answers.
                for answer in answers:
                    answer['value'] = interaction_instance.normalize_answer(
                        answer['value'])

                trained_answers = set()
                for answer_group in interaction.answer_groups:
                    for rule_spec in answer_group.rule_specs:
                        if rule_spec.rule_type == rule_domain.FUZZY_RULE_TYPE:
                            trained_answers.update(
                                interaction_instance.normalize_answer(trained)
                                for trained in
                                rule_spec.inputs['training_data'])

                # Include all the answers which have been confirmed to be
                # associated with the default outcome.
                trained_answers.update(
                    set(
                        interaction_instance.normalize_answer(confirmed)
                        for confirmed in
                        interaction.confirmed_unclassified_answers))

                unhandled_answers = [
                    answer for answer in answers
                    if answer['value'] not in trained_answers
                ]
            except Exception as e:
                logging.warning(
                    'Error loading untrained answers for interaction %s: %s.' %
                    (interaction.id, e))

        self.render_json({'unhandled_answers': unhandled_answers})