def untag_deleted_misconceptions(committer_id, skill_id, skill_description):
    """Untags deleted misconceptions from questions belonging
    to a skill with the provided skill_id.

    Args:
        committer_id: str. The id of the user who triggered the update.
        skill_id: str. The skill id.
        skill_description: str. The description of the skill.
    """
    question_skill_links = get_question_skill_links_of_skill(
        skill_id, skill_description)
    question_ids = [model.question_id for model in question_skill_links]
    questions = question_fetchers.get_questions_by_ids(question_ids)
    skill = skill_fetchers.get_skill_by_id(skill_id)
    skill_misconception_ids = (
        [
            skill.generate_skill_misconception_id(misconception.id)
            for misconception in skill.misconceptions
        ]
    )
    for question in questions:
        change_list = []
        inapplicable_skill_misconception_ids = (
            question.inapplicable_skill_misconception_ids)
        deleted_inapplicable_skill_misconception_ids = (
            utils.compute_list_difference(
                inapplicable_skill_misconception_ids, skill_misconception_ids))
        for misconception_id in deleted_inapplicable_skill_misconception_ids:
            old_misconception_ids = list(
                question.inapplicable_skill_misconception_ids)
            question.inapplicable_skill_misconception_ids.remove(
                misconception_id)
            change_list.append(question_domain.QuestionChange({
                'cmd': 'update_question_property',
                'property_name': 'inapplicable_skill_misconception_ids',
                'new_value': question.inapplicable_skill_misconception_ids,
                'old_value': old_misconception_ids
            }))
        old_question_state_data_dict = question.question_state_data.to_dict()
        answer_groups = (
            list(question.question_state_data.interaction.answer_groups))
        for i in python_utils.RANGE(len(answer_groups)):
            tagged_skill_misconception_id = (
                answer_groups[i].to_dict()['tagged_skill_misconception_id'])
            if tagged_skill_misconception_id not in skill_misconception_ids:
                answer_groups[i].tagged_skill_misconception_id = None
        question.question_state_data.interaction.answer_groups = answer_groups
        change_list.append(question_domain.QuestionChange({
            'cmd': 'update_question_property',
            'property_name': 'question_state_data',
            'new_value': question.question_state_data.to_dict(),
            'old_value': old_question_state_data_dict
        }))
        update_question(
            committer_id, question.id, change_list,
            'Untagged deleted misconception id.')
Exemple #2
0
def untag_deleted_misconceptions(
        committer_id, skill_id, skill_description,
        deleted_skill_misconception_ids):
    """Untags deleted misconceptions from questions belonging
    to a skill with the provided skill_id.

    Args:
        committer_id: str. The id of the user who triggered the update.
        skill_id: str. The skill id.
        skill_description: str. The description of the skill.
        deleted_skill_misconception_ids: list(str). The skill misconception
            ids of deleted misconceptions. The list items take the form
            <skill_id>-<misconception_id>.
    """
    question_skill_links = get_question_skill_links_of_skill(
        skill_id, skill_description)
    question_ids = [model.question_id for model in question_skill_links]
    questions = question_fetchers.get_questions_by_ids(question_ids)
    for question in questions:
        change_list = []
        inapplicable_skill_misconception_ids = (
            question.inapplicable_skill_misconception_ids)
        deleted_inapplicable_skill_misconception_ids = (
            list(
                set(deleted_skill_misconception_ids) &
                set(inapplicable_skill_misconception_ids)))
        if deleted_inapplicable_skill_misconception_ids:
            new_inapplicable_skill_misconception_ids = (
                utils.compute_list_difference(
                    question.inapplicable_skill_misconception_ids,
                    deleted_inapplicable_skill_misconception_ids))
            change_list.append(question_domain.QuestionChange({
                'cmd': 'update_question_property',
                'property_name': 'inapplicable_skill_misconception_ids',
                'new_value': new_inapplicable_skill_misconception_ids,
                'old_value': question.inapplicable_skill_misconception_ids
            }))
        old_question_state_data_dict = question.question_state_data.to_dict()
        answer_groups = (
            list(question.question_state_data.interaction.answer_groups))
        for answer_group in answer_groups:
            tagged_skill_misconception_id = (
                answer_group.to_dict()['tagged_skill_misconception_id'])
            if (tagged_skill_misconception_id
                    in deleted_skill_misconception_ids):
                answer_group.tagged_skill_misconception_id = None
        question.question_state_data.interaction.answer_groups = answer_groups
        change_list.append(question_domain.QuestionChange({
            'cmd': 'update_question_property',
            'property_name': 'question_state_data',
            'new_value': question.question_state_data.to_dict(),
            'old_value': old_question_state_data_dict
        }))
        update_question(
            committer_id, question.id, change_list,
            'Untagged deleted skill misconception ids.')
    def test_pre_update_validate_change_question_dict(self):
        change = {
            'cmd': question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION,
            'question_dict': {
                'question_state_data': self._create_valid_question_data(
                    'default_state').to_dict(),
                'language_code': 'en',
                'question_state_data_schema_version': (
                    feconf.CURRENT_STATE_SCHEMA_VERSION)
            },
            'skill_id': 'skill_1'
        }

        suggestion = suggestion_registry.SuggestionAddQuestion(
            'exploration.exp1.thread1', 'exp1', 1,
            suggestion_models.STATUS_ACCEPTED, self.author_id,
            self.reviewer_id, change,
            'question.topic_1', self.fake_date)

        with self.assertRaisesRegexp(
            Exception,
            'The new change question_dict must not be equal to the '
            'old question_dict'):
            suggestion.pre_update_validate(
                question_domain.QuestionChange(change))
Exemple #4
0
    def test_update_question(self):
        question_data = self._create_valid_question_data('ABC')
        question_id = 'dummy'
        question_data_schema_version = 1
        language_code = 'en'
        question = question_domain.Question(question_id, question_data,
                                            question_data_schema_version,
                                            language_code)

        new_question_data = self._create_valid_question_data('DEF')
        question_id = question_services.add_question(self.owner_id, question)
        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'question_data',
            'new_value': new_question_data,
            'old_value': question_data
        }
        change_list = [question_domain.QuestionChange(change_dict)]

        question_services.update_question(self.owner_id, question_id,
                                          change_list,
                                          ('updated question data'))

        model = question_models.QuestionModel.get(question_id)
        self.assertEqual(model.question_data, new_question_data)
        self.assertEqual(model.question_data_schema_version,
                         question_data_schema_version)
        self.assertEqual(model.language_code, language_code)
    def map(item):
        if item.deleted:
            yield (QuestionMigrationOneOffJob._DELETED_KEY, 1)
            return

        # Note: the read will bring the question up to the newest version.
        question = question_services.get_question_by_id(item.id)
        try:
            question.validate()
        except Exception as e:
            logging.error('Question %s failed validation: %s' % (item.id, e))
            yield (QuestionMigrationOneOffJob._ERROR_KEY,
                   'Question %s failed validation: %s' % (item.id, e))
            return

        # Write the new question into the datastore if it's different from
        # the old version.
        if (item.question_state_data_schema_version <=
                feconf.CURRENT_STATE_SCHEMA_VERSION):
            commit_cmds = [
                question_domain.QuestionChange({
                    'cmd':
                    question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION,  # pylint: disable=line-too-long
                    'from_version':
                    item.question_state_data_schema_version,
                    'to_version':
                    feconf.CURRENT_STATE_SCHEMA_VERSION
                })
            ]
            question_services.update_question(
                feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds,
                'Update question state schema version to %d.' %
                (feconf.CURRENT_STATE_SCHEMA_VERSION))
            yield (QuestionMigrationOneOffJob._MIGRATED_KEY, 1)
    def test_pre_update_validate_change_skill_id(self):
        expected_suggestion_dict = self.suggestion_dict

        suggestion = suggestion_registry.SuggestionAddQuestion(
            expected_suggestion_dict['suggestion_id'],
            expected_suggestion_dict['target_id'],
            expected_suggestion_dict['target_version_at_submission'],
            expected_suggestion_dict['status'], self.author_id,
            self.reviewer_id, expected_suggestion_dict['change'],
            expected_suggestion_dict['score_category'], self.fake_date)

        change = {
            'cmd': question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION,
            'question_dict': {
                'question_state_data': self._create_valid_question_data(
                    'default_state').to_dict(),
                'language_code': 'en',
                'question_state_data_schema_version': (
                    feconf.CURRENT_STATE_SCHEMA_VERSION)
            },
            'skill_id': 'skill_2'
        }

        with self.assertRaisesRegexp(
            Exception, 'The new change skill_id must be equal to skill_1'):
            suggestion.pre_update_validate(
                question_domain.QuestionChange(change))
    def test_update_question(self):
        state = exp_domain.State.create_default_state('ABC')
        question_data = state.to_dict()
        question_id = 'dummy'
        title = 'A Question'
        question_data_schema_version = 1
        collection_id = 'col1'
        language_code = 'en'
        question = question_domain.Question(question_id, title, question_data,
                                            question_data_schema_version,
                                            collection_id, language_code)

        question_id = question_services.add_question(self.owner_id, question)
        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'title',
            'new_value': 'ABC',
            'old_value': 'A Question'
        }
        change_list = [question_domain.QuestionChange(change_dict)]
        question_services.update_question(self.owner_id, question_id,
                                          change_list, 'updated title')

        model = question_models.QuestionModel.get(question_id)
        self.assertEqual(model.title, 'ABC')
        self.assertEqual(model.question_data, question_data)
        self.assertEqual(model.question_data_schema_version,
                         question_data_schema_version)
        self.assertEqual(model.collection_id, collection_id)
        self.assertEqual(model.language_code, language_code)
Exemple #8
0
    def put(self, question_id):
        """Updates properties of the given question."""
        if not constants.ENABLE_NEW_STRUCTURES:
            raise self.PageNotFoundException

        question = question_services.get_question_by_id(question_id,
                                                        strict=False)

        if question is None:
            raise self.PageNotFoundException(
                'The question with the given id doesn\'t exist.')

        commit_message = self.payload.get('commit_message')
        if not question_id:
            raise self.PageNotFoundException
        if not commit_message:
            raise self.PageNotFoundException
        if not self.payload.get('change_list'):
            raise self.PageNotFoundException
        change_list = [
            question_domain.QuestionChange(change)
            for change in self.payload.get('change_list')
        ]

        for change in change_list:
            if (change.cmd ==
                    question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION):
                raise self.InvalidInputException

        question_services.update_question(self.user_id, question_id,
                                          change_list, commit_message)

        question_dict = question_services.get_question_by_id(
            question_id).to_dict()
        return self.render_json({'question_dict': question_dict})
    def put(self, question_id):
        """Updates properties of the given question."""
        commit_message = self.payload.get('commit_message')

        if not commit_message:
            raise self.PageNotFoundException

        if (commit_message is not None
                and len(commit_message) > constants.MAX_COMMIT_MESSAGE_LENGTH):
            raise self.InvalidInputException(
                'Commit messages must be at most %s characters long.' %
                constants.MAX_COMMIT_MESSAGE_LENGTH)

        if not self.payload.get('change_list'):
            raise self.PageNotFoundException
        change_list = [
            question_domain.QuestionChange(change)
            for change in self.payload.get('change_list')
        ]

        for change in change_list:
            if (change.cmd ==
                    question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION):
                raise self.InvalidInputException

        question_services.update_question(self.user_id, question_id,
                                          change_list, commit_message)

        question_dict = question_services.get_question_by_id(
            question_id).to_dict()
        self.render_json({'question_dict': question_dict})
Exemple #10
0
    def test_create_new(self):
        """Test to verify __init__ method of the Question Change object
        when cmd is create_new.
        """
        change_dict = {'cmd': 'create_new'}
        observed_object = question_domain.QuestionChange(
            change_dict=change_dict, )

        self.assertEqual('create_new', observed_object.cmd)
Exemple #11
0
    def test_audit_job_failure(self):
        """Test that the audit job catches errors that would otherwise occur
        during the migration.
        """
        swap_states_schema_36 = self.swap(
            feconf, 'CURRENT_STATE_SCHEMA_VERSION', 36)
        with swap_states_schema_36:
            self.save_new_question(
                self.QUESTION_ID, self.albert_id,
                self._create_valid_question_data('ABC'), [self.skill_id])

        # Bring the main question to the latest schema.
        latest_schema_version = python_utils.UNICODE(
            feconf.CURRENT_STATE_SCHEMA_VERSION)
        migration_change_list = [
            question_domain.QuestionChange({
                'cmd': (
                    question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION
                ),
                'from_version': '37',
                'to_version': latest_schema_version
            })
        ]
        question_services.update_question(
            self.albert_id, self.QUESTION_ID, migration_change_list,
            'Ran Question Migration job.')
        question_model = question_models.QuestionModel.get(self.QUESTION_ID)
        self.assertEqual(
            question_model.question_state_data_schema_version,
            feconf.CURRENT_STATE_SCHEMA_VERSION)

        # Make a mock conversion function that raises an error when trying to
        # convert the old snapshot.
        mock_conversion = classmethod(
            lambda cls, question_dict: question_dict['property_that_dne'])

        with self.swap(
            question_domain.Question, '_convert_state_v36_dict_to_v37_dict',
            mock_conversion
        ):
            job_id = (
                question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.
                create_new())
            question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.enqueue(
                job_id)
            self.process_and_flush_pending_mapreduce_tasks()

        actual_output = (
            question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.get_output(
                job_id))
        expected_output_message = (
            u'[u\'MIGRATION_ERROR\', [u"Question snapshot %s-1 failed '
            'migration to state v37: u\'property_that_dne\'"]]'
            % self.QUESTION_ID
        )
        self.assertIn(expected_output_message, actual_output)
Exemple #12
0
    def test_migrate_state_schema_to_latest_version(self):
        """Test to verify __init__ method of the Question Change object
        when cmd is migrate_state_schema_to_latest_version.
        """
        change_dict = {
            'cmd': 'migrate_state_schema_to_latest_version',
            'from_version': 0,
            'to_version': 10,
        }
        observed_object = question_domain.QuestionChange(
            change_dict=change_dict, )

        self.assertEqual(0, observed_object.from_version)
        self.assertEqual(10, observed_object.to_version)
Exemple #13
0
    def test_cannot_update_question_with_no_commit_message(self):
        new_question_data = self._create_valid_question_data('DEF')
        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'question_state_data',
            'new_value': new_question_data.to_dict(),
            'old_value': self.question.question_state_data.to_dict()
        }
        change_list = [question_domain.QuestionChange(change_dict)]

        with self.assertRaisesRegexp(
            Exception, 'Expected a commit message, received none.'):
            question_services.update_question(
                self.editor_id, self.question_id, change_list, None)
Exemple #14
0
    def test_create_new_fully_specified_question(self):
        """Test to verify __init__ method of the Question Change object
        when cmd is create_new_fully_specified_question.
        """
        change_dict = {
            'cmd': 'create_new_fully_specified_question',
            'question_dict': {},
            'skill_id': '10',
        }
        observed_object = question_domain.QuestionChange(
            change_dict=change_dict, )

        self.assertEqual('10', observed_object.skill_id)
        self.assertEqual({}, observed_object.question_dict)
Exemple #15
0
 def put(self, question_id):
     """Handles PUT requests."""
     commit_message = self.payload.get('commit_message')
     if not question_id:
         raise self.PageNotFoundException
     if not commit_message:
         raise self.PageNotFoundException
     if not self.payload.get('change_list'):
         raise self.PageNotFoundException
     change_list = [
         question_domain.QuestionChange(change)
         for change in json.loads(self.payload.get('change_list'))
     ]
     question_services.update_question(self.user_id, question_id,
                                       change_list, commit_message)
     return self.render_json({'question_id': question_id})
Exemple #16
0
    def test_audit_job_success(self):
        """Test that the audit job runs correctly on snapshots that use a
        previous state schema.
        """
        swap_states_schema_36 = self.swap(
            feconf, 'CURRENT_STATE_SCHEMA_VERSION', 36)
        with swap_states_schema_36:
            question = self.save_new_question(
                self.QUESTION_ID, self.albert_id,
                self._create_valid_question_data('ABC'), [self.skill_id])
        self.assertLess(question.question_state_data_schema_version, 37)

        # Bring the main question to schema version 37.
        migration_change_list = [
            question_domain.QuestionChange({
                'cmd': (
                    question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION
                ),
                'from_version': '36',
                'to_version': '37'
            })
        ]
        swap_states_schema_37 = self.swap(
            feconf, 'CURRENT_STATE_SCHEMA_VERSION', 37)
        with swap_states_schema_37:
            question_services.update_question(
                self.albert_id, self.QUESTION_ID, migration_change_list,
                'Ran Question Migration job.')
            question_model = question_models.QuestionModel.get(self.QUESTION_ID)
            self.assertEqual(
                question_model.question_state_data_schema_version, 37)

            job_id = (
                question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.
                create_new())
            question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.enqueue(
                job_id)
            self.process_and_flush_pending_mapreduce_tasks()

        actual_output = (
            question_jobs_one_off.QuestionSnapshotsMigrationAuditJob.get_output(
                job_id))
        expected_output = [
            '[u\'SUCCESS\', 1]',
            '[u\'SUCCESS - Snapshot is already at latest schema version\', 1]'
        ]
        self.assertEqual(sorted(actual_output), sorted(expected_output))
    def test_update_question(self):
        new_question_data = self._create_valid_question_data('DEF')
        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'question_state_data',
            'new_value': new_question_data.to_dict(),
            'old_value': self.question.question_state_data.to_dict()
        }
        change_list = [question_domain.QuestionChange(change_dict)]

        question_services.update_question(self.editor_id, self.question_id,
                                          change_list, 'updated question data')

        question = question_services.get_question_by_id(self.question_id)
        self.assertEqual(question.question_state_data.to_dict(),
                         new_question_data.to_dict())
        self.assertEqual(question.version, 2)
Exemple #18
0
    def test_update_question_property(self):
        """Test to verify __init__ method of the Question Change object
        when cmd is update_question_property.
        """
        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'question_state_data',
            'new_value': 'new_value',
            'old_value': 'old_value'
        }
        observed_object = question_domain.QuestionChange(
            change_dict=change_dict)

        self.assertEqual('update_question_property', observed_object.cmd)
        self.assertEqual('question_state_data', observed_object.property_name)
        self.assertEqual('new_value', observed_object.new_value)
        self.assertEqual('old_value', observed_object.old_value)
Exemple #19
0
    def test_update_question_language_code(self):
        self.assertEqual(self.question.language_code, 'en')
        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'language_code',
            'new_value': 'bn',
            'old_value': 'en'
        }
        change_list = [question_domain.QuestionChange(change_dict)]

        question_services.update_question(
            self.editor_id, self.question_id, change_list,
            'updated question language code')

        question = question_services.get_question_by_id(self.question_id)
        self.assertEqual(question.language_code, 'bn')
        self.assertEqual(question.version, 2)
Exemple #20
0
 def __init__(  # pylint: disable=super-init-not-called
         self, suggestion_id, target_id, target_version_at_submission,
         status, author_id, final_reviewer_id, change, score_category,
         last_updated):
     """Initializes an object of type SuggestionAddQuestion
     corresponding to the SUGGESTION_TYPE_ADD_QUESTION choice.
     """
     self.suggestion_id = suggestion_id
     self.suggestion_type = suggestion_models.SUGGESTION_TYPE_ADD_QUESTION
     self.target_type = suggestion_models.TARGET_TYPE_TOPIC
     self.target_id = target_id
     self.target_version_at_submission = target_version_at_submission
     self.status = status
     self.author_id = author_id
     self.final_reviewer_id = final_reviewer_id
     self.change = question_domain.QuestionChange(change)
     self.score_category = score_category
     self.last_updated = last_updated
Exemple #21
0
    def test_to_dict(self):
        """Test to verify to_dict method of the Question Change object."""
        expected_object_dict = {
            'cmd': 'update_question_property',
            'property_name': 'question_state_data',
            'new_value': 'new_value',
            'old_value': 'old_value',
        }

        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'question_state_data',
            'new_value': 'new_value',
            'old_value': 'old_value',
        }
        observed_object = question_domain.QuestionChange(
            change_dict=change_dict, )

        self.assertEqual(expected_object_dict, observed_object.to_dict())
Exemple #22
0
def _update_linked_skill_ids_of_question(
        user_id, question_id, new_linked_skill_ids, old_linked_skill_ids):
    """Updates the question linked_skill ids in the Question model.

    Args:
        user_id: str. ID of the creator.
        question_id: str. ID of the question linked to the skill.
        new_linked_skill_ids: list(str). New linked skill IDs of the question.
        old_linked_skill_ids: list(str). Current linked skill IDs of the
        question.
    """
    change_dict = {
        'cmd': 'update_question_property',
        'property_name': 'linked_skill_ids',
        'new_value': new_linked_skill_ids,
        'old_value': old_linked_skill_ids
    }
    change_list = [question_domain.QuestionChange(change_dict)]
    update_question(
        user_id, question_id, change_list, 'updated linked skill ids')
    def test_migration_job_succeeds_on_default_question(self):
        swap_states_schema_version_37 = self.swap(
            feconf, 'CURRENT_STATE_SCHEMA_VERSION', 37)
        with swap_states_schema_version_37:
            self.save_new_question(
                self.QUESTION_ID, self.albert_id,
                self._create_valid_question_data('ABC'), [self.skill_id])

        # Bring the main question to schema version 38.
        migration_change_list = [
            question_domain.QuestionChange({
                'cmd': (
                    question_domain.CMD_MIGRATE_STATE_SCHEMA_TO_LATEST_VERSION
                ),
                'from_version': '37',
                'to_version': '38'
            })
        ]
        swap_states_schema_version_38 = self.swap(
            feconf, 'CURRENT_STATE_SCHEMA_VERSION', 38)
        with swap_states_schema_version_38:
            question_services.update_question(
                self.albert_id, self.QUESTION_ID, migration_change_list,
                'Ran Question Migration job.')

            job_id = (
                question_jobs_one_off.QuestionSnapshotsMigrationJob.
                create_new())
            question_jobs_one_off.QuestionSnapshotsMigrationJob.enqueue(
                job_id)
            self.process_and_flush_pending_mapreduce_tasks()

        actual_output = (
            question_jobs_one_off.QuestionSnapshotsMigrationJob.get_output(
                job_id))
        expected_output = [
            '[u\'SUCCESS - Model saved\', 1]',
            '[u\'SUCCESS - Model upgraded\', 1]',
            '[u\'SUCCESS - Snapshot is already at latest schema version\', 1]']
        self.assertEqual(sorted(actual_output), sorted(expected_output))
 def __init__(  # pylint: disable=super-init-not-called
         self, suggestion_id, target_id, target_version_at_submission,
         status, author_id, final_reviewer_id, change, score_category,
         last_updated):
     """Initializes an object of type SuggestionAddQuestion
     corresponding to the SUGGESTION_TYPE_ADD_QUESTION choice.
     """
     self.suggestion_id = suggestion_id
     self.suggestion_type = suggestion_models.SUGGESTION_TYPE_ADD_QUESTION
     self.target_type = suggestion_models.TARGET_TYPE_SKILL
     self.target_id = target_id
     self.target_version_at_submission = target_version_at_submission
     self.status = status
     self.author_id = author_id
     self.final_reviewer_id = final_reviewer_id
     self.change = question_domain.QuestionChange(change)
     # Update question_state_data_schema_version here instead of surfacing
     # the version in the frontend.
     self.change.question_dict['question_state_data_schema_version'] = (
         feconf.CURRENT_STATE_SCHEMA_VERSION)
     self.score_category = score_category
     self.last_updated = last_updated
Exemple #25
0
    def test_pre_update_validate_change_cmd(self):
        expected_suggestion_dict = self.suggestion_dict

        suggestion = suggestion_registry.SuggestionAddQuestion(
            expected_suggestion_dict['suggestion_id'],
            expected_suggestion_dict['target_id'],
            expected_suggestion_dict['target_version_at_submission'],
            expected_suggestion_dict['status'], self.author_id,
            self.reviewer_id, expected_suggestion_dict['change'],
            expected_suggestion_dict['score_category'], self.fake_date)

        change = {
            'cmd': question_domain.CMD_UPDATE_QUESTION_PROPERTY,
            'property_name': question_domain.QUESTION_PROPERTY_LANGUAGE_CODE,
            'new_value': 'bn',
            'old_value': 'en'
        }
        with self.assertRaisesRegexp(
                Exception, 'The new change cmd must be equal to '
                'create_new_fully_specified_question'):
            suggestion.pre_update_validate(
                question_domain.QuestionChange(change))
Exemple #26
0
    def test_update_question(self):
        state = exp_domain.State.create_default_state('ABC')
        question_data = state.to_dict()
        question_id = 'dummy'
        title = 'A Question'
        question_data_schema_version = 1
        collection_id = 'col1'
        language_code = 'en'
        question = question_domain.Question(question_id, title, question_data,
                                            question_data_schema_version,
                                            collection_id, language_code)

        question_id = question_services.add_question(self.owner_id, question)
        change_dict = {
            'cmd': 'update_question_property',
            'property_name': 'title',
            'new_value': 'ABC',
            'old_value': 'A Question'
        }
        change_list = [question_domain.QuestionChange(change_dict)]
        with self.assertRaisesRegexp(
                Exception, ('The question with ID %s is not present'
                            ' in the given collection' % question_id)):
            question_services.update_question(self.owner_id, 'random',
                                              question_id, change_list,
                                              'updated')

        question_services.update_question(self.owner_id, collection_id,
                                          question_id, change_list,
                                          ('updated title'))

        model = question_models.QuestionModel.get(question_id)
        self.assertEqual(model.title, 'ABC')
        self.assertEqual(model.question_data, question_data)
        self.assertEqual(model.question_data_schema_version,
                         question_data_schema_version)
        self.assertEqual(model.collection_id, collection_id)
        self.assertEqual(model.language_code, language_code)
Exemple #27
0
    def put(self, question_id):
        """Updates properties of the given question."""
        commit_message = self.payload.get('commit_message')

        if not commit_message:
            raise self.PageNotFoundException
        if not self.payload.get('change_list'):
            raise self.PageNotFoundException
        change_list = [
            question_domain.QuestionChange(change)
            for change in self.payload.get('change_list')
        ]

        for change in change_list:
            if (change.cmd ==
                    question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION):
                raise self.InvalidInputException

        question_services.update_question(self.user_id, question_id,
                                          change_list, commit_message)

        question_dict = question_services.get_question_by_id(
            question_id).to_dict()
        self.render_json({'question_dict': question_dict})
Exemple #28
0
    def test_migrate_question_state_from_v33_to_v34(self):
        feedback_html_content = (
            '<p>Feedback</p><oppia-noninteractive-math raw_latex-with-value="'
            '&amp;quot;+,-,-,+&amp;quot;"></oppia-noninteractive-math>')
        answer_group = {
            'outcome': {
                'dest': 'abc',
                'feedback': {
                    'content_id': 'feedback_1',
                    'html': feedback_html_content
                },
                'labelled_as_correct': True,
                'param_changes': [],
                'refresher_exploration_id': None,
                'missing_prerequisite_skill_id': None
            },
            'rule_specs': [{
                'inputs': {
                    'x': ['A']
                },
                'rule_type': 'Equals'
            }],
            'training_data': [],
            'tagged_skill_misconception_id': None
        }
        question_state_dict = {
            'content': {
                'content_id': 'content_1',
                'html': 'Question 1'
            },
            'recorded_voiceovers': {
                'voiceovers_mapping': {}
            },
            'written_translations': {
                'translations_mapping': {
                    'explanation': {}
                }
            },
            'interaction': {
                'answer_groups': [answer_group],
                'confirmed_unclassified_answers': [],
                'customization_args': {
                    'choices': {
                        'value': ''
                    },
                    'showChoicesInShuffledOrder': {
                        'value': True
                    }
                },
                'default_outcome': {
                    'dest': None,
                    'feedback': {
                        'content_id': 'feedback_1',
                        'html': 'Correct Answer'
                    },
                    'param_changes': [],
                    'refresher_exploration_id': None,
                    'labelled_as_correct': True,
                    'missing_prerequisite_skill_id': None
                },
                'hints': [{
                    'hint_content': {
                        'content_id': 'hint_1',
                        'html': 'Hint 1'
                    }
                }],
                'solution': {},
                'id':
                'MultipleChoiceInput'
            },
            'param_changes': [],
            'solicit_answer_details': False,
            'classifier_model_id': None
        }
        expected_feeedback_html_content = (
            '<p>Feedback</p><oppia-noninteractive-math math_content-with-val'
            'ue="{&amp;quot;raw_latex&amp;quot;: &amp;quot;+,-,-,+&amp;quot;,'
            ' &amp;quot;svg_filename&amp;quot;: &amp;quot;&amp;quot;}"></oppi'
            'a-noninteractive-math>')
        question_model = (question_models.QuestionModel(
            id='question_id',
            question_state_data=question_state_dict,
            language_code='en',
            version=0,
            linked_skill_ids=['skill_id'],
            question_state_data_schema_version=33))
        commit_cmd = (question_domain.QuestionChange(
            {'cmd': question_domain.CMD_CREATE_NEW}))
        commit_cmd_dicts = [commit_cmd.to_dict()]
        question_model.commit('user_id_admin', 'question model created',
                              commit_cmd_dicts)

        current_schema_version_swap = self.swap(
            feconf, 'CURRENT_STATE_SCHEMA_VERSION', 34)

        with current_schema_version_swap:
            question = question_fetchers.get_question_from_model(
                question_model)

        self.assertEqual(question.question_state_data_schema_version, 34)

        migrated_answer_group = (
            question.question_state_data.interaction.answer_groups[0])
        self.assertEqual(migrated_answer_group.outcome.feedback.html,
                         expected_feeedback_html_content)
Exemple #29
0
    def test_migrate_question_state_from_v29_to_v30(self):
        answer_group = {
            'outcome': {
                'dest': 'abc',
                'feedback': {
                    'content_id': 'feedback_1',
                    'html': '<p>Feedback</p>'
                },
                'labelled_as_correct': True,
                'param_changes': [],
                'refresher_exploration_id': None,
                'missing_prerequisite_skill_id': None
            },
            'rule_specs': [{
                'inputs': {
                    'x': 'Test'
                },
                'rule_type': 'Contains'
            }],
            'training_data': [],
            'tagged_misconception_id': None
        }
        question_state_dict = {
            'content': {
                'content_id': 'content_1',
                'html': 'Question 1'
            },
            'recorded_voiceovers': {
                'voiceovers_mapping': {}
            },
            'written_translations': {
                'translations_mapping': {
                    'explanation': {}
                }
            },
            'interaction': {
                'answer_groups': [answer_group],
                'confirmed_unclassified_answers': [],
                'customization_args': {},
                'default_outcome': {
                    'dest': None,
                    'feedback': {
                        'content_id': 'feedback_1',
                        'html': 'Correct Answer'
                    },
                    'param_changes': [],
                    'refresher_exploration_id': None,
                    'labelled_as_correct': True,
                    'missing_prerequisite_skill_id': None
                },
                'hints': [{
                    'hint_content': {
                        'content_id': 'hint_1',
                        'html': 'Hint 1'
                    }
                }],
                'solution': {
                    'correct_answer': 'This is the correct answer',
                    'answer_is_exclusive': False,
                    'explanation': {
                        'content_id': 'explanation_1',
                        'html': 'Solution explanation'
                    }
                },
                'id':
                'TextInput'
            },
            'param_changes': [],
            'solicit_answer_details': False,
            'classifier_model_id': None
        }
        question_model = question_models.QuestionModel(
            id='question_id',
            question_state_data=question_state_dict,
            language_code='en',
            version=0,
            linked_skill_ids=['skill_id'],
            question_state_data_schema_version=29)
        commit_cmd = question_domain.QuestionChange(
            {'cmd': question_domain.CMD_CREATE_NEW})
        commit_cmd_dicts = [commit_cmd.to_dict()]
        question_model.commit('user_id_admin', 'question model created',
                              commit_cmd_dicts)

        current_schema_version_swap = self.swap(
            feconf, 'CURRENT_STATE_SCHEMA_VERSION', 30)

        with current_schema_version_swap:
            question = question_fetchers.get_question_from_model(
                question_model)

        self.assertEqual(question.question_state_data_schema_version, 30)

        answer_groups = question.question_state_data.interaction.answer_groups
        self.assertEqual(answer_groups[0].tagged_skill_misconception_id, None)