def test_get_subtopic_pages_with_ids(self): subtopic_ids = [self.subtopic_id] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) self.assertEqual( subtopic_pages[0].to_dict(), self.subtopic_page.to_dict()) subtopic_ids = [2] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) self.assertEqual(subtopic_pages, [None]) subtopic_ids = [self.subtopic_id, 2] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) expected_subtopic_pages = [self.subtopic_page.to_dict(), None] self.assertEqual( [subtopic_pages[0].to_dict(), subtopic_pages[1]], expected_subtopic_pages) subtopic_ids = [] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) self.assertEqual(subtopic_pages, []) subtopic_ids = [2, 2] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) self.assertEqual(subtopic_pages, [None, None])
def test_get_subtopic_pages_with_ids(self) -> None: subtopic_ids = [self.subtopic_id] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) # Ruling out the possibility of None for mypy type checking. assert subtopic_pages[0] is not None self.assertEqual(subtopic_pages[0].to_dict(), self.subtopic_page.to_dict()) subtopic_ids = [2] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) self.assertEqual(subtopic_pages, [None]) subtopic_ids = [self.subtopic_id, 2] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) expected_subtopic_pages = [self.subtopic_page.to_dict(), None] # Ruling out the possibility of None for mypy type checking. assert subtopic_pages[0] is not None self.assertEqual([subtopic_pages[0].to_dict(), subtopic_pages[1]], expected_subtopic_pages) subtopic_ids = [] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) self.assertEqual(subtopic_pages, []) subtopic_ids = [2, 2] subtopic_pages = subtopic_page_services.get_subtopic_pages_with_ids( self.TOPIC_ID, subtopic_ids) self.assertEqual(subtopic_pages, [None, None])
def apply_change_list(topic_id, change_list): """Applies a changelist to a topic and returns the result. The incoming changelist should not have simultaneuous creations and deletion of subtopics. Args: topic_id: str. ID of the given topic. change_list: list(TopicChange). A change list to be applied to the given topic. Raises: Exception. The incoming changelist had simultaneuous creation and deletion of subtopics. Returns: tuple(Topic, dict, list(int), list(int), list(SubtopicPageChange)). The modified topic object, the modified subtopic pages dict keyed by subtopic page id containing the updated domain objects of each subtopic page, a list of ids of the deleted subtopics, a list of ids of the newly created subtopics and a list of changes applied to modified subtopic pages. """ topic = topic_fetchers.get_topic_by_id(topic_id) newly_created_subtopic_ids = [] existing_subtopic_page_ids_to_be_modified = [] deleted_subtopic_ids = [] modified_subtopic_pages_list = [] modified_subtopic_pages = {} modified_subtopic_change_cmds = collections.defaultdict(list) for change in change_list: if (change.cmd == subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY): if change.subtopic_id < topic.next_subtopic_id: existing_subtopic_page_ids_to_be_modified.append( change.subtopic_id) subtopic_page_id = ( subtopic_page_domain.SubtopicPage.get_subtopic_page_id( topic_id, change.subtopic_id)) modified_subtopic_change_cmds[subtopic_page_id].append(change) modified_subtopic_pages_list = ( subtopic_page_services.get_subtopic_pages_with_ids( topic_id, existing_subtopic_page_ids_to_be_modified)) for subtopic_page in modified_subtopic_pages_list: modified_subtopic_pages[subtopic_page.id] = subtopic_page try: for change in change_list: if change.cmd == topic_domain.CMD_ADD_SUBTOPIC: topic.add_subtopic(change.subtopic_id, change.title) subtopic_page_id = ( subtopic_page_domain.SubtopicPage.get_subtopic_page_id( topic_id, change.subtopic_id)) modified_subtopic_pages[subtopic_page_id] = ( subtopic_page_domain.SubtopicPage. create_default_subtopic_page( # pylint: disable=line-too-long change.subtopic_id, topic_id)) modified_subtopic_change_cmds[subtopic_page_id].append( subtopic_page_domain.SubtopicPageChange({ 'cmd': 'create_new', 'topic_id': topic_id, 'subtopic_id': change.subtopic_id })) newly_created_subtopic_ids.append(change.subtopic_id) elif change.cmd == topic_domain.CMD_DELETE_SUBTOPIC: topic.delete_subtopic(change.subtopic_id) if change.subtopic_id in newly_created_subtopic_ids: raise Exception('The incoming changelist had simultaneous' ' creation and deletion of subtopics.') deleted_subtopic_ids.append(change.subtopic_id) elif change.cmd == topic_domain.CMD_ADD_CANONICAL_STORY: topic.add_canonical_story(change.story_id) elif change.cmd == topic_domain.CMD_DELETE_CANONICAL_STORY: topic.delete_canonical_story(change.story_id) elif change.cmd == topic_domain.CMD_REARRANGE_CANONICAL_STORY: topic.rearrange_canonical_story(change.from_index, change.to_index) elif change.cmd == topic_domain.CMD_ADD_ADDITIONAL_STORY: topic.add_additional_story(change.story_id) elif change.cmd == topic_domain.CMD_DELETE_ADDITIONAL_STORY: topic.delete_additional_story(change.story_id) elif change.cmd == topic_domain.CMD_ADD_UNCATEGORIZED_SKILL_ID: topic.add_uncategorized_skill_id( change.new_uncategorized_skill_id) elif change.cmd == topic_domain.CMD_REMOVE_UNCATEGORIZED_SKILL_ID: topic.remove_uncategorized_skill_id( change.uncategorized_skill_id) elif change.cmd == topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC: topic.move_skill_id_to_subtopic(change.old_subtopic_id, change.new_subtopic_id, change.skill_id) elif change.cmd == topic_domain.CMD_REARRANGE_SKILL_IN_SUBTOPIC: topic.rearrange_skill_in_subtopic(change.subtopic_id, change.from_index, change.to_index) elif change.cmd == topic_domain.CMD_REARRANGE_SUBTOPIC: topic.rearrange_subtopic(change.from_index, change.to_index) elif change.cmd == topic_domain.CMD_REMOVE_SKILL_ID_FROM_SUBTOPIC: topic.remove_skill_id_from_subtopic(change.subtopic_id, change.skill_id) elif change.cmd == topic_domain.CMD_UPDATE_TOPIC_PROPERTY: if (change.property_name == topic_domain.TOPIC_PROPERTY_NAME): topic.update_name(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_ABBREVIATED_NAME): topic.update_abbreviated_name(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_URL_FRAGMENT): topic.update_url_fragment(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_DESCRIPTION): topic.update_description(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE): topic.update_language_code(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_THUMBNAIL_FILENAME): topic.update_thumbnail_filename(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_THUMBNAIL_BG_COLOR): topic.update_thumbnail_bg_color(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_META_TAG_CONTENT): topic.update_meta_tag_content(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_PRACTICE_TAB_IS_DISPLAYED): topic.update_practice_tab_is_displayed(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_PAGE_TITLE_FRAGMENT_FOR_WEB): topic.update_page_title_fragment_for_web(change.new_value) elif (change.cmd == subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY): subtopic_page_id = ( subtopic_page_domain.SubtopicPage.get_subtopic_page_id( topic_id, change.subtopic_id)) if ((modified_subtopic_pages[subtopic_page_id] is None) or (change.subtopic_id in deleted_subtopic_ids)): raise Exception('The subtopic with id %s doesn\'t exist' % (change.subtopic_id)) if (change.property_name == subtopic_page_domain. SUBTOPIC_PAGE_PROPERTY_PAGE_CONTENTS_HTML): page_contents = state_domain.SubtitledHtml.from_dict( change.new_value) page_contents.validate() modified_subtopic_pages[ subtopic_page_id].update_page_contents_html( page_contents) elif (change.property_name == subtopic_page_domain. SUBTOPIC_PAGE_PROPERTY_PAGE_CONTENTS_AUDIO): modified_subtopic_pages[ subtopic_page_id].update_page_contents_audio( state_domain.RecordedVoiceovers.from_dict( change.new_value)) elif change.cmd == topic_domain.CMD_UPDATE_SUBTOPIC_PROPERTY: if (change.property_name == topic_domain.SUBTOPIC_PROPERTY_TITLE): topic.update_subtopic_title(change.subtopic_id, change.new_value) if (change.property_name == topic_domain.SUBTOPIC_PROPERTY_THUMBNAIL_FILENAME): topic.update_subtopic_thumbnail_filename( change.subtopic_id, change.new_value) if (change.property_name == topic_domain.SUBTOPIC_PROPERTY_THUMBNAIL_BG_COLOR): topic.update_subtopic_thumbnail_bg_color( change.subtopic_id, change.new_value) if (change.property_name == topic_domain.SUBTOPIC_PROPERTY_URL_FRAGMENT): topic.update_subtopic_url_fragment(change.subtopic_id, change.new_value) elif (change.cmd == topic_domain.CMD_MIGRATE_SUBTOPIC_SCHEMA_TO_LATEST_VERSION): # Loading the topic model from the datastore into a # Topic domain object automatically converts it to use the # latest schema version. As a result, simply resaving the # topic is sufficient to apply the schema migration. continue return (topic, modified_subtopic_pages, deleted_subtopic_ids, newly_created_subtopic_ids, modified_subtopic_change_cmds) except Exception as e: logging.error('%s %s %s %s' % (e.__class__.__name__, e, topic_id, change_list)) python_utils.reraise_exception()
def apply_change_list(topic_id, change_list): """Applies a changelist to a topic and returns the result. The incoming changelist should not have simultaneuous creations and deletion of subtopics. Args: topic_id: str. ID of the given topic. change_list: list(TopicChange). A change list to be applied to the given topic. Raises: Exception. The incoming changelist had simultaneuous creation and deletion of subtopics. Returns: Topic, dict, list(int), list(int). The modified topic object, the modified subtopic pages dict keyed by subtopic page id containing the updated domain objects of each subtopic page, a list of ids of the deleted subtopics and a list of ids of the newly created subtopics. """ topic = get_topic_by_id(topic_id) newly_created_subtopic_ids = [] existing_subtopic_page_ids_to_be_modified = [] deleted_subtopic_ids = [] modified_subtopic_pages_list = [] modified_subtopic_pages = {} for change in change_list: if (change.cmd == subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY): if change.id < topic.next_subtopic_id: existing_subtopic_page_ids_to_be_modified.append(change.id) modified_subtopic_pages_list = ( subtopic_page_services.get_subtopic_pages_with_ids( topic_id, existing_subtopic_page_ids_to_be_modified)) for subtopic_page in modified_subtopic_pages_list: modified_subtopic_pages[subtopic_page.id] = subtopic_page try: for change in change_list: if change.cmd == topic_domain.CMD_ADD_SUBTOPIC: topic.add_subtopic(change.subtopic_id, change.title) subtopic_page_id = ( subtopic_page_domain.SubtopicPage.get_subtopic_page_id( topic_id, change.subtopic_id)) modified_subtopic_pages[subtopic_page_id] = ( subtopic_page_domain.SubtopicPage. create_default_subtopic_page( #pylint: disable=line-too-long change.subtopic_id, topic_id)) newly_created_subtopic_ids.append(change.subtopic_id) elif change.cmd == topic_domain.CMD_DELETE_SUBTOPIC: topic.delete_subtopic(change.id) if change.id in newly_created_subtopic_ids: raise Exception('The incoming changelist had simultaneous' ' creation and deletion of subtopics.') deleted_subtopic_ids.append(change.id) elif change.cmd == topic_domain.CMD_ADD_UNCATEGORIZED_SKILL_ID: topic.add_uncategorized_skill_id(change.id) elif change.cmd == topic_domain.CMD_REMOVE_UNCATEGORIZED_SKILL_ID: topic.remove_uncategorized_skill_id(change.id) elif change.cmd == topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC: topic.move_skill_id_to_subtopic(change.old_subtopic_id, change.new_subtopic_id, change.skill_id) elif change.cmd == topic_domain.CMD_REMOVE_SKILL_ID_FROM_SUBTOPIC: topic.remove_skill_id_from_subtopic(change.subtopic_id, change.skill_id) elif change.cmd == topic_domain.CMD_UPDATE_TOPIC_PROPERTY: if (change.property_name == topic_domain.TOPIC_PROPERTY_NAME): topic.update_name(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_DESCRIPTION): topic.update_description(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_CANONICAL_STORY_IDS): topic.update_canonical_story_ids(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_ADDITIONAL_STORY_IDS): topic.update_additional_story_ids(change.new_value) elif (change.property_name == topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE): topic.update_language_code(change.new_value) else: raise Exception('Invalid change dict.') elif (change.cmd == subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY): subtopic_page_id = ( subtopic_page_domain.SubtopicPage.get_subtopic_page_id( topic_id, change.id)) if ((modified_subtopic_pages[subtopic_page_id] is None) or (change.id in deleted_subtopic_ids)): raise Exception('The subtopic with id %s doesn\'t exist' % change.id) if (change.property_name == subtopic_page_domain. SUBTOPIC_PAGE_PROPERTY_PAGE_CONTENTS_HTML): modified_subtopic_pages[ subtopic_page_id].update_page_contents_html( change.new_value) elif (change.property_name == subtopic_page_domain. SUBTOPIC_PAGE_PROPERTY_PAGE_CONTENTS_AUDIO): modified_subtopic_pages[ subtopic_page_id].update_page_contents_audio( change.new_value) else: raise Exception('Invalid change dict.') elif change.cmd == topic_domain.CMD_UPDATE_SUBTOPIC_PROPERTY: if (change.property_name == topic_domain.SUBTOPIC_PROPERTY_TITLE): topic.update_subtopic_title(change.id, change.new_value) else: raise Exception('Invalid change dict.') elif (change.cmd == topic_domain.CMD_MIGRATE_SUBTOPIC_SCHEMA_TO_LATEST_VERSION): # Loading the topic model from the datastore into a # Topic domain object automatically converts it to use the # latest schema version. As a result, simply resaving the # topic is sufficient to apply the schema migration. continue else: raise Exception('Invalid change dict.') return (topic, modified_subtopic_pages, deleted_subtopic_ids, newly_created_subtopic_ids) except Exception as e: logging.error('%s %s %s %s' % (e.__class__.__name__, e, topic_id, change_list)) raise