def translate(self, text, source_language_code, target_language_code):
        """Returns the saved expected response for a given input. If no
        response exists for the given input, returns a default response.

        Args:
            text: str. The text to be translated.
            source_language_code: str. An allowlisted language code.
            target_language_code: str. An allowlisted language code.

        Raises:
            ValueError. Invalid source language code.
            ValueError. Invalid target language code.

        Returns:
            str. The translated text.
        """
        if not utils.is_valid_language_code(source_language_code):
            raise ValueError('Invalid source language code: %s' %
                             source_language_code)
        if not utils.is_valid_language_code(target_language_code):
            raise ValueError('Invalid target language code: %s' %
                             target_language_code)

        key = (source_language_code, target_language_code, text)
        return self.expected_responses.get(key, self.DEFAULT_RESPONSE)
Exemple #2
0
    def validate(self):
        """Validates properties of the MachineTranslation.

        Raises:
            ValidationError. One or more attributes of the MachineTranslation
                are invalid.
        """
        if not isinstance(self.source_language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected source_language_code to be a string, received %s' %
                self.source_language_code
            )
        # TODO(#12341): Tidy up this logic once we have a canonical list of
        # language codes.
        if not utils.is_supported_audio_language_code(
                self.source_language_code
            ) and not utils.is_valid_language_code(
                self.source_language_code
            ):
            raise utils.ValidationError(
                'Invalid source language code: %s' % self.source_language_code)

        if not isinstance(self.target_language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected target_language_code to be a string, received %s' %
                self.target_language_code
            )
        # TODO(#12341): Tidy up this logic once we have a canonical list of
        # language codes.
        if not utils.is_supported_audio_language_code(
                self.target_language_code
            ) and not utils.is_valid_language_code(
                self.target_language_code
            ):
            raise utils.ValidationError(
                'Invalid target language code: %s' % self.target_language_code)

        if self.source_language_code == self.target_language_code:
            raise utils.ValidationError(
                (
                    'Expected source_language_code to be different from '
                    'target_language_code: "%s" = "%s"') % (
                        self.source_language_code, self.target_language_code))

        if not isinstance(self.source_text, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected source_text to be a string, received %s' %
                self.source_text
            )

        if not isinstance(self.translated_text, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected translated_text to be a string, received %s' %
                self.translated_text
            )
Exemple #3
0
    def validate(self):
        """Validates various properties of the story summary object.

        Raises:
            ValidationError: One or more attributes of story summary are
                invalid.
        """
        if not isinstance(self.title, basestring):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)

        if self.title == '':
            raise utils.ValidationError('Title field should not be empty')

        if not isinstance(self.description, basestring):
            raise utils.ValidationError(
                'Expected description to be a string, received %s'
                % self.description)

        if not isinstance(self.node_count, int):
            raise utils.ValidationError(
                'Expected node_count to be a int, received \'%s\'' % (
                    self.node_count))

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError(
                'Invalid language code: %s' % self.language_code)
Exemple #4
0
    def partial_validate(self):
        """Validates the Question domain object, but doesn't require the
        object to contain an ID and a version. To be used to validate the
        question before it is finalized.
        """

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language_code to be a string, received %s' %
                self.language_code)

        if not isinstance(self.question_state_schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.question_state_schema_version)

        if not isinstance(self.question_state_data, state_domain.State):
            raise utils.ValidationError(
                'Expected question state data to be a State object, '
                'received %s' % self.question_state_data)

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        INTERACTION_SPECS = interaction_registry.Registry.get_all_specs()
        at_least_one_correct_answer = False
        dest_is_specified = False
        interaction = self.question_state_data.interaction
        for answer_group in interaction.answer_groups:
            if answer_group.outcome.labelled_as_correct:
                at_least_one_correct_answer = True
            if answer_group.outcome.dest is not None:
                dest_is_specified = True

        if interaction.default_outcome.labelled_as_correct:
            at_least_one_correct_answer = True

        if interaction.default_outcome.dest is not None:
            dest_is_specified = True

        if not at_least_one_correct_answer:
            raise utils.ValidationError(
                'Expected at least one answer group to have a correct ' +
                'answer.')

        if dest_is_specified:
            raise utils.ValidationError(
                'Expected all answer groups to have destination as None.')

        if not interaction.hints:
            raise utils.ValidationError(
                'Expected the question to have at least one hint')

        if ((interaction.solution is None)
                and (INTERACTION_SPECS[interaction.id]['can_have_solution'])):
            raise utils.ValidationError(
                'Expected the question to have a solution')
        self.question_state_data.validate({}, False)
Exemple #5
0
    def is_valid_audio_language_code(obj: str) -> bool:
        """Checks if the given obj (a string) represents a valid language code.

        Args:
            obj: str. The language code to verify.

        Returns:
            bool. Whether the given object is a valid audio language code.
        """
        return utils.is_valid_language_code(obj)
Exemple #6
0
    def validate(self):
        """Validates various properties of the story object.

        Raises:
            ValidationError: One or more attributes of story are invalid.
        """
        self.require_valid_title(self.title)

        if not isinstance(self.description, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected description to be a string, received %s'
                % self.description)

        if not isinstance(self.notes, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected notes to be a string, received %s' % self.notes)

        if not isinstance(self.story_contents_schema_version, int):
            raise utils.ValidationError(
                'Expected story contents schema version to be an integer, '
                'received %s' % self.story_contents_schema_version)

        if (self.story_contents_schema_version !=
                feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION):
            raise utils.ValidationError(
                'Expected story contents schema version to be %s, '
                'received %s' % (
                    feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION,
                    self.story_contents_schema_version))

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError(
                'Invalid language code: %s' % self.language_code)

        if not isinstance(
                self.corresponding_topic_id, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected corresponding_topic_id should be a string, received: '
                '%s' % self.corresponding_topic_id)

        self.story_contents.validate()
Exemple #7
0
    def validate(self):
        """Validates various properties of the Skill Summary object.

        Raises:
            ValidationError: One or more attributes of skill summary are
                invalid.
        """
        if not isinstance(self.description, python_utils.BASESTRING):
            raise utils.ValidationError('Description should be a string.')

        if self.description == '':
            raise utils.ValidationError(
                'Description field should not be empty')

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)
        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        if not isinstance(self.misconception_count, int):
            raise utils.ValidationError(
                'Expected misconception_count to be an int, '
                'received \'%s\'' % self.misconception_count)

        if self.misconception_count < 0:
            raise utils.ValidationError(
                'Expected misconception_count to be non-negative, '
                'received \'%s\'' % self.misconception_count)

        if not isinstance(self.worked_examples_count, int):
            raise utils.ValidationError(
                'Expected worked_examples_count to be an int, '
                'received \'%s\'' % self.worked_examples_count)

        if self.worked_examples_count < 0:
            raise utils.ValidationError(
                'Expected worked_examples_count to be non-negative, '
                'received \'%s\'' % self.worked_examples_count)
Exemple #8
0
    def validate(self):
        """Validates various properties of the story object.

        Raises:
            ValidationError: One or more attributes of story are invalid.
        """
        self.require_valid_title(self.title)

        if not isinstance(self.description, basestring):
            raise utils.ValidationError(
                'Expected description to be a string, received %s' %
                self.description)

        if not isinstance(self.notes, basestring):
            raise utils.ValidationError(
                'Expected notes to be a string, received %s' % self.notes)

        if not isinstance(self.schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.schema_version)

        if self.schema_version != feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION:
            raise utils.ValidationError(
                'Expected schema version to be %s, received %s' %
                (feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION,
                 self.schema_version))

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        self.story_contents.validate()
Exemple #9
0
    def partial_validate(self):
        """Validates the Question domain object, but doesn't require the
        object to contain an ID and a version. To be used to validate the
        question before it is finalized.
        """

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language_code to be a string, received %s' %
                self.language_code)

        if not self.linked_skill_ids:
            raise utils.ValidationError(
                'linked_skill_ids is either null or an empty list')

        if not (isinstance(self.linked_skill_ids, list) and (all(
                isinstance(elem, python_utils.BASESTRING)
                for elem in (self.linked_skill_ids)))):
            raise utils.ValidationError(
                'Expected linked_skill_ids to be a list of strings, '
                'received %s' % self.linked_skill_ids)

        if len(set(self.linked_skill_ids)) != len(self.linked_skill_ids):
            raise utils.ValidationError(
                'linked_skill_ids has duplicate skill ids')

        if not isinstance(self.question_state_data_schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.question_state_data_schema_version)

        if not isinstance(self.question_state_data, state_domain.State):
            raise utils.ValidationError(
                'Expected question state data to be a State object, '
                'received %s' % self.question_state_data)

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        interaction_specs = interaction_registry.Registry.get_all_specs()
        at_least_one_correct_answer = False
        dest_is_specified = False
        interaction = self.question_state_data.interaction
        for answer_group in interaction.answer_groups:
            if answer_group.outcome.labelled_as_correct:
                at_least_one_correct_answer = True
            if answer_group.outcome.dest is not None:
                dest_is_specified = True

        if interaction.default_outcome.labelled_as_correct:
            at_least_one_correct_answer = True

        if interaction.default_outcome.dest is not None:
            dest_is_specified = True

        if not at_least_one_correct_answer:
            raise utils.ValidationError(
                'Expected at least one answer group to have a correct ' +
                'answer.')

        if dest_is_specified:
            raise utils.ValidationError(
                'Expected all answer groups to have destination as None.')

        if not interaction.hints:
            raise utils.ValidationError(
                'Expected the question to have at least one hint')

        if ((interaction.solution is None)
                and (interaction_specs[interaction.id]['can_have_solution'])):
            raise utils.ValidationError(
                'Expected the question to have a solution')
        self.question_state_data.validate({}, False)
Exemple #10
0
    def validate(self):
        """Validates all properties of this topic and its constituents.

        Raises:
            ValidationError: One or more attributes of the Topic are not
                valid.
        """
        self.require_valid_name(self.name)
        if not isinstance(self.description, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected description to be a string, received %s' %
                self.description)

        if not isinstance(self.subtopics, list):
            raise utils.ValidationError(
                'Expected subtopics to be a list, received %s' %
                self.subtopics)

        if not isinstance(self.next_subtopic_id, int):
            raise utils.ValidationError(
                'Expected next_subtopic_id to be an int, received %s' %
                self.next_subtopic_id)

        if not isinstance(self.subtopic_schema_version, int):
            raise utils.ValidationError(
                'Expected subtopic schema version to be an integer, received %s'
                % self.subtopic_schema_version)

        if not isinstance(self.story_reference_schema_version, int):
            raise utils.ValidationError(
                'Expected story reference schema version to be an integer, '
                'received %s' % self.story_reference_schema_version)

        if (self.subtopic_schema_version !=
                feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION):
            raise utils.ValidationError(
                'Expected subtopic schema version to be %s, received %s' %
                (feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION,
                 self.subtopic_schema_version))

        for subtopic in self.subtopics:
            if not isinstance(subtopic, Subtopic):
                raise utils.ValidationError(
                    'Expected each subtopic to be a Subtopic object, '
                    'received %s' % subtopic)
            subtopic.validate()
            if subtopic.id >= self.next_subtopic_id:
                raise utils.ValidationError(
                    'The id for subtopic %s is greater than or equal to '
                    'next_subtopic_id %s' %
                    (subtopic.id, self.next_subtopic_id))

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)
        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        if not isinstance(self.canonical_story_references, list):
            raise utils.ValidationError(
                'Expected canonical story references to be a list, received %s'
                % self.canonical_story_references)

        canonical_story_ids = self.get_canonical_story_ids()
        if len(canonical_story_ids) > len(set(canonical_story_ids)):
            raise utils.ValidationError(
                'Expected all canonical story ids to be distinct.')

        if not isinstance(self.additional_story_references, list):
            raise utils.ValidationError(
                'Expected additional story references to be a list, received %s'
                % self.additional_story_references)
        additional_story_ids = self.get_additional_story_ids()
        if len(additional_story_ids) > len(set(additional_story_ids)):
            raise utils.ValidationError(
                'Expected all additional story ids to be distinct.')

        for story_id in additional_story_ids:
            if story_id in canonical_story_ids:
                raise utils.ValidationError(
                    'Expected additional story ids list and canonical story '
                    'ids list to be mutually exclusive. The story_id %s is '
                    'present in both lists' % story_id)

        all_story_references = self.get_all_story_references()
        for reference in all_story_references:
            reference.validate()

        if not isinstance(self.uncategorized_skill_ids, list):
            raise utils.ValidationError(
                'Expected uncategorized skill ids to be a list, received %s' %
                self.uncategorized_skill_ids)
Exemple #11
0
    def validate(self):
        """Validates all properties of this topic summary.

        Raises:
            ValidationError: One or more attributes of the Topic summary
                are not valid.
        """
        if not isinstance(self.name, python_utils.BASESTRING):
            raise utils.ValidationError('Name should be a string.')
        if self.name == '':
            raise utils.ValidationError('Name field should not be empty')

        if not isinstance(self.canonical_name, python_utils.BASESTRING):
            raise utils.ValidationError('Canonical name should be a string.')
        if self.canonical_name == '':
            raise utils.ValidationError(
                'Canonical name field should not be empty')

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)
        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        if not isinstance(self.canonical_story_count, int):
            raise utils.ValidationError(
                'Expected canonical story count to be an integer, '
                'received \'%s\'' % self.canonical_story_count)

        if self.canonical_story_count < 0:
            raise utils.ValidationError(
                'Expected canonical_story_count to be non-negative, '
                'received \'%s\'' % self.canonical_story_count)

        if not isinstance(self.additional_story_count, int):
            raise utils.ValidationError(
                'Expected additional story count to be an integer, '
                'received \'%s\'' % self.additional_story_count)

        if self.additional_story_count < 0:
            raise utils.ValidationError(
                'Expected additional_story_count to be non-negative, '
                'received \'%s\'' % self.additional_story_count)

        if not isinstance(self.uncategorized_skill_count, int):
            raise utils.ValidationError(
                'Expected uncategorized skill count to be an integer, '
                'received \'%s\'' % self.uncategorized_skill_count)

        if self.uncategorized_skill_count < 0:
            raise utils.ValidationError(
                'Expected uncategorized_skill_count to be non-negative, '
                'received \'%s\'' % self.uncategorized_skill_count)

        if not isinstance(self.total_skill_count, int):
            raise utils.ValidationError(
                'Expected total skill count to be an integer, received \'%s\''
                % self.total_skill_count)

        if self.total_skill_count < 0:
            raise utils.ValidationError(
                'Expected total_skill_count to be non-negative, '
                'received \'%s\'' % self.total_skill_count)

        if self.total_skill_count < self.uncategorized_skill_count:
            raise utils.ValidationError(
                'Expected total_skill_count to be greater than or equal to '
                'uncategorized_skill_count %s, received \'%s\'' %
                (self.uncategorized_skill_count, self.total_skill_count))

        if not isinstance(self.subtopic_count, int):
            raise utils.ValidationError(
                'Expected subtopic count to be an integer, received \'%s\'' %
                self.subtopic_count)

        if self.subtopic_count < 0:
            raise utils.ValidationError(
                'Expected subtopic_count to be non-negative, '
                'received \'%s\'' % self.subtopic_count)
Exemple #12
0
    def validate(self):
        """Validates various properties of the CollectionSummary.

        Raises:
            ValidationError. One or more attributes of the CollectionSummary
                are invalid.
        """
        if not isinstance(self.title, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(
            self.title, 'the collection title', allow_empty=True)

        if not isinstance(self.category, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected category to be a string, received %s'
                % self.category)
        utils.require_valid_name(
            self.category, 'the collection category', allow_empty=True)

        if not isinstance(self.objective, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not self.language_code:
            raise utils.ValidationError(
                'A language must be specified (in the \'Settings\' tab).')

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError(
                'Invalid language code: %s' % self.language_code)

        if not isinstance(self.tags, list):
            raise utils.ValidationError(
                'Expected tags to be a list, received %s' % self.tags)

        for tag in self.tags:
            if not isinstance(tag, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each tag to be a string, received \'%s\'' % tag)

            if not tag:
                raise utils.ValidationError('Tags should be non-empty.')

            if not re.match(constants.TAG_REGEX, tag):
                raise utils.ValidationError(
                    'Tags should only contain lowercase letters and spaces, '
                    'received \'%s\'' % tag)

            if (tag[0] not in string.ascii_lowercase or
                    tag[-1] not in string.ascii_lowercase):
                raise utils.ValidationError(
                    'Tags should not start or end with whitespace, received '
                    '\'%s\'' % tag)

            if re.search(r'\s\s+', tag):
                raise utils.ValidationError(
                    'Adjacent whitespace in tags should be collapsed, '
                    'received \'%s\'' % tag)

        if len(set(self.tags)) < len(self.tags):
            raise utils.ValidationError(
                'Expected tags to be unique, but found duplicates')

        if not isinstance(self.status, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected status to be string, received %s' % self.status)

        if not isinstance(self.community_owned, bool):
            raise utils.ValidationError(
                'Expected community_owned to be bool, received %s' % (
                    self.community_owned))

        if not isinstance(self.owner_ids, list):
            raise utils.ValidationError(
                'Expected owner_ids to be list, received %s' % self.owner_ids)
        for owner_id in self.owner_ids:
            if not isinstance(owner_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in owner_ids to '
                    'be string, received %s' % owner_id)

        if not isinstance(self.editor_ids, list):
            raise utils.ValidationError(
                'Expected editor_ids to be list, received %s' % self.editor_ids)
        for editor_id in self.editor_ids:
            if not isinstance(editor_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in editor_ids to '
                    'be string, received %s' % editor_id)

        if not isinstance(self.viewer_ids, list):
            raise utils.ValidationError(
                'Expected viewer_ids to be list, received %s' % self.viewer_ids)
        for viewer_id in self.viewer_ids:
            if not isinstance(viewer_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in viewer_ids to '
                    'be string, received %s' % viewer_id)

        if not isinstance(self.contributor_ids, list):
            raise utils.ValidationError(
                'Expected contributor_ids to be list, received %s' % (
                    self.contributor_ids))
        for contributor_id in self.contributor_ids:
            if not isinstance(contributor_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in contributor_ids to '
                    'be string, received %s' % contributor_id)

        if not isinstance(self.contributors_summary, dict):
            raise utils.ValidationError(
                'Expected contributors_summary to be dict, received %s' % (
                    self.contributors_summary))
    def validate(self, strict=True):
        """Validates all properties of this collection and its constituents.

        Raises:
            ValidationError: One or more attributes of the Collection are not
            valid.
        """

        # NOTE TO DEVELOPERS: Please ensure that this validation logic is the
        # same as that in the frontend CollectionValidatorService.

        if not isinstance(self.title, basestring):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(self.title,
                                 'the collection title',
                                 allow_empty=True)

        if not isinstance(self.category, basestring):
            raise utils.ValidationError(
                'Expected category to be a string, received %s' %
                self.category)
        utils.require_valid_name(self.category,
                                 'the collection category',
                                 allow_empty=True)

        if not isinstance(self.objective, basestring):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not self.language_code:
            raise utils.ValidationError(
                'A language must be specified (in the \'Settings\' tab).')

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        # TODO(sll): Remove this check once App Engine supports 3-letter
        # language codes in search.
        if len(self.language_code) != 2:
            raise utils.ValidationError(
                'Invalid language_code, it should have exactly 2 letters: %s' %
                self.language_code)

        if not isinstance(self.tags, list):
            raise utils.ValidationError(
                'Expected tags to be a list, received %s' % self.tags)

        if len(set(self.tags)) < len(self.tags):
            raise utils.ValidationError(
                'Expected tags to be unique, but found duplicates')

        for tag in self.tags:
            if not isinstance(tag, basestring):
                raise utils.ValidationError(
                    'Expected each tag to be a string, received \'%s\'' % tag)

            if not tag:
                raise utils.ValidationError('Tags should be non-empty.')

            if not re.match(feconf.TAG_REGEX, tag):
                raise utils.ValidationError(
                    'Tags should only contain lowercase letters and spaces, '
                    'received \'%s\'' % tag)

            if (tag[0] not in string.ascii_lowercase
                    or tag[-1] not in string.ascii_lowercase):
                raise utils.ValidationError(
                    'Tags should not start or end with whitespace, received '
                    ' \'%s\'' % tag)

            if re.search(r'\s\s+', tag):
                raise utils.ValidationError(
                    'Adjacent whitespace in tags should be collapsed, '
                    'received \'%s\'' % tag)

        if not isinstance(self.schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.schema_version)

        if self.schema_version != feconf.CURRENT_COLLECTION_SCHEMA_VERSION:
            raise utils.ValidationError(
                'Expected schema version to be %s, received %s' %
                (feconf.CURRENT_COLLECTION_SCHEMA_VERSION,
                 self.schema_version))

        if not isinstance(self.nodes, list):
            raise utils.ValidationError(
                'Expected nodes to be a list, received %s' % self.nodes)

        all_exp_ids = self.exploration_ids
        if len(set(all_exp_ids)) != len(all_exp_ids):
            raise utils.ValidationError(
                'There are explorations referenced in the collection more '
                'than once.')

        # Validate all collection nodes.
        for node in self.nodes:
            node.validate()

        if strict:
            if not self.title:
                raise utils.ValidationError(
                    'A title must be specified for the collection.')

            if not self.objective:
                raise utils.ValidationError(
                    'An objective must be specified for the collection.')

            if not self.category:
                raise utils.ValidationError(
                    'A category must be specified for the collection.')

            if not self.nodes:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration in the '
                    'collection.')

            # Ensure the collection may be started.
            if not self.first_exploration_id:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration.')
Exemple #14
0
 def test_is_valid_language_code(self):
     self.assertTrue(utils.is_valid_language_code('en'))
     self.assertFalse(utils.is_valid_language_code('unknown'))
Exemple #15
0
    def validate(self):
        """Validates various properties of the Skill object.

        Raises:
            ValidationError: One or more attributes of skill are invalid.
        """
        self.require_valid_description(self.description)

        Misconception.require_valid_misconception_id(self.next_misconception_id)

        if not isinstance(self.misconceptions_schema_version, int):
            raise utils.ValidationError(
                'Expected misconceptions schema version to be an integer, '
                'received %s' % self.misconceptions_schema_version)
        if (
                self.misconceptions_schema_version !=
                feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION):
            raise utils.ValidationError(
                'Expected misconceptions schema version to be %s, received %s'
                % (
                    feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION,
                    self.misconceptions_schema_version)
            )

        if not isinstance(self.skill_contents_schema_version, int):
            raise utils.ValidationError(
                'Expected skill contents schema version to be an integer, '
                'received %s' % self.skill_contents_schema_version)
        if (
                self.skill_contents_schema_version !=
                feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION):
            raise utils.ValidationError(
                'Expected skill contents schema version to be %s, received %s'
                % (
                    feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION,
                    self.skill_contents_schema_version)
            )

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)
        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError(
                'Invalid language code: %s' % self.language_code)

        if not isinstance(self.skill_contents, SkillContents):
            raise utils.ValidationError(
                'Expected skill_contents to be a SkillContents object, '
                'received %s' % self.skill_contents)
        self.skill_contents.validate()

        if not isinstance(self.misconceptions, list):
            raise utils.ValidationError(
                'Expected misconceptions to be a list, '
                'received %s' % self.skill_contents)
        misconception_id_list = []
        for misconception in self.misconceptions:
            if not isinstance(misconception, Misconception):
                raise utils.ValidationError(
                    'Expected each misconception to be a Misconception '
                    'object, received %s' % misconception)
            if misconception.id in misconception_id_list:
                raise utils.ValidationError(
                    'Duplicate misconception ID found: %s' % misconception.id)
            misconception_id_list.append(misconception.id)
            if int(misconception.id) >= int(self.next_misconception_id):
                raise utils.ValidationError(
                    'The misconception with id %s is out of bounds.'
                    % misconception.id)
            misconception.validate()
        if (self.all_questions_merged and
                self.superseding_skill_id is None):
            raise utils.ValidationError(
                'Expected a value for superseding_skill_id when '
                'all_questions_merged is True.')
        if (self.superseding_skill_id is not None and
                self.all_questions_merged is None):
            raise utils.ValidationError(
                'Expected a value for all_questions_merged when '
                'superseding_skill_id is set.')
Exemple #16
0
    def validate(self):
        """Validates various properties of the Skill object.

        Raises:
            ValidationError: One or more attributes of skill are invalid.
        """
        self.require_valid_description(self.description)

        Misconception.require_valid_misconception_id(
            self.next_misconception_id)

        if not isinstance(self.misconceptions_schema_version, int):
            raise utils.ValidationError(
                'Expected misconceptions schema version to be an integer, '
                'received %s' % self.misconceptions_schema_version)
        if (self.misconceptions_schema_version !=
                feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION):
            raise utils.ValidationError(
                'Expected misconceptions schema version to be %s, received %s'
                % (feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION,
                   self.misconceptions_schema_version))

        if not isinstance(self.rubric_schema_version, int):
            raise utils.ValidationError(
                'Expected rubric schema version to be an integer, '
                'received %s' % self.rubric_schema_version)
        if (self.rubric_schema_version !=
                feconf.CURRENT_RUBRIC_SCHEMA_VERSION):
            raise utils.ValidationError(
                'Expected rubric schema version to be %s, received %s' %
                (feconf.CURRENT_RUBRIC_SCHEMA_VERSION,
                 self.rubric_schema_version))

        if not isinstance(self.skill_contents_schema_version, int):
            raise utils.ValidationError(
                'Expected skill contents schema version to be an integer, '
                'received %s' % self.skill_contents_schema_version)
        if (self.skill_contents_schema_version !=
                feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION):
            raise utils.ValidationError(
                'Expected skill contents schema version to be %s, received %s'
                % (feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION,
                   self.skill_contents_schema_version))

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)
        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        if not isinstance(self.skill_contents, SkillContents):
            raise utils.ValidationError(
                'Expected skill_contents to be a SkillContents object, '
                'received %s' % self.skill_contents)
        self.skill_contents.validate()

        if not isinstance(self.rubrics, list):
            raise utils.ValidationError('Expected rubrics to be a list, '
                                        'received %s' % self.skill_contents)

        difficulties_list = []
        for rubric in self.rubrics:
            if not isinstance(rubric, Rubric):
                raise utils.ValidationError(
                    'Expected each rubric to be a Rubric '
                    'object, received %s' % rubric)
            if rubric.difficulty in difficulties_list:
                raise utils.ValidationError('Duplicate rubric found for: %s' %
                                            rubric.difficulty)
            difficulties_list.append(rubric.difficulty)
            rubric.validate()

        if len(difficulties_list) != 3:
            raise utils.ValidationError(
                'All 3 difficulties should be addressed in rubrics')

        if difficulties_list != constants.SKILL_DIFFICULTIES:
            raise utils.ValidationError(
                'The difficulties should be ordered as follows [%s, %s, %s]' %
                (constants.SKILL_DIFFICULTIES[0],
                 constants.SKILL_DIFFICULTIES[1],
                 constants.SKILL_DIFFICULTIES[2]))

        if not isinstance(self.misconceptions, list):
            raise utils.ValidationError(
                'Expected misconceptions to be a list, '
                'received %s' % self.misconceptions)

        if not isinstance(self.prerequisite_skill_ids, list):
            raise utils.ValidationError(
                'Expected prerequisite_skill_ids to be a list, '
                'received %s' % self.prerequisite_skill_ids)

        for skill_id in self.prerequisite_skill_ids:
            if not isinstance(skill_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each skill ID to be a string, '
                    'received %s' % skill_id)
        misconception_id_list = []
        for misconception in self.misconceptions:
            if not isinstance(misconception, Misconception):
                raise utils.ValidationError(
                    'Expected each misconception to be a Misconception '
                    'object, received %s' % misconception)
            if misconception.id in misconception_id_list:
                raise utils.ValidationError(
                    'Duplicate misconception ID found: %s' % misconception.id)
            misconception_id_list.append(misconception.id)
            if int(misconception.id) >= int(self.next_misconception_id):
                raise utils.ValidationError(
                    'The misconception with id %s is out of bounds.' %
                    misconception.id)
            misconception.validate()
        if (self.all_questions_merged and self.superseding_skill_id is None):
            raise utils.ValidationError(
                'Expected a value for superseding_skill_id when '
                'all_questions_merged is True.')
        if (self.superseding_skill_id is not None
                and self.all_questions_merged is None):
            raise utils.ValidationError(
                'Expected a value for all_questions_merged when '
                'superseding_skill_id is set.')
Exemple #17
0
    def get(self):
        """Handles GET requests. Responds with a mapping from content id to
        translation of form:

            dict('translated_texts', dict(str, str|None))

        If no translation is found for a given content id, that id is mapped to
        None.

        Params:
            exp_id: str. The ID of the exploration being translated.
            state_name: str. The name of the exploration state being translated.
            content_ids: str[]. The content IDs of the texts to be translated.
            target_language_code: str. The language code of the target
                translation language.

        Data Response:

            dict('translated_texts': dict(str, str|None))

            A dictionary containing the translated texts stored as a mapping
                from content ID to the translated text. If an error occured
                during retrieval of some content translations, but not others,
                failed translations are mapped to None.

        Raises:
            400 (Bad Request): InvalidInputException. At least one input is
                missing or improperly formatted.
            404 (Not Found): PageNotFoundException. At least one identifier does
                not correspond to an entry in the datastore.
        """
        exp_id = self.request.get('exp_id')
        if not exp_id:
            raise self.InvalidInputException('Missing exp_id')

        state_name = self.request.get('state_name')
        if not state_name:
            raise self.InvalidInputException('Missing state_name')

        content_ids_string = self.request.get('content_ids')
        content_ids = []
        try:
            content_ids = json.loads(content_ids_string)
        except:
            raise self.InvalidInputException(
                'Improperly formatted content_ids: %s' % content_ids_string)

        target_language_code = self.request.get('target_language_code')
        if not target_language_code:
            raise self.InvalidInputException('Missing target_language_code')

        # TODO(#12341): Tidy up this logic once we have a canonical list of
        # language codes.
        if not utils.is_supported_audio_language_code(
                target_language_code) and not utils.is_valid_language_code(
                    target_language_code):
            raise self.InvalidInputException(
                'Invalid target_language_code: %s' % target_language_code)

        exp = exp_fetchers.get_exploration_by_id(exp_id, strict=False)
        if exp is None:
            raise self.PageNotFoundException()
        state_names_to_content_id_mapping = exp.get_translatable_text(
            target_language_code)
        if state_name not in state_names_to_content_id_mapping:
            raise self.PageNotFoundException()
        content_id_to_text_mapping = (
            state_names_to_content_id_mapping[state_name])
        translated_texts = {}
        for content_id in content_ids:
            if content_id not in content_id_to_text_mapping:
                translated_texts[content_id] = None
                continue

            source_text = content_id_to_text_mapping[content_id]
            translated_texts[content_id] = (
                translation_services.get_and_cache_machine_translation(
                    exp.language_code, target_language_code, source_text))

        self.values = {'translated_texts': translated_texts}
        self.render_json(self.values)