def test_get_with_twenty_or_more_questions_with_multiple_skills(self): number_of_skills = 3 number_of_questions = [1, 2, 2] self.topic_id = 'new_topic' skill_ids = ([ skill_services.get_new_skill_id() for _ in range(number_of_skills) ]) self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'new_topic', 'new-topic', 'description', 'fragm') for index in range(number_of_skills): self.topic.uncategorized_skill_ids.append(skill_ids[index]) self.topic.thumbnail_filename = 'Image.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) self.topic.practice_tab_is_displayed = True subtopic_1 = topic_domain.Subtopic.create_default_subtopic( 1, 'Subtopic Title 1', 'url-frag-one') subtopic_1.skill_ids = ['skill_id_1'] subtopic_1.url_fragment = 'sub-one-frag' self.topic.subtopics = [subtopic_1] self.topic.next_subtopic_id = 2 topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id) for i in range(number_of_skills): self.save_new_skill(skill_ids[i], self.admin_id, description='Skill Description') for i in range(number_of_skills): for j in range(number_of_questions[i]): question_id = question_services.get_new_question_id() self.save_new_question(question_id, self.admin_id, self._create_valid_question_data(j), [skill_ids[i]]) question_services.create_new_question_skill_link( self.admin_id, question_id, skill_ids[i], 0.5) json_response = self.get_json('%s/staging/%s' % (feconf.TOPIC_DATA_HANDLER, 'new-topic')) expected_dict = { 'topic_name': 'new_topic', 'topic_id': self.topic_id, 'canonical_story_dicts': [], 'additional_story_dicts': [], 'practice_tab_is_displayed': True } self.assertDictContainsSubset(expected_dict, json_response) self.logout()
def setUp(self): super(TranslatableTextHandlerTest, self).setUp() self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) explorations = [ exp_domain.Exploration.create_default_exploration( '%s' % i, title='title %d' % i, category='category%d' % i, ) for i in python_utils.RANGE(2) ] for exp in explorations: exp_services.save_new_exploration(self.owner_id, exp) topic = topic_domain.Topic.create_default_topic( topic_id='0', name='topic', abbreviated_name='abbrev') topic_services.save_new_topic(self.owner_id, topic) stories = [ story_domain.Story.create_default_story('%s' % i, title='title %d' % i, corresponding_topic_id='0') for i in python_utils.RANGE(2) ] for index, story in enumerate(stories): story.language_code = 'en' story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story(self.owner_id, topic.id, story.id) story_services.update_story(self.owner_id, 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': explorations[index].id }) ], 'Changes.')
def test_get_fails_when_skill_ids_dont_exist(self): topic = topic_domain.Topic.create_default_topic( 'topic_id_3', 'topic_without_skills', 'noskills', 'description') topic.thumbnail_filename = 'Topic.svg' topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic.subtopics.append( topic_domain.Subtopic( 1, 'subtopic_name', ['non_existent_skill'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'subtopic-name-three')) topic.next_subtopic_id = 2 topic_services.save_new_topic(self.admin_id, topic) topic_services.publish_topic('topic_id_3', self.admin_id) self.get_json('%s/staging/%s?selected_subtopic_ids=[1]' % (feconf.PRACTICE_SESSION_DATA_URL_PREFIX, 'noskills'), expected_status_int=404)
def setUp(self): super(OpportunityServicesUnitTest, self).setUp() self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.TOPIC_ID = 'topic' self.STORY_ID = 'story' explorations = [ self.save_new_valid_exploration('%s' % i, self.owner_id, title='title %d' % i, category='category%d' % i, end_state_name='End State') for i in python_utils.RANGE(5) ] for exp in explorations: self.publish_exploration(self.owner_id, exp.id) topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID, 'topic', 'abbrev', 'description') topic_services.save_new_topic(self.owner_id, topic) story = story_domain.Story.create_default_story( self.STORY_ID, title='A story', corresponding_topic_id=self.TOPIC_ID) story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID, self.STORY_ID) 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.')
def test_get(self): self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.login(self.ADMIN_EMAIL, is_super_admin=True) topic_id_1 = topic_services.get_new_topic_id() topic_id_2 = topic_services.get_new_topic_id() private_topic = topic_domain.Topic.create_default_topic( topic_id_1, 'private_topic_name', 'abbrev', 'description') topic_services.save_new_topic(admin_id, private_topic) public_topic = topic_domain.Topic.create_default_topic( topic_id_2, 'public_topic_name', 'abbrev', 'description') public_topic.thumbnail_filename = 'Topic.svg' public_topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic_services.save_new_topic(admin_id, public_topic) topic_services.publish_topic(topic_id_2, admin_id) csrf_token = self.get_new_csrf_token() new_config_value = [{ 'name': 'math', 'topic_ids': [topic_id_1, topic_id_2] }] payload = { 'action': 'save_config_properties', 'new_config_property_values': { config_domain.TOPIC_IDS_FOR_CLASSROOM_PAGES.name: ( new_config_value), } } self.post_json('/adminhandler', payload, csrf_token=csrf_token) self.logout() with self.swap(constants, 'ENABLE_NEW_STRUCTURE_PLAYERS', True): json_response = self.get_json( '%s/%s' % (feconf.CLASSROOM_DATA_HANDLER, 'math')) topic_summary_dict = ( topic_services.get_topic_summary_by_id(topic_id_2).to_dict()) expected_dict = { 'topic_summary_dicts': [topic_summary_dict] } self.assertDictContainsSubset(expected_dict, json_response)
def test_get_with_more_questions_with_fifty_or_more_skills(self): number_of_skills = 60 number_of_questions = [0] * 60 number_of_questions[46] = 2 number_of_questions[20] = 3 number_of_questions[29] = 10 self.topic_id = 'new_topic' skill_ids = ([ skill_services.get_new_skill_id() for _ in python_utils.RANGE(number_of_skills) ]) self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'new_topic', 'new-topic', 'description') for index in python_utils.RANGE(number_of_skills): self.topic.uncategorized_skill_ids.append(skill_ids[index]) self.topic.thumbnail_filename = 'Image.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id) for i in python_utils.RANGE(number_of_skills): self.save_new_skill(skill_ids[i], self.admin_id, description='Skill Description') for i in python_utils.RANGE(number_of_skills): for j in python_utils.RANGE(number_of_questions[i]): question_id = question_services.get_new_question_id() self.save_new_question(question_id, self.admin_id, self._create_valid_question_data(j), [skill_ids[i]]) question_services.create_new_question_skill_link( self.admin_id, question_id, skill_ids[i], 0.5) with self.swap(constants, 'ENABLE_NEW_STRUCTURE_PLAYERS', True): json_response = self.get_json( '%s/staging/%s' % (feconf.TOPIC_DATA_HANDLER, 'new-topic')) expected_dict = { 'topic_name': 'new_topic', 'topic_id': self.topic_id, 'canonical_story_dicts': [], 'additional_story_dicts': [], 'train_tab_should_be_displayed': True } self.assertDictContainsSubset(expected_dict, json_response) self.logout()
def test_get_fails_when_skill_ids_dont_exist(self): topic = topic_domain.Topic.create_default_topic( 'topic_id_3', 'topic_without_skills', 'abbrev') topic.thumbnail_filename = 'Topic.svg' topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic.subtopics.append(topic_domain.Subtopic( 1, 'subtopic_name', ['non_existent_skill'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0])) topic.next_subtopic_id = 2 topic_services.save_new_topic(self.admin_id, topic) topic_services.publish_topic('topic_id_3', self.admin_id) with self.swap(constants, 'ENABLE_NEW_STRUCTURE_PLAYERS', True): self.get_json( '%s/%s?selected_subtopic_ids=1' % ( feconf.PRACTICE_SESSION_DATA_URL_PREFIX, 'topic_without_skills'), expected_status_int=404)
def setUp(self): """Completes the sign-up process for the various users.""" super(BasePracticeSessionsControllerTests, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.topic_id = 'topic' self.topic_id_1 = 'topic1' self.skill_id1 = 'skill_id_1' self.skill_id2 = 'skill_id_2' self.save_new_skill( self.skill_id1, self.admin_id, description='Skill 1') self.save_new_skill( self.skill_id2, self.admin_id, description='Skill 2') self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'public_topic_name', 'public-topic-name', 'description') self.topic.subtopics.append(topic_domain.Subtopic( 1, 'subtopic_name', [self.skill_id1], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'subtopic-name-one')) self.topic.subtopics.append(topic_domain.Subtopic( 2, 'subtopic_name_2', [self.skill_id2], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'subtopic-name-two')) self.topic.next_subtopic_id = 3 self.topic.thumbnail_filename = 'Topic.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic_services.save_new_topic(self.admin_id, self.topic) self.topic = topic_domain.Topic.create_default_topic( self.topic_id_1, 'private_topic_name', 'private-topic-name', 'description') self.topic.thumbnail_filename = 'Topic.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id)
def _publish_topic(self, topic_id, topic_name): """Creates and publishes a topic. Args: topic_id: str. Topic ID. topic_name: str. Topic name. """ topic = topic_domain.Topic.create_default_topic( topic_id, topic_name, 'abbrev', 'description') topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' topic.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_3'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-three')] topic.next_subtopic_id = 2 topic_services.save_new_topic(self.admin_id, topic) topic_services.publish_topic(topic_id, self.admin_id)
def setUp(self): super(OpportunityServicesIntegrationTest, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.TOPIC_ID = 'topic' self.STORY_ID = 'story' self.USER_ID = 'user' self.SKILL_ID = 'skill' self.QUESTION_ID = question_services.get_new_question_id() # Since a valid exploration is created here, it has EndExploration # state as well, so the content in that has to be taken into account as # well when checking content_count in the tests. explorations = [ self.save_new_valid_exploration('%s' % i, self.owner_id, title='title %d' % i, category='category%d' % i, end_state_name='End State') for i in python_utils.RANGE(5) ] for exp in explorations: self.publish_exploration(self.owner_id, exp.id) topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID, 'topic', 'abbrev', 'description') topic_services.save_new_topic(self.owner_id, topic) story = story_domain.Story.create_default_story( self.STORY_ID, title='A story', corresponding_topic_id=self.TOPIC_ID) story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID, self.STORY_ID)
def setUp(self): super(StorySnapshotMetadataModelValidatorTests, self).setUp() self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.signup(USER_EMAIL, USER_NAME) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.user_id = self.get_user_id_from_email(USER_EMAIL) topic = topic_domain.Topic.create_default_topic( '0', 'topic', 'abbrev', 'description') stories = [story_domain.Story.create_default_story( '%s' % i, 'title %d' % i, 'description %d' % i, '0', 'title-%s' % chr(97 + i) ) for i in python_utils.RANGE(3)] for story in stories: if story.id != '0': story_services.save_new_story(self.owner_id, story) else: story_services.save_new_story(self.user_id, story) topic.add_canonical_story(story.id) topic_services.save_new_topic(self.owner_id, topic) self.model_instance_0 = ( story_models.StorySnapshotMetadataModel.get_by_id( '0-1')) self.model_instance_1 = ( story_models.StorySnapshotMetadataModel.get_by_id( '1-1')) self.model_instance_2 = ( story_models.StorySnapshotMetadataModel.get_by_id( '2-1')) self.job_class = ( prod_validation_jobs_one_off .StorySnapshotMetadataModelAuditOneOffJob)
def test_get_with_five_or_more_questions(self): number_of_questions = 6 self.topic_id = 'new_topic' self.skill_id_1 = skill_services.get_new_skill_id() self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'new_topic', 'abbrev') self.topic.uncategorized_skill_ids.append(self.skill_id_1) self.topic.thumbnail_filename = 'Image.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id) self.save_new_skill(self.skill_id_1, self.admin_id, description='Skill Description 1') for index in python_utils.RANGE(number_of_questions): question_id = question_services.get_new_question_id() self.save_new_question(question_id, self.admin_id, self._create_valid_question_data(index), [self.skill_id_1]) question_services.create_new_question_skill_link( self.admin_id, question_id, self.skill_id_1, 0.5) with self.swap(constants, 'ENABLE_NEW_STRUCTURE_PLAYERS', True): json_response = self.get_json( '%s/%s' % (feconf.TOPIC_DATA_HANDLER, 'new_topic')) expected_dict = { 'topic_name': 'new_topic', 'topic_id': self.topic_id, 'canonical_story_dicts': [], 'additional_story_dicts': [], 'uncategorized_skill_ids': [self.skill_id_1], 'subtopics': [], 'degrees_of_mastery': { self.skill_id_1: None }, 'skill_descriptions': { self.skill_id_1: 'Skill Description 1' }, 'train_tab_should_be_displayed': True } self.assertDictContainsSubset(expected_dict, json_response) self.logout()
def test_get_with_no_skills_ids(self): self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'topic_with_no_skills', 'abbrev') topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id) with self.swap(constants, 'ENABLE_NEW_STRUCTURE_PLAYERS', True): json_response = self.get_json( '%s/%s' % (feconf.TOPIC_DATA_HANDLER, 'topic_with_no_skills')) expected_dict = { 'topic_name': 'topic_with_no_skills', 'topic_id': self.topic_id, 'canonical_story_dicts': [], 'additional_story_dicts': [], 'uncategorized_skill_ids': [], 'subtopics': [], 'degrees_of_mastery': {}, 'skill_descriptions': {}, 'train_tab_should_be_displayed': False } self.assertDictContainsSubset(expected_dict, json_response)
def test_get_with_no_skills_ids(self): self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'topic_with_no_skills', 'topic-with-no-skills', 'description') topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id) json_response = self.get_json( '%s/staging/%s' % ( feconf.TOPIC_DATA_HANDLER, 'topic-with-no-skills')) expected_dict = { 'topic_name': 'topic_with_no_skills', 'topic_id': self.topic_id, 'canonical_story_dicts': [], 'additional_story_dicts': [], 'uncategorized_skill_ids': [], 'subtopics': [], 'degrees_of_mastery': {}, 'skill_descriptions': {}, 'practice_tab_is_displayed': False } self.assertDictContainsSubset(expected_dict, json_response)
def test_get_all_topic_names(self): response = self.get_json('/getalltopicnames') self.assertEqual(response, {'topic_names': []}) topic_id = '0' topic = topic_domain.Topic.create_default_topic( topic_id, 'topic', 'abbrev', 'description') topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' topic.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_3'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-three') ] topic.next_subtopic_id = 2 topic_services.save_new_topic(self.owner_id, topic) topic_services.publish_topic(topic_id, self.admin_id) response = self.get_json('/getalltopicnames') self.assertEqual(response, {'topic_names': ['topic']})
def _publish_valid_topic(self, topic, uncategorized_skill_ids): """Saves and publishes a valid topic with linked skills and subtopic. Args: topic: Topic. The topic to be saved and published. uncategorized_skill_ids: list(str). List of uncategorized skills IDs to add to the supplied topic. """ topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' subtopic_id = 1 subtopic_skill_id = 'subtopic_skill_id' + topic.id topic.subtopics = [ topic_domain.Subtopic( subtopic_id, 'Title', [subtopic_skill_id], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic') ] topic.next_subtopic_id = 2 subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( subtopic_id, topic.id)) subtopic_page_services.save_subtopic_page( self.owner_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Sample' }) ]) topic_services.save_new_topic(self.owner_id, topic) topic_services.publish_topic(topic.id, self.admin_id) for skill_id in uncategorized_skill_ids: self.save_new_skill(skill_id, self.admin_id, description='skill_description') topic_services.add_uncategorized_skill(self.admin_id, topic.id, skill_id)
def setUp(self): super(OpportunityServicesIntegrationTest, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.TOPIC_ID = 'topic' self.STORY_ID = 'story' self.USER_ID = 'user' self.SKILL_ID = 'skill' self.QUESTION_ID = question_services.get_new_question_id() explorations = [ exp_domain.Exploration.create_default_exploration( '%s' % i, title='title %d' % i, category='category%d' % i, ) for i in python_utils.RANGE(5) ] for exp in explorations: exp_services.save_new_exploration(self.owner_id, exp) topic = topic_domain.Topic.create_default_topic(topic_id=self.TOPIC_ID, name='topic') topic_services.save_new_topic(self.owner_id, topic) story = story_domain.Story.create_default_story( self.STORY_ID, title='A story', corresponding_topic_id=self.TOPIC_ID) story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID, self.STORY_ID)
def test_regeneration_job_skips_invalid_topic(self): observed_log_messages = [] def _mock_get_topic_by_id(unused_topic_id): """Mocks get_topic_by_id().""" return 'invalid_topic' def _mock_logging_function(msg, *args): """Mocks logging.error().""" observed_log_messages.append(msg % args) topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID, 'A title', 'url-frag-two', 'description') topic_services.save_new_topic(self.albert_id, topic) get_topic_by_id_swap = self.swap(topic_fetchers, 'get_topic_by_id', _mock_get_topic_by_id) logging_exception_swap = self.swap(logging, 'exception', _mock_logging_function) with get_topic_by_id_swap, logging_exception_swap: job_id = (topic_jobs_one_off.RegenerateTopicSummaryOneOffJob. create_new()) topic_jobs_one_off.RegenerateTopicSummaryOneOffJob.enqueue(job_id) self.process_and_flush_pending_mapreduce_tasks() output = topic_jobs_one_off.RegenerateTopicSummaryOneOffJob.get_output( job_id) self.assertEqual(observed_log_messages, [ u'Failed to create topic summary %s: \'unicode\' ' 'object has no attribute \'canonical_story_references\'' % topic.id ]) for message in output: self.assertRegexpMatches( message, 'object has no attribute \'canonical_story_references\'')
def setUp(self): """Completes the sign-up process for the various users.""" super(BasePracticeSessionsControllerTests, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.topic_id = 'topic' self.topic_id_1 = 'topic1' self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'public_topic_name') self.topic.uncategorized_skill_ids.append('skill_id_1') self.topic.subtopics.append(topic_domain.Subtopic( 1, 'subtopic_name', ['skill_id_2'])) self.topic.next_subtopic_id = 2 topic_services.save_new_topic(self.admin_id, self.topic) self.topic = topic_domain.Topic.create_default_topic( self.topic_id_1, 'private_topic_name') topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id)
def test_job_skips_deleted_topic(self): """Tests that RemoveDeletedSkillsFromTopicOneOffJob job skips deleted topic and does not attempt to remove uncategorized skills for skills that are deleted. """ topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID, 'A name', 'abbrev', 'description') topic.add_uncategorized_skill_id('skill_1') topic.add_uncategorized_skill_id('skill_2') topic_services.save_new_topic(self.albert_id, topic) # Delete the topic before migration occurs. topic_services.delete_topic(self.albert_id, self.TOPIC_ID) # Ensure the topic is deleted. with self.assertRaisesRegexp(Exception, 'Entity .* not found'): topic_fetchers.get_topic_by_id(self.TOPIC_ID) # Start migration job on sample topic. job_id = (topic_jobs_one_off.RemoveDeletedSkillsFromTopicOneOffJob. create_new()) topic_jobs_one_off.RemoveDeletedSkillsFromTopicOneOffJob.enqueue( job_id) # This running without errors indicates the deleted topic is # being ignored. self.process_and_flush_pending_mapreduce_tasks() # Ensure the topic is still deleted. with self.assertRaisesRegexp(Exception, 'Entity .* not found'): topic_fetchers.get_topic_by_id(self.TOPIC_ID) output = (topic_jobs_one_off.RemoveDeletedSkillsFromTopicOneOffJob. get_output(job_id)) expected = [[u'topic_deleted', [u'Encountered 1 deleted topics.']]] self.assertEqual(expected, [ast.literal_eval(x) for x in output])
def setUp(self): super(OpportunityServicesUnitTest, self).setUp() self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.TOPIC_ID = 'topic' self.STORY_ID = 'story' explorations = [ self.save_new_valid_exploration('%s' % i, self.owner_id, title='title %d' % i, category='category%d' % i, end_state_name='End State', correctness_feedback_enabled=True) for i in python_utils.RANGE(5) ] for exp in explorations: self.publish_exploration(self.owner_id, exp.id) topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID, 'topic', 'abbrev', 'description') topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' topic.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'dummy-subtopic-url') ] topic.next_subtopic_id = 2 topic_services.save_new_topic(self.owner_id, topic) topic_services.publish_topic(self.TOPIC_ID, self.admin_id) story = story_domain.Story.create_default_story( self.STORY_ID, 'A story', 'Description', self.TOPIC_ID, 'story-two') story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID, self.STORY_ID) topic_services.publish_story(self.TOPIC_ID, self.STORY_ID, self.admin_id) 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.')
def setUp(self): super(OpportunityServicesIntegrationTest, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.TOPIC_ID = 'topic' self.STORY_ID = 'story' self.USER_ID = 'user' self.SKILL_ID = 'skill' self.QUESTION_ID = question_services.get_new_question_id() self.THREAD_ID = 'exploration.exp1.thread_1' # Since a valid exploration is created here, it has EndExploration # state as well, so the content in that has to be taken into account as # well when checking content_count in the tests. explorations = [ self.save_new_valid_exploration('%s' % i, self.owner_id, title='title %d' % i, category='category%d' % i, end_state_name='End State', correctness_feedback_enabled=True) for i in python_utils.RANGE(5) ] for exp in explorations: self.publish_exploration(self.owner_id, exp.id) topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID, 'topic', 'abbrev', 'description') topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' topic.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'dummy-subtopic-url') ] topic.next_subtopic_id = 2 subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, self.TOPIC_ID)) subtopic_page_services.save_subtopic_page( self.owner_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Sample' }) ]) topic_services.save_new_topic(self.owner_id, topic) topic_services.publish_topic(self.TOPIC_ID, self.admin_id) story = story_domain.Story.create_default_story( self.STORY_ID, 'A story', 'description', self.TOPIC_ID, 'story-one') story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID, self.STORY_ID) topic_services.publish_story(self.TOPIC_ID, self.STORY_ID, self.admin_id)
def setUp(self): super(ContributionOpportunitiesHandlerTest, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) explorations = [exp_domain.Exploration.create_default_exploration( '%s' % i, title='title %d' % i, category='category%d' % i, ) for i in python_utils.RANGE(2)] for exp in explorations: exp_services.save_new_exploration(self.owner_id, exp) topic = topic_domain.Topic.create_default_topic( topic_id='0', name='topic', abbreviated_name='abbrev') topic_services.save_new_topic(self.owner_id, topic) self.skill_id_0 = 'skill_id_0' self.skill_id_1 = 'skill_id_1' self.skill_ids = [self.skill_id_0, self.skill_id_1] for skill_id in self.skill_ids: self.save_new_skill(skill_id, self.admin_id, 'skill_description') topic_services.add_uncategorized_skill( self.admin_id, '0', skill_id) self.expected_skill_opportunity_dict_0 = { 'id': self.skill_id_0, 'skill_description': 'skill_description', 'question_count': 0, 'topic_name': 'topic' } self.expected_skill_opportunity_dict_1 = { 'id': self.skill_id_1, 'skill_description': 'skill_description', 'question_count': 0, 'topic_name': 'topic' } stories = [story_domain.Story.create_default_story( '%s' % i, title='title %d' % i, corresponding_topic_id='0' ) for i in python_utils.RANGE(2)] for index, story in enumerate(stories): story.language_code = 'en' story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story( self.owner_id, topic.id, story.id) story_services.update_story( self.owner_id, 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': explorations[index].id })], 'Changes.') self.expected_opportunity_dict_1 = { 'id': '0', 'topic_name': 'topic', 'story_title': 'title 0', 'chapter_title': 'Node1', 'content_count': 2, 'translation_counts': {} } self.expected_opportunity_dict_2 = { 'id': '1', 'topic_name': 'topic', 'story_title': 'title 1', 'chapter_title': 'Node1', 'content_count': 2, 'translation_counts': {} }
def _load_dummy_new_structures_data(self): """Loads the database with two topics (one of which is empty), a story and three skills in the topic (two of them in a subtopic) and a question attached to each skill. Raises: Exception: Cannot load new structures data in production mode. Exception: User does not have enough rights to generate data. """ if constants.DEV_MODE: if self.user.role != feconf.ROLE_ID_ADMIN: raise Exception( 'User does not have enough rights to generate data.') topic_id_1 = topic_services.get_new_topic_id() topic_id_2 = topic_services.get_new_topic_id() story_id = story_services.get_new_story_id() skill_id_1 = skill_services.get_new_skill_id() skill_id_2 = skill_services.get_new_skill_id() skill_id_3 = skill_services.get_new_skill_id() question_id_1 = question_services.get_new_question_id() question_id_2 = question_services.get_new_question_id() question_id_3 = question_services.get_new_question_id() skill_1 = self._create_dummy_skill(skill_id_1, 'Dummy Skill 1', '<p>Dummy Explanation 1</p>') skill_2 = self._create_dummy_skill(skill_id_2, 'Dummy Skill 2', '<p>Dummy Explanation 2</p>') skill_3 = self._create_dummy_skill(skill_id_3, 'Dummy Skill 3', '<p>Dummy Explanation 3</p>') question_1 = self._create_dummy_question(question_id_1, 'Question 1', [skill_id_1]) question_2 = self._create_dummy_question(question_id_2, 'Question 2', [skill_id_2]) question_3 = self._create_dummy_question(question_id_3, 'Question 3', [skill_id_3]) question_services.add_question(self.user_id, question_1) question_services.add_question(self.user_id, question_2) question_services.add_question(self.user_id, question_3) question_services.create_new_question_skill_link( self.user_id, question_id_1, skill_id_1, 0.3) question_services.create_new_question_skill_link( self.user_id, question_id_2, skill_id_2, 0.5) question_services.create_new_question_skill_link( self.user_id, question_id_3, skill_id_3, 0.7) topic_1 = topic_domain.Topic.create_default_topic( topic_id_1, 'Dummy Topic 1', 'abbrev') topic_2 = topic_domain.Topic.create_default_topic( topic_id_2, 'Empty Topic', 'abbrev') topic_1.add_canonical_story(story_id) topic_1.add_uncategorized_skill_id(skill_id_1) topic_1.add_uncategorized_skill_id(skill_id_2) topic_1.add_uncategorized_skill_id(skill_id_3) topic_1.add_subtopic(1, 'Dummy Subtopic Title') topic_1.move_skill_id_to_subtopic(None, 1, skill_id_2) topic_1.move_skill_id_to_subtopic(None, 1, skill_id_3) subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, topic_id_1)) self._reload_exploration('0') self._reload_exploration('16') story = story_domain.Story.create_default_story( story_id, 'Dummy Story 1', topic_id_1) story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'Dummy Chapter 1') story.update_node_destination_node_ids( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), ['%s%d' % (story_domain.NODE_ID_PREFIX, 2)]) story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), '0') story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, 2), 'Dummy Chapter 2') story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, 2), '16') skill_services.save_new_skill(self.user_id, skill_1) skill_services.save_new_skill(self.user_id, skill_2) skill_services.save_new_skill(self.user_id, skill_3) story_services.save_new_story(self.user_id, story) topic_services.save_new_topic(self.user_id, topic_1) topic_services.save_new_topic(self.user_id, topic_2) subtopic_page_services.save_subtopic_page( self.user_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Dummy Subtopic Title' }) ]) topic_services.publish_story(topic_id_1, story_id, self.user_id) topic_services.publish_topic(topic_id_1, self.user_id) else: raise Exception('Cannot load new structures data in production.')
def _load_dummy_new_structures_data(self): """Loads the database with two topics (one of which is empty), a story and three skills in the topic (two of them in a subtopic) and a question attached to each skill. Raises: Exception: Cannot load new structures data in production mode. Exception: User does not have enough rights to generate data. """ if constants.DEV_MODE: if self.user.role != feconf.ROLE_ID_ADMIN: raise Exception( 'User does not have enough rights to generate data.') topic_id_1 = topic_services.get_new_topic_id() topic_id_2 = topic_services.get_new_topic_id() story_id = story_services.get_new_story_id() skill_id_1 = skill_services.get_new_skill_id() skill_id_2 = skill_services.get_new_skill_id() skill_id_3 = skill_services.get_new_skill_id() question_id_1 = question_services.get_new_question_id() question_id_2 = question_services.get_new_question_id() question_id_3 = question_services.get_new_question_id() skill_1 = self._create_dummy_skill(skill_id_1, 'Dummy Skill 1', '<p>Dummy Explanation 1</p>') skill_2 = self._create_dummy_skill(skill_id_2, 'Dummy Skill 2', '<p>Dummy Explanation 2</p>') skill_3 = self._create_dummy_skill(skill_id_3, 'Dummy Skill 3', '<p>Dummy Explanation 3</p>') question_1 = self._create_dummy_question(question_id_1, 'Question 1', [skill_id_1]) question_2 = self._create_dummy_question(question_id_2, 'Question 2', [skill_id_2]) question_3 = self._create_dummy_question(question_id_3, 'Question 3', [skill_id_3]) question_services.add_question(self.user_id, question_1) question_services.add_question(self.user_id, question_2) question_services.add_question(self.user_id, question_3) question_services.create_new_question_skill_link( self.user_id, question_id_1, skill_id_1, 0.3) question_services.create_new_question_skill_link( self.user_id, question_id_2, skill_id_2, 0.5) question_services.create_new_question_skill_link( self.user_id, question_id_3, skill_id_3, 0.7) topic_1 = topic_domain.Topic.create_default_topic( topic_id_1, 'Dummy Topic 1', 'abbrev', 'description') topic_2 = topic_domain.Topic.create_default_topic( topic_id_2, 'Empty Topic', 'abbrev', 'description') topic_1.add_canonical_story(story_id) topic_1.add_uncategorized_skill_id(skill_id_1) topic_1.add_uncategorized_skill_id(skill_id_2) topic_1.add_uncategorized_skill_id(skill_id_3) topic_1.add_subtopic(1, 'Dummy Subtopic Title') topic_1.move_skill_id_to_subtopic(None, 1, skill_id_2) topic_1.move_skill_id_to_subtopic(None, 1, skill_id_3) subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, topic_id_1)) # These explorations were chosen since they pass the validations # for published stories. self._reload_exploration('15') self._reload_exploration('25') self._reload_exploration('13') story = story_domain.Story.create_default_story( story_id, 'Help Jaime win the Arcade', topic_id_1) story_node_dicts = [{ 'exp_id': '15', 'title': 'What are the place values?', 'description': 'Jaime learns the place value of each digit ' + 'in a big number.' }, { 'exp_id': '25', 'title': 'Finding the value of a number', 'description': 'Jaime understands the value of his ' + 'arcade score.' }, { 'exp_id': '13', 'title': 'Comparing Numbers', 'description': 'Jaime learns if a number is smaller or ' + 'greater than another number.' }] def generate_dummy_story_nodes(node_id, exp_id, title, description): """Generates and connects sequential story nodes. Args: node_id: int. The node id. exp_id: str. The exploration id. title: str. The title of the story node. description: str. The description of the story node. """ story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, node_id), title) story.update_node_description( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), description) story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), exp_id) if node_id != len(story_node_dicts): story.update_node_destination_node_ids( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), ['%s%d' % (story_domain.NODE_ID_PREFIX, node_id + 1)]) exp_services.update_exploration(self.user_id, exp_id, [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'category', 'new_value': 'Astronomy' }) ], 'Change category') for i, story_node_dict in enumerate(story_node_dicts): generate_dummy_story_nodes(i + 1, **story_node_dict) skill_services.save_new_skill(self.user_id, skill_1) skill_services.save_new_skill(self.user_id, skill_2) skill_services.save_new_skill(self.user_id, skill_3) story_services.save_new_story(self.user_id, story) topic_services.save_new_topic(self.user_id, topic_1) topic_services.save_new_topic(self.user_id, topic_2) subtopic_page_services.save_subtopic_page( self.user_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Dummy Subtopic Title' }) ]) topic_services.publish_story(topic_id_1, story_id, self.user_id) else: raise Exception('Cannot load new structures data in production.')
def setUp(self): super(ExplorationOpportunitySummaryModelRegenerationJobTest, self).setUp() self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.topic_id_1 = 'topic1' self.topic_id_2 = 'topic2' story_id_1 = 'story1' story_id_2 = 'story2' explorations = [ exp_domain.Exploration.create_default_exploration( '%s' % i, title='title %d' % i, category='category%d' % i, ) for i in python_utils.RANGE(2) ] for exp in explorations: exp_services.save_new_exploration(self.owner_id, exp) self.publish_exploration(self.owner_id, exp.id) topic_1 = topic_domain.Topic.create_default_topic( topic_id=self.topic_id_1, name='topic1', abbreviated_name='abbrev') topic_services.save_new_topic(self.owner_id, topic_1) topic_2 = topic_domain.Topic.create_default_topic( topic_id=self.topic_id_2, name='topic2', abbreviated_name='abbrev') topic_services.save_new_topic(self.owner_id, topic_2) story_1 = story_domain.Story.create_default_story( story_id_1, title='A story', corresponding_topic_id=self.topic_id_1) story_2 = story_domain.Story.create_default_story( story_id_2, title='A story', corresponding_topic_id=self.topic_id_2) story_services.save_new_story(self.owner_id, story_1) story_services.save_new_story(self.owner_id, story_2) topic_services.add_canonical_story(self.owner_id, self.topic_id_1, story_id_1) topic_services.add_canonical_story(self.owner_id, self.topic_id_2, story_id_2) story_services.update_story(self.owner_id, story_id_1, [ 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.') story_services.update_story(self.owner_id, story_id_2, [ 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': '1' }) ], 'Changes.')
def test_get(self): self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) admin_id = self.get_user_id_from_email(self.CURRICULUM_ADMIN_EMAIL) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME]) self.login(self.CURRICULUM_ADMIN_EMAIL, is_super_admin=True) topic_id_1 = topic_fetchers.get_new_topic_id() topic_id_2 = topic_fetchers.get_new_topic_id() private_topic = topic_domain.Topic.create_default_topic( topic_id_1, 'private_topic_name', 'private-topic-name', 'description') topic_services.save_new_topic(admin_id, private_topic) public_topic = topic_domain.Topic.create_default_topic( topic_id_2, 'public_topic_name', 'public-topic-name', 'description') public_topic.thumbnail_filename = 'Topic.svg' public_topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) public_topic.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_1', 'skill_id_2', 'skill_id_3'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-three') ] public_topic.next_subtopic_id = 2 topic_services.save_new_topic(admin_id, public_topic) topic_services.publish_topic(topic_id_2, admin_id) csrf_token = self.get_new_csrf_token() new_config_value = [{ 'name': 'math', 'topic_ids': [topic_id_1, topic_id_2], 'course_details': 'Course details for classroom.', 'topic_list_intro': 'Topics covered for classroom', 'url_fragment': 'math', }] payload = { 'action': 'save_config_properties', 'new_config_property_values': { config_domain.CLASSROOM_PAGES_DATA.name: (new_config_value), } } self.post_json('/adminhandler', payload, csrf_token=csrf_token) self.logout() json_response = self.get_json('%s/%s' % (feconf.CLASSROOM_DATA_HANDLER, 'math')) public_topic_summary_dict = ( topic_fetchers.get_topic_summary_by_id(topic_id_2).to_dict()) public_topic_summary_dict['is_published'] = True private_topic_summary_dict = ( topic_fetchers.get_topic_summary_by_id(topic_id_1).to_dict()) private_topic_summary_dict['is_published'] = False expected_dict = { 'name': 'math', 'topic_summary_dicts': [private_topic_summary_dict, public_topic_summary_dict], 'course_details': 'Course details for classroom.', 'topic_list_intro': 'Topics covered for classroom' } self.assertDictContainsSubset(expected_dict, json_response)
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicViewerControllerTests, self).setUp() self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.topic_id = 'topic' self.story_id_1 = 'story_id_1' self.story_id_2 = 'story_id_2' self.topic_id_1 = 'topic1' self.topic_id_2 = 'topic2' self.skill_id_1 = skill_services.get_new_skill_id() self.skill_id_2 = skill_services.get_new_skill_id() self.story_1 = story_domain.Story.create_default_story( self.story_id_1, 'story_title', self.topic_id_1) self.story_1.description = 'story_description' self.story_1.node_titles = [] self.story_2 = story_domain.Story.create_default_story( self.story_id_2, 'story_title', self.topic_id_2) self.story_2.description = 'story_description' self.story_2.node_titles = [] self.topic = topic_domain.Topic.create_default_topic( self.topic_id, 'public_topic_name', 'abbrev') self.topic.uncategorized_skill_ids.append(self.skill_id_1) self.topic.subtopics.append( topic_domain.Subtopic( 1, 'subtopic_name', [self.skill_id_2], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0])) self.topic.next_subtopic_id = 2 self.topic.thumbnail_filename = 'Image.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) self.topic.canonical_story_references.append( topic_domain.StoryReference.create_default_story_reference( self.story_id_1)) self.topic.additional_story_references.append( topic_domain.StoryReference.create_default_story_reference( self.story_id_2)) topic_services.save_new_topic(self.admin_id, self.topic) story_services.save_new_story(self.admin_id, self.story_1) story_services.save_new_story(self.admin_id, self.story_2) self.topic = topic_domain.Topic.create_default_topic( self.topic_id_1, 'private_topic_name', 'abbrev') self.topic.thumbnail_filename = 'Image.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) topic_services.save_new_topic(self.admin_id, self.topic) topic_services.publish_topic(self.topic_id, self.admin_id) topic_services.publish_story(self.topic_id, self.story_id_1, self.admin_id) topic_services.publish_story(self.topic_id, self.story_id_2, self.admin_id) self.save_new_skill(self.skill_id_1, self.user_id, description='Skill Description 1') self.save_new_skill(self.skill_id_2, self.user_id, description='Skill Description 2') skill_services.create_user_skill_mastery(self.user_id, self.skill_id_1, 0.3) skill_services.create_user_skill_mastery(self.user_id, self.skill_id_2, 0.5)
def setUp(self): super(ContributionOpportunitiesHandlerTest, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) explorations = [ self.save_new_valid_exploration('%s' % i, self.owner_id, title='title %d' % i, category='category%d' % i, end_state_name='End State') for i in python_utils.RANGE(2) ] for exp in explorations: self.publish_exploration(self.owner_id, exp.id) topic = topic_domain.Topic.create_default_topic( '0', 'topic', 'abbrev', 'description') topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' topic_services.save_new_topic(self.owner_id, topic) topic_services.publish_topic('0', self.admin_id) self.skill_id_0 = 'skill_id_0' self.skill_id_1 = 'skill_id_1' self.skill_ids = [self.skill_id_0, self.skill_id_1] for skill_id in self.skill_ids: self.save_new_skill(skill_id, self.admin_id, description='skill_description') topic_services.add_uncategorized_skill(self.admin_id, '0', skill_id) self.expected_skill_opportunity_dict_0 = { 'id': self.skill_id_0, 'skill_description': 'skill_description', 'question_count': 0, 'topic_name': 'topic' } self.expected_skill_opportunity_dict_1 = { 'id': self.skill_id_1, 'skill_description': 'skill_description', 'question_count': 0, 'topic_name': 'topic' } stories = [ story_domain.Story.create_default_story('%s' % i, 'title %d' % i, 'description %d' % i, '0', 'title-%s' % chr(97 + i)) for i in python_utils.RANGE(2) ] for index, story in enumerate(stories): story.language_code = 'en' story_services.save_new_story(self.owner_id, story) topic_services.add_canonical_story(self.owner_id, topic.id, story.id) topic_services.publish_story(topic.id, story.id, self.admin_id) story_services.update_story(self.owner_id, 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': explorations[index].id }) ], 'Changes.') # The content_count is 4 for the expected dicts below since a valid # exploration with EndExploration is created above, so the content in # the last state is also included in the count. This content includes: # 2 content, 1 TextInput interaction customization argument # (placeholder), and 1 outcome. self.expected_opportunity_dict_1 = { 'id': '0', 'topic_name': 'topic', 'story_title': 'title 0', 'chapter_title': 'Node1', 'content_count': 2, 'translation_counts': {} } self.expected_opportunity_dict_2 = { 'id': '1', 'topic_name': 'topic', 'story_title': 'title 1', 'chapter_title': 'Node1', 'content_count': 2, 'translation_counts': {} }
def test_interactions_are_reported_correctly(self): topic_id_1 = 'topicid1' topic_id_2 = 'topicid2' story_id = story_services.get_new_story_id() skill_id_1 = skill_services.get_new_skill_id() skill_id_2 = skill_services.get_new_skill_id() skill_id_3 = skill_services.get_new_skill_id() skill_1 = self._create_dummy_skill(skill_id_1, 'Dummy Skill 1', '<p>Dummy Explanation 1</p>') skill_2 = self._create_dummy_skill(skill_id_2, 'Dummy Skill 2', '<p>Dummy Explanation 2</p>') skill_3 = self._create_dummy_skill(skill_id_3, 'Dummy Skill 3', '<p>Dummy Explanation 3</p>') topic_1 = topic_domain.Topic.create_default_topic( topic_id_1, 'Dummy Topic 1', 'dummy-topic-one', 'description') topic_2 = topic_domain.Topic.create_default_topic( topic_id_2, 'Empty Topic', 'empty-topic', 'description') topic_1.add_canonical_story(story_id) topic_1.add_uncategorized_skill_id(skill_id_1) topic_1.add_uncategorized_skill_id(skill_id_2) topic_1.add_uncategorized_skill_id(skill_id_3) topic_1.add_subtopic(1, 'Dummy Subtopic Title') topic_1.move_skill_id_to_subtopic(None, 1, skill_id_2) topic_1.move_skill_id_to_subtopic(None, 1, skill_id_3) # These explorations were chosen since they pass the validations # for published stories. exp_services.load_demo('15') exp_services.load_demo('25') exp_services.load_demo('13') exp_services.update_exploration( self.user_id, '15', [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'correctness_feedback_enabled', 'new_value': True }) ], 'Changed correctness_feedback_enabled.') exp_services.update_exploration( self.user_id, '25', [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'correctness_feedback_enabled', 'new_value': True }) ], 'Changed correctness_feedback_enabled.') exp_services.update_exploration( self.user_id, '13', [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'correctness_feedback_enabled', 'new_value': True }) ], 'Changed correctness_feedback_enabled.') story = story_domain.Story.create_default_story( story_id, 'Help Jaime win the Arcade', 'Description', topic_id_1, 'help-jamie-win-arcade') story_node_dicts = [{ 'exp_id': '15', 'title': 'What are the place values?', 'description': 'a' }, { 'exp_id': '25', 'title': 'Finding the value of a number', 'description': 'b' }, { 'exp_id': '13', 'title': 'Comparing Numbers', 'description': 'c' }] def generate_dummy_story_nodes(node_id, exp_id, title, description): """Generates and connects sequential story nodes. Args: node_id: int. The node id. exp_id: str. The exploration id. title: str. The title of the story node. description: str. The description of the story node. """ story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, node_id), title) story.update_node_description( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), description) story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), exp_id) if node_id != len(story_node_dicts): story.update_node_destination_node_ids( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), ['%s%d' % (story_domain.NODE_ID_PREFIX, node_id + 1)]) exp_services.update_exploration(self.user_id, exp_id, [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'category', 'new_value': 'Astronomy' }) ], 'Change category') for i, story_node_dict in enumerate(story_node_dicts): generate_dummy_story_nodes(i + 1, **story_node_dict) skill_services.save_new_skill(self.user_id, skill_1) skill_services.save_new_skill(self.user_id, skill_2) skill_services.save_new_skill(self.user_id, skill_3) story_services.save_new_story(self.user_id, story) topic_services.save_new_topic(self.user_id, topic_1) topic_services.save_new_topic(self.user_id, topic_2) topic_services.publish_story(topic_id_1, story_id, self.user_id) job_id = (topic_jobs_one_off.InteractionsInStoriesAuditOneOffJob. create_new()) topic_jobs_one_off.InteractionsInStoriesAuditOneOffJob.enqueue(job_id) self.process_and_flush_pending_mapreduce_tasks() output = (topic_jobs_one_off.InteractionsInStoriesAuditOneOffJob. get_output(job_id)) expected = [[ '%s (%s)' % ('Dummy Topic 1', topic_id_1), [ u'[u\'EndExploration\', u\'ImageClickInput\', u\'Continue\', ' u'u\'MultipleChoiceInput\', u\'TextInput\']' ] ], ['%s (%s)' % ('Empty Topic', topic_id_2), [u'[]']]] self.assertEqual(expected, [ast.literal_eval(x) for x in output])