def validate(self): """Validates StateAnswers domain object entity.""" if not isinstance(self.exploration_id, basestring): raise utils.ValidationError( 'Expected exploration_id to be a string, received %s' % str(self.exploration_id)) if not isinstance(self.state_name, basestring): raise utils.ValidationError( 'Expected state_name to be a string, received %s' % str(self.state_name)) if self.interaction_id is not None: if not isinstance(self.interaction_id, basestring): raise utils.ValidationError( 'Expected interaction_id to be a string, received %s' % str(self.interaction_id)) # Verify interaction_id is valid. if (self.interaction_id not in interaction_registry.Registry.get_all_interaction_ids()): raise utils.ValidationError('Unknown interaction_id: %s' % self.interaction_id) if not isinstance(self.submitted_answer_list, list): raise utils.ValidationError( 'Expected submitted_answer_list to be a list, received %s' % str(self.submitted_answer_list)) if not isinstance(self.schema_version, int): raise utils.ValidationError( 'Expected schema_version to be an integer, received %s' % str(self.schema_version)) if self.schema_version < 1: raise utils.ValidationError('schema_version < 1: %d' % self.schema_version) if self.schema_version > feconf.CURRENT_STATE_ANSWERS_SCHEMA_VERSION: raise utils.ValidationError( 'schema_version > feconf.CURRENT_STATE_ANSWERS_SCHEMA_VERSION ' '(%d): %d' % (feconf.CURRENT_STATE_ANSWERS_SCHEMA_VERSION, self.schema_version))
def validate(self): """Validates different attributes of the class.""" if not isinstance(self.can_review_translation_for_language_codes, list): raise utils.ValidationError( 'Expected can_review_translation_for_language_codes to be a ' 'list, found: %s' % type(self.can_review_translation_for_language_codes)) for language_code in self.can_review_translation_for_language_codes: if not utils.is_supported_audio_language_code(language_code): raise utils.ValidationError('Invalid language_code: %s' % (language_code)) if len(self.can_review_translation_for_language_codes) != len( set(self.can_review_translation_for_language_codes)): raise utils.ValidationError( 'Expected can_review_translation_for_language_codes list not ' 'to have duplicate values, found: %s' % (self.can_review_translation_for_language_codes)) if not isinstance(self.can_review_voiceover_for_language_codes, list): raise utils.ValidationError( 'Expected can_review_voiceover_for_language_codes to be a ' 'list, found: %s' % type(self.can_review_voiceover_for_language_codes)) for language_code in self.can_review_voiceover_for_language_codes: if not utils.is_supported_audio_language_code(language_code): raise utils.ValidationError('Invalid language_code: %s' % (language_code)) if len(self.can_review_voiceover_for_language_codes) != len( set(self.can_review_voiceover_for_language_codes)): raise utils.ValidationError( 'Expected can_review_voiceover_for_language_codes list not to ' 'have duplicate values, found: %s' % (self.can_review_voiceover_for_language_codes)) if not isinstance(self.can_review_questions, bool): raise utils.ValidationError( 'Expected can_review_questions to be a boolean value, ' 'found: %s' % type(self.can_review_questions)) if not isinstance(self.can_submit_questions, bool): raise utils.ValidationError( 'Expected can_submit_questions to be a boolean value, ' 'found: %s' % type(self.can_submit_questions))
def does_topic_with_url_fragment_exist(url_fragment): """Checks if topic with provided url fragment exists. Args: url_fragment: str. The url fragment for the topic. Returns: bool. Whether the the url fragment for the topic exists. Raises: Exception. Topic URL fragment is not a string. """ if not isinstance(url_fragment, python_utils.BASESTRING): raise utils.ValidationError('Topic URL fragment should be a string.') existing_topic = ( topic_fetchers.get_topic_by_url_fragment(url_fragment)) return existing_topic is not None
def does_blog_post_with_url_fragment_exist(url_fragment): """Checks if blog post with provided url fragment exists. Args: url_fragment: str. The url fragment for the blog post. Returns: bool. Whether the the url fragment for the blog post exists. Raises: Exception. Blog Post URL fragment is not a string. """ if not isinstance(url_fragment, python_utils.BASESTRING): raise utils.ValidationError( 'Blog Post URL fragment should be a string. Recieved:' '%s' % url_fragment) existing_blog_post = get_blog_post_by_url_fragment(url_fragment) return existing_blog_post is not None
def validate(self): """Validates properties of the MachineTranslatedText. Raises: ValidationError. One or more attributes of the MachineTranslatedText 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 is 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)
def validate(self): """Validates the SubtopicPageContentsObject, verifying that all fields are of the correct type. """ self.subtitled_html.validate() # TODO(tjiang11): Extract content ids to audio translations out into # its own object to reuse throughout audio-capable structures. if not isinstance(self.content_ids_to_audio_translations, dict): raise utils.ValidationError( 'Expected content_ids_to_audio_translations to be a dict,' 'received %s' % self.content_ids_to_audio_translations) for (content_id, audio_translations) in ( self.content_ids_to_audio_translations.iteritems()): if not isinstance(content_id, basestring): raise utils.ValidationError( 'Expected content_id to be a string, received: %s' % content_id) if not isinstance(audio_translations, dict): raise utils.ValidationError( 'Expected audio_translations to be a dict, received %s' % audio_translations) allowed_audio_language_codes = [ language['id'] for language in ( constants.SUPPORTED_AUDIO_LANGUAGES)] for language_code, translation in audio_translations.iteritems(): if not isinstance(language_code, basestring): raise utils.ValidationError( 'Expected language code to be a string, received: %s' % language_code) if language_code not in allowed_audio_language_codes: raise utils.ValidationError( 'Unrecognized language code: %s' % language_code) translation.validate() content_ids = set([self.subtitled_html.content_id]) audio_content_ids = set( [audio[0] for audio in self.content_ids_to_audio_translations.iteritems()]) for c in audio_content_ids: if c not in content_ids: raise utils.ValidationError( 'Expected content_ids_to_audio_translations to contain ' 'only content_ids in the subtopic page. ' 'content_ids_to_audio_translations: %s. ' 'content IDs found: %s' % (audio_content_ids, content_ids))
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()
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)
def validate(self): """Validates the PlatformParameterFilter domain object.""" if self._type not in self.SUPPORTED_FILTER_TYPES: raise utils.ValidationError( 'Unsupported filter type \'%s\'' % self._type) for op, _ in self._conditions: if op not in self.SUPPORTED_OP_FOR_FILTERS[self._type]: raise utils.ValidationError( 'Unsupported comparison operator \'%s\' for %s filter, ' 'expected one of %s.' % ( op, self._type, self.SUPPORTED_OP_FOR_FILTERS[self._type])) if self._type == 'server_mode': for _, mode in self._conditions: if mode not in ALLOWED_SERVER_MODES: raise utils.ValidationError( 'Invalid server mode \'%s\', must be one of %s.' % ( mode, ALLOWED_SERVER_MODES)) elif self._type == 'user_locale': for _, locale in self._conditions: if locale not in ALLOWED_USER_LOCALES: raise utils.ValidationError( 'Invalid user locale \'%s\', must be one of %s.' % ( locale, ALLOWED_USER_LOCALES)) elif self._type == 'client_type': for _, client_type in self._conditions: if client_type not in ALLOWED_CLIENT_TYPES: raise utils.ValidationError( 'Invalid client type \'%s\', must be one of %s.' % ( client_type, ALLOWED_CLIENT_TYPES)) elif self._type == 'app_version_flavor': for _, flavor in self._conditions: if flavor not in ALLOWED_APP_VERSION_FLAVOR: raise utils.ValidationError( 'Invalid app version flavor \'%s\', must be one of' ' %s.' % (flavor, ALLOWED_APP_VERSION_FLAVOR)) elif self._type == 'app_version': for _, version in self._conditions: if not APP_VERSION_WITHOUT_HASH_REGEXP.match(version): raise utils.ValidationError( 'Invalid version expression \'%s\', expected to match' 'regexp %s.' % ( version, APP_VERSION_WITHOUT_HASH_REGEXP))
def validate(self): """Validates a suggestion object of type SuggestionAddQuestion. Raises: ValidationError: One or more attributes of the SuggestionAddQuestion object are invalid. """ super(SuggestionAddQuestion, self).validate() if self.get_score_type() != suggestion_models.SCORE_TYPE_QUESTION: raise utils.ValidationError( 'Expected the first part of score_category to be "%s" ' ', received "%s"' % ( suggestion_models.SCORE_TYPE_QUESTION, self.get_score_type())) if not isinstance(self.change, question_domain.QuestionChange): raise utils.ValidationError( 'Expected change to be an instance of QuestionChange') if not self.change.cmd: raise utils.ValidationError('Expected change to contain cmd') if ( self.change.cmd != question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION): raise utils.ValidationError('Expected cmd to be %s, obtained %s' % ( question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION, self.change.cmd)) if not self.change.question_dict: raise utils.ValidationError( 'Expected change to contain question_dict') question = question_domain.Question( None, state_domain.State.from_dict( self.change.question_dict['question_state_data']), self.change.question_dict['question_state_data_schema_version'], self.change.question_dict['language_code'], None, self.change.question_dict['linked_skill_ids']) question.partial_validate() question_state_data_schema_version = ( self.change.question_dict['question_state_data_schema_version']) if not ( question_state_data_schema_version >= 1 and question_state_data_schema_version <= feconf.CURRENT_STATE_SCHEMA_VERSION): raise utils.ValidationError( 'Expected question state schema version to be between 1 and ' '%s' % feconf.CURRENT_STATE_SCHEMA_VERSION)
def accept(self, unused_commit_message): """Accepts the suggestion. Args: unused_commit_message: str. This parameter is passed in for consistency with the existing suggestions. As a default commit message is used in the add_question function, the arg is unused. """ question_dict = self.change.question_dict question_dict['version'] = 1 question_dict['id'] = (question_services.get_new_question_id()) question = question_domain.Question.from_dict(question_dict) question.validate() question_services.add_question(self.author_id, question) skill = skill_services.get_skill_by_id(self.change.skill_id, strict=False) if skill is None: raise utils.ValidationError( 'The skill with the given id doesn\'t exist.') question_services.create_new_question_skill_link( question_dict['id'], self.change.skill_id)
def validate(self): """Validates various properties of the story object. Raises: ValidationError: One or more attributes of story are invalid. """ if not isinstance(self.title, basestring): raise utils.ValidationError( 'Expected title to be a string, received %s' % 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 any([ self.language_code == lc['code'] for lc in constants.ALL_LANGUAGE_CODES ]): raise utils.ValidationError('Invalid language code: %s' % self.language_code) self.story_contents.validate()
def validate(self): """Validates the classifier before it is saved to storage.""" if not isinstance(self.id, basestring): raise utils.ValidationError( 'Expected id to be a string, received %s' % self.id) if not isinstance(self.exp_id, basestring): raise utils.ValidationError( 'Expected exp_id to be a string, received %s' % self.exp_id) if not isinstance(self.exp_version_when_created, int): raise utils.ValidationError( 'Expected exp_version_when_created to be an int, received %s' % self.exp_version_when_created) if not isinstance(self.state_name, basestring): raise utils.ValidationError( 'Expected id to be a string, received %s' % self.state_name) utils.require_valid_name(self.state_name, 'the state name') if not isinstance(self.algorithm_id, basestring): raise utils.ValidationError( 'Expected algorithm_id to be a string, received %s' % self.algorithm_id) utils.require_valid_name(self.algorithm_id, 'the algorithm id') algorithm_ids = [ classifier_details['algorithm_id'] for classifier_details in feconf.INTERACTION_CLASSIFIER_MAPPING.values() ] if self.algorithm_id not in algorithm_ids: raise utils.ValidationError('Invalid algorithm id: %s' % self.algorithm_id) if not isinstance(self.classifier_data, dict): raise utils.ValidationError( 'Expected classifier_data to be a dict, received %s' % (self.classifier_data)) classifier_class = ( classifier_registry.Registry.get_classifier_by_algorithm_id( self.algorithm_id)) classifier_class.validate(self.classifier_data)
def update_blog_post(blog_post_id, change_dict): """Updates the blog post and its summary model in the datastore. Args: blog_post_id: str. The ID of the blog post which is to be updated. change_dict: dict. A dict containing all the changes keyed by corresponding field name (title, content, thumbnail_filename, tags). """ updated_blog_post = apply_change_dict(blog_post_id, change_dict) if 'title' in change_dict: blog_post_models = blog_models.BlogPostModel.query().filter( blog_models.BlogPostModel.title == updated_blog_post.title).filter( blog_models.BlogPostModel.deleted == False).fetch() # pylint: disable=singleton-comparison if blog_post_models != []: raise utils.ValidationError( 'Blog Post with given title already exists: %s' % updated_blog_post.title) _save_blog_post(updated_blog_post) updated_blog_post_summary = compute_summary_of_blog_post(updated_blog_post) _save_blog_post_summary(updated_blog_post_summary)
def validate(self): """Validates a visualization object. This is only used in tests for the validity of interactions. """ # Check that the calculation id exists. calculation_registry.Registry.get_calculation_by_id( self.calculation_id) # Check that the options_dict is valid. expected_option_names = sorted( [spec['name'] for spec in self._OPTIONS_SPECS]) actual_option_names = sorted(self.options.keys()) if actual_option_names != expected_option_names: raise utils.ValidationError( 'For visualization %s, expected option names %s; received ' 'names %s' % (self.id, expected_option_names, actual_option_names)) # Check that the schemas are correct. for spec in self._OPTIONS_SPECS: schema_utils.normalize_against_schema(self.options[spec['name']], spec['schema'])
def validate(self): """Validates the Question domain object before it is saved.""" if not isinstance(self.question_id, basestring): raise utils.ValidationError( 'Expected ID to be a string, received %s' % self.question_id) if not isinstance(self.title, basestring): raise utils.ValidationError( 'Expected title to be a string, received %s' % self.title) if not isinstance(self.question_data, dict): raise utils.ValidationError( 'Expected question_data to be a dict, received %s' % self.question_data) question_data = exp_domain.State.from_dict(self.question_data) question_data.validate(None, True) if not isinstance(self.question_data_schema_version, int): raise utils.ValidationError( 'Expected question_data_schema_version to be a integer,' + 'received %s' % self.question_data_schema_version) if not isinstance(self.collection_id, basestring): raise utils.ValidationError( 'Expected collection_id to be a string, received %s' % self.collection_id) if not isinstance(self.language_code, basestring): raise utils.ValidationError( 'Expected language_code to be a string, received %s' % self.language_code) if not any([ self.language_code == lc['code'] for lc in constants.ALL_LANGUAGE_CODES ]): raise utils.ValidationError('Invalid language code: %s' % self.language_code)
def validate(cls, value_dict): """Validates customization args for a rich text component. Raises: TypeError. If any customization arg is invalid. """ arg_names_to_obj_classes = {} customization_arg_specs = cls.rich_text_component_specs[ cls.__name__]['customization_arg_specs'] for customization_arg_spec in customization_arg_specs: arg_name = '%s-with-value' % customization_arg_spec['name'] schema = customization_arg_spec['schema'] if schema['type'] != 'custom': obj_type = schema['type'] else: obj_type = schema['obj_type'] obj_class = cls.obj_types_to_obj_classes[obj_type] arg_names_to_obj_classes[arg_name] = obj_class required_attr_names = list(arg_names_to_obj_classes.keys()) attr_names = list(value_dict.keys()) if set(attr_names) != set(required_attr_names): missing_attr_names = list( set(required_attr_names) - set(attr_names)) extra_attr_names = list(set(attr_names) - set(required_attr_names)) raise utils.ValidationError( 'Missing attributes: %s, Extra attributes: %s' % ( ', '.join(missing_attr_names), ', '.join(extra_attr_names) ) ) for arg_name in required_attr_names: arg_obj_class = arg_names_to_obj_classes[arg_name] arg_obj_class.normalize(value_dict[arg_name])
def validate(self): """Validates the CommunityContributionStats object. Raises: ValidationError. One or more attributes of the CommunityContributionStats object is invalid. """ for language_code, reviewer_count in ( self.translation_reviewer_counts_by_lang_code.items()): if reviewer_count < 0: raise utils.ValidationError( 'Expected the translation reviewer count to be ' 'non-negative for %s language code, recieved: %s.' % (language_code, reviewer_count)) # Translation languages are a part of audio languages. if not utils.is_supported_audio_language_code(language_code): raise utils.ValidationError( 'Invalid language code for the translation reviewer ' 'counts: %s.' % language_code) for language_code, suggestion_count in ( self.translation_suggestion_counts_by_lang_code.items()): if suggestion_count < 0: raise utils.ValidationError( 'Expected the translation suggestion count to be ' 'non-negative for %s language code, recieved: %s.' % (language_code, suggestion_count)) # Translation languages are a part of audio languages. if not utils.is_supported_audio_language_code(language_code): raise utils.ValidationError( 'Invalid language code for the translation suggestion ' 'counts: %s.' % language_code) if self.question_reviewer_count < 0: raise utils.ValidationError( 'Expected the question reviewer count to be non-negative, ' 'recieved: %s.' % (self.question_reviewer_count)) if self.question_suggestion_count < 0: raise utils.ValidationError( 'Expected the question suggestion count to be non-negative, ' 'recieved: %s.' % (self.question_suggestion_count))
def validate(self): """Validates the PlatformParameterFilter domain object.""" if self._type not in self.SUPPORTED_FILTER_TYPES: raise utils.ValidationError('Unsupported filter type \'%s\'' % self._type) for op, _ in self._conditions: if op not in self.SUPPORTED_OP_FOR_FILTERS[self._type]: raise utils.ValidationError( 'Unsupported comparison operator \'%s\' for %s filter, ' 'expected one of %s.' % (op, self._type, self.SUPPORTED_OP_FOR_FILTERS[self._type])) if self._type == 'server_mode': for _, mode in self._conditions: if not any([ mode == server_mode.value for server_mode in ALLOWED_SERVER_MODES ]): raise utils.ValidationError( 'Invalid server mode \'%s\', must be one of %s.' % (mode, ALLOWED_SERVER_MODES)) elif self._type == 'platform_type': for _, platform_type in self._conditions: if platform_type not in ALLOWED_PLATFORM_TYPES: raise utils.ValidationError( 'Invalid platform type \'%s\', must be one of %s.' % (platform_type, ALLOWED_PLATFORM_TYPES)) elif self._type == 'app_version_flavor': for _, flavor in self._conditions: if flavor not in ALLOWED_APP_VERSION_FLAVORS: raise utils.ValidationError( 'Invalid app version flavor \'%s\', must be one of' ' %s.' % (flavor, ALLOWED_APP_VERSION_FLAVORS)) elif self._type == 'app_version': for _, version in self._conditions: if not APP_VERSION_WITHOUT_HASH_REGEXP.match(version): raise utils.ValidationError( 'Invalid version expression \'%s\', expected to match' 'regexp %s.' % (version, APP_VERSION_WITHOUT_HASH_REGEXP))
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, python_utils.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, python_utils.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 an int, received \'%s\'' % (self.node_count)) if self.node_count < 0: raise utils.ValidationError( 'Expected node_count to be non-negative, received \'%s\'' % (self.node_count)) 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)
def validate(self): """Validates various properties of the SubtopicPage object. Raises: ValidationError. One or more attributes of the subtopic page are invalid. """ if not isinstance(self.topic_id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected topic_id to be a string, received %s' % self.topic_id) if not isinstance(self.version, int): raise utils.ValidationError( 'Expected version number to be an int, received %s' % self.version) self.page_contents.validate() if not isinstance(self.page_contents_schema_version, int): raise utils.ValidationError( 'Expected page contents schema version to be an integer, ' 'received %s' % self.page_contents_schema_version) if ( self.page_contents_schema_version != feconf.CURRENT_SUBTOPIC_PAGE_CONTENTS_SCHEMA_VERSION): raise utils.ValidationError( 'Expected page contents schema version to be %s, received %s' % ( feconf.CURRENT_SUBTOPIC_PAGE_CONTENTS_SCHEMA_VERSION, self.page_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 any( self.language_code == lc['code'] for lc in constants.SUPPORTED_CONTENT_LANGUAGES ): raise utils.ValidationError( 'Invalid language code: %s' % self.language_code)
def validate(self): """Checks that user_id, created_exploration_ids and edited_exploration_ids fields of this UserContributions domain object are valid. Raises: ValidationError. The user_id is not str. ValidationError. The created_exploration_ids is not a list. ValidationError. The exploration_id in created_exploration_ids is not str. ValidationError. The edited_exploration_ids is not a list. ValidationError. The exploration_id in edited_exploration_ids is not str. """ if not isinstance(self.user_id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected user_id to be a string, received %s' % self.user_id) if not self.user_id: raise utils.ValidationError('No user id specified.') if not isinstance(self.created_exploration_ids, list): raise utils.ValidationError( 'Expected created_exploration_ids to be a list, received %s' % self.created_exploration_ids) for exploration_id in self.created_exploration_ids: if not isinstance(exploration_id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected exploration_id in created_exploration_ids ' 'to be a string, received %s' % ( exploration_id)) if not isinstance(self.edited_exploration_ids, list): raise utils.ValidationError( 'Expected edited_exploration_ids to be a list, received %s' % self.edited_exploration_ids) for exploration_id in self.edited_exploration_ids: if not isinstance(exploration_id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected exploration_id in edited_exploration_ids ' 'to be a string, received %s' % ( exploration_id))
def validate(self): """Validates a suggestion object of type SuggestionTranslateContent. Raises: ValidationError. One or more attributes of the SuggestionTranslateContent object are invalid. """ super(SuggestionTranslateContent, self).validate() if not isinstance(self.change, exp_domain.ExplorationChange): raise utils.ValidationError( 'Expected change to be an ExplorationChange, received %s' % type(self.change)) # The score sub_type needs to match the validation for exploration # category, i.e the second part of the score_category should match # the target exploration's category and we have a prod validation # for the same. if self.get_score_type() != suggestion_models.SCORE_TYPE_TRANSLATION: raise utils.ValidationError( 'Expected the first part of score_category to be %s ' ', received %s' % (suggestion_models.SCORE_TYPE_TRANSLATION, self.get_score_type())) if self.change.cmd != exp_domain.CMD_ADD_TRANSLATION: raise utils.ValidationError( 'Expected cmd to be %s, received %s' % (exp_domain.CMD_ADD_TRANSLATION, self.change.cmd)) if not utils.is_supported_audio_language_code( self.change.language_code): raise utils.ValidationError('Invalid language_code: %s' % self.change.language_code) if self.language_code is None: raise utils.ValidationError('language_code cannot be None') if self.language_code != self.change.language_code: raise utils.ValidationError( 'Expected language_code to be %s, received %s' % (self.change.language_code, self.language_code))
def validate(self): """Validates the Question summary domain object before it is saved. Raises: ValidationError. One or more attributes of question summary are invalid. """ if not isinstance(self.id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected id to be a string, received %s' % self.id) if not isinstance(self.question_content, python_utils.BASESTRING): raise utils.ValidationError( 'Expected question content to be a string, received %s' % self.question_content) if not isinstance(self.interaction_id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected interaction id to be a string, received %s' % self.interaction_id) if not isinstance(self.created_on, datetime.datetime): raise utils.ValidationError( 'Expected created on to be a datetime, received %s' % self.created_on) if not isinstance(self.last_updated, datetime.datetime): raise utils.ValidationError( 'Expected last updated to be a datetime, received %s' % self.last_updated) if not (isinstance(self.misconception_ids, list) and ( all(isinstance(elem, python_utils.BASESTRING) for elem in ( self.misconception_ids)))): raise utils.ValidationError( 'Expected misconception ids to be a list of ' 'strings, received %s' % self.misconception_ids)
def validate(self): """Validates the EvaluationContext domain object.""" if self._client_type not in ALLOWED_CLIENT_TYPES: raise utils.ValidationError( 'Invalid client type \'%s\', must be one of %s.' % ( self._client_type, ALLOWED_CLIENT_TYPES)) if ( self._browser_type is not None and self._browser_type not in ALLOWED_BROWSER_TYPES): raise utils.ValidationError( 'Invalid browser type \'%s\', must be one of %s.' % ( self._browser_type, ALLOWED_BROWSER_TYPES)) if self._app_version is not None: match = APP_VERSION_WITH_HASH_REGEXP.match(self._app_version) if match is None: raise utils.ValidationError( 'Invalid version \'%s\', expected to match regexp %s.' % ( self._app_version, APP_VERSION_WITH_HASH_REGEXP)) elif ( match.group(2) is not None and match.group(2) not in ALLOWED_APP_VERSION_FLAVOR): raise utils.ValidationError( 'Invalid version flavor \'%s\', must be one of %s if' ' specified.' % ( match.group(2), ALLOWED_APP_VERSION_FLAVOR)) if self._user_locale not in ALLOWED_USER_LOCALES: raise utils.ValidationError( 'Invalid user locale \'%s\', must be one of %s.' % ( self._user_locale, ALLOWED_USER_LOCALES)) if self._server_mode not in ALLOWED_SERVER_MODES: raise utils.ValidationError( 'Invalid server mode \'%s\', must be one of %s.' % ( self._server_mode, ALLOWED_SERVER_MODES))
def validate(self): """Validates an ActivityRights object. Raises: utils.ValidationError: if any of the owners, editors and viewers lists overlap, or if a community-owned exploration has owners, editors or viewers specified. """ if self.community_owned: if self.owner_ids or self.editor_ids or self.viewer_ids: raise utils.ValidationError( 'Community-owned explorations should have no owners, ' 'editors or viewers specified.') if self.community_owned and self.status == ACTIVITY_STATUS_PRIVATE: raise utils.ValidationError( 'Community-owned explorations cannot be private.') if self.status != ACTIVITY_STATUS_PRIVATE and self.viewer_ids: raise utils.ValidationError( 'Public explorations should have no viewers specified.') owner_editor = set(self.owner_ids).intersection(set(self.editor_ids)) owner_viewer = set(self.owner_ids).intersection(set(self.viewer_ids)) editor_viewer = set(self.editor_ids).intersection(set(self.viewer_ids)) if owner_editor: raise utils.ValidationError( 'A user cannot be both an owner and an editor: %s' % owner_editor) if owner_viewer: raise utils.ValidationError( 'A user cannot be both an owner and a viewer: %s' % owner_viewer) if editor_viewer: raise utils.ValidationError( 'A user cannot be both an owner and an editor: %s' % editor_viewer)
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)
def _save_collection(committer_id, collection, commit_message, change_list): """Validates a collection and commits it to persistent storage. If successful, increments the version number of the incoming collection domain object by 1. Args: committer_id: str. ID of the given committer. collection: Collection. The collection domain object to be saved. commit_message: str. The commit message. change_list: list(dict). List of changes applied to a collection. Each entry in change_list is a dict that represents a CollectionChange. Raises: ValidationError: An invalid exploration was referenced in the collection. Exception: The collection model and the incoming collection domain object have different version numbers. """ if not change_list: raise Exception( 'Unexpected error: received an invalid change list when trying to ' 'save collection %s: %s' % (collection.id, change_list)) collection_rights = rights_manager.get_collection_rights(collection.id) if collection_rights.status != rights_manager.ACTIVITY_STATUS_PRIVATE: collection.validate(strict=True) else: collection.validate(strict=False) # Validate that all explorations referenced by the collection exist. exp_ids = collection.exploration_ids exp_summaries = ( exp_services.get_exploration_summaries_matching_ids(exp_ids)) exp_summaries_dict = { exp_id: exp_summaries[ind] for (ind, exp_id) in enumerate(exp_ids) } for collection_node in collection.nodes: if not exp_summaries_dict[collection_node.exploration_id]: raise utils.ValidationError( 'Expected collection to only reference valid explorations, ' 'but found an exploration with ID: %s (was it deleted?)' % collection_node.exploration_id) # Ensure no explorations are being added that are 'below' the public status # of this collection. If the collection is private, it can have both # private and public explorations. If it's public, it can only have public # explorations. # TODO(bhenning): Ensure the latter is enforced above when trying to # publish a collection. if rights_manager.is_collection_public(collection.id): validate_exps_in_collection_are_public(collection) collection_model = collection_models.CollectionModel.get(collection.id, strict=False) if collection_model is None: collection_model = collection_models.CollectionModel(id=collection.id) else: if collection.version > collection_model.version: raise Exception( 'Unexpected error: trying to update version %s of collection ' 'from version %s. Please reload the page and try again.' % (collection_model.version, collection.version)) elif collection.version < collection_model.version: raise Exception( 'Trying to update version %s of collection from version %s, ' 'which is too old. Please reload the page and try again.' % (collection_model.version, collection.version)) collection_model.category = collection.category collection_model.title = collection.title collection_model.objective = collection.objective collection_model.language_code = collection.language_code collection_model.tags = collection.tags collection_model.schema_version = collection.schema_version collection_model.collection_contents = { 'nodes': [collection_node.to_dict() for collection_node in collection.nodes], 'skills': { skill_id: skill.to_dict() for skill_id, skill in collection.skills.iteritems() }, 'next_skill_index': collection.next_skill_index } collection_model.node_count = len(collection_model.nodes) collection_model.commit(committer_id, commit_message, change_list) memcache_services.delete(_get_collection_memcache_key(collection.id)) index_collections_given_ids([collection.id]) collection.version += 1
def update_story( committer_id, story_id, change_list, commit_message): """Updates a story. Commits changes. # NOTE: This function should not be called on its own. Access it # through `topic_services.update_story_and_topic_summary`. Args: committer_id: str. The id of the user who is performing the update action. story_id: str. The story id. change_list: list(StoryChange). These changes are applied in sequence to produce the resulting story. commit_message: str or None. A description of changes made to the story. Raises: ValidationError. Exploration is already linked to a different story. """ if not commit_message: raise ValueError('Expected a commit message but received none.') old_story = story_fetchers.get_story_by_id(story_id) new_story, exp_ids_removed_from_story, exp_ids_added_to_story = ( apply_change_list(story_id, change_list)) story_is_published = _is_story_published_and_present_in_topic(new_story) exploration_context_models_to_be_deleted = ( exp_models.ExplorationContextModel.get_multi( exp_ids_removed_from_story)) exploration_context_models_to_be_deleted = [ model for model in exploration_context_models_to_be_deleted if model is not None] exploration_context_models_collisions_list = ( exp_models.ExplorationContextModel.get_multi( exp_ids_added_to_story)) for context_model in exploration_context_models_collisions_list: if context_model is not None and context_model.story_id != story_id: raise utils.ValidationError( 'The exploration with ID %s is already linked to story ' 'with ID %s' % (context_model.id, context_model.story_id)) if ( old_story.url_fragment != new_story.url_fragment and does_story_exist_with_url_fragment(new_story.url_fragment)): raise utils.ValidationError( 'Story Url Fragment is not unique across the site.') _save_story( committer_id, new_story, commit_message, change_list, story_is_published) create_story_summary(new_story.id) if story_is_published and _is_topic_published(new_story): opportunity_services.update_exploration_opportunities( old_story, new_story) suggestion_services.auto_reject_translation_suggestions_for_exp_ids( exp_ids_removed_from_story) exp_models.ExplorationContextModel.delete_multi( exploration_context_models_to_be_deleted) new_exploration_context_models = [exp_models.ExplorationContextModel( id=exp_id, story_id=story_id ) for exp_id in exp_ids_added_to_story] exp_models.ExplorationContextModel.update_timestamps_multi( new_exploration_context_models) exp_models.ExplorationContextModel.put_multi(new_exploration_context_models)
def validate_explorations_for_story(exp_ids, strict): """Validates the explorations in the given story and checks whether they are compatible with the mobile app and ready for publishing. Args: exp_ids: list(str). The exp IDs to validate. strict: bool. Whether to raise an Exception when a validation error is encountered. If not, a list of the error messages are returned. strict should be True when this is called before saving the story and False when this function is called from the frontend. Returns: list(str). The various validation error messages (if strict is False). Raises: ValidationError. Expected story to only reference valid explorations. ValidationError. Exploration with ID is not public. Please publish explorations before adding them to a story. ValidationError. All explorations in a story should be of the same category. """ validation_error_messages = [] # Strict = False, since the existence of explorations is checked below. exps_dict = ( exp_fetchers.get_multiple_explorations_by_id(exp_ids, strict=False)) exp_rights = ( rights_manager.get_multiple_exploration_rights_by_ids(exp_ids)) exp_rights_dict = {} for rights in exp_rights: if rights is not None: exp_rights_dict[rights.id] = rights.status for exp_id in exp_ids: if exp_id not in exps_dict: error_string = ( 'Expected story to only reference valid explorations, but found' ' a reference to an invalid exploration with ID: %s' % exp_id) if strict: raise utils.ValidationError(error_string) validation_error_messages.append(error_string) else: if exp_rights_dict[exp_id] != constants.ACTIVITY_STATUS_PUBLIC: error_string = ( 'Exploration with ID %s is not public. Please publish ' 'explorations before adding them to a story.' % exp_id) if strict: raise utils.ValidationError(error_string) validation_error_messages.append(error_string) if exps_dict: for exp_id in exp_ids: if exp_id in exps_dict: sample_exp_id = exp_id break common_exp_category = exps_dict[sample_exp_id].category for exp_id in exps_dict: exp = exps_dict[exp_id] if exp.category != common_exp_category: error_string = ( 'All explorations in a story should be of the ' 'same category. The explorations with ID %s and %s have' ' different categories.' % (sample_exp_id, exp_id)) if strict: raise utils.ValidationError(error_string) validation_error_messages.append(error_string) try: validation_error_messages.extend( exp_services.validate_exploration_for_story(exp, strict)) except Exception as e: logging.exception( 'Exploration validation failed for exploration with ID: ' '%s. Error: %s' % (exp_id, e)) raise Exception(e) return validation_error_messages