def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicEditorControllerTest, self).setUp() self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.topic_manager_id = self.get_user_id_from_email( self.TOPIC_MANAGER_EMAIL) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([self.TOPIC_MANAGER_USERNAME]) self.topic_manager = user_services.UserActionsInfo( self.topic_manager_id) self.admin = user_services.UserActionsInfo(self.admin_id) self.new_user = user_services.UserActionsInfo(self.new_user_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id, self.admin_id, 'Skill Description') self.topic_id = topic_services.get_new_topic_id() self.save_new_topic(self.topic_id, self.admin_id, 'Name', 'Description', [], [], [self.skill_id], [], 1) changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 }) ] topic_services.update_topic_and_subtopic_pages(self.admin_id, self.topic_id, changelist, 'Added subtopic.')
def test_get_published_summaries(self): # Unpublished topics should not be returned. topic_summaries = topic_fetchers.get_published_topic_summaries() self.assertEqual(len(topic_summaries), 0) # Publish the topic. changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC, 'old_subtopic_id': None, 'new_subtopic_id': self.subtopic_id, 'skill_id': self.skill_id_1 }) ] topic_services.update_topic_and_subtopic_pages( self.user_id_admin, self.TOPIC_ID, changelist, 'Updated subtopic skill ids.') topic_services.publish_topic(self.TOPIC_ID, self.user_id_admin) topic_summaries = topic_fetchers.get_published_topic_summaries() self.assertEqual(len(topic_summaries), 1) self.assertEqual(topic_summaries[0].name, 'Name') self.assertEqual(topic_summaries[0].canonical_story_count, 0) self.assertEqual(topic_summaries[0].additional_story_count, 0) self.assertEqual(topic_summaries[0].total_skill_count, 2) self.assertEqual(topic_summaries[0].uncategorized_skill_count, 1) self.assertEqual(topic_summaries[0].subtopic_count, 1)
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseQuestionsListControllerTests, self).setUp() self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.CURRICULUM_ADMIN_EMAIL) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME]) self.admin = user_services.get_user_actions_info(self.admin_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill( self.skill_id, self.admin_id, description='Skill Description') self.skill_id_2 = skill_services.get_new_skill_id() self.save_new_skill( self.skill_id_2, self.admin_id, description='Skill Description 2') self.topic_id = topic_fetchers.get_new_topic_id() self.save_new_topic( self.topic_id, self.admin_id, name='Name', description='Description', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[self.skill_id, self.skill_id_2], subtopics=[], next_subtopic_id=1) self.skill_id_3 = skill_services.get_new_skill_id() changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 })] topic_services.update_topic_and_subtopic_pages( self.admin_id, self.topic_id, changelist, 'Added subtopic.')
def setUp(self): super(TopicServicesUnitTests, self).setUp() self.TOPIC_ID = topic_services.get_new_topic_id() changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 })] self.save_new_topic( self.TOPIC_ID, self.user_id, 'Name', 'Description', [self.story_id_1, self.story_id_2], [self.story_id_3], [self.skill_id_1, self.skill_id_2], [], 1 ) self.signup('*****@*****.**', 'A') self.signup('*****@*****.**', 'B') self.signup(self.ADMIN_EMAIL, username=self.ADMIN_USERNAME) self.user_id_a = self.get_user_id_from_email('*****@*****.**') self.user_id_b = self.get_user_id_from_email('*****@*****.**') self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL) topic_services.update_topic_and_subtopic_pages( self.user_id_admin, self.TOPIC_ID, changelist, 'Added a subtopic') self.topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([user_services.get_username(self.user_id_a)]) self.user_a = user_services.UserActionsInfo(self.user_id_a) self.user_b = user_services.UserActionsInfo(self.user_id_b) self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
def test_cannot_update_topic_and_subtopic_pages_with_mismatch_of_versions( self): topic_model = topic_models.TopicModel.get(self.TOPIC_ID) topic_model.version = 0 topic_model.commit(self.user_id, 'changed version', []) changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE, 'old_value': 'en', 'new_value': 'bn' })] with self.assertRaisesRegexp( Exception, 'Unexpected error: trying to update version 1 of topic ' 'from version 2. Please reload the page and try again.'): topic_services.update_topic_and_subtopic_pages( self.user_id, self.TOPIC_ID, changelist, 'change language_code') topic_model = topic_models.TopicModel.get(self.TOPIC_ID) topic_model.version = 100 topic_model.commit(self.user_id, 'changed version', []) with self.assertRaisesRegexp( Exception, 'Trying to update version 101 of topic from version 2, ' 'which is too old. Please reload the page and try again.'): topic_services.update_topic_and_subtopic_pages( self.user_id, self.TOPIC_ID, changelist, 'change language_code')
def test_cannot_update_topic_and_subtopic_pages_with_empty_changelist(self): with self.assertRaisesRegexp( Exception, 'Unexpected error: received an invalid change list when trying to ' 'save topic'): topic_services.update_topic_and_subtopic_pages( self.user_id, self.TOPIC_ID, [], 'commit message')
def test_opportunities_updates_with_updating_topic_name(self): self.add_exploration_0_to_story() translation_opportunities, _, _ = ( opportunity_services.get_translation_opportunities('hi', None)) self.assertEqual(len(translation_opportunities), 1) opportunity = translation_opportunities[0] self.assertEqual(opportunity.story_title, 'A story') self.assertEqual(opportunity.topic_name, 'topic') topic_services.update_topic_and_subtopic_pages( self.owner_id, self.TOPIC_ID, [ topic_domain.TopicChange({ 'cmd': 'update_topic_property', 'property_name': 'name', 'old_value': 'topic', 'new_value': 'A new topic' }) ], 'Change topic title.') translation_opportunities, _, _ = ( opportunity_services.get_translation_opportunities('hi', None)) self.assertEqual(len(translation_opportunities), 1) opportunity = translation_opportunities[0] self.assertEqual(opportunity.story_title, 'A story') self.assertEqual(opportunity.topic_name, 'A new topic')
def test_missing_subtopic_page_commit_log_entry_model_failure(self): topic_services.update_topic_and_subtopic_pages(self.owner_id, '0', [ subtopic_page_domain.SubtopicPageChange({ 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_html', 'subtopic_id': 1, 'new_value': { 'html': '<p>html</p>', 'content_id': 'content' }, 'old_value': {} }) ], 'Changes.') subtopic_models.SubtopicPageCommitLogEntryModel.get_by_id( 'subtopicpage-0-1-1').delete() expected_output = [ (u'[u\'failed validation check for ' 'subtopic_page_commit_log_entry_ids field check of ' 'SubtopicPageModel\', ' '[u"Entity id 0-1: based on field ' 'subtopic_page_commit_log_entry_ids having value ' 'subtopicpage-0-1-1, expected model ' 'SubtopicPageCommitLogEntryModel ' 'with id subtopicpage-0-1-1 but it doesn\'t exist"]]'), u'[u\'fully-validated SubtopicPageModel\', 2]' ] self.run_job_and_check_output(expected_output, sort=True, literal_eval=False)
def test_get_all_skill_ids_assigned_to_some_topic(self): change_list = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC, 'old_subtopic_id': None, 'new_subtopic_id': 1, 'skill_id': self.skill_id_1 }) ] topic_services.update_topic_and_subtopic_pages( self.user_id_admin, self.TOPIC_ID, change_list, 'Moved skill to subtopic.') topic_id = topic_fetchers.get_new_topic_id() self.save_new_topic( topic_id, self.user_id, name='Name 2', description='Description', abbreviated_name='random', url_fragment='name-three', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[self.skill_id_1, 'skill_3'], subtopics=[], next_subtopic_id=1) self.assertEqual( topic_fetchers.get_all_skill_ids_assigned_to_some_topic(), {self.skill_id_1, self.skill_id_2, 'skill_3'})
def test_get_topic_by_version(self): topic_id = topic_services.get_new_topic_id() self.save_new_topic(topic_id, self.user_id, name='topic name', abbreviated_name='abbrev', thumbnail_filename='img.png', description='Description', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[], next_subtopic_id=1) changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE, 'old_value': 'en', 'new_value': 'bn' }) ] topic_services.update_topic_and_subtopic_pages(self.user_id, topic_id, changelist, 'Change language code') topic_v0 = topic_fetchers.get_topic_by_id(topic_id, version=0) topic_v1 = topic_fetchers.get_topic_by_id(topic_id, version=1) self.assertEqual(topic_v1.language_code, 'en') self.assertEqual(topic_v0.language_code, 'bn')
def remove_skill_from_all_topics(user_id, skill_id): """Deletes the skill with the given id from all the associated topics. Args: user_id: str. The unique user ID of the user. skill_id: str. ID of the skill. """ all_topics = topic_fetchers.get_all_topics() for topic in all_topics: change_list = [] if skill_id in topic.get_all_skill_ids(): for subtopic in topic.subtopics: if skill_id in subtopic.skill_ids: change_list.append(topic_domain.TopicChange({ 'cmd': 'remove_skill_id_from_subtopic', 'subtopic_id': subtopic.id, 'skill_id': skill_id })) break change_list.append(topic_domain.TopicChange({ 'cmd': 'remove_uncategorized_skill_id', 'uncategorized_skill_id': skill_id })) skill_name = get_skill_summary_by_id(skill_id).description topic_services.update_topic_and_subtopic_pages( user_id, topic.id, change_list, 'Removed skill with id %s and name %s from the topic' % ( skill_id, skill_name))
def put(self, topic_id): """Updates properties of the given topic. Also, each change_dict given for editing should have an additional property called is_topic_change, which would be a boolean. If True, it means that change is for a topic (includes adding and removing subtopics), while False would mean it is for a Subtopic Page (this includes editing its html data as of now). """ topic_domain.Topic.require_valid_topic_id(topic_id) topic = topic_fetchers.get_topic_by_id(topic_id, strict=False) version = self.payload.get('version') self._require_valid_version(version, topic.version) commit_message = self.payload.get('commit_message') topic_and_subtopic_page_change_dicts = self.payload.get( 'topic_and_subtopic_page_change_dicts') topic_and_subtopic_page_change_list = [] for change in topic_and_subtopic_page_change_dicts: if change['cmd'] == ( subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY): topic_and_subtopic_page_change_list.append( subtopic_page_domain.SubtopicPageChange(change)) else: topic_and_subtopic_page_change_list.append( topic_domain.TopicChange(change)) try: topic_services.update_topic_and_subtopic_pages( self.user_id, topic_id, topic_and_subtopic_page_change_list, commit_message) except utils.ValidationError as e: raise self.InvalidInputException(e) topic = topic_fetchers.get_topic_by_id(topic_id, strict=False) skill_id_to_description_dict, deleted_skill_ids = ( skill_services.get_descriptions_of_skills( topic.get_all_skill_ids())) skill_id_to_rubrics_dict, deleted_skill_ids = ( skill_services.get_rubrics_of_skills(topic.get_all_skill_ids())) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with id %s' % (deleted_skills_string, topic_id)) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in topic with ' 'id %s' % (deleted_skills_string, topic_id)) self.values.update({ 'topic_dict': topic.to_dict(), 'skill_id_to_description_dict': skill_id_to_description_dict, 'skill_id_to_rubrics_dict': skill_id_to_rubrics_dict }) self.render_json(self.values)
def map(item): if item.deleted: yield (TopicMigrationOneOffJob._DELETED_KEY, 1) return # Note: the read will bring the topic up to the newest version. topic = topic_fetchers.get_topic_by_id(item.id) try: topic.validate() except Exception as e: logging.exception( 'Topic %s failed validation: %s' % (item.id, e)) yield ( TopicMigrationOneOffJob._ERROR_KEY, 'Topic %s failed validation: %s' % (item.id, e)) return # Write the new topic into the datastore if it's different from # the old version. if (item.subtopic_schema_version <= feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION): commit_cmds = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_MIGRATE_SUBTOPIC_SCHEMA_TO_LATEST_VERSION, # pylint: disable=line-too-long 'from_version': item.subtopic_schema_version, 'to_version': feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION })] topic_services.update_topic_and_subtopic_pages( feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds, 'Update topic\'s subtopic schema version to %d.' % ( feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION)) yield (TopicMigrationOneOffJob._MIGRATED_KEY, 1)
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicEditorControllerTests, self).setUp() self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.topic_manager_id = self.get_user_id_from_email( self.TOPIC_MANAGER_EMAIL) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([self.TOPIC_MANAGER_USERNAME]) self.topic_manager = user_services.UserActionsInfo( self.topic_manager_id) self.admin = user_services.UserActionsInfo(self.admin_id) self.new_user = user_services.UserActionsInfo(self.new_user_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id, self.admin_id, description='Skill Description') self.skill_id_2 = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id_2, self.admin_id, description='Skill Description 2') self.topic_id = topic_services.get_new_topic_id() self.save_new_topic( self.topic_id, self.admin_id, name='Name', abbreviated_name='abbrev', thumbnail_filename='topic.png', description='Description', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[self.skill_id, self.skill_id_2], subtopics=[], next_subtopic_id=1) changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 }), topic_domain.TopicChange({ 'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC, 'old_subtopic_id': None, 'new_subtopic_id': 1, 'skill_id': self.skill_id }) ] topic_services.update_topic_and_subtopic_pages(self.admin_id, self.topic_id, changelist, 'Added subtopic.')
def setUp(self) -> None: super(TopicFetchersUnitTests, self).setUp() self.TOPIC_ID = topic_fetchers.get_new_topic_id() changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1, 'url_fragment': 'sample-fragment' }) ] self.save_new_topic( # type: ignore[no-untyped-call] self.TOPIC_ID, self.user_id, name='Name', abbreviated_name='name', url_fragment='name-one', description='Description', canonical_story_ids=[self.story_id_1, self.story_id_2], additional_story_ids=[self.story_id_3], uncategorized_skill_ids=[self.skill_id_1, self.skill_id_2], subtopics=[], next_subtopic_id=1) self.save_new_story(self.story_id_1, self.user_id, self.TOPIC_ID) # type: ignore[no-untyped-call] self.save_new_story( # type: ignore[no-untyped-call] self.story_id_3, self.user_id, self.TOPIC_ID, title='Title 3', description='Description 3') self.signup('*****@*****.**', 'A') self.signup('*****@*****.**', 'B') self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.user_id_a = self.get_user_id_from_email( '*****@*****.**') # type: ignore[no-untyped-call] self.user_id_b = self.get_user_id_from_email( '*****@*****.**') # type: ignore[no-untyped-call] self.user_id_admin = (self.get_user_id_from_email( self.CURRICULUM_ADMIN_EMAIL)) # type: ignore[no-untyped-call] topic_services.update_topic_and_subtopic_pages( # type: ignore[no-untyped-call] self.user_id_admin, self.TOPIC_ID, changelist, 'Added a subtopic') self.topic: Optional[topic_domain.Topic] = ( topic_fetchers.get_topic_by_id(self.TOPIC_ID)) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME ]) # type: ignore[no-untyped-call] self.set_topic_managers( # type: ignore[no-untyped-call] [user_services.get_username(self.user_id_a)], self.TOPIC_ID) self.user_a = user_services.get_user_actions_info(self.user_id_a) self.user_b = user_services.get_user_actions_info(self.user_id_b) self.user_admin = user_services.get_user_actions_info( self.user_id_admin)
def post(self): """Handles POST requests.""" name = self.payload.get('name') url_fragment = self.payload.get('url_fragment') description = self.payload.get('description') thumbnail_filename = self.payload.get('filename') thumbnail_bg_color = self.payload.get('thumbnailBgColor') raw_image = self.request.get('image') page_title_frag = self.payload.get('page_title_fragment') try: topic_domain.Topic.require_valid_name(name) except Exception as e: raise self.InvalidInputException( 'Invalid topic name, received %s.' % name) from e new_topic_id = topic_fetchers.get_new_topic_id() topic = topic_domain.Topic.create_default_topic( new_topic_id, name, url_fragment, description, page_title_frag) topic_services.save_new_topic(self.user_id, topic) try: file_format = image_validation_services.validate_image_and_filename( raw_image, thumbnail_filename) except utils.ValidationError as e: raise self.InvalidInputException(e) entity_id = new_topic_id filename_prefix = 'thumbnail' image_is_compressible = (file_format in feconf.COMPRESSIBLE_IMAGE_FORMATS) fs_services.save_original_and_compressed_versions_of_image( thumbnail_filename, feconf.ENTITY_TYPE_TOPIC, entity_id, raw_image, filename_prefix, image_is_compressible) topic_services.update_topic_and_subtopic_pages( self.user_id, new_topic_id, [ topic_domain.TopicChange({ 'cmd': 'update_topic_property', 'property_name': 'thumbnail_filename', 'old_value': None, 'new_value': thumbnail_filename }), topic_domain.TopicChange({ 'cmd': 'update_topic_property', 'property_name': 'thumbnail_bg_color', 'old_value': None, 'new_value': thumbnail_bg_color }), ], 'Add topic thumbnail.') self.render_json({'topicId': new_topic_id})
def put(self, topic_id): """Updates properties of the given topic. Also, each change_dict given for editing should have an additional property called is_topic_change, which would be a boolean. If True, it means that change is for a topic (includes adding and removing subtopics), while False would mean it is for a Subtopic Page (this includes editing its html data as of now). """ if not feconf.ENABLE_NEW_STRUCTURES: raise self.PageNotFoundException topic_domain.Topic.require_valid_topic_id(topic_id) topic = topic_services.get_topic_by_id(topic_id, strict=False) if topic is None: raise self.PageNotFoundException( Exception('The topic with the given id doesn\'t exist.')) version = self.payload.get('version') self._require_valid_version(version, topic.version) commit_message = self.payload.get('commit_message') topic_and_subtopic_page_change_dicts = self.payload.get( 'topic_and_subtopic_page_change_dicts') topic_and_subtopic_page_change_list = [] for change in topic_and_subtopic_page_change_dicts: if change['change_affects_subtopic_page']: topic_and_subtopic_page_change_list.append( subtopic_page_domain.SubtopicPageChange(change)) else: topic_and_subtopic_page_change_list.append( topic_domain.TopicChange(change)) try: topic_services.update_topic_and_subtopic_pages( self.user_id, topic_id, topic_and_subtopic_page_change_list, commit_message) except utils.ValidationError as e: raise self.InvalidInputException(e) topic = topic_services.get_topic_by_id(topic_id, strict=False) skill_ids = topic.get_all_skill_ids() skill_id_to_description_dict = ( skill_services.get_skill_descriptions_by_ids(topic_id, skill_ids)) self.values.update({ 'topic_dict': topic.to_dict(), 'skill_id_to_description_dict': skill_id_to_description_dict }) self.render_json(self.values)
def replace_skill_id_in_all_topics(user_id, old_skill_id, new_skill_id): """Replaces the old skill id with the new one in all the associated topics. Args: user_id: str. The unique user ID of the user. old_skill_id: str. The old skill id. new_skill_id: str. The new skill id. Raises: Exception. The new skill already present. """ all_topics = topic_fetchers.get_all_topics() for topic in all_topics: change_list = [] if old_skill_id in topic.get_all_skill_ids(): if new_skill_id in topic.get_all_skill_ids(): raise Exception( 'Found topic \'%s\' contains the two skills to be merged. ' 'Please unassign one of these skills from topic ' 'and retry this operation.' % topic.name) if old_skill_id in topic.uncategorized_skill_ids: change_list.extend([topic_domain.TopicChange({ 'cmd': 'remove_uncategorized_skill_id', 'uncategorized_skill_id': old_skill_id }), topic_domain.TopicChange({ 'cmd': 'add_uncategorized_skill_id', 'new_uncategorized_skill_id': new_skill_id })]) for subtopic in topic.subtopics: if old_skill_id in subtopic.skill_ids: change_list.extend([topic_domain.TopicChange({ 'cmd': topic_domain.CMD_REMOVE_SKILL_ID_FROM_SUBTOPIC, 'subtopic_id': subtopic.id, 'skill_id': old_skill_id }), topic_domain.TopicChange({ 'cmd': 'remove_uncategorized_skill_id', 'uncategorized_skill_id': old_skill_id }), topic_domain.TopicChange({ 'cmd': 'add_uncategorized_skill_id', 'new_uncategorized_skill_id': new_skill_id }), topic_domain.TopicChange({ 'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC, 'old_subtopic_id': None, 'new_subtopic_id': subtopic.id, 'skill_id': new_skill_id })]) break topic_services.update_topic_and_subtopic_pages( user_id, topic.id, change_list, 'Replace skill id %s with skill id %s in the topic' % ( old_skill_id, new_skill_id))
def test_update_topic_language_code(self): topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.assertEqual(topic.language_code, 'en') changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE, 'old_value': 'en', 'new_value': 'bn' })] topic_services.update_topic_and_subtopic_pages( self.user_id, self.TOPIC_ID, changelist, 'Change language code') topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.assertEqual(topic.language_code, 'bn')
def map(item): if item.deleted: yield (RemoveDeletedSkillsFromTopicOneOffJob._DELETED_KEY, 1) return # Note: the read will bring the topic up to the newest version. topic = topic_fetchers.get_topic_by_id(item.id) skill_ids_to_be_removed_from_subtopic = [] all_skill_ids_to_be_removed = [] commit_cmds = [] # This block of code removes deleted skills from subtopics, but keeps # them in the topic. for subtopic in topic.get_all_subtopics(): subtopic_skill_models = skill_models.SkillModel.get_multi( subtopic['skill_ids']) for skill_id, skill_model in python_utils.ZIP( subtopic['skill_ids'], subtopic_skill_models): if skill_model is None: commit_cmds.append( topic_domain.TopicChange({ 'cmd': topic_domain.CMD_REMOVE_SKILL_ID_FROM_SUBTOPIC, 'skill_id': skill_id, 'subtopic_id': subtopic['id'] })) skill_ids_to_be_removed_from_subtopic.append(skill_id) all_skill_models = skill_models.SkillModel.get_multi( topic.get_all_skill_ids()) # This block of code removes all deleted skills from topics. for skill_id, skill_model in python_utils.ZIP( topic.get_all_skill_ids(), all_skill_models): if skill_model is None: commit_cmds.append( topic_domain.TopicChange({ 'cmd': topic_domain.CMD_REMOVE_UNCATEGORIZED_SKILL_ID, 'uncategorized_skill_id': skill_id })) all_skill_ids_to_be_removed.append(skill_id) if commit_cmds: topic_services.update_topic_and_subtopic_pages( feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds, 'Remove deleted skill id.') yield ('Skill IDs deleted for topic %s:' % item.id, all_skill_ids_to_be_removed) yield (RemoveDeletedSkillsFromTopicOneOffJob._PROCESSED_KEY, 1)
def test_update_topic_additional_story_ids(self): topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.assertEqual(topic.additional_story_ids, [self.story_id_3]) changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_ADDITIONAL_STORY_IDS, 'old_value': [self.story_id_3], 'new_value': ['new_story_id'] })] topic_services.update_topic_and_subtopic_pages( self.user_id, self.TOPIC_ID, changelist, 'Change additional story ids') topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.assertEqual(topic.additional_story_ids, ['new_story_id'])
def test_standard_operation(self): topic_services.update_topic_and_subtopic_pages( self.owner_id, '0', [subtopic_page_domain.SubtopicPageChange({ 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_html', 'subtopic_id': 1, 'new_value': { 'html': '<p>html</p>', 'content_id': 'content' }, 'old_value': {} })], 'Changes.') expected_output = [ u'[u\'fully-validated SubtopicPageCommitLogEntryModel\', 4]'] self.run_job_and_check_output( expected_output, sort=False, literal_eval=False)
def put(self, topic_id): """Updates properties of the given topic. Also, each change_dict given for editing should have an additional property called is_topic_change, which would be a boolean. If True, it means that change is for a topic (includes adding and removing subtopics), while False would mean it is for a Subtopic Page (this includes editing its html data as of now). """ topic_domain.Topic.require_valid_topic_id(topic_id) topic = topic_services.get_topic_by_id(topic_id, strict=False) version = self.payload.get('version') self._require_valid_version(version, topic.version) commit_message = self.payload.get('commit_message') topic_and_subtopic_page_change_dicts = self.payload.get( 'topic_and_subtopic_page_change_dicts') topic_and_subtopic_page_change_list = [] for change in topic_and_subtopic_page_change_dicts: if change['cmd'] == ( subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY): topic_and_subtopic_page_change_list.append( subtopic_page_domain.SubtopicPageChange(change)) else: topic_and_subtopic_page_change_list.append( topic_domain.TopicChange(change)) try: topic_services.update_topic_and_subtopic_pages( self.user_id, topic_id, topic_and_subtopic_page_change_list, commit_message) except utils.ValidationError as e: raise self.InvalidInputException(e) topic = topic_services.get_topic_by_id(topic_id, strict=False) skill_ids = topic.get_all_skill_ids() skill_id_to_description_dict = ( skill_services.get_skill_descriptions_by_ids(topic_id, skill_ids)) self.values.update({ 'topic_dict': topic.to_dict(), 'skill_id_to_description_dict': skill_id_to_description_dict }) self.render_json(self.values)
def setUp(self): super(TopicFetchersUnitTests, self).setUp() self.TOPIC_ID = topic_services.get_new_topic_id() changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 }) ] self.save_new_topic( self.TOPIC_ID, self.user_id, name='Name', abbreviated_name='name', url_fragment='name-one', description='Description', canonical_story_ids=[self.story_id_1, self.story_id_2], additional_story_ids=[self.story_id_3], uncategorized_skill_ids=[self.skill_id_1, self.skill_id_2], subtopics=[], next_subtopic_id=1) self.save_new_story(self.story_id_1, self.user_id, self.TOPIC_ID) self.save_new_story(self.story_id_3, self.user_id, self.TOPIC_ID, title='Title 3', description='Description 3') self.signup('*****@*****.**', 'A') self.signup('*****@*****.**', 'B') self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.user_id_a = self.get_user_id_from_email('*****@*****.**') self.user_id_b = self.get_user_id_from_email('*****@*****.**') self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL) topic_services.update_topic_and_subtopic_pages(self.user_id_admin, self.TOPIC_ID, changelist, 'Added a subtopic') self.topic = topic_fetchers.get_topic_by_id(self.TOPIC_ID) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([user_services.get_username(self.user_id_a)]) self.user_a = user_services.UserActionsInfo(self.user_id_a) self.user_b = user_services.UserActionsInfo(self.user_id_b) self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
def test_get_all_skill_ids_assigned_to_some_topic(self): change_list = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC, 'old_subtopic_id': None, 'new_subtopic_id': 1, 'skill_id': self.skill_id_1 }) ] topic_services.update_topic_and_subtopic_pages( self.user_id_admin, self.TOPIC_ID, change_list, 'Moved skill to subtopic.') topic_id = topic_services.get_new_topic_id() self.save_new_topic(topic_id, self.user_id, 'Name 2', 'Description', [], [], [self.skill_id_1, 'skill_3'], [], 1) self.assertEqual( topic_services.get_all_skill_ids_assigned_to_some_topic(), set([self.skill_id_1, self.skill_id_2, 'skill_3']))
def test_delete_subtopic_with_skill_ids(self): changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_DELETE_SUBTOPIC, 'subtopic_id': self.subtopic_id })] subtopic_page = subtopic_page_services.get_subtopic_page_by_id( self.TOPIC_ID, 1, strict=False) self.assertEqual(subtopic_page.id, self.TOPIC_ID + '-1') topic_services.update_topic_and_subtopic_pages( self.user_id_admin, self.TOPIC_ID, changelist, 'Removed 1 subtopic.') subtopic_page = subtopic_page_services.get_subtopic_page_by_id( self.TOPIC_ID, 1, strict=False) self.assertIsNone(subtopic_page) topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.assertEqual( topic.uncategorized_skill_ids, [self.skill_id_1, self.skill_id_2]) self.assertEqual(topic.subtopics, [])
def test_update_topic(self): topic_services.assign_role(self.user_admin, self.user_a, topic_domain.ROLE_MANAGER, self.TOPIC_ID) # Test whether an admin can edit a topic. changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_DESCRIPTION, 'old_value': 'Description', 'new_value': 'New Description' }) ] topic_services.update_topic_and_subtopic_pages(self.user_id_admin, self.TOPIC_ID, changelist, 'Updated Description.') topic = topic_services.get_topic_by_id(self.TOPIC_ID) topic_summary = topic_services.get_topic_summary_by_id(self.TOPIC_ID) self.assertEqual(topic.description, 'New Description') self.assertEqual(topic.version, 3) self.assertEqual(topic_summary.version, 3) # Test whether a topic_manager can edit a topic. changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_NAME, 'old_value': 'Name', 'new_value': 'New Name' }) ] topic_services.update_topic_and_subtopic_pages(self.user_id_a, self.TOPIC_ID, changelist, 'Updated Name.') topic = topic_services.get_topic_by_id(self.TOPIC_ID) topic_summary = topic_services.get_topic_summary_by_id(self.TOPIC_ID) self.assertEqual(topic.name, 'New Name') self.assertEqual(topic.version, 4) self.assertEqual(topic_summary.name, 'New Name') self.assertEqual(topic_summary.version, 4)
def test_get_topic_by_version(self): topic_id = topic_services.get_new_topic_id() self.save_new_topic( topic_id, self.user_id, 'topic name', 'Description', [], [], [], [], 1) changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE, 'old_value': 'en', 'new_value': 'bn' })] topic_services.update_topic_and_subtopic_pages( self.user_id, topic_id, changelist, 'Change language code') topic_v0 = topic_services.get_topic_by_id(topic_id, version=0) topic_v1 = topic_services.get_topic_by_id(topic_id, version=1) self.assertEqual(topic_v1.language_code, 'en') self.assertEqual(topic_v0.language_code, 'bn')
def test_update_subtopic_property(self): topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.assertEqual(len(topic.subtopics), 1) self.assertEqual(topic.subtopics[0].title, 'Title') changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_SUBTOPIC_PROPERTY, 'property_name': 'title', 'subtopic_id': 1, 'old_value': 'Title', 'new_value': 'New Title' })] topic_services.update_topic_and_subtopic_pages( self.user_id_admin, self.TOPIC_ID, changelist, 'Update title of subtopic.') topic = topic_services.get_topic_by_id(self.TOPIC_ID) self.assertEqual(len(topic.subtopics), 1) self.assertEqual(topic.subtopics[0].title, 'New Title')
def test_opportunities_updates_with_updating_topic_name(self): story_services.update_story(self.owner_id, self.STORY_ID, [ story_domain.StoryChange({ 'cmd': 'add_story_node', 'node_id': 'node_1', 'title': 'Node1', }), story_domain.StoryChange({ 'cmd': 'update_story_node_property', 'property_name': 'exploration_id', 'node_id': 'node_1', 'old_value': None, 'new_value': '0' }) ], 'Changes.') translation_opportunities, _, _ = ( opportunity_services.get_translation_opportunities('hi', None)) self.assertEqual(len(translation_opportunities), 1) opportunity = translation_opportunities[0] self.assertEqual(opportunity['story_title'], 'A story') self.assertEqual(opportunity['topic_name'], 'topic') topic_services.update_topic_and_subtopic_pages( self.owner_id, self.TOPIC_ID, [ topic_domain.TopicChange({ 'cmd': 'update_topic_property', 'property_name': 'name', 'old_value': 'topic', 'new_value': 'A new topic' }) ], 'Change topic title.') translation_opportunities, _, _ = ( opportunity_services.get_translation_opportunities('hi', None)) self.assertEqual(len(translation_opportunities), 1) opportunity = translation_opportunities[0] self.assertEqual(opportunity['story_title'], 'A story') self.assertEqual(opportunity['topic_name'], 'A new topic')