def test_migration_job_skips_deleted_collection(self):
        """Tests that the collection migration job skips deleted collection
        and does not attempt to migrate.
        """
        collection = collection_domain.Collection.create_default_collection(
            self.COLLECTION_ID, 'A title', 'A Category', 'An Objective')
        collection_services.save_new_collection(self.albert_id, collection)

        # Note: This creates a summary based on the upgraded model (which is
        # fine). A summary is needed to delete the collection.
        collection_services.create_collection_summary(
            self.COLLECTION_ID, None)

        # Delete the exploration before migration occurs.
        collection_services.delete_collection(
            self.albert_id, self.COLLECTION_ID)

        # Ensure the exploration is deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            collection_services.get_collection_by_id(self.COLLECTION_ID)

        # Start migration job on sample collection.
        job_id = (
            collection_jobs_one_off.CollectionMigrationJob.create_new())
        collection_jobs_one_off.CollectionMigrationJob.enqueue(job_id)

        # This running without errors indicates the deleted collection is
        # being ignored.
        self.process_and_flush_pending_tasks()

        # Ensure the exploration is still deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            collection_services.get_collection_by_id(self.COLLECTION_ID)
    def setUp(self):
        super(ActivityReferencesModelValidatorTests, self).setUp()

        self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME)

        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.owner = user_services.UserActionsInfo(self.owner_id)

        exploration = exp_domain.Exploration.create_default_exploration(
            '1exp', title='title', category='category')

        exp_services.save_new_exploration(self.owner_id, exploration)

        collection = collection_domain.Collection.create_default_collection(
            '1col', title='title', category='category')

        collection_services.save_new_collection(self.owner_id, collection)

        self.model_instance = (
            activity_models.ActivityReferencesModel.get_or_create(
                feconf.ACTIVITY_REFERENCE_LIST_FEATURED))
        self.model_instance.activity_references = [{
            'type': constants.ACTIVITY_TYPE_EXPLORATION,
            'id': '1exp',
        }, {
            'type': constants.ACTIVITY_TYPE_COLLECTION,
            'id': '1col',
        }]
        self.model_instance.put()

        self.job_class = (
            prod_validation_jobs_one_off.ActivityReferencesModelAuditOneOffJob)
Example #3
0
    def test_collection_rights_handler(self):
        collection_id = 'collection_id'
        collection = collection_domain.Collection.create_default_collection(
            collection_id, 'A title', 'A Category', 'An Objective')
        collection_services.save_new_collection(self.owner_id, collection)

        # Check that collection is published correctly.
        rights_manager.assign_role_for_collection(
            self.owner_id, collection_id, self.editor_id,
            rights_manager.ROLE_EDITOR)
        rights_manager.publish_collection(self.owner_id, collection_id)

        # Check that collection cannot be unpublished by non admin.
        with self.assertRaisesRegexp(
            Exception, 'This collection cannot be unpublished.'):
            rights_manager.unpublish_collection(self.owner_id, collection_id)
        collection_rights = rights_manager.get_collection_rights(collection_id)
        self.assertEqual(collection_rights.status,
                         rights_manager.ACTIVITY_STATUS_PUBLIC)

        # Check that collection can be unpublished by admin.
        rights_manager.unpublish_collection(self.admin_id, collection_id)
        collection_rights = rights_manager.get_collection_rights(collection_id)
        self.assertEqual(collection_rights.status,
                         rights_manager.ACTIVITY_STATUS_PRIVATE)
Example #4
0
    def setUp(self):
        super(OneOffReindexActivitiesJobTests, self).setUp()

        self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME)
        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.owner = user_services.UserActionsInfo(self.owner_id)

        explorations = [
            exp_domain.Exploration.create_default_exploration(
                '%s' % i, title='title %d' % i, category='category%d' % i)
            for i in python_utils.RANGE(3)
        ]

        for exp in explorations:
            exp_services.save_new_exploration(self.owner_id, exp)
            rights_manager.publish_exploration(self.owner, exp.id)

        collections = [
            collection_domain.Collection.create_default_collection(
                '%s' % i, title='title %d' % i, category='category%d' % i)
            for i in python_utils.RANGE(3, 6)
        ]

        for collection in collections:
            collection_services.save_new_collection(self.owner_id, collection)
            rights_manager.publish_collection(self.owner, collection.id)

        self.process_and_flush_pending_tasks()
    def test_migration_job_does_not_convert_up_to_date_collection(self):
        """Tests that the collection migration job does not convert an
        collection that is already the latest collection content schema version.
        """
        # Create a new, collection that should not be affected by the
        # job.
        collection = collection_domain.Collection.create_default_collection(
            self.COLLECTION_ID, 'A title', 'A Category', 'An Objective')
        collection_services.save_new_collection(self.albert_id, collection)
        self.assertEqual(
            collection.schema_version,
            feconf.CURRENT_COLLECTION_SCHEMA_VERSION)
        yaml_before_migration = collection.to_yaml()

        # Start migration job.
        job_id = (
            collection_jobs_one_off.CollectionMigrationJob.create_new())
        collection_jobs_one_off.CollectionMigrationJob.enqueue(job_id)
        self.process_and_flush_pending_tasks()

        # Verify the collection is exactly the same after migration.
        updated_collection = (
            collection_services.get_collection_by_id(self.COLLECTION_ID))
        self.assertEqual(
            updated_collection.schema_version,
            feconf.CURRENT_COLLECTION_SCHEMA_VERSION)
        after_converted_yaml = updated_collection.to_yaml()
        self.assertEqual(after_converted_yaml, yaml_before_migration)
    def test_migration_job_skips_deleted_collection(self):
        """Tests that the collection migration job skips deleted collection
        and does not attempt to migrate.
        """
        collection = collection_domain.Collection.create_default_collection(
            self.COLLECTION_ID, 'A title', 'A Category', 'An Objective')
        collection_services.save_new_collection(self.albert_id, collection)

        # Note: This creates a summary based on the upgraded model (which is
        # fine). A summary is needed to delete the collection.
        collection_services.create_collection_summary(self.COLLECTION_ID, None)

        # Delete the exploration before migration occurs.
        collection_services.delete_collection(self.albert_id,
                                              self.COLLECTION_ID)

        # Ensure the exploration is deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            collection_services.get_collection_by_id(self.COLLECTION_ID)

        # Start migration job on sample collection.
        job_id = (collection_jobs_one_off.CollectionMigrationJob.create_new())
        collection_jobs_one_off.CollectionMigrationJob.enqueue(job_id)

        # This running without errors indicates the deleted collection is
        # being ignored.
        self.process_and_flush_pending_tasks()

        # Ensure the exploration is still deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            collection_services.get_collection_by_id(self.COLLECTION_ID)
Example #7
0
    def test_get_collection_rights(self):
        whitelisted_usernames = [self.OWNER_USERNAME]
        self.set_collection_editors(whitelisted_usernames)

        self.login(self.OWNER_EMAIL)

        collection_id = 'collection_id'
        collection = collection_domain.Collection.create_default_collection(
            collection_id,
            title='A title',
            category='A Category',
            objective='An Objective')
        collection_services.save_new_collection(self.owner_id, collection)

        # Check that collection is published correctly.
        rights_manager.publish_collection(self.owner, collection_id)

        json_response = self.get_json(
            '%s/%s' % (feconf.COLLECTION_RIGHTS_PREFIX, self.COLLECTION_ID))

        self.assertTrue(json_response['can_edit'])
        self.assertFalse(json_response['can_unpublish'])
        self.assertEqual(self.COLLECTION_ID, json_response['collection_id'])
        self.assertFalse(json_response['is_private'])
        self.logout()
Example #8
0
    def save_new_valid_collection(self,
                                  collection_id,
                                  owner_id,
                                  title='A title',
                                  category='A category',
                                  objective='An objective',
                                  language_code=feconf.DEFAULT_LANGUAGE_CODE,
                                  exploration_id='an_exploration_id',
                                  end_state_name=DEFAULT_END_STATE_NAME):
        collection = collection_domain.Collection.create_default_collection(
            collection_id,
            title,
            category,
            objective,
            language_code=language_code)
        collection.add_node(
            self.save_new_valid_exploration(exploration_id,
                                            owner_id,
                                            title,
                                            category,
                                            objective,
                                            end_state_name=end_state_name).id)

        collection_services.save_new_collection(owner_id, collection)
        return collection
    def test_migration_job_does_not_convert_up_to_date_collection(self):
        """Tests that the collection migration job does not convert an
        collection that is already the latest collection content schema version.
        """
        # Create a new, collection that should not be affected by the
        # job.
        collection = collection_domain.Collection.create_default_collection(
            self.COLLECTION_ID, 'A title', 'A Category', 'An Objective')
        collection_services.save_new_collection(self.albert_id, collection)
        self.assertEqual(collection.schema_version,
                         feconf.CURRENT_COLLECTION_SCHEMA_VERSION)
        yaml_before_migration = collection.to_yaml()

        # Start migration job.
        job_id = (collection_jobs_one_off.CollectionMigrationJob.create_new())
        collection_jobs_one_off.CollectionMigrationJob.enqueue(job_id)
        self.process_and_flush_pending_tasks()

        # Verify the collection is exactly the same after migration.
        updated_collection = (collection_services.get_collection_by_id(
            self.COLLECTION_ID))
        self.assertEqual(updated_collection.schema_version,
                         feconf.CURRENT_COLLECTION_SCHEMA_VERSION)
        after_converted_yaml = updated_collection.to_yaml()
        self.assertEqual(after_converted_yaml, yaml_before_migration)
Example #10
0
    def save_new_default_collection(
            self,
            collection_id,
            owner_id,
            title='A title',
            category='A category',
            objective='An objective',
            language_code=constants.DEFAULT_LANGUAGE_CODE):
        """Saves a new default collection written by owner_id.

        Args:
            collection_id: str. The id of the new default collection.
            owner_id: str. The user_id of the creator of the collection.
            title: str. The title of the collection.
            category: str. The category this collection belongs to.
            objective: str. The objective of this collection.
            language_code: str. The language_code of this collection.

        Returns:
            Collection. The collection domain object.
        """
        collection = collection_domain.Collection.create_default_collection(
            collection_id,
            title=title,
            category=category,
            objective=objective,
            language_code=language_code)
        collection_services.save_new_collection(owner_id, collection)
        return collection
    def test_collection_rights_handler(self):
        collection_id = 'collection_id'
        collection = collection_domain.Collection.create_default_collection(
            collection_id, title='A title',
            category='A Category', objective='An Objective')
        collection_services.save_new_collection(self.owner_id, collection)

        # Check that collection is published correctly.
        rights_manager.assign_role_for_collection(
            self.owner, collection_id, self.editor_id,
            rights_domain.ROLE_EDITOR)
        rights_manager.publish_collection(self.owner, collection_id)

        # Check that collection cannot be unpublished by non admin.
        with self.assertRaisesRegexp(
            Exception, 'This collection cannot be unpublished.'):
            rights_manager.unpublish_collection(self.owner, collection_id)
        collection_rights = rights_manager.get_collection_rights(collection_id)
        self.assertEqual(
            collection_rights.status,
            rights_domain.ACTIVITY_STATUS_PUBLIC)

        # Check that collection can be unpublished by admin.
        rights_manager.unpublish_collection(self.admin, collection_id)
        collection_rights = rights_manager.get_collection_rights(collection_id)
        self.assertEqual(
            collection_rights.status,
            rights_domain.ACTIVITY_STATUS_PRIVATE)
Example #12
0
    def test_migration_job_does_not_convert_up_to_date_collection(self):
        """Tests that the collection migration job does not convert an
        collection that is already the latest collection content schema version.
        """
        # Create a new collection that should not be affected by the
        # job.
        collection = collection_domain.Collection.create_default_collection(
            self.COLLECTION_ID,
            title='A title',
            category='A Category',
            objective='An Objective')
        collection_services.save_new_collection(self.albert_id, collection)
        self.assertEqual(collection.schema_version,
                         feconf.CURRENT_COLLECTION_SCHEMA_VERSION)
        yaml_before_migration = collection.to_yaml()

        # Start migration job.
        job_id = (
            collection_jobs_one_off.CollectionMigrationOneOffJob.create_new())
        collection_jobs_one_off.CollectionMigrationOneOffJob.enqueue(job_id)
        self.process_and_flush_pending_tasks()

        # Verify the collection is exactly the same after migration.
        updated_collection = (collection_services.get_collection_by_id(
            self.COLLECTION_ID))
        self.assertEqual(updated_collection.schema_version,
                         feconf.CURRENT_COLLECTION_SCHEMA_VERSION)
        after_converted_yaml = updated_collection.to_yaml()
        self.assertEqual(after_converted_yaml, yaml_before_migration)

        output = collection_jobs_one_off.CollectionMigrationOneOffJob.get_output(job_id)  # pylint: disable=line-too-long
        expected = [[
            u'collection_migrated', [u'1 collections successfully migrated.']
        ]]
        self.assertEqual(expected, [ast.literal_eval(x) for x in output])
Example #13
0
    def post(self):
        """Handles POST requests."""
        new_collection_id = collection_services.get_new_collection_id()
        collection = collection_domain.Collection.create_default_collection(
            new_collection_id)
        collection_services.save_new_collection(self.user_id, collection)

        self.render_json({COLLECTION_ID_KEY: new_collection_id})
Example #14
0
    def test_get_collection_count(self):
        collection = collection_domain.Collection.create_default_collection(
            'id', title='A title',
            category='A Category', objective='An Objective')
        collection_services.save_new_collection('id', collection)

        num_collections = (
            collection_models.CollectionModel.get_collection_count())
        self.assertEqual(num_collections, 1)
Example #15
0
    def test_get_collection_count(self) -> None:
        collection = collection_domain.Collection.create_default_collection( # type: ignore[no-untyped-call]
            'id', title='A title',
            category='A Category', objective='An Objective')
        collection_services.save_new_collection('id', collection) # type: ignore[no-untyped-call]

        num_collections = (
            collection_models.CollectionModel.get_collection_count())
        self.assertEqual(num_collections, 1)
Example #16
0
    def save_new_default_collection(
        self, collection_id, owner_id, title="A title", category="A category", objective="An objective"
    ):
        """Saves a new default collection written by owner_id.

        Returns the collection domain object.
        """
        collection = collection_domain.Collection.create_default_collection(collection_id, title, category, objective)
        collection_services.save_new_collection(owner_id, collection)
        return collection
Example #17
0
    def post(self):
        """Handles POST requests."""
        new_collection_id = collection_services.get_new_collection_id()
        collection = collection_domain.Collection.create_default_collection(
            new_collection_id)
        collection_services.save_new_collection(self.user_id, collection)

        self.render_json({
            COLLECTION_ID_KEY: new_collection_id
        })
Example #18
0
 def test_has_reference_to_user_id(self):
     collection = collection_domain.Collection.create_default_collection(
         'id', title='A title',
         category='A Category', objective='An Objective')
     collection_services.save_new_collection('committer_id', collection)
     self.assertTrue(
         collection_models.CollectionModel
         .has_reference_to_user_id('committer_id'))
     self.assertFalse(
         collection_models.CollectionModel
         .has_reference_to_user_id('x_id'))
Example #19
0
    def save_new_default_collection(
            self, collection_id, owner_id, title='A title',
            category='A category', objective='An objective'):
        """Saves a new default collection written by owner_id.

        Returns the collection domain object.
        """
        collection = collection_domain.Collection.create_default_collection(
            collection_id, title, category, objective)
        collection_services.save_new_collection(owner_id, collection)
        return collection
Example #20
0
 def test_reconstitute(self) -> None:
     collection = collection_domain.Collection.create_default_collection( # type: ignore[no-untyped-call]
         'id', title='A title',
         category='A Category', objective='An Objective')
     collection_services.save_new_collection('id', collection) # type: ignore[no-untyped-call]
     collection_model = collection_models.CollectionModel.get_by_id('id')
     snapshot_dict = collection_model.compute_snapshot()
     snapshot_dict['nodes'] = ['node0', 'node1']
     snapshot_dict = collection_model.convert_to_valid_dict(snapshot_dict)
     collection_model = collection_models.CollectionModel(**snapshot_dict)
     self.assertNotIn('nodes', collection_model._properties) # pylint: disable=protected-access
     self.assertNotIn('nodes', collection_model._values) # pylint: disable=protected-access
Example #21
0
    def save_new_default_collection(
            self, collection_id, owner_id, title='A title',
            category='A category', objective='An objective',
            language_code=feconf.DEFAULT_LANGUAGE_CODE):
        """Saves a new default collection written by owner_id.

        Returns the collection domain object.
        """
        collection = collection_domain.Collection.create_default_collection(
            collection_id, title=title, category=category, objective=objective,
            language_code=language_code)
        collection_services.save_new_collection(owner_id, collection)
        return collection
Example #22
0
    def save_new_valid_collection(
            self, collection_id, owner_id, title='A title',
            category='A category', objective='An objective',
            exploration_id='an_exploration_id',
            end_state_name=DEFAULT_END_STATE_NAME):
        collection = collection_domain.Collection.create_default_collection(
            collection_id, title, category, objective=objective)
        collection.add_node(
            self.save_new_valid_exploration(
                exploration_id, owner_id, title, category, objective,
                end_state_name=end_state_name).id)

        collection_services.save_new_collection(owner_id, collection)
        return collection
Example #23
0
    def save_new_valid_collection(
            self,
            collection_id,
            owner_id,
            title='A title',
            category='A category',
            objective='An objective',
            language_code=constants.DEFAULT_LANGUAGE_CODE,
            exploration_id='an_exploration_id',
            end_state_name=DEFAULT_END_STATE_NAME):
        """Creates an Oppia collection and adds a node saving the
        exploration details.

        Args:
            collection_id: str. ID for the collection to be created.
            owner_id: str. The user_id of the creator of the collection.
            title: str. Title for the collection.
            category: str. The category of the exploration.
            objective: str. Objective for the exploration.
            language_code: str. The language code for the exploration.
            exploration_id: str. The exploration_id for the Oppia exploration.
            end_state_name: str. The name of the end state for the exploration.

        Returns:
            Collection. A newly-created collection containing the corresponding
                exploration details.
        """
        collection = collection_domain.Collection.create_default_collection(
            collection_id,
            title,
            category,
            objective,
            language_code=language_code)

        # Check whether exploration with given exploration_id exists or not.
        exploration = exp_services.get_exploration_by_id(exploration_id,
                                                         strict=False)
        if exploration is None:
            exploration = self.save_new_valid_exploration(
                exploration_id,
                owner_id,
                title,
                category,
                objective,
                end_state_name=end_state_name)
        collection.add_node(exploration.id)

        collection_services.save_new_collection(owner_id, collection)
        return collection
Example #24
0
    def setUp(self):
        super(UserSubscriptionsModelValidatorTests, self).setUp()

        self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME)
        self.signup(USER_EMAIL, USER_NAME)

        self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL)
        self.user_id = self.get_user_id_from_email(USER_EMAIL)
        self.owner = user_services.UserActionsInfo(self.owner_id)

        explorations = [exp_domain.Exploration.create_default_exploration(
            '%s' % i,
            title='title %d' % i,
            category='category%d' % i
        ) for i in xrange(3)]

        for exp in explorations:
            exp_services.save_new_exploration(self.owner_id, exp)
            rights_manager.publish_exploration(self.owner, exp.id)

        collections = [collection_domain.Collection.create_default_collection(
            '%s' % i,
            title='title %d' % i,
            category='category%d' % i
        ) for i in xrange(3, 6)]

        for collection in collections:
            collection_services.save_new_collection(self.owner_id, collection)
            rights_manager.publish_collection(self.owner, collection.id)

        thread_id = feedback_services.create_thread(
            'exploration', 'exp_id', None, 'a subject', 'some text')

        subscription_services.subscribe_to_thread(
            self.user_id, thread_id)
        subscription_services.subscribe_to_creator(self.user_id, self.owner_id)
        for exp in explorations:
            subscription_services.subscribe_to_exploration(
                self.user_id, exp.id)
        for collection in collections:
            subscription_services.subscribe_to_collection(
                self.user_id, collection.id)
        self.process_and_flush_pending_tasks()

        prod_validation_jobs_one_off.MODEL_TO_VALIDATOR_MAPPING = {
            user_models.UserSubscriptionsModel:
                prod_validation_jobs_one_off.UserSubscriptionsModelValidator,
        }
Example #25
0
    def post(self):
        """Handles POST requests."""
        title = self.payload.get('title')
        category = self.payload.get('category')
        objective = self.payload.get('objective')
        # TODO(bhenning): Implement support for language codes in collections.

        if not title:
            raise self.InvalidInputException('No title supplied.')
        if not category:
            raise self.InvalidInputException('No category chosen.')

        new_collection_id = collection_services.get_new_collection_id()
        collection = collection_domain.Collection.create_default_collection(
            new_collection_id, title, category, objective=objective)
        collection_services.save_new_collection(self.user_id, collection)

        self.render_json({COLLECTION_ID_KEY: new_collection_id})
Example #26
0
    def test_migration_job_skips_deleted_collection(self):
        """Tests that the collection migration job skips deleted collection
        and does not attempt to migrate.
        """
        collection = collection_domain.Collection.create_default_collection(
            self.COLLECTION_ID,
            title='A title',
            category='A Category',
            objective='An Objective')
        collection_services.save_new_collection(self.albert_id, collection)

        # Note: This creates a summary based on the upgraded model (which is
        # fine). A summary is needed to delete the collection.
        collection_services.regenerate_collection_and_contributors_summaries(
            self.COLLECTION_ID)

        # Delete the exploration before migration occurs.
        collection_services.delete_collection(self.albert_id,
                                              self.COLLECTION_ID)

        # Ensure the exploration is deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            collection_services.get_collection_by_id(self.COLLECTION_ID)

        # Start migration job on sample collection.
        job_id = (
            collection_jobs_one_off.CollectionMigrationOneOffJob.create_new())
        collection_jobs_one_off.CollectionMigrationOneOffJob.enqueue(job_id)

        # This running without errors indicates the deleted collection is
        # being ignored.
        self.process_and_flush_pending_mapreduce_tasks()

        # Ensure the exploration is still deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            collection_services.get_collection_by_id(self.COLLECTION_ID)

        output = (collection_jobs_one_off.CollectionMigrationOneOffJob.
                  get_output(job_id))
        expected = [[
            u'collection_deleted', [u'Encountered 1 deleted collections.']
        ]]
        self.assertEqual(expected, [ast.literal_eval(x) for x in output])
Example #27
0
    def post(self):
        """Handles POST requests."""
        title = self.payload.get('title')
        category = self.payload.get('category')
        objective = self.payload.get('objective')
        # TODO(bhenning): Implement support for language codes in collections.

        if not title:
            raise self.InvalidInputException('No title supplied.')
        if not category:
            raise self.InvalidInputException('No category chosen.')

        new_collection_id = collection_services.get_new_collection_id()
        collection = collection_domain.Collection.create_default_collection(
            new_collection_id, title, category, objective=objective)
        collection_services.save_new_collection(self.user_id, collection)

        self.render_json({
            COLLECTION_ID_KEY: new_collection_id
        })
Example #28
0
    def save_new_default_collection(
            self,
            collection_id,
            owner_id,
            title='A title',
            category='A category',
            objective='An objective',
            language_code=feconf.DEFAULT_LANGUAGE_CODE):
        """Saves a new default collection written by owner_id.

        Returns the collection domain object.
        """
        collection = collection_domain.Collection.create_default_collection(
            collection_id,
            title=title,
            category=category,
            objective=objective,
            language_code=language_code)
        collection_services.save_new_collection(owner_id, collection)
        return collection
Example #29
0
    def test_get_collection_rights(self):
        whitelisted_usernames = [self.OWNER_USERNAME]
        self.set_config_property(
            config_domain.WHITELISTED_COLLECTION_EDITOR_USERNAMES,
            whitelisted_usernames)

        self.login(self.OWNER_EMAIL)

        collection_id = 'collection_id'
        collection = collection_domain.Collection.create_default_collection(
            collection_id, 'A title', 'A Category', 'An Objective')
        collection_services.save_new_collection(self.owner_id, collection)

        # Check that collection is published correctly.
        rights_manager.publish_collection(self.owner_id, collection_id)

        json_response = self.get_json(
            '%s/%s' % (feconf.COLLECTION_RIGHTS_PREFIX, self.COLLECTION_ID))

        self.assertTrue(json_response['can_edit'])
        self.assertFalse(json_response['can_unpublish'])
        self.assertEqual(self.COLLECTION_ID, json_response['collection_id'])
        self.assertFalse(json_response['is_private'])
        self.logout()