def setUp(self): super(LearnerGroupStudentProgressHandlerTests, self).setUp() self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.signup(self.STUDENT_1_EMAIL, self.STUDENT_1_USERNAME) self.signup(self.STUDENT_2_EMAIL, self.STUDENT_2_USERNAME) self.STUDENT_ID_1 = self.get_user_id_from_email(self.STUDENT_1_EMAIL) self.STUDENT_ID_2 = self.get_user_id_from_email(self.STUDENT_2_EMAIL) self.facilitator_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) 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.LEARNER_GROUP_ID = ( learner_group_fetchers.get_new_learner_group_id()) learner_group_services.create_learner_group( self.LEARNER_GROUP_ID, 'Learner Group Name', 'Description', [self.facilitator_id], [self.STUDENT_ID_1, self.STUDENT_ID_2], [self.SUBTOPIC_PAGE_ID_1], [self.STORY_ID_1]) # Set up topics, subtopics and stories for learner group syllabus. self.save_new_valid_exploration(self.EXP_ID_0, self.admin_id, title='Title 1', end_state_name='End', correctness_feedback_enabled=True) self.save_new_valid_exploration(self.EXP_ID_1, self.admin_id, title='Title 2', end_state_name='End', correctness_feedback_enabled=True) self.save_new_valid_exploration(self.EXP_ID_7, self.admin_id, title='Title 3', end_state_name='End', correctness_feedback_enabled=True) self.publish_exploration(self.admin_id, self.EXP_ID_0) self.publish_exploration(self.admin_id, self.EXP_ID_1) self.publish_exploration(self.admin_id, self.EXP_ID_7) story = story_domain.Story.create_default_story( self.STORY_ID_1, 'Title', 'Description', self.TOPIC_ID_1, self.STORY_URL_FRAGMENT) story.meta_tag_content = 'story meta content' exp_summary_dicts = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( [self.EXP_ID_0, self.EXP_ID_1, self.EXP_ID_7], user=self.admin)) self.node_1 = { 'id': self.NODE_ID_1, 'title': 'Title 1', 'description': 'Description 1', 'thumbnail_filename': 'image_1.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0], 'thumbnail_size_in_bytes': 21131, 'destination_node_ids': ['node_3'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_1, 'exp_summary_dict': exp_summary_dicts[1], 'completed': False } self.node_2 = { 'id': self.NODE_ID_2, 'title': 'Title 2', 'description': 'Description 2', 'thumbnail_filename': 'image_2.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0], 'thumbnail_size_in_bytes': 21131, 'destination_node_ids': ['node_1'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_0, 'exp_summary_dict': exp_summary_dicts[0], 'completed': True } self.node_3 = { 'id': self.NODE_ID_3, 'title': 'Title 3', 'description': 'Description 3', 'thumbnail_filename': 'image_3.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0], 'thumbnail_size_in_bytes': 21131, 'destination_node_ids': [], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_7, 'exp_summary_dict': exp_summary_dicts[2], 'completed': False } story.story_contents.nodes = [ story_domain.StoryNode.from_dict(self.node_1), story_domain.StoryNode.from_dict(self.node_2), story_domain.StoryNode.from_dict(self.node_3) ] self.nodes = story.story_contents.nodes story.story_contents.initial_node_id = 'node_2' story.story_contents.next_node_id = 'node_4' story_services.save_new_story(self.admin_id, story) self.subtopic_1 = topic_domain.Subtopic.create_default_subtopic( 1, 'Subtopic Title 1', 'sub-one-frag') self.subtopic_2 = topic_domain.Subtopic.create_default_subtopic( 2, 'Subtopic Title 2', 'sub-two-frag') self.SKILL_ID_1 = skill_services.get_new_skill_id() self.SKILL_ID_2 = skill_services.get_new_skill_id() self.subtopic_1.skill_ids = [self.SKILL_ID_1] self.subtopic_2.skill_ids = [self.SKILL_ID_2] self.save_new_topic(self.TOPIC_ID_1, 'user', name='Topic', description='A new topic', canonical_story_ids=[story.id], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_1, self.subtopic_2], next_subtopic_id=3) topic_services.publish_topic(self.TOPIC_ID_1, self.admin_id) topic_services.publish_story(self.TOPIC_ID_1, self.STORY_ID_1, self.admin_id) # Add the invited students to the learner group. learner_group_services.add_student_to_learner_group( self.LEARNER_GROUP_ID, self.STUDENT_ID_1, True) learner_group_services.add_student_to_learner_group( self.LEARNER_GROUP_ID, self.STUDENT_ID_2, False) # Add some progress for the students. story_services.record_completed_node_in_story_context( self.STUDENT_ID_1, self.STORY_ID_1, self.NODE_ID_1) story_services.record_completed_node_in_story_context( self.STUDENT_ID_1, self.STORY_ID_1, self.NODE_ID_2) story_services.record_completed_node_in_story_context( self.STUDENT_ID_2, self.STORY_ID_1, self.NODE_ID_3) self.SKILL_IDS = [self.SKILL_ID_1, self.SKILL_ID_2] skill_services.create_user_skill_mastery(self.STUDENT_ID_1, self.SKILL_ID_1, self.DEGREE_OF_MASTERY_1) skill_services.create_user_skill_mastery(self.STUDENT_ID_2, self.SKILL_ID_2, self.DEGREE_OF_MASTERY_2)
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 = [ 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(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.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_3'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'dummy-subtopic-three') ] topic.next_subtopic_id = 2 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': {} } config_services.set_property('admin', 'contributor_dashboard_is_enabled', True)
def setUp(self): super( ExplorationOpportunitySummaryModelRegenerationJobTest, 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.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( self.topic_id_1, 'topic', 'abbrev-one', 'description') topic_1.thumbnail_filename = 'thumbnail.svg' topic_1.thumbnail_bg_color = '#C6DCDA' topic_services.save_new_topic(self.owner_id, topic_1) topic_services.publish_topic(self.topic_id_1, self.admin_id) topic_2 = topic_domain.Topic.create_default_topic( self.topic_id_2, 'topic2', 'abbrev-two', 'description') topic_2.thumbnail_filename = 'thumbnail.svg' topic_2.thumbnail_bg_color = '#C6DCDA' topic_services.save_new_topic(self.owner_id, topic_2) topic_services.publish_topic(self.topic_id_2, self.admin_id) story_1 = story_domain.Story.create_default_story( story_id_1, 'A story', 'description', self.topic_id_1, 'story-one') story_2 = story_domain.Story.create_default_story( story_id_2, 'A story', 'description', self.topic_id_2, 'story-two') 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.publish_story(self.topic_id_1, story_id_1, self.admin_id) topic_services.add_canonical_story( self.owner_id, self.topic_id_2, story_id_2) topic_services.publish_story(self.topic_id_2, story_id_2, self.admin_id) 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 setUp(self): """Completes the sign-up process for the various users.""" super(BaseReviewTestsControllerTests, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.signup(self.VIEWER_EMAIL, self.VIEWER_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.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.topic_id = 'topic_id' self.story_id_1 = 'story_id_1' self.story_id_2 = 'story_id_2' self.story_id_3 = 'story_id_3' self.node_id = 'node_1' self.node_id_2 = 'node_2' self.exp_id = 'exp_id' self.story_url_fragment_1 = 'public-story-title' self.story_url_fragment_2 = 'private-story-title' self.save_new_valid_exploration(self.exp_id, self.owner_id) self.publish_exploration(self.owner_id, self.exp_id) self.node_1 = { 'id': self.node_id, 'title': 'Title 1', 'description': 'Description 1', 'thumbnail_filename': 'image.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS['chapter'][0], 'destination_node_ids': [], 'acquired_skill_ids': ['skill_id_1', 'skill_id_2'], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.exp_id } self.save_new_skill('skill_id_1', self.admin_id, description='Skill 1') self.save_new_skill('skill_id_2', self.admin_id, description='Skill 2') self.story = story_domain.Story.create_default_story( self.story_id_1, 'Public Story Title', 'Description', self.topic_id, self.story_url_fragment_1) self.story.story_contents.nodes = [ story_domain.StoryNode.from_dict(self.node_1) ] self.story.story_contents.initial_node_id = self.node_id self.story.story_contents.next_node_id = self.node_id_2 story_services.save_new_story(self.admin_id, self.story) self.story_2 = story_domain.Story.create_default_story( self.story_id_2, 'Private Story Title', 'Description', self.topic_id, self.story_url_fragment_2) story_services.save_new_story(self.admin_id, self.story_2) self.save_new_topic( self.topic_id, 'user', name='Topic', description='A new topic', canonical_story_ids=[self.story_id_1, self.story_id_3], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[], next_subtopic_id=0) topic_services.publish_topic(self.topic_id, self.admin_id) topic_services.publish_story(self.topic_id, self.story_id_1, self.admin_id) self.login(self.VIEWER_EMAIL)
def test_handler_updates_story_summary_dicts(self): self.login(self.CURRICULUM_ADMIN_EMAIL) topic_id = topic_fetchers.get_new_topic_id() canonical_story_id = story_services.get_new_story_id() additional_story_id = story_services.get_new_story_id() # 'self.topic_id' does not contain any canonical_story_summary_dicts # or additional_story_summary_dicts. response = self.get_json( '%s/%s' % (feconf.TOPIC_EDITOR_STORY_URL, self.topic_id)) self.assertEqual(response['canonical_story_summary_dicts'], []) self.assertEqual(response['additional_story_summary_dicts'], []) self.save_new_topic(topic_id, self.admin_id, name='New name', abbreviated_name='topic-two', url_fragment='topic-two', description='New description', canonical_story_ids=[canonical_story_id], additional_story_ids=[additional_story_id], uncategorized_skill_ids=[self.skill_id], subtopics=[], next_subtopic_id=1) self.save_new_story(canonical_story_id, self.admin_id, topic_id, title='title', description='description', notes='note') self.save_new_story(additional_story_id, self.admin_id, topic_id, title='another title', description='another description', notes='another note') topic_services.publish_story(topic_id, canonical_story_id, self.admin_id) response = self.get_json('%s/%s' % (feconf.TOPIC_EDITOR_STORY_URL, topic_id)) canonical_story_summary_dict = response[ 'canonical_story_summary_dicts'][0] additional_story_summary_dict = response[ 'additional_story_summary_dicts'][0] self.assertEqual(canonical_story_summary_dict['description'], 'description') self.assertEqual(canonical_story_summary_dict['title'], 'title') self.assertEqual(canonical_story_summary_dict['id'], canonical_story_id) self.assertEqual(canonical_story_summary_dict['story_is_published'], True) self.assertEqual(additional_story_summary_dict['description'], 'another description') self.assertEqual(additional_story_summary_dict['title'], 'another title') self.assertEqual(additional_story_summary_dict['id'], additional_story_id) self.assertEqual(additional_story_summary_dict['story_is_published'], False) self.logout()
def setUp(self): """Completes the sign up process for the various users.""" super(BaseStoryViewerControllerTests, self).setUp() self.VIEWER_EMAIL = '*****@*****.**' self.VIEWER_USERNAME = '******' 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.login(self.ADMIN_EMAIL) self.TOPIC_ID = 'topic_id' self.STORY_ID_1 = 'story_id_1' self.NODE_ID_1 = 'node_1' self.NODE_ID_2 = 'node_2' self.NODE_ID_3 = 'node_3' self.EXP_ID = 'exp_id' self.save_new_valid_exploration( self.EXP_ID, self.admin_id, title='Bridges in England', category='Architecture', language_code='en') rights_manager.publish_exploration(self.admin, self.EXP_ID) story = story_domain.Story.create_default_story( self.STORY_ID_1, 'Title', self.TOPIC_ID) story.description = ('Description') exp_summary_dict = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( [self.EXP_ID], user=self.admin)[0]) self.node_1 = { 'id': self.NODE_ID_1, 'title': 'Title 1', 'destination_node_ids': ['node_3'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID, 'exp_summary_dict': exp_summary_dict, 'completed': False } self.node_2 = { 'id': self.NODE_ID_2, 'title': 'Title 2', 'destination_node_ids': ['node_1'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID, 'exp_summary_dict': exp_summary_dict, 'completed': True } self.node_3 = { 'id': self.NODE_ID_3, 'title': 'Title 3', 'destination_node_ids': [], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': None } story.story_contents.nodes = [ story_domain.StoryNode.from_dict(self.node_1), story_domain.StoryNode.from_dict(self.node_2), story_domain.StoryNode.from_dict(self.node_3) ] self.nodes = story.story_contents.nodes story.story_contents.initial_node_id = 'node_2' story.story_contents.next_node_id = 'node_4' story_services.save_new_story(self.admin_id, story) self.save_new_topic( self.TOPIC_ID, 'user', 'Topic', 'A new topic', [story.id], [], [], [], 0) topic_services.publish_topic(self.TOPIC_ID, self.admin_id) topic_services.publish_story( self.TOPIC_ID, self.STORY_ID_1, self.admin_id) self.logout() self.signup(self.VIEWER_EMAIL, self.VIEWER_USERNAME) self.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL) self.login(self.VIEWER_EMAIL) self._record_completion(self.viewer_id, self.STORY_ID_1, self.NODE_ID_2)
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', 'description', self.topic_id_1, 'story-frag-one') 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', 'description', self.topic_id_2, 'story-frag-two') 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', 'public', 'description') 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], 'subtopic-name')) 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', 'private_topic_name', 'description') self.topic.thumbnail_filename = 'Image.svg' self.topic.thumbnail_bg_color = ( constants.ALLOWED_THUMBNAIL_BG_COLORS['topic'][0]) self.topic.url_fragment = 'private' 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 test_get_learner_dashboard_ids(self): self.login(self.VIEWER_EMAIL) self.save_new_default_exploration(self.EXP_ID_1, self.owner_id, title=self.EXP_TITLE_1) self.publish_exploration(self.owner_id, self.EXP_ID_1) self.save_new_default_exploration(self.EXP_ID_2, self.owner_id, title=self.EXP_TITLE_2) self.publish_exploration(self.owner_id, self.EXP_ID_2) self.save_new_default_exploration(self.EXP_ID_3, self.owner_id, title=self.EXP_TITLE_3) self.publish_exploration(self.owner_id, self.EXP_ID_3) self.save_new_default_collection(self.COL_ID_1, self.owner_id, title=self.COL_TITLE_1) self.publish_collection(self.owner_id, self.COL_ID_1) self.save_new_default_collection(self.COL_ID_2, self.owner_id, title=self.COL_TITLE_2) self.publish_collection(self.owner_id, self.COL_ID_2) self.save_new_default_collection(self.COL_ID_3, self.owner_id, title=self.COL_TITLE_3) self.publish_collection(self.owner_id, self.COL_ID_3) self.save_new_topic(self.TOPIC_ID_1, self.owner_id, name=self.TOPIC_NAME_1, url_fragment='topic-one', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_0], next_subtopic_id=1) self.save_new_story(self.STORY_ID_1, self.owner_id, self.TOPIC_ID_1) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID_1, self.STORY_ID_1) topic_services.publish_story(self.TOPIC_ID_1, self.STORY_ID_1, self.admin_id) topic_services.publish_topic(self.TOPIC_ID_1, self.admin_id) self.save_new_topic(self.TOPIC_ID_2, self.owner_id, name=self.TOPIC_NAME_2, url_fragment='topic-two', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_1], next_subtopic_id=1) self.save_new_story(self.STORY_ID_2, self.owner_id, self.TOPIC_ID_2) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID_2, self.STORY_ID_2) topic_services.publish_story(self.TOPIC_ID_2, self.STORY_ID_2, self.admin_id) topic_services.publish_topic(self.TOPIC_ID_2, self.admin_id) self.save_new_topic(self.TOPIC_ID_3, self.owner_id, name=self.TOPIC_NAME_3, url_fragment='topic-three', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_1], next_subtopic_id=1) self.save_new_story(self.STORY_ID_3, self.owner_id, self.TOPIC_ID_3) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID_3, self.STORY_ID_3) topic_services.publish_story(self.TOPIC_ID_3, self.STORY_ID_3, self.admin_id) topic_services.publish_topic(self.TOPIC_ID_3, self.admin_id) state_name = 'state_name' version = 1 learner_progress_services.mark_exploration_as_completed( self.viewer_id, self.EXP_ID_1) learner_progress_services.mark_exploration_as_incomplete( self.viewer_id, self.EXP_ID_2, state_name, version) learner_progress_services.add_exp_to_learner_playlist( self.viewer_id, self.EXP_ID_3) learner_progress_services.mark_collection_as_completed( self.viewer_id, self.COL_ID_1) learner_progress_services.mark_collection_as_incomplete( self.viewer_id, self.COL_ID_2) learner_progress_services.add_collection_to_learner_playlist( self.viewer_id, self.COL_ID_3) learner_progress_services.mark_story_as_completed( self.viewer_id, self.STORY_ID_1) learner_progress_services.mark_topic_as_learnt(self.viewer_id, self.TOPIC_ID_1) learner_progress_services.record_topic_started(self.viewer_id, self.TOPIC_ID_2) learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_3) response = self.get_json(feconf.LEARNER_DASHBOARD_IDS_DATA_URL) learner_dashboard_activity_ids = ( response['learner_dashboard_activity_ids']) self.assertEqual( learner_dashboard_activity_ids['completed_exploration_ids'], [self.EXP_ID_1]) self.assertEqual( learner_dashboard_activity_ids['incomplete_exploration_ids'], [self.EXP_ID_2]) self.assertEqual( learner_dashboard_activity_ids['exploration_playlist_ids'], [self.EXP_ID_3]) self.assertEqual( learner_dashboard_activity_ids['completed_collection_ids'], [self.COL_ID_1]) self.assertEqual( learner_dashboard_activity_ids['incomplete_collection_ids'], [self.COL_ID_2]) self.assertEqual( learner_dashboard_activity_ids['collection_playlist_ids'], [self.COL_ID_3]) self.assertEqual(learner_dashboard_activity_ids['completed_story_ids'], [self.STORY_ID_1]) self.assertEqual(learner_dashboard_activity_ids['learnt_topic_ids'], [self.TOPIC_ID_1]) self.assertEqual( learner_dashboard_activity_ids['partially_learnt_topic_ids'], [self.TOPIC_ID_2]) self.assertEqual(learner_dashboard_activity_ids['topic_ids_to_learn'], [self.TOPIC_ID_3])
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) else: raise Exception('Cannot load new structures data in production.')
def test_can_get_completed_chapters_count(self): self.save_new_topic(self.TOPIC_ID_1, self.owner_id, name=self.TOPIC_NAME_1, url_fragment='topic-one', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_0], next_subtopic_id=1) self.save_new_story(self.STORY_ID_1, self.owner_id, self.TOPIC_ID_1) topic_services.add_canonical_story(self.owner_id, self.TOPIC_ID_1, self.STORY_ID_1) self.save_new_default_exploration(self.EXP_ID_1, self.owner_id, 'Title 1') self.publish_exploration(self.owner_id, self.EXP_ID_1) changelist = [ story_domain.StoryChange({ 'cmd': story_domain.CMD_ADD_STORY_NODE, 'node_id': 'node_1', 'title': 'Title 1' }), story_domain.StoryChange({ 'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY, 'property_name': (story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID), 'node_id': 'node_1', 'old_value': None, 'new_value': self.EXP_ID_1 }) ] story_services.update_story(self.owner_id, self.STORY_ID_1, changelist, 'Added first node.') topic_services.publish_story(self.TOPIC_ID_1, self.STORY_ID_1, self.admin_id) topic_services.publish_topic(self.TOPIC_ID_1, self.admin_id) self.login(self.CURRICULUM_ADMIN_EMAIL, is_super_admin=True) csrf_token = self.get_new_csrf_token() new_config_value = [{ 'name': 'math', 'url_fragment': 'math', 'topic_ids': [self.TOPIC_ID_1], 'course_details': '', 'topic_list_intro': '' }] 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() self.login(self.VIEWER_EMAIL) self.assertEqual( self.get_json(feconf.LEARNER_COMPLETED_CHAPTERS_COUNT_DATA_URL) ['completed_chapters_count'], 0) story_services.record_completed_node_in_story_context( self.viewer_id, self.STORY_ID_1, 'node_1') self.assertEqual( self.get_json(feconf.LEARNER_COMPLETED_CHAPTERS_COUNT_DATA_URL) ['completed_chapters_count'], 1) self.logout()
def setUp(self): super(ExplorationOpportunitySummaryModelValidatorTests, self).setUp() self.job_class = (prod_validation_jobs_one_off. ExplorationOpportunitySummaryModelAuditOneOffJob) 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', 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_2'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'dummy-subtopic-three') ] 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.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-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) story_change_list = [ story_domain.StoryChange({ 'cmd': 'add_story_node', 'node_id': 'node_%s' % i, 'title': 'Node %s' % i, }) for i in python_utils.RANGE(1, 4) ] story_change_list += [ story_domain.StoryChange({ 'cmd': 'update_story_node_property', 'property_name': 'destination_node_ids', 'node_id': 'node_%s' % i, 'old_value': [], 'new_value': ['node_%s' % (i + 1)] }) for i in python_utils.RANGE(1, 3) ] story_change_list += [ story_domain.StoryChange({ 'cmd': 'update_story_node_property', 'property_name': 'exploration_id', 'node_id': 'node_%s' % i, 'old_value': None, 'new_value': '%s' % i }) for i in python_utils.RANGE(1, 4) ] story_services.update_story(self.owner_id, self.STORY_ID, story_change_list, 'Changes.') self.model_instance_1 = ( opportunity_models.ExplorationOpportunitySummaryModel.get_by_id( '1')) self.model_instance_2 = ( opportunity_models.ExplorationOpportunitySummaryModel.get_by_id( '2')) self.model_instance_3 = ( opportunity_models.ExplorationOpportunitySummaryModel.get_by_id( '3'))
def setUp(self): super(ContributionOpportunitiesHandlerTest, self).setUp() self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.admin_id = self.get_user_id_from_email( self.CURRICULUM_ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.set_curriculum_admins([self.CURRICULUM_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', correctness_feedback_enabled=True) for i in python_utils.RANGE(2) ] for exp in explorations: self.publish_exploration(self.owner_id, exp.id) self.topic_id = '0' topic = topic_domain.Topic.create_default_topic( self.topic_id, 'topic', 'abbrev', 'description') self.skill_id_0 = 'skill_id_0' self.skill_id_1 = 'skill_id_1' self._publish_valid_topic(topic, [self.skill_id_0, self.skill_id_1]) # Add skill opportunity topic to a classroom. config_services.set_property(self.admin_id, 'classroom_pages_data', [{ 'name': 'math', 'url_fragment': 'math-one', 'topic_ids': [self.topic_id], 'course_details': '', 'topic_list_intro': '' }]) 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': {}, 'translation_in_review_counts': {} } self.expected_opportunity_dict_2 = { 'id': '1', 'topic_name': 'topic', 'story_title': 'title 1', 'chapter_title': 'Node1', 'content_count': 2, 'translation_counts': {}, 'translation_in_review_counts': {} } config_services.set_property('admin', 'contributor_dashboard_is_enabled', True)
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 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])
def setUp(self): super(VoiceoverApplicationServicesUnitTests, self).setUp() self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.signup(self.APPLICANT_EMAIL, self.APPLICANT_USERNAME) self.admin_id = self.get_user_id_from_email( self.CURRICULUM_ADMIN_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.applicant_id = self.get_user_id_from_email(self.APPLICANT_EMAIL) self.applicant = user_services.get_user_actions_info(self.applicant_id) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME]) self.admin = user_services.get_user_actions_info(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 = [ self.save_new_valid_exploration( '%s' % i, self.owner_id, title='title %d' % i, category=constants.ALL_CATEGORIES[i], end_state_name='End State', correctness_feedback_enabled=True) for i in range(2) ] 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', 'fragm') 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], 21131, 'dummy-subtopic-three') ] 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, 'a-story') 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.') self.add_user_role(self.CURRICULUM_ADMIN_USERNAME, feconf.ROLE_ID_VOICEOVER_ADMIN)
def setUp(self): super(ExplorationOpportunitySummaryModelRegenerationJobTest, 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.topic_id_1 = 'topic1' self.topic_id_2 = 'topic2' story_id_1 = 'story1' story_id_2 = 'story2' explorations = [ self.save_new_valid_exploration('%s' % i, self.owner_id, title='title %d' % i, end_state_name='End State', correctness_feedback_enabled=True) for i in python_utils.RANGE(2) ] for exp in explorations: self.publish_exploration(self.owner_id, exp.id) topic_1 = topic_domain.Topic.create_default_topic( self.topic_id_1, 'topic', 'abbrev-one', 'description') topic_1.thumbnail_filename = 'thumbnail.svg' topic_1.thumbnail_bg_color = '#C6DCDA' topic_1.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'dummy-subtopic-three') ] topic_1.next_subtopic_id = 2 subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, self.topic_id_1)) 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_1) topic_services.publish_topic(self.topic_id_1, self.admin_id) topic_2 = topic_domain.Topic.create_default_topic( self.topic_id_2, 'topic2', 'abbrev-two', 'description') topic_2.thumbnail_filename = 'thumbnail.svg' topic_2.thumbnail_bg_color = '#C6DCDA' topic_2.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_2'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 'dummy-subtopic-three') ] subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, self.topic_id_2)) 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_2.next_subtopic_id = 2 topic_services.save_new_topic(self.owner_id, topic_2) topic_services.publish_topic(self.topic_id_2, self.admin_id) story_1 = story_domain.Story.create_default_story( story_id_1, 'A story', 'description', self.topic_id_1, 'story-one') story_2 = story_domain.Story.create_default_story( story_id_2, 'A story', 'description', self.topic_id_2, 'story-two') 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.publish_story(self.topic_id_1, story_id_1, self.admin_id) topic_services.add_canonical_story(self.owner_id, self.topic_id_2, story_id_2) topic_services.publish_story(self.topic_id_2, story_id_2, self.admin_id) 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 post(self): """Generates structures for Android end-to-end tests. This handler generates structures for Android end-to-end tests in order to evaluate the integration of network requests from the Android client to the backend. This handler should only be called once (or otherwise raises an exception), and can only be used in development mode (this handler is unavailable in production). Note that the handler outputs an empty JSON dict when the request is successful. The specific structures that are generated: Topic: A topic with both a test story and a subtopic. Story: A story with 'android_interactions' as a exploration node. Exploration: 'android_interactions' from the local assets. Subtopic: A dummy subtopic to validate the topic. Skill: A dummy skill to validate the subtopic. Raises: Exception. When used in production mode. InvalidInputException. The topic is already created but not published. InvalidInputException. The topic is already published. """ if not constants.DEV_MODE: raise Exception('Cannot load new structures data in production.') if topic_services.does_topic_with_name_exist('Android test'): topic = topic_fetchers.get_topic_by_name('Android test') topic_rights = topic_fetchers.get_topic_rights(topic.id, strict=False) if topic_rights.topic_is_published: raise self.InvalidInputException( 'The topic is already published.') raise self.InvalidInputException( 'The topic exists but is not published.') exp_id = '26' user_id = feconf.SYSTEM_COMMITTER_ID # Generate new Structure id for topic, story, skill and question. topic_id = topic_fetchers.get_new_topic_id() story_id = story_services.get_new_story_id() skill_id = skill_services.get_new_skill_id() question_id = question_services.get_new_question_id() # Create dummy skill and question. skill = self._create_dummy_skill(skill_id, 'Dummy Skill for Android', '<p>Dummy Explanation 1</p>') question = self._create_dummy_question(question_id, 'Question 1', [skill_id]) question_services.add_question(user_id, question) question_services.create_new_question_skill_link( user_id, question_id, skill_id, 0.3) # Create and update topic to validate before publishing. topic = topic_domain.Topic.create_default_topic( topic_id, 'Android test', 'test-topic-one', 'description', 'fragm') topic.update_url_fragment('test-topic') topic.update_meta_tag_content('tag') topic.update_page_title_fragment_for_web('page title for topic') # Save the dummy image to the filesystem to be used as thumbnail. with utils.open_file(os.path.join(feconf.TESTS_DATA_DIR, 'test_svg.svg'), 'rb', encoding=None) as f: raw_image = f.read() fs = fs_services.GcsFileSystem(feconf.ENTITY_TYPE_TOPIC, topic_id) fs.commit('%s/test_svg.svg' % (constants.ASSET_TYPE_THUMBNAIL), raw_image, mimetype='image/svg+xml') # Update thumbnail properties. topic_services.update_thumbnail_filename(topic, 'test_svg.svg') topic.update_thumbnail_bg_color('#C6DCDA') # Add other structures to the topic. topic.add_canonical_story(story_id) topic.add_uncategorized_skill_id(skill_id) topic.add_subtopic(1, 'Test Subtopic Title', 'testsubtop') # Update and validate subtopic. topic_services.update_subtopic_thumbnail_filename( topic, 1, 'test_svg.svg') topic.update_subtopic_thumbnail_bg_color(1, '#FFFFFF') topic.update_subtopic_url_fragment(1, 'suburl') topic.move_skill_id_to_subtopic(None, 1, skill_id) subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, topic_id)) # Upload local exploration to the datastore and enable feedback. exp_services.load_demo(exp_id) rights_manager.release_ownership_of_exploration( user_services.get_system_user(), exp_id) exp_services.update_exploration( user_id, exp_id, [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'correctness_feedback_enabled', 'new_value': True }) ], 'Changed correctness_feedback_enabled.') # Add and update the exploration/node to the story. story = story_domain.Story.create_default_story( story_id, 'Android End to End testing', 'Description', topic_id, 'android-end-to-end-testing') story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'Testing with UI Automator') story.update_node_description( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'To test all Android interactions') story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), exp_id) # Save the dummy image to the filesystem to be used as thumbnail. with utils.open_file(os.path.join(feconf.TESTS_DATA_DIR, 'test_svg.svg'), 'rb', encoding=None) as f: raw_image = f.read() fs = fs_services.GcsFileSystem(feconf.ENTITY_TYPE_STORY, story_id) fs.commit('%s/test_svg.svg' % (constants.ASSET_TYPE_THUMBNAIL), raw_image, mimetype='image/svg+xml') story.update_node_thumbnail_filename( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'test_svg.svg') story.update_node_thumbnail_bg_color( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), '#F8BF74') # Update and validate the story. story.update_meta_tag_content('tag') story.update_thumbnail_filename('test_svg.svg') story.update_thumbnail_bg_color( constants.ALLOWED_THUMBNAIL_BG_COLORS['story'][0]) # Save the previously created structures # (skill, story, topic, subtopic). skill_services.save_new_skill(user_id, skill) story_services.save_new_story(user_id, story) topic_services.save_new_topic(user_id, topic) subtopic_page_services.save_subtopic_page( user_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Dummy Subtopic Title', 'url_fragment': 'dummy-fragment' }) ]) # Generates translation opportunities for the Contributor Dashboard. exp_ids_in_story = story.story_contents.get_all_linked_exp_ids() opportunity_services.add_new_exploration_opportunities( story_id, exp_ids_in_story) # Publish the story and topic. topic_services.publish_story(topic_id, story_id, user_id) topic_services.publish_topic(topic_id, user_id) # Upload thumbnails to be accessible through AssetsDevHandler. self._upload_thumbnail(topic_id, feconf.ENTITY_TYPE_TOPIC) self._upload_thumbnail(story_id, feconf.ENTITY_TYPE_STORY) self.render_json({})
def test_redirect_for_single_node_story(self): self.login(self.CURRICULUM_ADMIN_EMAIL) self.STORY_URL_FRAGMENT = 'story-two' self.NEW_USER_EMAIL = '*****@*****.**' self.NEW_USER_USERNAME = '******' self.save_new_valid_exploration( self.EXP_ID_0, self.admin_id, title='Title 1', end_state_name='End', correctness_feedback_enabled=True) self.publish_exploration(self.admin_id, self.EXP_ID_0) story = story_domain.Story.create_default_story( self.NEW_STORY_ID, 'Title', 'Description', self.NEW_TOPIC_ID, self.STORY_URL_FRAGMENT) story.meta_tag_content = 'story meta content' exp_summary_dicts = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( [self.EXP_ID_0], user=self.admin)) self.node_1 = { 'id': self.NODE_ID_1, 'title': 'Title 1', 'description': 'Description 1', 'thumbnail_filename': 'image_1.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS[ 'chapter'][0], 'thumbnail_size_in_bytes': 21131, 'destination_node_ids': [], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_1, 'exp_summary_dict': exp_summary_dicts[0], 'completed': False } story.story_contents.nodes = [ story_domain.StoryNode.from_dict(self.node_1) ] self.nodes = story.story_contents.nodes story.story_contents.initial_node_id = 'node_1' story.story_contents.next_node_id = 'node_2' story_services.save_new_story(self.admin_id, story) subtopic_1 = topic_domain.Subtopic.create_default_subtopic( 1, 'Subtopic Title 1') subtopic_1.skill_ids = ['skill_id_1'] subtopic_1.url_fragment = 'sub-one-frag' self.save_new_topic( self.NEW_TOPIC_ID, 'user', name='new topic', url_fragment='topic-frag', description='A new topic', canonical_story_ids=[story.id], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[subtopic_1], next_subtopic_id=2) topic_services.publish_topic(self.NEW_TOPIC_ID, self.admin_id) topic_services.publish_story( self.NEW_TOPIC_ID, self.NEW_STORY_ID, self.admin_id) self.logout() self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.login(self.NEW_USER_EMAIL) with self.swap(constants, 'ENABLE_NEW_STRUCTURE_VIEWER_UPDATES', True): response = self.get_html_response( '%s/staging/topic-frag/%s/%s' % ( feconf.STORY_PROGRESS_URL_PREFIX, self.STORY_URL_FRAGMENT, self.NODE_ID_1), expected_status_int=302) self.assertEqual( 'http://localhost/learn/staging/topic-frag/story/story-two', response.headers['location'])
def setUp(self): """Completes the sign up process for the various users.""" super(BaseStoryViewerControllerTests, self).setUp() self.VIEWER_EMAIL = '*****@*****.**' self.VIEWER_USERNAME = '******' 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.login(self.ADMIN_EMAIL) self.TOPIC_ID = 'topic_id' self.STORY_ID = 'story_id' self.NODE_ID_1 = 'node_1' self.NODE_ID_2 = 'node_2' self.NODE_ID_3 = 'node_3' self.EXP_ID_0 = '0' self.EXP_ID_1 = '1' self.EXP_ID_7 = '7' self.save_new_valid_exploration( self.EXP_ID_0, self.admin_id, title='Title 1', end_state_name='End') self.save_new_valid_exploration( self.EXP_ID_1, self.admin_id, title='Title 2', end_state_name='End') self.save_new_valid_exploration( self.EXP_ID_7, self.admin_id, title='Title 3', end_state_name='End') self.publish_exploration(self.admin_id, self.EXP_ID_0) self.publish_exploration(self.admin_id, self.EXP_ID_1) self.publish_exploration(self.admin_id, self.EXP_ID_7) story = story_domain.Story.create_default_story( self.STORY_ID, 'Title', 'Description', self.TOPIC_ID) exp_summary_dicts = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( [self.EXP_ID_0, self.EXP_ID_1, self.EXP_ID_7], user=self.admin)) self.node_1 = { 'id': self.NODE_ID_1, 'title': 'Title 1', 'description': 'Description 1', 'thumbnail_filename': 'image_1.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS[ 'chapter'][0], 'destination_node_ids': ['node_3'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_1, 'exp_summary_dict': exp_summary_dicts[1], 'completed': False } self.node_2 = { 'id': self.NODE_ID_2, 'title': 'Title 2', 'description': 'Description 2', 'thumbnail_filename': 'image_2.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS[ 'chapter'][0], 'destination_node_ids': ['node_1'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_0, 'exp_summary_dict': exp_summary_dicts[0], 'completed': True } self.node_3 = { 'id': self.NODE_ID_3, 'title': 'Title 3', 'description': 'Description 3', 'thumbnail_filename': 'image_3.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS[ 'chapter'][0], 'destination_node_ids': [], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_7, 'exp_summary_dict': exp_summary_dicts[2], 'completed': False } story.story_contents.nodes = [ story_domain.StoryNode.from_dict(self.node_1), story_domain.StoryNode.from_dict(self.node_2), story_domain.StoryNode.from_dict(self.node_3) ] self.nodes = story.story_contents.nodes story.story_contents.initial_node_id = 'node_2' story.story_contents.next_node_id = 'node_4' story_services.save_new_story(self.admin_id, story) self.save_new_topic( self.TOPIC_ID, 'user', name='Topic', description='A new topic', canonical_story_ids=[story.id], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[], next_subtopic_id=0) topic_services.publish_topic(self.TOPIC_ID, self.admin_id) topic_services.publish_story( self.TOPIC_ID, self.STORY_ID, self.admin_id) self.logout() self.signup(self.VIEWER_EMAIL, self.VIEWER_USERNAME) self.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL) self.login(self.VIEWER_EMAIL) self._record_completion(self.viewer_id, self.STORY_ID, self.NODE_ID_2)
def test_mark_topic_as_learnt_and_story_as_completed(self): self.NEW_USER_EMAIL = '*****@*****.**' self.NEW_USER_USERNAME = '******' self.save_new_valid_exploration( self.EXP_ID_3, self.admin_id, title='Title 3', end_state_name='End', correctness_feedback_enabled=True) self.publish_exploration(self.admin_id, self.EXP_ID_3) story = story_domain.Story.create_default_story( self.NEW_STORY_ID, 'Title', 'Description', self.TOPIC_ID, self.STORY_URL_FRAGMENT_TWO) story.meta_tag_content = 'story meta content' exp_summary_dicts = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( [self.EXP_ID_3], user=self.admin)) self.node_1 = { 'id': self.NODE_ID_1, 'title': 'Title 1', 'description': 'Description 1', 'thumbnail_filename': 'image_1.svg', 'thumbnail_bg_color': constants.ALLOWED_THUMBNAIL_BG_COLORS[ 'chapter'][0], 'thumbnail_size_in_bytes': 21131, 'destination_node_ids': [], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': self.EXP_ID_3, 'exp_summary_dict': exp_summary_dicts[0], 'completed': False } story.story_contents.nodes = [ story_domain.StoryNode.from_dict(self.node_1) ] self.nodes = story.story_contents.nodes story.story_contents.initial_node_id = 'node_1' story.story_contents.next_node_id = 'node_2' story_services.save_new_story(self.admin_id, story) topic_services.add_canonical_story( self.admin_id, self.TOPIC_ID, self.NEW_STORY_ID) topic_services.publish_story( self.TOPIC_ID, self.NEW_STORY_ID, self.admin_id) csrf_token = self.get_new_csrf_token() story_services.record_completed_node_in_story_context( self.viewer_id, self.STORY_ID, self.NODE_ID_2) story_services.record_completed_node_in_story_context( self.viewer_id, self.STORY_ID, self.NODE_ID_1) with self.swap(constants, 'ENABLE_NEW_STRUCTURE_VIEWER_UPDATES', True): self.post_json( '%s/staging/topic/%s/%s' % ( feconf.STORY_PROGRESS_URL_PREFIX, self.STORY_URL_FRAGMENT, self.NODE_ID_3 ), {}, csrf_token=csrf_token ) self.assertEqual(len( learner_progress_services.get_all_learnt_topic_ids( self.viewer_id)), 1) self.assertEqual(len( learner_progress_services.get_all_completed_story_ids( self.viewer_id)), 1) def _mock_none_function(_): """Mocks None.""" return None story_fetchers_swap = self.swap( story_fetchers, 'get_story_by_id', _mock_none_function) with story_fetchers_swap: with self.capture_logging(min_level=logging.ERROR) as captured_logs: self.post_json( '%s/staging/topic/%s/%s' % ( feconf.STORY_PROGRESS_URL_PREFIX, self.STORY_URL_FRAGMENT, self.NODE_ID_3 ), {}, csrf_token=csrf_token) self.assertEqual( captured_logs, ['Could not find a story corresponding to %s ' 'id.' % self.STORY_ID])
def setUp(self): super(TranslatableTextHandlerTest, 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', correctness_feedback_enabled=True) 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.subtopics = [ topic_domain.Subtopic( 1, 'Title', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], '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) 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.')
def setUp(self): super(LearnerGroupSearchSyllabusHandlerTests, self).setUp() self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.facilitator_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.admin_id = self.get_user_id_from_email( self.CURRICULUM_ADMIN_EMAIL) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME]) self.LEARNER_GROUP_ID = ( learner_group_fetchers.get_new_learner_group_id()) learner_group_services.create_learner_group( self.LEARNER_GROUP_ID, 'Learner Group Name', 'Description', [self.facilitator_id], [self.STUDENT_ID], ['subtopic_id_1'], ['story_id_1']) # Set up topics, subtopics and stories for learner group syllabus. topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID_0, 'Place Values', 'abbrev', 'description', 'fragm') topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' topic.subtopics = [ topic_domain.Subtopic( 1, 'Naming Numbers', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-url') ] topic.next_subtopic_id = 2 topic.skill_ids_for_diagnostic_test = ['skill_id_1'] topic_services.save_new_topic(self.admin_id, topic) self.save_new_story(self.STORY_ID_0, self.admin_id, self.TOPIC_ID_0, 'Story test 0') topic_services.add_canonical_story(self.admin_id, self.TOPIC_ID_0, self.STORY_ID_0) # Publish the topic and its stories. topic_services.publish_topic(self.TOPIC_ID_0, self.admin_id) topic_services.publish_story(self.TOPIC_ID_0, self.STORY_ID_0, self.admin_id) # Create another topic. topic = topic_domain.Topic.create_default_topic( self.TOPIC_ID_1, 'Negative Numbers', 'abbrev-one', 'description 1', 'fragm') topic.thumbnail_filename = 'thumbnail.svg' topic.thumbnail_bg_color = '#C6DCDA' topic.subtopics = [ topic_domain.Subtopic( 1, 'Intro to negative numbers', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-url-one') ] topic.next_subtopic_id = 2 topic.skill_ids_for_diagnostic_test = ['skill_id_1'] topic_services.save_new_topic(self.admin_id, topic) self.save_new_story(self.STORY_ID_1, self.admin_id, self.TOPIC_ID_1, 'Story test 1') topic_services.add_canonical_story(self.admin_id, self.TOPIC_ID_1, self.STORY_ID_1) # Publish the topic and its stories. topic_services.publish_topic(self.TOPIC_ID_1, self.admin_id) topic_services.publish_story(self.TOPIC_ID_1, self.STORY_ID_1, self.admin_id)
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 feconf.ROLE_ID_CURRICULUM_ADMIN not in self.user.roles: raise Exception( 'User does not have enough rights to generate data.') topic_id_1 = topic_fetchers.get_new_topic_id() topic_id_2 = topic_fetchers.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', 'dummy-topic-one', 'description', 'fragm') topic_2 = topic_domain.Topic.create_default_topic( topic_id_2, 'Empty Topic', 'empty-topic', 'description', 'fragm') 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', 'dummysubtopic') 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') 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': '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', 'url_fragment': 'dummy-fragment' }) ]) # Generates translation opportunities for the Contributor Dashboard. exp_ids_in_story = story.story_contents.get_all_linked_exp_ids() opportunity_services.add_new_exploration_opportunities( story_id, exp_ids_in_story) 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(StoryExplorationsAuditOneOffJobTests, self).setUp() # Setup user who will own the test stories. self.signup(self.ALBERT_EMAIL, self.ALBERT_NAME) self.albert_id = self.get_user_id_from_email(self.ALBERT_EMAIL) self.set_admins([self.ALBERT_NAME]) self.TOPIC_ID = topic_fetchers.get_new_topic_id() self.story_id_1 = 'story_id_1' self.story_id_2 = 'story_id_2' self.story_id_3 = 'story_id_3' self.skill_id_1 = 'skill_id_1' self.skill_id_2 = 'skill_id_2' self.save_new_topic( self.TOPIC_ID, self.albert_id, name='Name', 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_valid_exploration('exp_id_1', self.albert_id, title='title', category='Category 1', correctness_feedback_enabled=True) self.publish_exploration(self.albert_id, 'exp_id_1') self.save_new_valid_exploration('exp_id_2', self.albert_id, title='title', category='Category 1', correctness_feedback_enabled=True) self.publish_exploration(self.albert_id, 'exp_id_2') change_list = [ story_domain.StoryChange({ 'cmd': story_domain.CMD_ADD_STORY_NODE, 'node_id': 'node_1', 'title': 'Title 1' }), story_domain.StoryChange({ 'cmd': story_domain.CMD_ADD_STORY_NODE, 'node_id': 'node_2', 'title': 'Title 2' }), story_domain.StoryChange({ 'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY, 'property_name': (story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID), 'node_id': 'node_1', 'old_value': None, 'new_value': 'exp_id_1' }), story_domain.StoryChange({ 'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY, 'property_name': (story_domain.STORY_NODE_PROPERTY_DESTINATION_NODE_IDS), 'node_id': 'node_1', 'old_value': [], 'new_value': ['node_2'] }), story_domain.StoryChange({ 'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY, 'property_name': (story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID), 'node_id': 'node_2', 'old_value': None, 'new_value': 'exp_id_2' }) ] story = story_domain.Story.create_default_story( self.story_id_1, 'A title', 'Description', self.TOPIC_ID, 'title-four') story_services.save_new_story(self.albert_id, story) story = story_domain.Story.create_default_story( self.story_id_2, 'A title 2', 'Description 2', self.TOPIC_ID, 'title-five') story_services.save_new_story(self.albert_id, story) story_services.update_story(self.albert_id, self.story_id_1, change_list, 'Updated story nodes.') topic_services.publish_story(self.TOPIC_ID, self.story_id_1, self.albert_id) self.process_and_flush_pending_mapreduce_tasks()