Beispiel #1
0
def _create_exploration(
        committer_id, exploration, commit_message, commit_cmds, cloned_from):
    """Ensures that rights for a new exploration are saved first.

    This is because _save_exploration() depends on the rights object being
    present to tell it whether to do strict validation or not.
    """
    # This line is needed because otherwise a rights object will be created,
    # but the creation of an exploration object will fail.
    exploration.validate()
    rights_manager.create_new_exploration_rights(
        exploration.id, committer_id, cloned_from)
    model = exp_models.ExplorationModel(
        id=exploration.id,
        category=exploration.category,
        title=exploration.title,
        init_state_name=exploration.init_state_name,
        states={
            state_name: state.to_dict()
            for (state_name, state) in exploration.states.iteritems()},
        param_specs=exploration.param_specs_dict,
        param_changes=exploration.param_change_dicts,
        default_skin=exploration.default_skin
    )
    model.commit(committer_id, commit_message, commit_cmds)
    exploration.version += 1
Beispiel #2
0
def _create_exploration(
        committer_id, exploration, commit_message, commit_cmds):
    """Ensures that rights for a new exploration are saved first.

    This is because _save_exploration() depends on the rights object being
    present to tell it whether to do strict validation or not.
    """
    # This line is needed because otherwise a rights object will be created,
    # but the creation of an exploration object will fail.
    exploration.validate(allow_null_interaction=True)
    rights_manager.create_new_exploration_rights(exploration.id, committer_id)
    model = exp_models.ExplorationModel(
        id=exploration.id,
        category=exploration.category,
        title=exploration.title,
        objective=exploration.objective,
        language_code=exploration.language_code,
        skill_tags=exploration.skill_tags,
        blurb=exploration.blurb,
        author_notes=exploration.author_notes,
        default_skin=exploration.default_skin,
        init_state_name=exploration.init_state_name,
        states={
            state_name: state.to_dict()
            for (state_name, state) in exploration.states.iteritems()},
        param_specs=exploration.param_specs_dict,
        param_changes=exploration.param_change_dicts,
    )
    model.commit(committer_id, commit_message, commit_cmds)
    event_services.ExplorationContentChangeEventHandler.record(exploration.id)
    exploration.version += 1
    create_exploration_summary(exploration.id)
Beispiel #3
0
def _create_exploration(
        committer_id, exploration, commit_message, commit_cmds):
    """Ensures that rights for a new exploration are saved first.

    This is because _save_exploration() depends on the rights object being
    present to tell it whether to do strict validation or not.
    """
    # This line is needed because otherwise a rights object will be created,
    # but the creation of an exploration object will fail.
    exploration.validate()
    rights_manager.create_new_exploration_rights(exploration.id, committer_id)
    model = exp_models.ExplorationModel(
        id=exploration.id,
        category=exploration.category,
        title=exploration.title,
        objective=exploration.objective,
        language_code=exploration.language_code,
        skill_tags=exploration.skill_tags,
        blurb=exploration.blurb,
        author_notes=exploration.author_notes,
        default_skin=exploration.default_skin,
        init_state_name=exploration.init_state_name,
        states={
            state_name: state.to_dict()
            for (state_name, state) in exploration.states.iteritems()},
        param_specs=exploration.param_specs_dict,
        param_changes=exploration.param_change_dicts,
    )
    model.commit(committer_id, commit_message, commit_cmds)
    exploration.version += 1
Beispiel #4
0
    def save_new_exp_with_states_schema_v0(self, exp_id, user_id, title):
        """Saves a new default exploration with a default version 0 states
        dictionary.

        This function should only be used for creating explorations in tests
        involving migration of datastore explorations that use an old states
        schema version.

        Note that it makes an explicit commit to the datastore instead of using
        the usual functions for updating and creating explorations. This is
        because the latter approach would result in an exploration with the
        *current* states schema version.
        """
        exp_model = exp_models.ExplorationModel(
            id=exp_id,
            category="category",
            title=title,
            objective="Old objective",
            language_code="en",
            tags=[],
            blurb="",
            author_notes="",
            skin_customizations={"panels_contents": {}},
            states_schema_version=0,
            init_state_name=feconf.DEFAULT_INIT_STATE_NAME,
            states=self.VERSION_0_STATES_DICT,
            param_specs={},
            param_changes=[],
        )
        rights_manager.create_new_exploration_rights(exp_id, user_id)

        commit_message = "New exploration created with title '%s'." % title
        exp_model.commit(user_id, commit_message, [{"cmd": "create_new", "title": "title", "category": "category"}])
Beispiel #5
0
    def save_new_exp_with_states_schema_v34(self, exp_id, user_id, states_dict):
        """Saves a new default exploration with a default version 34 states
        dictionary.

        This function should only be used for creating explorations in tests
        involving migration of datastore explorations that use an old states
        schema version.
        Note that it makes an explicit commit to the datastore instead of using
        the usual functions for updating and creating explorations. This is
        because the latter approach would result in an exploration with the
        *current* states schema version.

        Args:
            exp_id: str. The exploration ID.
            user_id: str. The user_id of the creator.
            states_dict: dict. The dict representation of all the states.
        """
        exp_model = exp_models.ExplorationModel(
            id=exp_id,
            category='category',
            title='title',
            objective='Old objective',
            language_code='en',
            tags=[],
            blurb='',
            author_notes='',
            states_schema_version=34,
            init_state_name=feconf.DEFAULT_INIT_STATE_NAME,
            states=states_dict,
            param_specs={},
            param_changes=[]
        )
        rights_manager.create_new_exploration_rights(exp_id, user_id)

        commit_message = 'New exploration created with title \'title\'.'
        exp_model.commit(
            user_id, commit_message, [{
                'cmd': 'create_new',
                'title': 'title',
                'category': 'category',
            }])
        exp_rights = exp_models.ExplorationRightsModel.get_by_id(exp_id)
        exp_summary_model = exp_models.ExpSummaryModel(
            id=exp_id,
            title='title',
            category='category',
            objective='Old objective',
            language_code='en',
            tags=[],
            ratings=feconf.get_empty_ratings(),
            scaled_average_rating=feconf.EMPTY_SCALED_AVERAGE_RATING,
            status=exp_rights.status,
            community_owned=exp_rights.community_owned,
            owner_ids=exp_rights.owner_ids,
            contributor_ids=[],
            contributors_summary={},
        )
        exp_summary_model.update_timestamps()
        exp_summary_model.put()
Beispiel #6
0
    def test_migration_job_skips_deleted_explorations(self):
        """Tests that the exploration migration job skips deleted explorations
        and does not attempt to migrate.
        """
        # Save new default exploration with a default version 0 states
        # dictionary.
        exp_model = exp_models.ExplorationModel(
            id=self.NEW_EXP_ID,
            category='category',
            title='title',
            objective='',
            language_code='en',
            tags=[],
            blurb='',
            author_notes='',
            default_skin='conversation_v1',
            skin_customizations={'panels_contents': {}},
            states_schema_version=0,
            init_state_name=feconf.DEFAULT_INIT_STATE_NAME,
            states=self.VERSION_0_STATES_DICT,
            param_specs={},
            param_changes=[]
        )
        rights_manager.create_new_exploration_rights(
            self.NEW_EXP_ID, self.ALBERT_ID)
        exp_model.commit(self.ALBERT_ID, 'old commit', [{
            'cmd': 'create_new',
            'title': 'title',
            'category': 'category',
        }])

        # Note: This creates a summary based on the upgraded model (which is
        # fine). A summary is needed to delete the exploration.
        exp_services.create_exploration_summary(self.NEW_EXP_ID)

        # Delete the exploration before migration occurs.
        exp_services.delete_exploration(self.ALBERT_ID, self.NEW_EXP_ID)

        # Ensure the exploration is deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            exp_services.get_exploration_by_id(self.NEW_EXP_ID)

        # Start migration job on sample exploration.
        job_id = exp_jobs.ExplorationMigrationJobManager.create_new()
        exp_jobs.ExplorationMigrationJobManager.enqueue(job_id)

        # This running without errors indicates the deleted exploration is being
        # ignored, since otherwise exp_services.get_exploration_by_id (used
        # within the job) will raise an error.
        self.process_and_flush_pending_tasks()

        # Ensure the exploration is still deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            exp_services.get_exploration_by_id(self.NEW_EXP_ID)
Beispiel #7
0
    def test_migration_job_does_not_have_validation_fail_on_default_exp(self):
        """Tests that the exploration migration job does not have a validation
        failure for a default exploration (of states schema version 0), due to
        the exploration having a null interaction ID in its initial state.
        """
        # Save new default exploration with a default version 0 states
        # dictionary. This will be used to test default exploration migration,
        # which includes ensuring the job does not have a validation failure for
        # an exploration with a null interaction ID.
        exp_model = exp_models.ExplorationModel(
            id=self.NEW_EXP_ID,
            category='category',
            title='title',
            objective='',
            language_code='en',
            tags=[],
            blurb='',
            author_notes='',
            default_skin='conversation_v1',
            skin_customizations={'panels_contents': {}},
            states_schema_version=0,
            init_state_name=feconf.DEFAULT_INIT_STATE_NAME,
            states=self.VERSION_0_STATES_DICT,
            param_specs={},
            param_changes=[]
        )
        rights_manager.create_new_exploration_rights(
            self.NEW_EXP_ID, self.ALBERT_ID)
        exp_model.commit(self.ALBERT_ID, 'old commit', [{
            'cmd': 'create_new',
            'title': 'title',
            'category': 'category',
        }])

        # Start migration job on sample exploration.
        job_id = exp_jobs.ExplorationMigrationJobManager.create_new()
        exp_jobs.ExplorationMigrationJobManager.enqueue(job_id)
        self.process_and_flush_pending_tasks()

        # Verify the new exploration has been migrated by the job.
        updated_exp = exp_services.get_exploration_by_id(self.NEW_EXP_ID)
        self.assertEqual(
            updated_exp.states_schema_version,
            feconf.CURRENT_EXPLORATION_STATES_SCHEMA_VERSION)

        # Ensure the states structure within the exploration was changed.
        self.assertNotEqual(
            updated_exp.to_dict()['states'],
            self.VERSION_0_STATES_DICT)
Beispiel #8
0
    def setUp(self):
        super(FeedbackThreadTests, self).setUp()

        self.signup(self.OWNER_EMAIL_1, self.OWNER_USERNAME_1)
        self.signup(self.OWNER_EMAIL_2, self.OWNER_USERNAME_2)
        self.signup(self.USER_EMAIL, self.USER_USERNAME)
        self.owner_id_1 = self.get_user_id_from_email(self.OWNER_EMAIL_1)
        self.owner_id_2 = self.get_user_id_from_email(self.OWNER_EMAIL_2)
        self.user_id = self.get_user_id_from_email(self.USER_EMAIL)
        self.owner_2 = user_services.UserActionsInfo(self.owner_id_2)

        # Create an exploration.
        self.save_new_valid_exploration(
            self.EXP_ID, self.owner_id_1, title=self.EXP_TITLE,
            category='Architecture', language_code='en')

        rights_manager.create_new_exploration_rights(
            self.EXP_ID, self.owner_id_2)
        rights_manager.publish_exploration(self.owner_2, self.EXP_ID)
Beispiel #9
0
    def save_new_exp_with_states_schema_v0(self, exp_id, user_id, title):
        """Saves a new default exploration with a default version 0 states
        dictionary.

        This function should only be used for creating explorations in tests
        involving migration of datastore explorations that use an old states
        schema version.

        Note that it makes an explicit commit to the datastore instead of using
        the usual functions for updating and creating explorations. This is
        because the latter approach would result in an exploration with the
        *current* states schema version.
        """
        exp_model = exp_models.ExplorationModel(
            id=exp_id,
            category='category',
            title=title,
            objective='Old objective',
            language_code='en',
            tags=[],
            blurb='',
            author_notes='',
            default_skin='conversation_v1',
            skin_customizations={'panels_contents': {}},
            states_schema_version=0,
            init_state_name=feconf.DEFAULT_INIT_STATE_NAME,
            states=self.VERSION_0_STATES_DICT,
            param_specs={},
            param_changes=[])
        rights_manager.create_new_exploration_rights(exp_id, user_id)

        commit_message = 'New exploration created with title \'%s\'.' % title
        exp_model.commit(user_id, commit_message, [{
            'cmd': 'create_new',
            'title': 'title',
            'category': 'category',
        }])
Beispiel #10
0
    def save_new_exp_with_states_schema_v0(self, exp_id, user_id, title):
        """Saves a new default exploration with a default version 0 states
        dictionary.

        This function should only be used for creating explorations in tests
        involving migration of datastore explorations that use an old states
        schema version.

        Note that it makes an explicit commit to the datastore instead of using
        the usual functions for updating and creating explorations. This is
        because the latter approach would result in an exploration with the
        *current* states schema version.

        Args:
            exp_id: str. The exploration ID.
            user_id: str. The user_id of the creator.
            title: str. The title of the exploration.
        """
        exp_model = exp_models.ExplorationModel(
            id=exp_id,
            category='category',
            title=title,
            objective='Old objective',
            language_code='en',
            tags=[],
            blurb='',
            author_notes='',
            states_schema_version=0,
            init_state_name=feconf.DEFAULT_INIT_STATE_NAME,
            states=self.VERSION_0_STATES_DICT,
            param_specs={},
            param_changes=[])
        rights_manager.create_new_exploration_rights(exp_id, user_id)

        commit_message = 'New exploration created with title \'%s\'.' % title
        exp_model.commit(user_id, commit_message, [{
            'cmd': 'create_new',
            'title': 'title',
            'category': 'category',
        }])
        exp_rights = exp_models.ExplorationRightsModel.get_by_id(exp_id)
        exp_summary_model = exp_models.ExpSummaryModel(
            id=exp_id,
            title=title,
            category='category',
            objective='Old objective',
            language_code='en',
            tags=[],
            ratings=feconf.get_empty_ratings(),
            scaled_average_rating=feconf.EMPTY_SCALED_AVERAGE_RATING,
            status=exp_rights.status,
            community_owned=exp_rights.community_owned,
            owner_ids=exp_rights.owner_ids,
            contributor_ids=[],
            contributors_summary={},
        )
        exp_summary_model.put()

        # Note: Also save state id mappping model for new exploration. If not
        # saved, it may cause errors in test cases.
        exploration = exp_services.get_exploration_from_model(exp_model)
        exp_services.create_and_save_state_id_mapping_model(exploration, [])
Beispiel #11
0
    def test_migration_job_creates_appropriate_classifier_models(self):
        """Tests that the exploration migration job creates appropriate
        classifier data models for explorations.
        """
        swap_states_schema_41 = self.swap(feconf,
                                          'CURRENT_STATE_SCHEMA_VERSION', 41)
        swap_exp_schema_46 = self.swap(exp_domain.Exploration,
                                       'CURRENT_EXP_SCHEMA_VERSION', 46)
        with swap_states_schema_41, swap_exp_schema_46:
            exp_model = exp_models.ExplorationModel(
                id=self.NEW_EXP_ID,
                category='category',
                title=self.EXP_TITLE,
                objective='Old objective',
                language_code='en',
                tags=[],
                blurb='',
                author_notes='',
                states_schema_version=41,
                init_state_name=feconf.DEFAULT_INIT_STATE_NAME,
                states={
                    'END': {
                        'classifier_model_id': None,
                        'content': {
                            'content_id': 'content',
                            'html': 'Congratulations, you have finished!',
                        },
                        'interaction': {
                            'answer_groups': [],
                            'confirmed_unclassified_answers': [],
                            'customization_args': {
                                'recommendedExplorationIds': {
                                    'value': []
                                },
                            },
                            'default_outcome': None,
                            'hints': [],
                            'id': 'EndExploration',
                            'solution': None,
                        },
                        'next_content_id_index': 0,
                        'param_changes': [],
                        'recorded_voiceovers': {
                            'voiceovers_mapping': {
                                'content': {},
                            }
                        },
                        'solicit_answer_details': False,
                        'written_translations': {
                            'translations_mapping': {
                                'content': {},
                            }
                        }
                    },
                    'Introduction': {
                        'classifier_model_id': None,
                        'content': {
                            'content_id': 'content',
                            'html': ''
                        },
                        'interaction': {
                            'answer_groups': [{
                                'outcome': {
                                    'dest': 'END',
                                    'feedback': {
                                        'content_id': 'feedback_1',
                                        'html': '<p>Correct!</p>',
                                    },
                                    'labelled_as_correct': False,
                                    'missing_prerequisite_skill_id': None,
                                    'param_changes': [],
                                    'refresher_exploration_id': None,
                                },
                                'rule_specs': [{
                                    'inputs': {
                                        'x': {
                                            'contentId': 'rule_input_3',
                                            'normalizedStrSet':
                                            ['InputString']
                                        }
                                    },
                                    'rule_type': 'Equals',
                                }],
                                'tagged_skill_misconception_id':
                                None,
                                'training_data':
                                ['answer1', 'answer2', 'answer3'],
                            }],
                            'confirmed_unclassified_answers': [],
                            'customization_args': {
                                'placeholder': {
                                    'value': {
                                        'content_id': 'ca_placeholder_2',
                                        'unicode_str': '',
                                    },
                                },
                                'rows': {
                                    'value': 1
                                },
                            },
                            'default_outcome': {
                                'dest': 'Introduction',
                                'feedback': {
                                    'content_id': 'default_outcome',
                                    'html': ''
                                },
                                'labelled_as_correct': False,
                                'missing_prerequisite_skill_id': None,
                                'param_changes': [],
                                'refresher_exploration_id': None,
                            },
                            'hints': [],
                            'id':
                            'TextInput',
                            'solution':
                            None,
                        },
                        'next_content_id_index': 4,
                        'param_changes': [],
                        'recorded_voiceovers': {
                            'voiceovers_mapping': {
                                'ca_placeholder_2': {},
                                'content': {},
                                'default_outcome': {},
                                'feedback_1': {},
                                'rule_input_3': {},
                            }
                        },
                        'solicit_answer_details': False,
                        'written_translations': {
                            'translations_mapping': {
                                'ca_placeholder_2': {},
                                'content': {},
                                'default_outcome': {},
                                'feedback_1': {},
                                'rule_input_3': {},
                            }
                        },
                    },
                },
                param_specs={},
                param_changes=[])
            rights_manager.create_new_exploration_rights(
                self.NEW_EXP_ID, self.albert_id)

        commit_message = ('New exploration created with title \'%s\'.' %
                          self.EXP_TITLE)
        exp_model.commit(self.albert_id, commit_message,
                         [{
                             'cmd': 'create_new',
                             'title': 'title',
                             'category': 'category',
                         }])
        exp_rights = exp_models.ExplorationRightsModel.get_by_id(
            self.NEW_EXP_ID)
        exp_summary_model = exp_models.ExpSummaryModel(
            id=self.NEW_EXP_ID,
            title=self.EXP_TITLE,
            category='category',
            objective='Old objective',
            language_code='en',
            tags=[],
            ratings=feconf.get_empty_ratings(),
            scaled_average_rating=feconf.EMPTY_SCALED_AVERAGE_RATING,
            status=exp_rights.status,
            community_owned=exp_rights.community_owned,
            owner_ids=exp_rights.owner_ids,
            contributor_ids=[],
            contributors_summary={})
        exp_summary_model.update_timestamps()
        exp_summary_model.put()

        exploration = exp_fetchers.get_exploration_by_id(self.NEW_EXP_ID)

        initial_state_name = list(exploration.states.keys())[0]
        # Store classifier model for the new exploration.
        classifier_model_id = (
            classifier_models.ClassifierTrainingJobModel.create(
                'TextClassifier',
                'TextInput', self.NEW_EXP_ID, exploration.version,
                datetime.datetime.utcnow(), {}, initial_state_name,
                feconf.TRAINING_JOB_STATUS_COMPLETE, 1))
        # Store training job model for the classifier model.
        classifier_models.StateTrainingJobsMappingModel.create(
            self.NEW_EXP_ID, exploration.version, initial_state_name,
            {'TextClassifier': classifier_model_id})

        # Start migration job on sample exploration.
        job_id = exp_jobs_one_off.ExplorationMigrationJobManager.create_new()
        exp_jobs_one_off.ExplorationMigrationJobManager.enqueue(job_id)
        with self.swap(feconf, 'ENABLE_ML_CLASSIFIERS', True):
            with self.swap(feconf, 'MIN_TOTAL_TRAINING_EXAMPLES', 2):
                with self.swap(feconf, 'MIN_ASSIGNED_LABELS', 1):
                    self.process_and_flush_pending_mapreduce_tasks()

        actual_output = (
            exp_jobs_one_off.ExplorationMigrationJobManager.get_output(job_id))
        expected_output = ['[u\'SUCCESS\', 1]']
        self.assertEqual(actual_output, expected_output)

        new_exploration = exp_fetchers.get_exploration_by_id(self.NEW_EXP_ID)
        initial_state_name = list(new_exploration.states.keys())[0]
        self.assertLess(exploration.version, new_exploration.version)
        classifier_exp_mapping_model = (
            classifier_models.StateTrainingJobsMappingModel.get_models(
                self.NEW_EXP_ID, new_exploration.version,
                [initial_state_name]))[0]
        self.assertEqual(
            classifier_exp_mapping_model.
            algorithm_ids_to_job_ids['TextClassifier'], classifier_model_id)