예제 #1
0
    def test_normal_user_cannot_update_skill_property(self):
        changelist = [
            skill_domain.SkillChange({
                'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
                'property_name': skill_domain.SKILL_PROPERTY_DESCRIPTION,
                'old_value': 'Description',
                'new_value': 'New description'
            })
        ]

        with self.assertRaisesRegexp(
            Exception,
            'The user does not have enough rights to edit the '
            'skill description.'):
            skill_services.update_skill(
                self.user_id_a, self.SKILL_ID, changelist,
                'Change description.')
예제 #2
0
    def map(item):
        if item.deleted:
            yield (SkillMigrationOneOffJob._DELETED_KEY, 1)
            return

        # Note: the read will bring the skill up to the newest version.
        skill = skill_services.get_skill_by_id(item.id)
        try:
            skill.validate()
        except Exception as e:
            logging.error(
                'Skill %s failed validation: %s' % (item.id, e))
            yield (
                SkillMigrationOneOffJob._ERROR_KEY,
                'Skill %s failed validation: %s' % (item.id, e))
            return

        # Write the new skill into the datastore if it's different from
        # the old version.
        commit_cmds = []
        if (
                item.skill_contents_schema_version <=
                feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION):
            commit_cmds.append(skill_domain.SkillChange({
                'cmd': skill_domain.CMD_MIGRATE_CONTENTS_SCHEMA_TO_LATEST_VERSION, # pylint: disable=line-too-long
                'from_version': item.skill_contents_schema_version,
                'to_version': feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION
            }))
        if (
                item.misconceptions_schema_version <=
                feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION):
            commit_cmds.append(skill_domain.SkillChange({
                'cmd': skill_domain.CMD_MIGRATE_MISCONCEPTIONS_SCHEMA_TO_LATEST_VERSION, # pylint: disable=line-too-long
                'from_version': item.misconceptions_schema_version,
                'to_version': feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION
            }))

        if commit_cmds:
            skill_services.update_skill(
                feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds,
                'Update skill content schema version to %d and '
                'skill misconceptions schema version to %d.' % (
                    feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION,
                    feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION))
            yield (SkillMigrationOneOffJob._MIGRATED_KEY, 1)
예제 #3
0
 def test_get_merged_skill_ids(self):
     skill_ids = skill_services.get_merged_skill_ids()
     self.assertEqual(len(skill_ids), 0)
     changelist = [
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
             'property_name': (
                 skill_domain.SKILL_PROPERTY_SUPERSEDING_SKILL_ID),
             'old_value': '',
             'new_value': 'TestSkillId'
         })
     ]
     skill_services.update_skill(
         self.USER_ID, self.SKILL_ID, changelist,
         'Merging skill.')
     skill_ids = skill_services.get_merged_skill_ids()
     self.assertEqual(len(skill_ids), 1)
     self.assertEqual(skill_ids[0], self.SKILL_ID)
예제 #4
0
    def test_delete_skill_misconception(self):
        skill = skill_services.get_skill_by_id(self.SKILL_ID)

        self.assertEqual(len(skill.misconceptions), 1)
        self.assertEqual(skill.misconceptions[0].id, self.MISCONCEPTION_ID_1)

        changelist = [
            skill_domain.SkillChange({
                'cmd': skill_domain.CMD_DELETE_SKILL_MISCONCEPTION,
                'misconception_id': self.MISCONCEPTION_ID_1,
            })
        ]

        skill_services.update_skill(
            self.USER_ID, self.SKILL_ID, changelist, 'Delete misconception.')
        skill = skill_services.get_skill_by_id(self.SKILL_ID)

        self.assertEqual(skill.misconceptions, [])
예제 #5
0
    def test_cannot_update_skill_with_invalid_change_list(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_context_manager = self.assertRaises(Exception)

        with logging_swap, assert_raises_context_manager:
            skill_services.update_skill(
                self.USER_ID, self.SKILL_ID, 'invalid_change_list',
                'commit message')

        self.assertEqual(len(observed_log_messages), 1)
        self.assertRegexpMatches(
            observed_log_messages[0], 'object has no'
            ' attribute \'cmd\' %s invalid_change_list' % self.SKILL_ID)
예제 #6
0
    def test_get_skill_by_id_with_different_versions(self) -> None:
        changelist = [
            skill_domain.SkillChange({
                'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
                'property_name': skill_domain.SKILL_PROPERTY_LANGUAGE_CODE,
                'old_value': 'en',
                'new_value': 'bn'
            })
        ]
        skill_services.update_skill(  # type: ignore[no-untyped-call]
            self.USER_ID, self.skill_id, changelist, 'update language code')

        skill = skill_fetchers.get_skill_by_id(self.skill_id, version=1)
        self.assertEqual(skill.id, self.skill_id)
        self.assertEqual(skill.language_code, 'en')

        skill = skill_fetchers.get_skill_by_id(self.skill_id, version=2)
        self.assertEqual(skill.id, self.skill_id)
        self.assertEqual(skill.language_code, 'bn')
예제 #7
0
 def post(self):
     """Handles the POST request."""
     if not constants.ENABLE_NEW_STRUCTURE_EDITORS:
         raise self.PageNotFoundException
     old_skill_id = self.payload.get('old_skill_id')
     new_skill_id = self.payload.get('new_skill_id')
     new_skill = skill_services.get_skill_by_id(new_skill_id, strict=False)
     if new_skill is None:
         raise self.PageNotFoundException(
             Exception('The new skill with the given id doesn\'t exist.'))
     old_skill = skill_services.get_skill_by_id(old_skill_id, strict=False)
     if old_skill is None:
         raise self.PageNotFoundException(
             Exception('The old skill with the given id doesn\'t exist.'))
     question_services.update_skill_ids_of_questions(
         old_skill_id, old_skill.description, new_skill_id)
     changelist = [
         skill_domain.SkillChange({
             'cmd':
             skill_domain.CMD_UPDATE_SKILL_PROPERTY,
             'property_name':
             (skill_domain.SKILL_PROPERTY_SUPERSEDING_SKILL_ID),
             'old_value':
             old_skill.superseding_skill_id,
             'new_value':
             new_skill_id
         }),
         skill_domain.SkillChange({
             'cmd':
             skill_domain.CMD_UPDATE_SKILL_PROPERTY,
             'property_name':
             (skill_domain.SKILL_PROPERTY_ALL_QUESTIONS_MERGED),
             'old_value':
             False,
             'new_value':
             True
         })
     ]
     skill_services.update_skill(
         self.user_id, old_skill_id, changelist,
         'Marking the skill as having being merged successfully.')
     self.render_json({'merged_into_skill': new_skill_id})
예제 #8
0
 def test_set_merge_complete_for_skill(self):
     changelist = [
         skill_domain.SkillChange({
             'cmd':
             skill_domain.CMD_UPDATE_SKILL_PROPERTY,
             'property_name':
             (skill_domain.SKILL_PROPERTY_ALL_QUESTIONS_MERGED),
             'id':
             0,
             'old_value':
             False,
             'new_value':
             True
         })
     ]
     skill_services.update_skill(self.USER_ID, self.SKILL_ID, changelist,
                                 'Setting merge complete for skill.')
     skill = skill_services.get_skill_by_id(self.SKILL_ID)
     self.assertEqual(skill.version, 2)
     self.assertEqual(skill.all_questions_merged, True)
예제 #9
0
 def test_update_skill(self):
     changelist = [
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_ADD_SKILL_MISCONCEPTION,
             'new_misconception_dict': {
                 'id': self.skill.next_misconception_id,
                 'name': 'test name',
                 'notes': '<p>test notes</p>',
                 'feedback': '<p>test feedback</p>'
             }
         }),
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_SKILL_MISCONCEPTIONS_PROPERTY,
             'property_name': (
                 skill_domain.SKILL_MISCONCEPTIONS_PROPERTY_NAME),
             'misconception_id': self.skill.next_misconception_id,
             'old_value': 'test name',
             'new_value': 'Name'
         }),
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_RUBRICS,
             'difficulty': constants.SKILL_DIFFICULTIES[0],
             'explanation': '<p>New Explanation</p>'
         }),
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_RUBRICS,
             'difficulty': constants.SKILL_DIFFICULTIES[1],
             'explanation': '<p>Explanation</p>'
         })
     ]
     skill_services.update_skill(
         self.USER_ID, self.SKILL_ID, changelist,
         'Updated misconception name.')
     skill = skill_services.get_skill_by_id(self.SKILL_ID)
     skill_summary = skill_services.get_skill_summary_by_id(self.SKILL_ID)
     self.assertEqual(skill_summary.misconception_count, 2)
     self.assertEqual(skill_summary.version, 2)
     self.assertEqual(skill.version, 2)
     self.assertEqual(skill.misconceptions[1].name, 'Name')
     self.assertEqual(skill.rubrics[0].explanation, '<p>New Explanation</p>')
     self.assertEqual(skill.rubrics[1].explanation, '<p>Explanation</p>')
    def test_update_skill_description_updates_skill_opportunity(self):
        self.save_new_skill(self.SKILL_ID, self.USER_ID, 'skill_description')
        changelist = [
            skill_domain.SkillChange({
                'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
                'property_name': (
                    skill_domain.SKILL_PROPERTY_DESCRIPTION),
                'old_value': 'skill_description',
                'new_value': 'new_description'
            })
        ]

        skill_services.update_skill(
            self.admin_id, self.SKILL_ID, changelist,
            'Updated misconception name.')

        skill_opportunities, _, _ = (
            opportunity_services.get_skill_opportunities(None))
        opportunity = skill_opportunities[0]
        self.assertEqual(opportunity['id'], self.SKILL_ID)
        self.assertEqual(opportunity['skill_description'], 'new_description')
예제 #11
0
    def test_cannot_update_misconception_feedback_with_invalid_id(self):
        changelist = [
            skill_domain.SkillChange({
                'cmd':
                skill_domain.CMD_UPDATE_SKILL_MISCONCEPTIONS_PROPERTY,
                'property_name':
                (skill_domain.SKILL_MISCONCEPTIONS_PROPERTY_FEEDBACK),
                'id':
                'invalid_id',
                'old_value':
                'default_feedback',
                'new_value':
                'new feedback'
            })
        ]

        with self.assertRaisesRegexp(
                Exception, 'There is no misconception with the given id.'):
            skill_services.update_skill(self.USER_ID, self.SKILL_ID,
                                        changelist,
                                        'Updated misconception feedback.')
예제 #12
0
    def test_cannot_update_misconception_must_be_addressed_with_invalid_id(
            self):
        changelist = [
            skill_domain.SkillChange({
                'cmd':
                skill_domain.CMD_UPDATE_SKILL_MISCONCEPTIONS_PROPERTY,
                'property_name':
                (skill_domain.SKILL_MISCONCEPTIONS_PROPERTY_MUST_BE_ADDRESSED),
                'misconception_id':
                'invalid_id',
                'old_value':
                False,
                'new_value':
                True
            })
        ]

        with self.assertRaisesRegexp(
                Exception, 'There is no misconception with the given id.'):
            skill_services.update_skill(
                self.USER_ID, self.SKILL_ID, changelist,
                'Updated misconception must_be_addressed.')
    def setUp(self):
        super(SkillCommitCmdMigrationOneOffJobTests, self).setUp()

        self.signup(self.ALBERT_EMAIL, self.ALBERT_NAME)
        self.albert_id = self.get_user_id_from_email(self.ALBERT_EMAIL)
        self.set_admins([self.ALBERT_NAME])

        rubrics = [
            skill_domain.Rubric(
                constants.SKILL_DIFFICULTIES[0], ['Explanation 1']),
            skill_domain.Rubric(
                constants.SKILL_DIFFICULTIES[1], ['Explanation 2']),
            skill_domain.Rubric(
                constants.SKILL_DIFFICULTIES[2], ['Explanation 3'])]

        skill = skill_domain.Skill.create_default_skill(
            self.SKILL_ID, 'A description', rubrics)
        skill_services.save_new_skill(self.albert_id, skill)

        skill_services.update_skill(
            self.albert_id, 'skill_id', [skill_domain.SkillChange({
                'cmd': skill_domain.CMD_UPDATE_RUBRICS,
                'difficulty': constants.SKILL_DIFFICULTIES[0],
                'explanations': ['New explanation'],
            }), skill_domain.SkillChange({
                'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
                'property_name': 'description',
                'old_value': '',
                'new_value': 'Test description'
            })], 'Changes.')

        self.model_instance_0 = (
            skill_models.SkillCommitLogEntryModel.get_by_id(
                'skill-skill_id-1'))
        self.model_instance_1 = (
            skill_models.SkillCommitLogEntryModel.get_by_id(
                'skill-skill_id-2'))

        self.process_and_flush_pending_mapreduce_tasks()
예제 #14
0
 def post(self):
     """Handles the POST request."""
     if not constants.ENABLE_NEW_STRUCTURE_EDITORS:
         raise self.PageNotFoundException
     old_skill_id = self.payload.get('old_skill_id')
     new_skill_id = self.payload.get('new_skill_id')
     question_services.update_skill_ids_of_questions(
         old_skill_id, new_skill_id)
     changelist = [
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
             'property_name': (
                 skill_domain.SKILL_PROPERTY_ALL_QUESTIONS_MERGED),
             'old_value': False,
             'new_value': True
         })
     ]
     skill_services.update_skill(
         self.user_id, old_skill_id, changelist,
         'Marking the skill as having being merged successfully.')
     self.render_json({
         'merged_into_skill': new_skill_id
     })
예제 #15
0
    def test_update_skill_explanation(self):
        skill = skill_services.get_skill_by_id(self.SKILL_ID)
        old_explanation = {'content_id': '1', 'html': '<p>Explanation</p>'}
        new_explanation = {'content_id': '1', 'html': '<p>New explanation</p>'}

        self.assertEqual(
            skill.skill_contents.explanation.to_dict(), old_explanation)

        changelist = [
            skill_domain.SkillChange({
                'cmd': skill_domain.CMD_UPDATE_SKILL_CONTENTS_PROPERTY,
                'property_name': (
                    skill_domain.SKILL_CONTENTS_PROPERTY_EXPLANATION),
                'old_value': old_explanation,
                'new_value': new_explanation
            })
        ]
        skill_services.update_skill(
            self.USER_ID, self.SKILL_ID, changelist, 'Change explanation.')

        skill = skill_services.get_skill_by_id(self.SKILL_ID)
        self.assertEqual(
            skill.skill_contents.explanation.to_dict(), new_explanation)
예제 #16
0
    def put(self, skill_id):
        """Updates properties of the given skill."""
        skill_domain.Skill.require_valid_skill_id(skill_id)
        skill = skill_fetchers.get_skill_by_id(skill_id, strict=False)
        if skill is None:
            raise self.PageNotFoundException(
                Exception('The skill with the given id doesn\'t exist.'))

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

        commit_message = self.payload.get('commit_message')

        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)

        change_dicts = self.payload.get('change_dicts')
        change_list = [
            skill_domain.SkillChange(change_dict)
            for change_dict in change_dicts
        ]
        try:
            skill_services.update_skill(
                self.user_id, skill_id, change_list, commit_message)
        except utils.ValidationError as e:
            raise self.InvalidInputException(e)

        skill_dict = skill_fetchers.get_skill_by_id(skill_id).to_dict()

        self.values.update({
            'skill': skill_dict
        })

        self.render_json(self.values)
예제 #17
0
 def test_merge_skill(self):
     changelist = [
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
             'property_name': (
                 skill_domain.SKILL_PROPERTY_SUPERSEDING_SKILL_ID),
             'old_value': '',
             'new_value': 'TestSkillId'
         }),
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_SKILL_PROPERTY,
             'property_name': (
                 skill_domain.SKILL_PROPERTY_ALL_QUESTIONS_MERGED),
             'old_value': None,
             'new_value': False
         })
     ]
     skill_services.update_skill(
         self.USER_ID, self.SKILL_ID, changelist,
         'Merging skill.')
     skill = skill_services.get_skill_by_id(self.SKILL_ID)
     self.assertEqual(skill.version, 2)
     self.assertEqual(skill.superseding_skill_id, 'TestSkillId')
     self.assertEqual(skill.all_questions_merged, False)
예제 #18
0
 def test_update_skill(self):
     changelist = [
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_ADD_SKILL_MISCONCEPTION,
             'id': self.MISCONCEPTION_ID_2
         }),
         skill_domain.SkillChange({
             'cmd': skill_domain.CMD_UPDATE_SKILL_MISCONCEPTIONS_PROPERTY,
             'property_name': (
                 skill_domain.SKILL_MISCONCEPTIONS_PROPERTY_NAME),
             'id': self.MISCONCEPTION_ID_2,
             'old_value': '',
             'new_value': 'Name'
         })
     ]
     skill_services.update_skill(
         self.USER_ID, self.SKILL_ID, changelist,
         'Updated misconception name.')
     skill = skill_services.get_skill_by_id(self.SKILL_ID)
     skill_summary = skill_services.get_skill_summary_by_id(self.SKILL_ID)
     self.assertEqual(skill_summary.misconception_count, 2)
     self.assertEqual(skill_summary.version, 2)
     self.assertEqual(skill.version, 2)
     self.assertEqual(skill.misconceptions[1].name, 'Name')