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