def setUp(self):
        """Completes the sign-up process for the various users."""
        super(BaseTopicEditorControllerTest, self).setUp()
        self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME)
        self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME)
        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)

        self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL)
        self.topic_manager_id = self.get_user_id_from_email(
            self.TOPIC_MANAGER_EMAIL)
        self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL)

        self.set_admins([self.ADMIN_USERNAME])
        self.set_topic_managers([self.TOPIC_MANAGER_USERNAME])

        self.topic_manager = user_services.UserActionsInfo(
            self.topic_manager_id)
        self.admin = user_services.UserActionsInfo(self.admin_id)
        self.new_user = user_services.UserActionsInfo(self.new_user_id)
        self.skill_id = skill_services.get_new_skill_id()
        self.save_new_skill(self.skill_id, self.admin_id, 'Skill Description')
        self.topic_id = topic_services.get_new_topic_id()
        self.save_new_topic(self.topic_id, self.admin_id, 'Name',
                            'Description', [], [], [self.skill_id], [], 1)
        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_ADD_SUBTOPIC,
                'title': 'Title',
                'subtopic_id': 1
            })
        ]
        topic_services.update_topic_and_subtopic_pages(self.admin_id,
                                                       self.topic_id,
                                                       changelist,
                                                       'Added subtopic.')
Exemple #2
0
    def test_get_published_summaries(self):
        # Unpublished topics should not be returned.
        topic_summaries = topic_fetchers.get_published_topic_summaries()
        self.assertEqual(len(topic_summaries), 0)

        # Publish the topic.
        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC,
                'old_subtopic_id': None,
                'new_subtopic_id': self.subtopic_id,
                'skill_id': self.skill_id_1
            })
        ]
        topic_services.update_topic_and_subtopic_pages(
            self.user_id_admin, self.TOPIC_ID, changelist,
            'Updated subtopic skill ids.')
        topic_services.publish_topic(self.TOPIC_ID, self.user_id_admin)

        topic_summaries = topic_fetchers.get_published_topic_summaries()

        self.assertEqual(len(topic_summaries), 1)
        self.assertEqual(topic_summaries[0].name, 'Name')
        self.assertEqual(topic_summaries[0].canonical_story_count, 0)
        self.assertEqual(topic_summaries[0].additional_story_count, 0)
        self.assertEqual(topic_summaries[0].total_skill_count, 2)
        self.assertEqual(topic_summaries[0].uncategorized_skill_count, 1)
        self.assertEqual(topic_summaries[0].subtopic_count, 1)
    def setUp(self):
        """Completes the sign-up process for the various users."""
        super(BaseQuestionsListControllerTests, self).setUp()
        self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME)
        self.admin_id = self.get_user_id_from_email(self.CURRICULUM_ADMIN_EMAIL)

        self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME])

        self.admin = user_services.get_user_actions_info(self.admin_id)
        self.skill_id = skill_services.get_new_skill_id()
        self.save_new_skill(
            self.skill_id, self.admin_id, description='Skill Description')
        self.skill_id_2 = skill_services.get_new_skill_id()
        self.save_new_skill(
            self.skill_id_2, self.admin_id, description='Skill Description 2')
        self.topic_id = topic_fetchers.get_new_topic_id()
        self.save_new_topic(
            self.topic_id, self.admin_id, name='Name',
            description='Description', canonical_story_ids=[],
            additional_story_ids=[],
            uncategorized_skill_ids=[self.skill_id, self.skill_id_2],
            subtopics=[], next_subtopic_id=1)
        self.skill_id_3 = skill_services.get_new_skill_id()
        changelist = [topic_domain.TopicChange({
            'cmd': topic_domain.CMD_ADD_SUBTOPIC,
            'title': 'Title',
            'subtopic_id': 1
        })]
        topic_services.update_topic_and_subtopic_pages(
            self.admin_id, self.topic_id, changelist, 'Added subtopic.')
    def setUp(self):
        super(TopicServicesUnitTests, self).setUp()
        self.TOPIC_ID = topic_services.get_new_topic_id()
        changelist = [topic_domain.TopicChange({
            'cmd': topic_domain.CMD_ADD_SUBTOPIC,
            'title': 'Title',
            'subtopic_id': 1
        })]
        self.save_new_topic(
            self.TOPIC_ID, self.user_id, 'Name', 'Description',
            [self.story_id_1, self.story_id_2], [self.story_id_3],
            [self.skill_id_1, self.skill_id_2], [], 1
        )
        self.signup('*****@*****.**', 'A')
        self.signup('*****@*****.**', 'B')
        self.signup(self.ADMIN_EMAIL, username=self.ADMIN_USERNAME)

        self.user_id_a = self.get_user_id_from_email('*****@*****.**')
        self.user_id_b = self.get_user_id_from_email('*****@*****.**')
        self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL)
        topic_services.update_topic_and_subtopic_pages(
            self.user_id_admin, self.TOPIC_ID, changelist, 'Added a subtopic')

        self.topic = topic_services.get_topic_by_id(self.TOPIC_ID)
        self.set_admins([self.ADMIN_USERNAME])
        self.set_topic_managers([user_services.get_username(self.user_id_a)])
        self.user_a = user_services.UserActionsInfo(self.user_id_a)
        self.user_b = user_services.UserActionsInfo(self.user_id_b)
        self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
Exemple #5
0
    def test_cannot_update_topic_and_subtopic_pages_with_mismatch_of_versions(
            self):
        topic_model = topic_models.TopicModel.get(self.TOPIC_ID)
        topic_model.version = 0
        topic_model.commit(self.user_id, 'changed version', [])

        changelist = [topic_domain.TopicChange({
            'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY,
            'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE,
            'old_value': 'en',
            'new_value': 'bn'
        })]

        with self.assertRaisesRegexp(
            Exception,
            'Unexpected error: trying to update version 1 of topic '
            'from version 2. Please reload the page and try again.'):
            topic_services.update_topic_and_subtopic_pages(
                self.user_id, self.TOPIC_ID, changelist, 'change language_code')

        topic_model = topic_models.TopicModel.get(self.TOPIC_ID)
        topic_model.version = 100
        topic_model.commit(self.user_id, 'changed version', [])

        with self.assertRaisesRegexp(
            Exception,
            'Trying to update version 101 of topic from version 2, '
            'which is too old. Please reload the page and try again.'):
            topic_services.update_topic_and_subtopic_pages(
                self.user_id, self.TOPIC_ID, changelist, 'change language_code')
Exemple #6
0
 def test_cannot_update_topic_and_subtopic_pages_with_empty_changelist(self):
     with self.assertRaisesRegexp(
         Exception,
         'Unexpected error: received an invalid change list when trying to '
         'save topic'):
         topic_services.update_topic_and_subtopic_pages(
             self.user_id, self.TOPIC_ID, [], 'commit message')
    def test_opportunities_updates_with_updating_topic_name(self):
        self.add_exploration_0_to_story()

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

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

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

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

        opportunity = translation_opportunities[0]
        self.assertEqual(opportunity.story_title, 'A story')
        self.assertEqual(opportunity.topic_name, 'A new topic')
    def test_missing_subtopic_page_commit_log_entry_model_failure(self):
        topic_services.update_topic_and_subtopic_pages(self.owner_id, '0', [
            subtopic_page_domain.SubtopicPageChange({
                'cmd': 'update_subtopic_page_property',
                'property_name': 'page_contents_html',
                'subtopic_id': 1,
                'new_value': {
                    'html': '<p>html</p>',
                    'content_id': 'content'
                },
                'old_value': {}
            })
        ], 'Changes.')
        subtopic_models.SubtopicPageCommitLogEntryModel.get_by_id(
            'subtopicpage-0-1-1').delete()

        expected_output = [
            (u'[u\'failed validation check for '
             'subtopic_page_commit_log_entry_ids field check of '
             'SubtopicPageModel\', '
             '[u"Entity id 0-1: based on field '
             'subtopic_page_commit_log_entry_ids having value '
             'subtopicpage-0-1-1, expected model '
             'SubtopicPageCommitLogEntryModel '
             'with id subtopicpage-0-1-1 but it doesn\'t exist"]]'),
            u'[u\'fully-validated SubtopicPageModel\', 2]'
        ]
        self.run_job_and_check_output(expected_output,
                                      sort=True,
                                      literal_eval=False)
Exemple #9
0
 def test_get_all_skill_ids_assigned_to_some_topic(self):
     change_list = [
         topic_domain.TopicChange({
             'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC,
             'old_subtopic_id': None,
             'new_subtopic_id': 1,
             'skill_id': self.skill_id_1
         })
     ]
     topic_services.update_topic_and_subtopic_pages(
         self.user_id_admin, self.TOPIC_ID, change_list,
         'Moved skill to subtopic.')
     topic_id = topic_fetchers.get_new_topic_id()
     self.save_new_topic(
         topic_id,
         self.user_id,
         name='Name 2',
         description='Description',
         abbreviated_name='random',
         url_fragment='name-three',
         canonical_story_ids=[],
         additional_story_ids=[],
         uncategorized_skill_ids=[self.skill_id_1, 'skill_3'],
         subtopics=[],
         next_subtopic_id=1)
     self.assertEqual(
         topic_fetchers.get_all_skill_ids_assigned_to_some_topic(),
         {self.skill_id_1, self.skill_id_2, 'skill_3'})
    def test_get_topic_by_version(self):
        topic_id = topic_services.get_new_topic_id()
        self.save_new_topic(topic_id,
                            self.user_id,
                            name='topic name',
                            abbreviated_name='abbrev',
                            thumbnail_filename='img.png',
                            description='Description',
                            canonical_story_ids=[],
                            additional_story_ids=[],
                            uncategorized_skill_ids=[],
                            subtopics=[],
                            next_subtopic_id=1)

        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY,
                'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE,
                'old_value': 'en',
                'new_value': 'bn'
            })
        ]
        topic_services.update_topic_and_subtopic_pages(self.user_id, topic_id,
                                                       changelist,
                                                       'Change language code')

        topic_v0 = topic_fetchers.get_topic_by_id(topic_id, version=0)
        topic_v1 = topic_fetchers.get_topic_by_id(topic_id, version=1)

        self.assertEqual(topic_v1.language_code, 'en')
        self.assertEqual(topic_v0.language_code, 'bn')
Exemple #11
0
def remove_skill_from_all_topics(user_id, skill_id):
    """Deletes the skill with the given id from all the associated topics.

    Args:
        user_id: str. The unique user ID of the user.
        skill_id: str. ID of the skill.
    """
    all_topics = topic_fetchers.get_all_topics()
    for topic in all_topics:
        change_list = []
        if skill_id in topic.get_all_skill_ids():
            for subtopic in topic.subtopics:
                if skill_id in subtopic.skill_ids:
                    change_list.append(topic_domain.TopicChange({
                        'cmd': 'remove_skill_id_from_subtopic',
                        'subtopic_id': subtopic.id,
                        'skill_id': skill_id
                    }))
                    break

            change_list.append(topic_domain.TopicChange({
                'cmd': 'remove_uncategorized_skill_id',
                'uncategorized_skill_id': skill_id
            }))
            skill_name = get_skill_summary_by_id(skill_id).description
            topic_services.update_topic_and_subtopic_pages(
                user_id, topic.id, change_list,
                'Removed skill with id %s and name %s from the topic' % (
                    skill_id, skill_name))
    def put(self, topic_id):
        """Updates properties of the given topic.
        Also, each change_dict given for editing should have an additional
        property called is_topic_change, which would be a boolean. If True, it
        means that change is for a topic (includes adding and removing
        subtopics), while False would mean it is for a Subtopic Page (this
        includes editing its html data as of now).
        """
        topic_domain.Topic.require_valid_topic_id(topic_id)
        topic = topic_fetchers.get_topic_by_id(topic_id, strict=False)

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

        commit_message = self.payload.get('commit_message')
        topic_and_subtopic_page_change_dicts = self.payload.get(
            'topic_and_subtopic_page_change_dicts')
        topic_and_subtopic_page_change_list = []
        for change in topic_and_subtopic_page_change_dicts:
            if change['cmd'] == (
                    subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY):
                topic_and_subtopic_page_change_list.append(
                    subtopic_page_domain.SubtopicPageChange(change))
            else:
                topic_and_subtopic_page_change_list.append(
                    topic_domain.TopicChange(change))
        try:
            topic_services.update_topic_and_subtopic_pages(
                self.user_id, topic_id, topic_and_subtopic_page_change_list,
                commit_message)
        except utils.ValidationError as e:
            raise self.InvalidInputException(e)

        topic = topic_fetchers.get_topic_by_id(topic_id, strict=False)

        skill_id_to_description_dict, deleted_skill_ids = (
            skill_services.get_descriptions_of_skills(
                topic.get_all_skill_ids()))

        skill_id_to_rubrics_dict, deleted_skill_ids = (
            skill_services.get_rubrics_of_skills(topic.get_all_skill_ids()))

        if deleted_skill_ids:
            deleted_skills_string = ', '.join(deleted_skill_ids)
            logging.error(
                'The deleted skills: %s are still present in topic with id %s'
                % (deleted_skills_string, topic_id))
            if feconf.CAN_SEND_EMAILS:
                email_manager.send_mail_to_admin(
                    'Deleted skills present in topic',
                    'The deleted skills: %s are still present in topic with '
                    'id %s' % (deleted_skills_string, topic_id))

        self.values.update({
            'topic_dict': topic.to_dict(),
            'skill_id_to_description_dict': skill_id_to_description_dict,
            'skill_id_to_rubrics_dict': skill_id_to_rubrics_dict
        })

        self.render_json(self.values)
Exemple #13
0
    def map(item):
        if item.deleted:
            yield (TopicMigrationOneOffJob._DELETED_KEY, 1)
            return

        # Note: the read will bring the topic up to the newest version.
        topic = topic_fetchers.get_topic_by_id(item.id)
        try:
            topic.validate()
        except Exception as e:
            logging.exception(
                'Topic %s failed validation: %s' % (item.id, e))
            yield (
                TopicMigrationOneOffJob._ERROR_KEY,
                'Topic %s failed validation: %s' % (item.id, e))
            return

        # Write the new topic into the datastore if it's different from
        # the old version.
        if (item.subtopic_schema_version <=
                feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION):
            commit_cmds = [topic_domain.TopicChange({
                'cmd': topic_domain.CMD_MIGRATE_SUBTOPIC_SCHEMA_TO_LATEST_VERSION, # pylint: disable=line-too-long
                'from_version': item.subtopic_schema_version,
                'to_version': feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION
            })]
            topic_services.update_topic_and_subtopic_pages(
                feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds,
                'Update topic\'s subtopic schema version to %d.' % (
                    feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION))
            yield (TopicMigrationOneOffJob._MIGRATED_KEY, 1)
Exemple #14
0
    def setUp(self):
        """Completes the sign-up process for the various users."""
        super(BaseTopicEditorControllerTests, self).setUp()
        self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME)
        self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME)
        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)

        self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL)
        self.topic_manager_id = self.get_user_id_from_email(
            self.TOPIC_MANAGER_EMAIL)
        self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL)

        self.set_admins([self.ADMIN_USERNAME])
        self.set_topic_managers([self.TOPIC_MANAGER_USERNAME])

        self.topic_manager = user_services.UserActionsInfo(
            self.topic_manager_id)
        self.admin = user_services.UserActionsInfo(self.admin_id)
        self.new_user = user_services.UserActionsInfo(self.new_user_id)
        self.skill_id = skill_services.get_new_skill_id()
        self.save_new_skill(self.skill_id,
                            self.admin_id,
                            description='Skill Description')
        self.skill_id_2 = skill_services.get_new_skill_id()
        self.save_new_skill(self.skill_id_2,
                            self.admin_id,
                            description='Skill Description 2')
        self.topic_id = topic_services.get_new_topic_id()
        self.save_new_topic(
            self.topic_id,
            self.admin_id,
            name='Name',
            abbreviated_name='abbrev',
            thumbnail_filename='topic.png',
            description='Description',
            canonical_story_ids=[],
            additional_story_ids=[],
            uncategorized_skill_ids=[self.skill_id, self.skill_id_2],
            subtopics=[],
            next_subtopic_id=1)
        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_ADD_SUBTOPIC,
                'title': 'Title',
                'subtopic_id': 1
            }),
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC,
                'old_subtopic_id': None,
                'new_subtopic_id': 1,
                'skill_id': self.skill_id
            })
        ]
        topic_services.update_topic_and_subtopic_pages(self.admin_id,
                                                       self.topic_id,
                                                       changelist,
                                                       'Added subtopic.')
Exemple #15
0
    def setUp(self) -> None:
        super(TopicFetchersUnitTests, self).setUp()
        self.TOPIC_ID = topic_fetchers.get_new_topic_id()
        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_ADD_SUBTOPIC,
                'title': 'Title',
                'subtopic_id': 1,
                'url_fragment': 'sample-fragment'
            })
        ]
        self.save_new_topic(  # type: ignore[no-untyped-call]
            self.TOPIC_ID,
            self.user_id,
            name='Name',
            abbreviated_name='name',
            url_fragment='name-one',
            description='Description',
            canonical_story_ids=[self.story_id_1, self.story_id_2],
            additional_story_ids=[self.story_id_3],
            uncategorized_skill_ids=[self.skill_id_1, self.skill_id_2],
            subtopics=[],
            next_subtopic_id=1)
        self.save_new_story(self.story_id_1, self.user_id,
                            self.TOPIC_ID)  # type: ignore[no-untyped-call]
        self.save_new_story(  # type: ignore[no-untyped-call]
            self.story_id_3,
            self.user_id,
            self.TOPIC_ID,
            title='Title 3',
            description='Description 3')
        self.signup('*****@*****.**', 'A')
        self.signup('*****@*****.**', 'B')
        self.signup(self.CURRICULUM_ADMIN_EMAIL,
                    self.CURRICULUM_ADMIN_USERNAME)

        self.user_id_a = self.get_user_id_from_email(
            '*****@*****.**')  # type: ignore[no-untyped-call]
        self.user_id_b = self.get_user_id_from_email(
            '*****@*****.**')  # type: ignore[no-untyped-call]
        self.user_id_admin = (self.get_user_id_from_email(
            self.CURRICULUM_ADMIN_EMAIL))  # type: ignore[no-untyped-call]
        topic_services.update_topic_and_subtopic_pages(  # type: ignore[no-untyped-call]
            self.user_id_admin, self.TOPIC_ID, changelist, 'Added a subtopic')

        self.topic: Optional[topic_domain.Topic] = (
            topic_fetchers.get_topic_by_id(self.TOPIC_ID))
        self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME
                                    ])  # type: ignore[no-untyped-call]
        self.set_topic_managers(  # type: ignore[no-untyped-call]
            [user_services.get_username(self.user_id_a)], self.TOPIC_ID)
        self.user_a = user_services.get_user_actions_info(self.user_id_a)
        self.user_b = user_services.get_user_actions_info(self.user_id_b)
        self.user_admin = user_services.get_user_actions_info(
            self.user_id_admin)
    def post(self):
        """Handles POST requests."""
        name = self.payload.get('name')
        url_fragment = self.payload.get('url_fragment')
        description = self.payload.get('description')
        thumbnail_filename = self.payload.get('filename')
        thumbnail_bg_color = self.payload.get('thumbnailBgColor')
        raw_image = self.request.get('image')
        page_title_frag = self.payload.get('page_title_fragment')

        try:
            topic_domain.Topic.require_valid_name(name)
        except Exception as e:
            raise self.InvalidInputException(
                'Invalid topic name, received %s.' % name) from e
        new_topic_id = topic_fetchers.get_new_topic_id()
        topic = topic_domain.Topic.create_default_topic(
            new_topic_id, name, url_fragment, description, page_title_frag)
        topic_services.save_new_topic(self.user_id, topic)

        try:
            file_format = image_validation_services.validate_image_and_filename(
                raw_image, thumbnail_filename)
        except utils.ValidationError as e:
            raise self.InvalidInputException(e)

        entity_id = new_topic_id
        filename_prefix = 'thumbnail'

        image_is_compressible = (file_format
                                 in feconf.COMPRESSIBLE_IMAGE_FORMATS)
        fs_services.save_original_and_compressed_versions_of_image(
            thumbnail_filename, feconf.ENTITY_TYPE_TOPIC, entity_id, raw_image,
            filename_prefix, image_is_compressible)

        topic_services.update_topic_and_subtopic_pages(
            self.user_id, new_topic_id, [
                topic_domain.TopicChange({
                    'cmd': 'update_topic_property',
                    'property_name': 'thumbnail_filename',
                    'old_value': None,
                    'new_value': thumbnail_filename
                }),
                topic_domain.TopicChange({
                    'cmd': 'update_topic_property',
                    'property_name': 'thumbnail_bg_color',
                    'old_value': None,
                    'new_value': thumbnail_bg_color
                }),
            ], 'Add topic thumbnail.')

        self.render_json({'topicId': new_topic_id})
Exemple #17
0
    def put(self, topic_id):
        """Updates properties of the given topic.
        Also, each change_dict given for editing should have an additional
        property called is_topic_change, which would be a boolean. If True, it
        means that change is for a topic (includes adding and removing
        subtopics), while False would mean it is for a Subtopic Page (this
        includes editing its html data as of now).
        """
        if not feconf.ENABLE_NEW_STRUCTURES:
            raise self.PageNotFoundException

        topic_domain.Topic.require_valid_topic_id(topic_id)
        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        if topic is None:
            raise self.PageNotFoundException(
                Exception('The topic with the given id doesn\'t exist.'))

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

        commit_message = self.payload.get('commit_message')
        topic_and_subtopic_page_change_dicts = self.payload.get(
            'topic_and_subtopic_page_change_dicts')
        topic_and_subtopic_page_change_list = []
        for change in topic_and_subtopic_page_change_dicts:
            if change['change_affects_subtopic_page']:
                topic_and_subtopic_page_change_list.append(
                    subtopic_page_domain.SubtopicPageChange(change))
            else:
                topic_and_subtopic_page_change_list.append(
                    topic_domain.TopicChange(change))
        try:
            topic_services.update_topic_and_subtopic_pages(
                self.user_id, topic_id, topic_and_subtopic_page_change_list,
                commit_message)
        except utils.ValidationError as e:
            raise self.InvalidInputException(e)

        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        skill_ids = topic.get_all_skill_ids()

        skill_id_to_description_dict = (
            skill_services.get_skill_descriptions_by_ids(topic_id, skill_ids))

        self.values.update({
            'topic_dict':
            topic.to_dict(),
            'skill_id_to_description_dict':
            skill_id_to_description_dict
        })

        self.render_json(self.values)
Exemple #18
0
def replace_skill_id_in_all_topics(user_id, old_skill_id, new_skill_id):
    """Replaces the old skill id with the new one in all the associated topics.

    Args:
        user_id: str. The unique user ID of the user.
        old_skill_id: str. The old skill id.
        new_skill_id: str. The new skill id.

    Raises:
        Exception. The new skill already present.
    """
    all_topics = topic_fetchers.get_all_topics()
    for topic in all_topics:
        change_list = []
        if old_skill_id in topic.get_all_skill_ids():
            if new_skill_id in topic.get_all_skill_ids():
                raise Exception(
                    'Found topic \'%s\' contains the two skills to be merged. '
                    'Please unassign one of these skills from topic '
                    'and retry this operation.' % topic.name)
            if old_skill_id in topic.uncategorized_skill_ids:
                change_list.extend([topic_domain.TopicChange({
                    'cmd': 'remove_uncategorized_skill_id',
                    'uncategorized_skill_id': old_skill_id
                }), topic_domain.TopicChange({
                    'cmd': 'add_uncategorized_skill_id',
                    'new_uncategorized_skill_id': new_skill_id
                })])
            for subtopic in topic.subtopics:
                if old_skill_id in subtopic.skill_ids:
                    change_list.extend([topic_domain.TopicChange({
                        'cmd': topic_domain.CMD_REMOVE_SKILL_ID_FROM_SUBTOPIC,
                        'subtopic_id': subtopic.id,
                        'skill_id': old_skill_id
                    }), topic_domain.TopicChange({
                        'cmd': 'remove_uncategorized_skill_id',
                        'uncategorized_skill_id': old_skill_id
                    }), topic_domain.TopicChange({
                        'cmd': 'add_uncategorized_skill_id',
                        'new_uncategorized_skill_id': new_skill_id
                    }), topic_domain.TopicChange({
                        'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC,
                        'old_subtopic_id': None,
                        'new_subtopic_id': subtopic.id,
                        'skill_id': new_skill_id
                    })])
                    break
            topic_services.update_topic_and_subtopic_pages(
                user_id, topic.id, change_list,
                'Replace skill id %s with skill id %s in the topic' % (
                    old_skill_id, new_skill_id))
Exemple #19
0
    def test_update_topic_language_code(self):
        topic = topic_services.get_topic_by_id(self.TOPIC_ID)
        self.assertEqual(topic.language_code, 'en')

        changelist = [topic_domain.TopicChange({
            'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY,
            'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE,
            'old_value': 'en',
            'new_value': 'bn'
        })]
        topic_services.update_topic_and_subtopic_pages(
            self.user_id, self.TOPIC_ID, changelist, 'Change language code')

        topic = topic_services.get_topic_by_id(self.TOPIC_ID)
        self.assertEqual(topic.language_code, 'bn')
Exemple #20
0
    def map(item):
        if item.deleted:
            yield (RemoveDeletedSkillsFromTopicOneOffJob._DELETED_KEY, 1)
            return

        # Note: the read will bring the topic up to the newest version.
        topic = topic_fetchers.get_topic_by_id(item.id)
        skill_ids_to_be_removed_from_subtopic = []
        all_skill_ids_to_be_removed = []
        commit_cmds = []

        # This block of code removes deleted skills from subtopics, but keeps
        # them in the topic.
        for subtopic in topic.get_all_subtopics():
            subtopic_skill_models = skill_models.SkillModel.get_multi(
                subtopic['skill_ids'])
            for skill_id, skill_model in python_utils.ZIP(
                    subtopic['skill_ids'], subtopic_skill_models):
                if skill_model is None:
                    commit_cmds.append(
                        topic_domain.TopicChange({
                            'cmd':
                            topic_domain.CMD_REMOVE_SKILL_ID_FROM_SUBTOPIC,
                            'skill_id': skill_id,
                            'subtopic_id': subtopic['id']
                        }))
                    skill_ids_to_be_removed_from_subtopic.append(skill_id)

        all_skill_models = skill_models.SkillModel.get_multi(
            topic.get_all_skill_ids())

        # This block of code removes all deleted skills from topics.
        for skill_id, skill_model in python_utils.ZIP(
                topic.get_all_skill_ids(), all_skill_models):
            if skill_model is None:
                commit_cmds.append(
                    topic_domain.TopicChange({
                        'cmd': topic_domain.CMD_REMOVE_UNCATEGORIZED_SKILL_ID,
                        'uncategorized_skill_id': skill_id
                    }))
                all_skill_ids_to_be_removed.append(skill_id)
        if commit_cmds:
            topic_services.update_topic_and_subtopic_pages(
                feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds,
                'Remove deleted skill id.')
            yield ('Skill IDs deleted for topic %s:' % item.id,
                   all_skill_ids_to_be_removed)
        yield (RemoveDeletedSkillsFromTopicOneOffJob._PROCESSED_KEY, 1)
Exemple #21
0
    def test_update_topic_additional_story_ids(self):
        topic = topic_services.get_topic_by_id(self.TOPIC_ID)
        self.assertEqual(topic.additional_story_ids, [self.story_id_3])

        changelist = [topic_domain.TopicChange({
            'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY,
            'property_name': topic_domain.TOPIC_PROPERTY_ADDITIONAL_STORY_IDS,
            'old_value': [self.story_id_3],
            'new_value': ['new_story_id']
        })]
        topic_services.update_topic_and_subtopic_pages(
            self.user_id, self.TOPIC_ID, changelist,
            'Change additional story ids')

        topic = topic_services.get_topic_by_id(self.TOPIC_ID)
        self.assertEqual(topic.additional_story_ids, ['new_story_id'])
Exemple #22
0
 def test_standard_operation(self):
     topic_services.update_topic_and_subtopic_pages(
         self.owner_id, '0', [subtopic_page_domain.SubtopicPageChange({
             'cmd': 'update_subtopic_page_property',
             'property_name': 'page_contents_html',
             'subtopic_id': 1,
             'new_value': {
                 'html': '<p>html</p>',
                 'content_id': 'content'
             },
             'old_value': {}
         })], 'Changes.')
     expected_output = [
         u'[u\'fully-validated SubtopicPageCommitLogEntryModel\', 4]']
     self.run_job_and_check_output(
         expected_output, sort=False, literal_eval=False)
Exemple #23
0
    def put(self, topic_id):
        """Updates properties of the given topic.
        Also, each change_dict given for editing should have an additional
        property called is_topic_change, which would be a boolean. If True, it
        means that change is for a topic (includes adding and removing
        subtopics), while False would mean it is for a Subtopic Page (this
        includes editing its html data as of now).
        """
        topic_domain.Topic.require_valid_topic_id(topic_id)
        topic = topic_services.get_topic_by_id(topic_id, strict=False)

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

        commit_message = self.payload.get('commit_message')
        topic_and_subtopic_page_change_dicts = self.payload.get(
            'topic_and_subtopic_page_change_dicts')
        topic_and_subtopic_page_change_list = []
        for change in topic_and_subtopic_page_change_dicts:
            if change['cmd'] == (
                    subtopic_page_domain.CMD_UPDATE_SUBTOPIC_PAGE_PROPERTY):
                topic_and_subtopic_page_change_list.append(
                    subtopic_page_domain.SubtopicPageChange(change))
            else:
                topic_and_subtopic_page_change_list.append(
                    topic_domain.TopicChange(change))
        try:
            topic_services.update_topic_and_subtopic_pages(
                self.user_id, topic_id, topic_and_subtopic_page_change_list,
                commit_message)
        except utils.ValidationError as e:
            raise self.InvalidInputException(e)

        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        skill_ids = topic.get_all_skill_ids()

        skill_id_to_description_dict = (
            skill_services.get_skill_descriptions_by_ids(topic_id, skill_ids))

        self.values.update({
            'topic_dict':
            topic.to_dict(),
            'skill_id_to_description_dict':
            skill_id_to_description_dict
        })

        self.render_json(self.values)
    def setUp(self):
        super(TopicFetchersUnitTests, self).setUp()
        self.TOPIC_ID = topic_services.get_new_topic_id()
        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_ADD_SUBTOPIC,
                'title': 'Title',
                'subtopic_id': 1
            })
        ]
        self.save_new_topic(
            self.TOPIC_ID,
            self.user_id,
            name='Name',
            abbreviated_name='name',
            url_fragment='name-one',
            description='Description',
            canonical_story_ids=[self.story_id_1, self.story_id_2],
            additional_story_ids=[self.story_id_3],
            uncategorized_skill_ids=[self.skill_id_1, self.skill_id_2],
            subtopics=[],
            next_subtopic_id=1)
        self.save_new_story(self.story_id_1, self.user_id, self.TOPIC_ID)
        self.save_new_story(self.story_id_3,
                            self.user_id,
                            self.TOPIC_ID,
                            title='Title 3',
                            description='Description 3')
        self.signup('*****@*****.**', 'A')
        self.signup('*****@*****.**', 'B')
        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)

        self.user_id_a = self.get_user_id_from_email('*****@*****.**')
        self.user_id_b = self.get_user_id_from_email('*****@*****.**')
        self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL)
        topic_services.update_topic_and_subtopic_pages(self.user_id_admin,
                                                       self.TOPIC_ID,
                                                       changelist,
                                                       'Added a subtopic')

        self.topic = topic_fetchers.get_topic_by_id(self.TOPIC_ID)
        self.set_admins([self.ADMIN_USERNAME])
        self.set_topic_managers([user_services.get_username(self.user_id_a)])
        self.user_a = user_services.UserActionsInfo(self.user_id_a)
        self.user_b = user_services.UserActionsInfo(self.user_id_b)
        self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
Exemple #25
0
 def test_get_all_skill_ids_assigned_to_some_topic(self):
     change_list = [
         topic_domain.TopicChange({
             'cmd': topic_domain.CMD_MOVE_SKILL_ID_TO_SUBTOPIC,
             'old_subtopic_id': None,
             'new_subtopic_id': 1,
             'skill_id': self.skill_id_1
         })
     ]
     topic_services.update_topic_and_subtopic_pages(
         self.user_id_admin, self.TOPIC_ID, change_list,
         'Moved skill to subtopic.')
     topic_id = topic_services.get_new_topic_id()
     self.save_new_topic(topic_id, self.user_id, 'Name 2', 'Description',
                         [], [], [self.skill_id_1, 'skill_3'], [], 1)
     self.assertEqual(
         topic_services.get_all_skill_ids_assigned_to_some_topic(),
         set([self.skill_id_1, self.skill_id_2, 'skill_3']))
 def test_delete_subtopic_with_skill_ids(self):
     changelist = [topic_domain.TopicChange({
         'cmd': topic_domain.CMD_DELETE_SUBTOPIC,
         'subtopic_id': self.subtopic_id
     })]
     subtopic_page = subtopic_page_services.get_subtopic_page_by_id(
         self.TOPIC_ID, 1, strict=False)
     self.assertEqual(subtopic_page.id, self.TOPIC_ID + '-1')
     topic_services.update_topic_and_subtopic_pages(
         self.user_id_admin, self.TOPIC_ID, changelist,
         'Removed 1 subtopic.')
     subtopic_page = subtopic_page_services.get_subtopic_page_by_id(
         self.TOPIC_ID, 1, strict=False)
     self.assertIsNone(subtopic_page)
     topic = topic_services.get_topic_by_id(self.TOPIC_ID)
     self.assertEqual(
         topic.uncategorized_skill_ids, [self.skill_id_1, self.skill_id_2])
     self.assertEqual(topic.subtopics, [])
Exemple #27
0
    def test_update_topic(self):
        topic_services.assign_role(self.user_admin, self.user_a,
                                   topic_domain.ROLE_MANAGER, self.TOPIC_ID)

        # Test whether an admin can edit a topic.
        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY,
                'property_name': topic_domain.TOPIC_PROPERTY_DESCRIPTION,
                'old_value': 'Description',
                'new_value': 'New Description'
            })
        ]
        topic_services.update_topic_and_subtopic_pages(self.user_id_admin,
                                                       self.TOPIC_ID,
                                                       changelist,
                                                       'Updated Description.')
        topic = topic_services.get_topic_by_id(self.TOPIC_ID)
        topic_summary = topic_services.get_topic_summary_by_id(self.TOPIC_ID)
        self.assertEqual(topic.description, 'New Description')
        self.assertEqual(topic.version, 3)
        self.assertEqual(topic_summary.version, 3)

        # Test whether a topic_manager can edit a topic.
        changelist = [
            topic_domain.TopicChange({
                'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY,
                'property_name': topic_domain.TOPIC_PROPERTY_NAME,
                'old_value': 'Name',
                'new_value': 'New Name'
            })
        ]
        topic_services.update_topic_and_subtopic_pages(self.user_id_a,
                                                       self.TOPIC_ID,
                                                       changelist,
                                                       'Updated Name.')
        topic = topic_services.get_topic_by_id(self.TOPIC_ID)
        topic_summary = topic_services.get_topic_summary_by_id(self.TOPIC_ID)
        self.assertEqual(topic.name, 'New Name')
        self.assertEqual(topic.version, 4)
        self.assertEqual(topic_summary.name, 'New Name')
        self.assertEqual(topic_summary.version, 4)
Exemple #28
0
    def test_get_topic_by_version(self):
        topic_id = topic_services.get_new_topic_id()
        self.save_new_topic(
            topic_id, self.user_id, 'topic name', 'Description',
            [], [], [], [], 1)

        changelist = [topic_domain.TopicChange({
            'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY,
            'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE,
            'old_value': 'en',
            'new_value': 'bn'
        })]
        topic_services.update_topic_and_subtopic_pages(
            self.user_id, topic_id, changelist, 'Change language code')

        topic_v0 = topic_services.get_topic_by_id(topic_id, version=0)
        topic_v1 = topic_services.get_topic_by_id(topic_id, version=1)

        self.assertEqual(topic_v1.language_code, 'en')
        self.assertEqual(topic_v0.language_code, 'bn')
Exemple #29
0
    def test_update_subtopic_property(self):
        topic = topic_services.get_topic_by_id(self.TOPIC_ID)

        self.assertEqual(len(topic.subtopics), 1)
        self.assertEqual(topic.subtopics[0].title, 'Title')

        changelist = [topic_domain.TopicChange({
            'cmd': topic_domain.CMD_UPDATE_SUBTOPIC_PROPERTY,
            'property_name': 'title',
            'subtopic_id': 1,
            'old_value': 'Title',
            'new_value': 'New Title'
        })]
        topic_services.update_topic_and_subtopic_pages(
            self.user_id_admin, self.TOPIC_ID, changelist,
            'Update title of subtopic.')
        topic = topic_services.get_topic_by_id(self.TOPIC_ID)

        self.assertEqual(len(topic.subtopics), 1)
        self.assertEqual(topic.subtopics[0].title, 'New Title')
Exemple #30
0
    def test_opportunities_updates_with_updating_topic_name(self):
        story_services.update_story(self.owner_id, self.STORY_ID, [
            story_domain.StoryChange({
                'cmd': 'add_story_node',
                'node_id': 'node_1',
                'title': 'Node1',
            }),
            story_domain.StoryChange({
                'cmd': 'update_story_node_property',
                'property_name': 'exploration_id',
                'node_id': 'node_1',
                'old_value': None,
                'new_value': '0'
            })
        ], 'Changes.')

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

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

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

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

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