Пример #1
0
    def test_cannot_mark_node_outline_as_unfinalized_with_invalid_node_id(
            self):
        change_list = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_NODE_OUTLINE_STATUS,
                'node_id': 'invalid_node',
                'old_value': '',
                'new_value': ''
            })
        ]

        with self.assertRaisesRegexp(
                Exception,
                'The node with id invalid_node is not part of this story'):
            story_services.update_story(self.USER_ID, self.STORY_ID,
                                        change_list,
                                        'Mark node outline as unfinalized.')
Пример #2
0
    def test_cannot_update_initial_node_with_invalid_node_id(self):
        change_list = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_CONTENTS_PROPERTY,
                'property_name': story_domain.INITIAL_NODE_ID,
                'old_value': '',
                'new_value': 'new_initial_node_id'
            })
        ]

        with self.assertRaisesRegexp(
                Exception,
                'The node with id new_initial_node_id is not part of this story'
        ):
            story_services.update_story(self.USER_ID, self.STORY_ID,
                                        change_list,
                                        'Updated story initial_node_id.')
Пример #3
0
    def test_opportunity_get_deleted_with_removing_exploration_from_story_node(
            self):
        self.add_exploration_0_to_story()

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        story_services.update_story(
            self.owner_id, self.STORY_ID, [story_domain.StoryChange({
                'cmd': 'delete_story_node',
                'node_id': 'node_1',
            })], 'Deleted one node.')

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 0)
Пример #4
0
    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(
            topic_id=self.TOPIC_ID, name='topic', abbreviated_name='abbrev')
        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.')
Пример #5
0
    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 = [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_services.save_new_topic(self.owner_id, topic)

        stories = [story_domain.Story.create_default_story(
            '%s' % i,
            'title %d' % i,
            'description %d' % i,
            '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.')
Пример #6
0
    def test_update_story_language_code(self):
        story = story_fetchers.get_story_by_id(self.STORY_ID)
        self.assertEqual(story.language_code, 'en')

        change_list = [story_domain.StoryChange({
            'cmd': story_domain.CMD_UPDATE_STORY_PROPERTY,
            'property_name': story_domain.STORY_PROPERTY_LANGUAGE_CODE,
            'old_value': 'en',
            'new_value': 'bn'
        })]

        story_services.update_story(
            self.USER_ID, self.STORY_ID, change_list,
            'Updated story language_code.')

        story = story_fetchers.get_story_by_id(self.STORY_ID)

        self.assertEqual(story.language_code, 'bn')
Пример #7
0
    def test_cannot_update_node_exploration_id_with_invalid_node_id(self):
        change_list = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name':
                story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID,
                'node_id': 'invalid_node',
                'old_value': '',
                'new_value': 'exp_id'
            })
        ]

        with self.assertRaisesRegexp(
                Exception,
                'The node with id invalid_node is not part of this story'):
            story_services.update_story(self.USER_ID, self.STORY_ID,
                                        change_list,
                                        'Updated story node_exploration_id.')
Пример #8
0
    def setUp(self):
        super(StoryFetchersUnitTests, self).setUp()
        self.STORY_ID = story_services.get_new_story_id()
        self.TOPIC_ID = topic_fetchers.get_new_topic_id()
        self.save_new_topic(self.TOPIC_ID,
                            self.USER_ID,
                            name='Topic',
                            description='A new topic',
                            canonical_story_ids=[],
                            additional_story_ids=[],
                            uncategorized_skill_ids=[],
                            subtopics=[],
                            next_subtopic_id=0)
        self.save_new_story(self.STORY_ID, self.USER_ID, self.TOPIC_ID)
        topic_services.add_canonical_story(self.USER_ID, self.TOPIC_ID,
                                           self.STORY_ID)
        changelist = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_ADD_STORY_NODE,
                'node_id': self.NODE_ID_1,
                'title': 'Title 1'
            })
        ]
        story_services.update_story(self.USER_ID, self.STORY_ID, changelist,
                                    'Added node.')
        self.story = story_fetchers.get_story_by_id(self.STORY_ID)
        self.signup('*****@*****.**', 'A')
        self.signup('*****@*****.**', 'B')
        self.signup(self.CURRICULUM_ADMIN_EMAIL,
                    self.CURRICULUM_ADMIN_USERNAME)

        self.user_id_a = self.get_user_id_from_email('*****@*****.**')
        self.user_id_b = self.get_user_id_from_email('*****@*****.**')
        self.user_id_admin = (self.get_user_id_from_email(
            self.CURRICULUM_ADMIN_EMAIL))

        self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME])
        self.set_topic_managers([user_services.get_username(self.user_id_a)],
                                self.TOPIC_ID)
        self.user_a = user_services.get_user_actions_info(self.user_id_a)
        self.user_b = user_services.get_user_actions_info(self.user_id_b)
        self.user_admin = user_services.get_user_actions_info(
            self.user_id_admin)
Пример #9
0
    def test_publish_and_unpublish_story(self):
        self.save_new_story('public_story', self.USER_ID, 'Title',
                            'Description', 'Notes', self.TOPIC_ID)
        topic_services.add_canonical_story(self.USER_ID, self.TOPIC_ID,
                                           'public_story')
        changelist = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_ADD_STORY_NODE,
                'node_id': self.NODE_ID_1,
                'title': 'Title 1'
            })
        ]
        story_services.update_story(self.USER_ID, 'public_story', changelist,
                                    'Added node.')
        self.save_new_default_exploration('exp_id',
                                          self.user_id_a,
                                          title='title')
        self.publish_exploration(self.user_id_a, 'exp_id')
        change_list = [
            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'
            })
        ]
        story_services.update_story(self.USER_ID, 'public_story', change_list,
                                    'Updated story node.')
        story_rights = story_services.get_story_rights('public_story')
        self.assertFalse(story_rights.story_is_published)
        story_services.publish_story('public_story', self.user_id_admin)

        with self.assertRaisesRegexp(
                Exception,
                'The user does not have enough rights to unpublish the story.'
        ):
            story_services.unpublish_story('public_story', self.user_id_a)
Пример #10
0
    def test_update_story_node_outline(self):
        story = story_fetchers.get_story_by_id(self.STORY_ID)
        self.assertEqual(story.story_contents.nodes[0].outline, '')

        change_list = [story_domain.StoryChange({
            'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
            'property_name': (
                story_domain.STORY_NODE_PROPERTY_OUTLINE),
            'node_id': 'node_1',
            'old_value': '',
            'new_value': 'new_outline'
        })]

        story_services.update_story(
            self.USER_ID, self.STORY_ID, change_list, 'Updated story outline.')

        story = story_fetchers.get_story_by_id(self.STORY_ID)

        self.assertEqual(story.story_contents.nodes[0].outline, 'new_outline')
Пример #11
0
    def test_cannot_update_story_with_non_story_change_changelist(self):
        observed_log_messages = []

        def _mock_logging_function(msg, *args):
            """Mocks logging.error()."""
            observed_log_messages.append(msg % args)

        logging_swap = self.swap(logging, 'error', _mock_logging_function)
        assert_raises_regexp_context_manager = self.assertRaisesRegexp(
            Exception, 'Expected change to be of type StoryChange')

        with logging_swap, assert_raises_regexp_context_manager:
            story_services.update_story(self.USER_ID, self.STORY_ID, [{}],
                                        'Updated story node.')

        self.assertEqual(observed_log_messages, [
            'Exception Expected change to be of type StoryChange %s [{}]' %
            self.STORY_ID
        ])
Пример #12
0
    def test_update_story_notes(self):
        story = story_fetchers.get_story_by_id(self.STORY_ID)
        self.assertEqual(story.notes, 'Notes')

        change_list = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_PROPERTY,
                'property_name': story_domain.STORY_PROPERTY_NOTES,
                'old_value': 'Notes',
                'new_value': 'New notes'
            })
        ]

        story_services.update_story(self.USER_ID, self.STORY_ID, change_list,
                                    'Updated story notes.')

        story = story_fetchers.get_story_by_id(self.STORY_ID)

        self.assertEqual(story.notes, 'New notes')
Пример #13
0
    def test_update_story_with_invalid_corresponding_topic_id_value(self):
        topic_id = topic_services.get_new_topic_id()
        story_id = story_services.get_new_story_id()
        self.save_new_story(
            story_id, self.USER_ID, 'Title', 'Description', 'Notes', topic_id)

        changelist = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_ADD_STORY_NODE,
                'node_id': self.NODE_ID_1,
                'title': 'Title 1'
            })
        ]

        with self.assertRaisesRegexp(
            Exception, ('Expected story to only belong to a valid topic, but '
                        'found an topic with ID: %s' % topic_id)):
            story_services.update_story(
                self.USER_ID, story_id, changelist, 'Added node.')
Пример #14
0
    def test_cannot_delete_starting_node_of_story(self):
        changelist = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_ADD_STORY_NODE,
                'node_id': self.NODE_ID_2,
                'title': 'Title 2'
            }),
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name': (
                    story_domain.STORY_NODE_PROPERTY_DESTINATION_NODE_IDS),
                'node_id': self.NODE_ID_2,
                'old_value': [],
                'new_value': [self.NODE_ID_1]
            }),
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_NODE_OUTLINE_STATUS,
                'node_id': self.NODE_ID_2,
                'old_value': False,
                'new_value': True
            }),
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_CONTENTS_PROPERTY,
                'property_name': (
                    story_domain.INITIAL_NODE_ID),
                'old_value': self.NODE_ID_1,
                'new_value': self.NODE_ID_2
            })
        ]
        story_services.update_story(
            self.USER_ID, self.STORY_ID, changelist, 'Added node.')

        change_list = [story_domain.StoryChange({
            'cmd': story_domain.CMD_DELETE_STORY_NODE,
            'node_id': self.NODE_ID_2
        })]

        with self.assertRaisesRegexp(
            Exception,
            'The node with id %s is the starting node for the story, '
            'change the starting node before deleting it.' % self.NODE_ID_2):
            story_services.update_story(
                self.USER_ID, self.STORY_ID, change_list, 'Delete node.')
Пример #15
0
    def test_cannot_update_story_with_mismatch_of_story_versions(self):
        self.save_new_default_exploration('exp_id',
                                          self.user_id_a,
                                          title='title')
        self.publish_exploration(self.user_id_a, 'exp_id')

        change_list = [
            story_domain.StoryChange({
                'cmd':
                story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name':
                (story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID),
                'node_id':
                self.NODE_ID_1,
                'old_value':
                None,
                'new_value':
                'exp_id'
            })
        ]

        story_model = story_models.StoryModel.get(self.STORY_ID)
        story_model.version = 0
        story_model.commit(self.user_id_a, 'Changed version', [])

        with self.assertRaisesRegexp(
                Exception,
                'Unexpected error: trying to update version 1 of story '
                'from version 2. Please reload the page and try again.'):
            story_services.update_story(self.USER_ID, self.STORY_ID,
                                        change_list, 'Updated story node.')

        story_model = story_models.StoryModel.get(self.STORY_ID)
        story_model.version = 10
        story_model.commit(self.user_id_a, 'Changed version', [])

        with self.assertRaisesRegexp(
                Exception,
                'Trying to update version 11 of story from version 2, '
                'which is too old. Please reload the page and try again.'):
            story_services.update_story(self.USER_ID, self.STORY_ID,
                                        change_list, 'Updated story node.')
Пример #16
0
    def setUp(self):
        super(StoryServicesUnitTests, self).setUp()
        self.STORY_ID = story_services.get_new_story_id()
        self.TOPIC_ID = topic_services.get_new_topic_id()
        self.save_new_topic(self.TOPIC_ID,
                            self.USER_ID,
                            name='Topic',
                            abbreviated_name='abbrev',
                            thumbnail_filename=None,
                            description='A new topic',
                            canonical_story_ids=[],
                            additional_story_ids=[],
                            uncategorized_skill_ids=[],
                            subtopics=[],
                            next_subtopic_id=0)
        self.save_new_story(self.STORY_ID, self.USER_ID, 'Title',
                            'Description', 'Notes', self.TOPIC_ID)
        topic_services.add_canonical_story(self.USER_ID, self.TOPIC_ID,
                                           self.STORY_ID)
        changelist = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_ADD_STORY_NODE,
                'node_id': self.NODE_ID_1,
                'title': 'Title 1'
            })
        ]
        story_services.update_story(self.USER_ID, self.STORY_ID, changelist,
                                    'Added node.')
        self.story = story_fetchers.get_story_by_id(self.STORY_ID)
        self.signup('*****@*****.**', 'A')
        self.signup('*****@*****.**', 'B')
        self.signup(self.ADMIN_EMAIL, username=self.ADMIN_USERNAME)

        self.user_id_a = self.get_user_id_from_email('*****@*****.**')
        self.user_id_b = self.get_user_id_from_email('*****@*****.**')
        self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL)

        self.set_admins([self.ADMIN_USERNAME])
        self.set_topic_managers([user_services.get_username(self.user_id_a)])
        self.user_a = user_services.UserActionsInfo(self.user_id_a)
        self.user_b = user_services.UserActionsInfo(self.user_id_b)
        self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
Пример #17
0
    def test_cannot_update_destination_node_ids_with_invalid_node_id(self):
        change_list = [
            story_domain.StoryChange({
                'cmd':
                story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name':
                (story_domain.STORY_NODE_PROPERTY_DESTINATION_NODE_IDS),
                'node_id':
                'invalid_node',
                'old_value': [],
                'new_value': []
            })
        ]

        with self.assertRaisesRegexp(
                Exception,
                'The node with id invalid_node is not part of this story'):
            story_services.update_story(
                self.USER_ID, self.STORY_ID, change_list,
                'Updated story new_destination_node_ids.')
Пример #18
0
    def test_cannot_update_node_exploration_id_with_existing_exploration_id(
            self):
        self.save_new_default_exploration('exp_id',
                                          self.user_id_a,
                                          title='title')
        self.publish_exploration(self.user_id_a, 'exp_id')

        change_list = [
            story_domain.StoryChange({
                'cmd':
                story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name':
                (story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID),
                'node_id':
                self.NODE_ID_1,
                'old_value':
                None,
                'new_value':
                'exp_id'
            })
        ]
        story_services.update_story(self.USER_ID, self.STORY_ID, change_list,
                                    'Updated story node.')

        change_list = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name':
                story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID,
                'node_id': self.NODE_ID_1,
                'old_value': '',
                'new_value': 'exp_id'
            })
        ]

        with self.assertRaisesRegexp(
                Exception,
                'A node with exploration id exp_id already exists.'):
            story_services.update_story(self.USER_ID, self.STORY_ID,
                                        change_list,
                                        'Updated story node_exploration_id.')
Пример #19
0
    def test_opportunities_updates_with_updating_topic_name(self):
        story_services.update_story(self.owner_id, self.STORY_ID, [
            story_domain.StoryChange({
                'cmd': 'add_story_node',
                'node_id': 'node_1',
                'title': 'Node1',
            }),
            story_domain.StoryChange({
                'cmd': 'update_story_node_property',
                'property_name': 'exploration_id',
                'node_id': 'node_1',
                'old_value': None,
                'new_value': '0'
            })
        ], 'Changes.')

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        opportunity = translation_opportunities[0]
        self.assertEqual(opportunity['story_title'], 'A story')
        self.assertEqual(opportunity['topic_name'], 'topic')

        topic_services.update_topic_and_subtopic_pages(
            self.owner_id, self.TOPIC_ID, [
                topic_domain.TopicChange({
                    'cmd': 'update_topic_property',
                    'property_name': 'name',
                    'old_value': 'topic',
                    'new_value': 'A new topic'
                })
            ], 'Change topic title.')

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        opportunity = translation_opportunities[0]
        self.assertEqual(opportunity['story_title'], 'A story')
        self.assertEqual(opportunity['topic_name'], 'A new topic')
Пример #20
0
def update_story_and_topic_summary(committer_id, story_id, change_list,
                                   commit_message, topic_id):
    """Updates a story. Commits changes. Then generates a new
    topic summary.

    Args:
        committer_id: str. The id of the user who is performing the update
            action.
        story_id: str. The story id.
        change_list: list(StoryChange). These changes are applied in sequence to
            produce the resulting story.
        commit_message: str or None. A description of changes made to the
            story.
        topic_id: str. The id of the topic to which the story is belongs.
    """
    story_services.update_story(committer_id, story_id, change_list,
                                commit_message)
    # Generate new TopicSummary after a Story has been updated to
    # make sure the TopicSummaryTile displays the correct number
    # of chapters on the classroom page.
    generate_topic_summary(topic_id)
Пример #21
0
    def test_cannot_update_story_with_invalid_exploration_id(self):
        change_list = [
            story_domain.StoryChange({
                'cmd':
                story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name':
                (story_domain.STORY_NODE_PROPERTY_EXPLORATION_ID),
                'node_id':
                self.NODE_ID_1,
                'old_value':
                None,
                'new_value':
                'invalid_exp_id'
            })
        ]

        with self.assertRaisesRegexp(
                Exception,
                'Expected story to only reference valid explorations'):
            story_services.update_story(self.USER_ID, self.STORY_ID,
                                        change_list, 'Updated story node.')
Пример #22
0
    def test_verification_is_unsuccessful_when_deletion_failed(self):
        wipeout_service.delete_user(
            wipeout_service.get_pending_deletion_request(self.user_2_id))

        story_services.update_story(self.user_2_id, self.STORY_2_ID, [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_ADD_STORY_NODE,
                'node_id': 'node_1',
                'title': 'Title 2'
            })
        ], 'Add node.')

        self.assertFalse(
            wipeout_service.verify_user_deleted(
                wipeout_service.get_pending_deletion_request(self.user_2_id)))

        wipeout_service.delete_user(
            wipeout_service.get_pending_deletion_request(self.user_2_id))
        self.assertTrue(
            wipeout_service.verify_user_deleted(
                wipeout_service.get_pending_deletion_request(self.user_2_id)))
Пример #23
0
    def test_update_story_acquired_skill_ids(self):
        story = story_fetchers.get_story_by_id(self.STORY_ID)
        self.assertEqual(story.story_contents.nodes[0].acquired_skill_ids, [])

        change_list = [story_domain.StoryChange({
            'cmd': story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
            'property_name': (
                story_domain.STORY_NODE_PROPERTY_ACQUIRED_SKILL_IDS),
            'node_id': 'node_1',
            'old_value': [],
            'new_value': ['skill_id']
        })]

        story_services.update_story(
            self.USER_ID, self.STORY_ID, change_list,
            'Updated story acquired_skill_ids.')

        story = story_fetchers.get_story_by_id(self.STORY_ID)

        self.assertEqual(
            story.story_contents.nodes[0].acquired_skill_ids, ['skill_id'])
Пример #24
0
    def test_opportunity_updates_with_updating_story_node_title(self):
        story_services.update_story(self.owner_id, self.STORY_ID, [
            story_domain.StoryChange({
                'cmd': 'add_story_node',
                'node_id': 'node_1',
                'title': 'Node1',
            }),
            story_domain.StoryChange({
                'cmd': 'update_story_node_property',
                'property_name': 'exploration_id',
                'node_id': 'node_1',
                'old_value': None,
                'new_value': '0'
            })
        ], 'Changes.')

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        opportunity = translation_opportunities[0]
        self.assertEqual(opportunity['chapter_title'], 'Node1')

        story_services.update_story(self.owner_id, self.STORY_ID, [
            story_domain.StoryChange({
                'cmd': 'update_story_node_property',
                'property_name': 'title',
                'node_id': 'node_1',
                'old_value': 'Node1',
                'new_value': 'A new Node1'
            })
        ], 'Change node title.')

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        opportunity = translation_opportunities[0]
        self.assertEqual(opportunity['chapter_title'], 'A new Node1')
Пример #25
0
    def test_post_returns_ready_for_review_when_acquired_skills_exist(self):
        csrf_token = self.get_new_csrf_token()
        self.save_new_skill('skill_1',
                            self.admin_id,
                            description='Skill Description')
        self.save_new_question('question_1', self.admin_id,
                               self._create_valid_question_data('ABC'),
                               ['skill_1'])
        question_services.create_new_question_skill_link(
            self.admin_id, 'question_1', 'skill_1', 0.3)
        changelist = [
            story_domain.StoryChange({
                'cmd':
                story_domain.CMD_UPDATE_STORY_NODE_PROPERTY,
                'property_name':
                (story_domain.STORY_NODE_PROPERTY_ACQUIRED_SKILL_IDS),
                'node_id':
                self.NODE_ID_1,
                'old_value': [],
                'new_value': ['skill_1']
            })
        ]
        story_services.update_story(self.admin_id, self.STORY_ID, changelist,
                                    'Added acquired skill.')

        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):
            json_response = 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(json_response['summaries']), 0)
        self.assertIsNone(json_response['next_node_id'])
        self.assertTrue(json_response['ready_for_review_test'])
Пример #26
0
    def test_update_story_which_not_corresponding_topic_id(self):
        topic_id = topic_services.get_new_topic_id()
        self.save_new_topic(
            topic_id, self.USER_ID, 'A New Topic', 'A new topic description.',
            [], [], [], [], 0)
        story_id = story_services.get_new_story_id()
        self.save_new_story(
            story_id, self.USER_ID, 'Title', 'Description', 'Notes', topic_id)

        changelist = [
            story_domain.StoryChange({
                'cmd': story_domain.CMD_ADD_STORY_NODE,
                'node_id': self.NODE_ID_1,
                'title': 'Title 1'
            })
        ]

        with self.assertRaisesRegexp(
            Exception, ('Expected story to belong to the topic %s, but it is '
                        'neither a part of the canonical stories or the '
                        'additional stories of the topic.' % topic_id)):
            story_services.update_story(
                self.USER_ID, story_id, changelist, 'Added node.')
    def test_opportunity_get_deleted_with_deleting_topic(self):
        story_services.update_story(
            self.owner_id, self.STORY_ID, [story_domain.StoryChange({
                'cmd': 'add_story_node',
                'node_id': 'node_1',
                'title': 'Node1',
            }), story_domain.StoryChange({
                'cmd': 'update_story_node_property',
                'property_name': 'exploration_id',
                'node_id': 'node_1',
                'old_value': None,
                'new_value': '0'
            })], 'Changes.')

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        topic_services.delete_topic(self.owner_id, self.TOPIC_ID)

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 0)
Пример #28
0
    def test_missing_story_commit_log_entry_model_failure(self):
        story_services.update_story(
            self.owner_id, '0', [story_domain.StoryChange({
                'cmd': 'update_story_property',
                'property_name': 'title',
                'new_value': 'New title',
                'old_value': 'title 0'
            })], 'Changes.')
        story_models.StoryCommitLogEntryModel.get_by_id(
            'story-0-1').delete()

        expected_output = [
            (
                u'[u\'failed validation check for '
                'story_commit_log_entry_ids field check of '
                'StoryModel\', '
                '[u"Entity id 0: based on field '
                'story_commit_log_entry_ids having value '
                'story-0-1, expected model StoryCommitLogEntryModel '
                'with id story-0-1 but it doesn\'t exist"]]'),
            u'[u\'fully-validated StoryModel\', 2]']
        self.run_job_and_check_output(
            expected_output, sort=True, literal_eval=False)
Пример #29
0
    def put(self, topic_id, story_id):
        """Updates properties of the given story."""
        if not constants.ENABLE_NEW_STRUCTURE_EDITORS:
            raise self.PageNotFoundException

        story_domain.Story.require_valid_story_id(story_id)
        topic_domain.Topic.require_valid_topic_id(topic_id)
        story = story_services.get_story_by_id(story_id, strict=False)
        if story is None:
            raise self.PageNotFoundException

        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        if topic is None or story_id not in topic.canonical_story_ids:
            raise self.PageNotFoundException

        version = self.payload.get('version')
        self._require_valid_version(version, story.version)

        commit_message = self.payload.get('commit_message')
        change_dicts = self.payload.get('change_dicts')
        change_list = [
            story_domain.StoryChange(change_dict)
            for change_dict in change_dicts
        ]
        try:
            story_services.update_story(
                self.user_id, story_id, change_list, commit_message)
        except utils.ValidationError as e:
            raise self.InvalidInputException(e)

        story_dict = story_services.get_story_by_id(story_id).to_dict()

        self.values.update({
            'story': story_dict
        })

        self.render_json(self.values)
Пример #30
0
    def map(item):
        if not constants.ENABLE_NEW_STRUCTURE_EDITORS:
            return

        if item.deleted:
            yield (StoryMigrationOneOffJob._DELETED_KEY, 1)
            return

        # Note: the read will bring the story up to the newest version.
        story = story_services.get_story_by_id(item.id)
        try:
            story.validate()
        except Exception as e:
            logging.error('Story %s failed validation: %s' % (item.id, e))
            yield (StoryMigrationOneOffJob._ERROR_KEY,
                   'Story %s failed validation: %s' % (item.id, e))
            return

        # Write the new story into the datastore if it's different from
        # the old version.
        if (item.story_contents_schema_version <=
                feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION):
            commit_cmds = [
                story_domain.StoryChange({
                    'cmd':
                    story_domain.CMD_MIGRATE_SCHEMA_TO_LATEST_VERSION,
                    'from_version':
                    item.story_contents_schema_version,
                    'to_version':
                    feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION
                })
            ]
            story_services.update_story(
                feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds,
                'Update story contents schema version to %d.' %
                (feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION))
            yield (StoryMigrationOneOffJob._MIGRATED_KEY, 1)