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.')
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)
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)
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, [])
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)
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')
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})
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)
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')
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.')
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()
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 })
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)
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)
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)
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')