def put(self, collection_id): """Updates properties of the given collection.""" collection = collection_services.get_collection_by_id(collection_id) version = self.payload.get('version') self._require_valid_version(version, collection.version) commit_message = self.payload.get('commit_message') change_list = self.payload.get('change_list') try: collection_services.update_collection( self.user_id, collection_id, change_list, commit_message) except utils.ValidationError as e: raise self.InvalidInputException(e) collection_dict = ( summary_services.get_learner_collection_dict_by_id( collection_id, self.user_id, allow_invalid_explorations=True)) # Send the updated collection back to the frontend. self.values.update({ 'collection': collection_dict }) self.render_json(self.values)
def put(self, collection_id): """Updates properties of the given collection.""" collection = collection_services.get_collection_by_id(collection_id) version = self.payload.get('version') _require_valid_version(version, collection.version) commit_message = self.payload.get('commit_message') if (commit_message is not None and len(commit_message) > constants.MAX_COMMIT_MESSAGE_LENGTH): raise self.InvalidInputException( 'Commit messages must be at most %s characters long.' % constants.MAX_COMMIT_MESSAGE_LENGTH) change_list = self.payload.get('change_list') collection_services.update_collection(self.user_id, collection_id, change_list, commit_message) collection_dict = (summary_services.get_learner_collection_dict_by_id( collection_id, self.user, allow_invalid_explorations=True)) # Send the updated collection back to the frontend. self.values.update({'collection': collection_dict}) self.render_json(self.values)
def map(item): if item.deleted: yield (CollectionMigrationJob._DELETED_KEY, 'Encountered deleted collection.') return # Note: the read will bring the collection up to the newest version. collection = collection_services.get_collection_by_id(item.id) try: collection.validate(strict=False) except Exception as e: logging.error( 'Collection %s failed validation: %s' % (item.id, e)) yield (CollectionMigrationJob._ERROR_KEY, 'Collection %s failed validation: %s' % (item.id, e)) return # Write the new collection into the datastore if it's different from # the old version. if item.schema_version <= feconf.CURRENT_COLLECTION_SCHEMA_VERSION: commit_cmds = [{ 'cmd': collection_domain.CMD_MIGRATE_SCHEMA_TO_LATEST_VERSION, 'from_version': item.schema_version, 'to_version': str( feconf.CURRENT_COLLECTION_SCHEMA_VERSION) }] collection_services.update_collection( feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds, 'Update collection schema version to %d.' % ( feconf.CURRENT_COLLECTION_SCHEMA_VERSION)) yield (CollectionMigrationJob._MIGRATED_KEY, 'Collection successfully migrated.')
def test_basic_computation_with_an_update_after_collection_is_created(self): with self._get_test_context(): self.save_new_default_collection( COLLECTION_ID, USER_ID, title=COLLECTION_TITLE) # Another user makes a commit; this, too, shows up in the # original user's dashboard. collection_services.update_collection( ANOTHER_USER_ID, COLLECTION_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'A new title' }], 'Update collection') expected_last_updated_ms = ( self._get_most_recent_collection_snapshot_created_on_ms( COLLECTION_ID)) ModifiedRecentUpdatesAggregator.start_computation() self.assertEqual( self.count_jobs_in_taskqueue( queue_name=taskqueue_services.QUEUE_NAME_DEFAULT), 1) self.process_and_flush_pending_tasks() recent_notifications = ( ModifiedRecentUpdatesAggregator.get_recent_notifications( USER_ID)[1]) self.assertEqual([{ 'type': feconf.UPDATE_TYPE_COLLECTION_COMMIT, 'last_updated_ms': expected_last_updated_ms, 'activity_id': COLLECTION_ID, 'activity_title': 'A new title', 'author_id': ANOTHER_USER_ID, 'subject': 'Update collection', }], recent_notifications)
def map(item): if item.deleted: yield (CollectionMigrationJob._DELETED_KEY, 'Encountered deleted collection.') return # Note: the read will bring the collection up to the newest version. collection = collection_services.get_collection_by_id(item.id) try: collection.validate(strict=False) except Exception as e: logging.error('Collection %s failed validation: %s' % (item.id, e)) yield (CollectionMigrationJob._ERROR_KEY, 'Collection %s failed validation: %s' % (item.id, e)) return # Write the new collection into the datastore if it's different from # the old version. if item.schema_version <= feconf.CURRENT_COLLECTION_SCHEMA_VERSION: commit_cmds = [{ 'cmd': collection_domain.CMD_MIGRATE_SCHEMA_TO_LATEST_VERSION, 'from_version': item.schema_version, 'to_version': str(feconf.CURRENT_COLLECTION_SCHEMA_VERSION) }] collection_services.update_collection( feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds, 'Update collection schema version to %d.' % (feconf.CURRENT_COLLECTION_SCHEMA_VERSION)) yield (CollectionMigrationJob._MIGRATED_KEY, 'Collection successfully migrated.')
def test_contribution_msec_updates_on_published_collections(self): self.save_new_valid_collection( self.COL_ID, self.admin_id, title=self.COLLECTION_TITLE, category=self.COLLECTION_CATEGORY, objective=self.COLLECTION_OBJECTIVE, exploration_id=self.EXP_ID) collection_services.publish_collection_and_update_user_profiles( self.admin_id, self.COL_ID) exp_services.publish_exploration_and_update_user_profiles( self.admin_id, self.EXP_ID) # Test all owners and editors of collection after publication have # updated first contribution times. self.assertIsNotNone(user_services.get_user_settings( self.admin_id).first_contribution_msec) # Test editor of published collection has updated # first contribution time. rights_manager.release_ownership_of_collection( self.admin_id, self.COL_ID) collection_services.update_collection( self.editor_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'Some new title' }], 'Changed the title') self.assertIsNotNone(user_services.get_user_settings( self.editor_id).first_contribution_msec)
def test_basic_computation_with_an_update_after_collection_is_created( self): with self._get_test_context(): self.save_new_default_collection(COLLECTION_ID, USER_ID, title=COLLECTION_TITLE) # Another user makes a commit; this, too, shows up in the # original user's dashboard. collection_services.update_collection( ANOTHER_USER_ID, COLLECTION_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'A new title' }], 'Update collection') expected_last_updated_ms = ( self._get_most_recent_collection_snapshot_created_on_ms( COLLECTION_ID)) ModifiedRecentUpdatesAggregator.start_computation() self.assertEqual( self.count_jobs_in_taskqueue( queue_name=taskqueue_services.QUEUE_NAME_DEFAULT), 1) self.process_and_flush_pending_tasks() recent_notifications = (ModifiedRecentUpdatesAggregator. get_recent_notifications(USER_ID)[1]) self.assertEqual([{ 'type': feconf.UPDATE_TYPE_COLLECTION_COMMIT, 'last_updated_ms': expected_last_updated_ms, 'activity_id': COLLECTION_ID, 'activity_title': 'A new title', 'author_id': ANOTHER_USER_ID, 'subject': 'Update collection', }], recent_notifications)
def test_adding_exploration_to_collection_does_not_create_subscription( self): self.save_new_default_collection(COLLECTION_ID, self.owner_id) # The author is subscribed to the collection but to no explorations. self.assertEqual( self._get_collection_ids_subscribed_to(self.owner_id), [COLLECTION_ID]) self.assertEqual( self._get_exploration_ids_subscribed_to(self.owner_id), []) # Another author creates an exploration. self.save_new_valid_exploration(EXP_ID, self.owner_2_id) # If the collection author adds the exploration to his/her collection, # the collection author should not be subscribed to the exploration nor # should the exploration author be subscribed to the collection. collection_services.update_collection(self.owner_id, COLLECTION_ID, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': EXP_ID }], 'Add new exploration to collection.') # Ensure subscriptions are as expected. self.assertEqual( self._get_collection_ids_subscribed_to(self.owner_id), [COLLECTION_ID]) self.assertEqual( self._get_exploration_ids_subscribed_to(self.owner_2_id), [EXP_ID])
def map(item): if item.deleted: yield (CollectionMigrationOneOffJob._DELETED_KEY, 1) return # Note: the read will bring the collection up to the newest version. collection = collection_services.get_collection_by_id(item.id) try: collection.validate(strict=False) except Exception as e: logging.exception( 'Collection %s failed validation: %s' % (item.id, e)) yield ( CollectionMigrationOneOffJob._ERROR_KEY, 'Collection %s failed validation: %s' % (item.id, e)) return # Write the new collection into the datastore if it's different from # the old version. # # Note: to_version really should be int, but left as str to conform # with legacy data. if item.schema_version <= feconf.CURRENT_COLLECTION_SCHEMA_VERSION: commit_cmds = [{ 'cmd': collection_domain.CMD_MIGRATE_SCHEMA_TO_LATEST_VERSION, 'from_version': item.schema_version, 'to_version': python_utils.UNICODE( feconf.CURRENT_COLLECTION_SCHEMA_VERSION) }] collection_services.update_collection( feconf.MIGRATION_BOT_USERNAME, item.id, commit_cmds, 'Update collection schema version to %d.' % ( feconf.CURRENT_COLLECTION_SCHEMA_VERSION)) yield (CollectionMigrationOneOffJob._MIGRATED_KEY, 1)
def test_contribution_msec_updates_on_published_collections(self): self.save_new_valid_collection(self.COL_ID, self.admin_id, title=self.COLLECTION_TITLE, category=self.COLLECTION_CATEGORY, objective=self.COLLECTION_OBJECTIVE, exploration_id=self.EXP_ID) collection_services.publish_collection_and_update_user_profiles( self.admin_id, self.COL_ID) exp_services.publish_exploration_and_update_user_profiles( self.admin_id, self.EXP_ID) # Test all owners and editors of collection after publication have # updated first contribution times. self.assertIsNotNone( user_services.get_user_settings( self.admin_id).first_contribution_msec) # Test editor of published collection has updated # first contribution time. rights_manager.release_ownership_of_collection(self.admin_id, self.COL_ID) collection_services.update_collection( self.editor_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'Some new title' }], 'Changed the title') self.assertIsNotNone( user_services.get_user_settings( self.editor_id).first_contribution_msec)
def setUp(self): super(QuestionsBatchHandlerTest, self).setUp() self.collection_id = 'coll_0' self.exp_id = 'exp_1' self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL) # Create a new collection and exploration. self.save_new_valid_collection(self.collection_id, self.owner_id, exploration_id=self.exp_id) # Add a skill. collection_services.update_collection( self.owner_id, self.collection_id, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_SKILL, 'name': 'test' }], 'Add a new skill') collection = collection_services.get_collection_by_id( self.collection_id) self.skill_id = collection.get_skill_id_from_skill_name('test') collection_node = collection.get_node(self.exp_id) collection_node.update_acquired_skill_ids([self.skill_id]) # Update the acquired skill IDs for the exploration. collection_services.update_collection( self.owner_id, self.collection_id, [{ 'cmd': collection_domain.CMD_EDIT_COLLECTION_NODE_PROPERTY, 'property_name': (collection_domain.COLLECTION_NODE_PROPERTY_ACQUIRED_SKILL_IDS ), # pylint: disable=line-too-long 'exploration_id': self.exp_id, 'new_value': [self.skill_id] }], 'Update skill') question = question_domain.Question( 'dummy', 'A Question', exp_domain.State.create_default_state('ABC').to_dict(), 1, self.collection_id, 'en') question_id = question_services.add_question(self.owner_id, question) self.question = question_services.get_question_by_id(question_id) question_services.add_question_id_to_skill(self.question.question_id, self.question.collection_id, self.skill_id, self.owner_id) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) collection_services.record_played_exploration_in_collection_context( self.new_user_id, self.collection_id, self.exp_id) self.payload = {}
def test_contribution_msec_does_not_update_until_collection_is_published( self): self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) collection = self.save_new_valid_collection( self.COL_ID, self.admin_id, title=self.COLLECTION_TITLE, category=self.COLLECTION_CATEGORY, objective=self.COLLECTION_OBJECTIVE, exploration_id=self.EXP_ID) # Test that saving a collection does not update first contribution # time. self.assertIsNone( user_services.get_user_settings( self.admin_id).first_contribution_msec) # Test that commit to unpublished collection does not update # contribution time. collection_services.update_collection( self.admin_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'Some new title' }], '') self.assertIsNone( user_services.get_user_settings( self.admin_id).first_contribution_msec) # Test that another user who commits to unpublished collection does not # have updated first contribution time. self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME) self.editor_id = self.get_user_id_from_email(self.EDITOR_EMAIL) rights_manager.assign_role_for_collection(self.admin_id, self.COL_ID, self.editor_id, 'editor') collection_services.update_collection( self.editor_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'category', 'new_value': 'Some new category' }], '') self.assertIsNone( user_services.get_user_settings( self.editor_id).first_contribution_msec) # Test that after an collection is published, all contributors have # updated first contribution times. collection_services.publish_collection_and_update_user_profiles( self.admin_id, self.COL_ID) self.assertIsNotNone( user_services.get_user_settings( self.admin_id).first_contribution_msec) self.assertIsNotNone( user_services.get_user_settings( self.editor_id).first_contribution_msec)
def setUp(self): super(LearnerProgressTest, self).setUp() self.signup(self.USER_EMAIL, self.USER_USERNAME) self.user_id = self.get_user_id_from_email(self.USER_EMAIL) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) # Save and publish explorations. self.save_new_valid_exploration( self.EXP_ID_0, self.owner_id, title='Bridges in England', category='Architecture', language_code='en') self.save_new_valid_exploration( self.EXP_ID_1, self.owner_id, title='Welcome to Gadgets', category='Architecture', language_code='fi') self.save_new_valid_exploration( self.EXP_ID_1_0, self.owner_id, title='Sillat Suomi', category='Architecture', language_code='fi') self.save_new_valid_exploration( self.EXP_ID_1_1, self.owner_id, title='Introduce Interactions in Oppia', category='Welcome', language_code='en') rights_manager.publish_exploration(self.owner_id, self.EXP_ID_0) rights_manager.publish_exploration(self.owner_id, self.EXP_ID_1) rights_manager.publish_exploration(self.owner_id, self.EXP_ID_1_0) rights_manager.publish_exploration(self.owner_id, self.EXP_ID_1_1) # Save a new collection. self.save_new_default_collection( self.COL_ID_0, self.owner_id, title='Welcome', category='Architecture') self.save_new_default_collection( self.COL_ID_1, self.owner_id, title='Bridges in England', category='Architecture') # Add two explorations to the previously saved collection and publish # it. for exp_id in [self.EXP_ID_1_0, self.EXP_ID_1_1]: collection_services.update_collection( self.owner_id, self.COL_ID_1, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': exp_id }], 'Added new exploration') # Publish the collections. rights_manager.publish_collection(self.owner_id, self.COL_ID_0) rights_manager.publish_collection(self.owner_id, self.COL_ID_1)
def test_get_question_batch(self): coll_id_0 = '0_collection_id' exp_id_0 = '0_exploration_id' self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) # Create a new collection and exploration. self.save_new_valid_collection(coll_id_0, self.owner_id, exploration_id=exp_id_0) # Add a skill. collection_services.update_collection( self.owner_id, coll_id_0, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_SKILL, 'name': 'skill0' }], 'Add a new skill') collection = collection_services.get_collection_by_id(coll_id_0) skill_id = collection.get_skill_id_from_skill_name('skill0') collection_node = collection.get_node(exp_id_0) collection_node.update_acquired_skill_ids([skill_id]) # Update the acquired skill IDs for the exploration. collection_services.update_collection( self.owner_id, coll_id_0, [{ 'cmd': collection_domain.CMD_EDIT_COLLECTION_NODE_PROPERTY, 'property_name': (collection_domain.COLLECTION_NODE_PROPERTY_ACQUIRED_SKILL_IDS ), # pylint: disable=line-too-long 'exploration_id': exp_id_0, 'new_value': [skill_id] }], 'Update skill') question = question_domain.Question( 'dummy', 'A Question', exp_domain.State.create_default_state('ABC').to_dict(), 1, coll_id_0, 'en') question_id = question_services.add_question(self.owner_id, question) question = question_services.get_question_by_id(question_id) question_services.add_question_id_to_skill(question.question_id, coll_id_0, skill_id, self.owner_id) collection_services.record_played_exploration_in_collection_context( self.owner_id, coll_id_0, exp_id_0) question_batch = question_services.get_questions_batch( coll_id_0, [skill_id], self.owner_id, 1) self.assertEqual(question_batch[0].title, question.title)
def test_contribution_msec_does_not_update_until_collection_is_published(self): self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) collection = self.save_new_valid_collection( self.COL_ID, self.admin_id, title=self.COLLECTION_TITLE, category=self.COLLECTION_CATEGORY, objective=self.COLLECTION_OBJECTIVE, exploration_id=self.EXP_ID) # Test that saving a collection does not update first contribution # time. self.assertIsNone(user_services.get_user_settings( self.admin_id).first_contribution_msec) # Test that commit to unpublished collection does not update # contribution time. collection_services.update_collection( self.admin_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'Some new title' }], '') self.assertIsNone(user_services.get_user_settings( self.admin_id).first_contribution_msec) # Test that another user who commits to unpublished collection does not # have updated first contribution time. self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME) self.editor_id = self.get_user_id_from_email(self.EDITOR_EMAIL) rights_manager.assign_role_for_collection( self.admin_id, self.COL_ID, self.editor_id, 'editor') collection_services.update_collection( self.editor_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'category', 'new_value': 'Some new category' }], '') self.assertIsNone(user_services.get_user_settings( self.editor_id).first_contribution_msec) # Test that after an collection is published, all contributors have # updated first contribution times. collection_services.publish_collection_and_update_user_profiles( self.admin_id, self.COL_ID) self.assertIsNotNone(user_services.get_user_settings( self.admin_id).first_contribution_msec) self.assertIsNotNone(user_services.get_user_settings( self.editor_id).first_contribution_msec)
def test_contributors_for_valid_nonrevert_contribution(self): # Let USER A make three commits. exploration = self.save_new_valid_exploration(self.EXP_ID, self.user_a_id) collection = self.save_new_valid_collection(self.COL_ID, self.user_a_id) exp_services.update_exploration(self.user_a_id, self.EXP_ID, [ exp_domain.ExplorationChange({ 'cmd': 'edit_exploration_property', 'property_name': 'title', 'new_value': 'New Exploration Title' }) ], 'Changed title.') exp_services.update_exploration(self.user_a_id, self.EXP_ID, [ exp_domain.ExplorationChange({ 'cmd': 'edit_exploration_property', 'property_name': 'objective', 'new_value': 'New Objective' }) ], 'Changed Objective.') collection_services.update_collection( self.user_a_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'New Exploration Title' }], 'Changed title.') collection_services.update_collection( self.user_a_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'objective', 'new_value': 'New Objective' }], 'Changed Objective.') output = self._run_one_off_job() self.assertEqual([['SUCCESS', 3]], output) exploration_summary = exp_fetchers.get_exploration_summary_by_id( exploration.id) self.assertEqual([self.user_a_id], exploration_summary.contributor_ids) self.assertEqual({self.user_a_id: 3}, exploration_summary.contributors_summary) collection_summary = collection_services.get_collection_summary_by_id( collection.id) self.assertEqual([self.user_a_id], collection_summary.contributor_ids) self.assertEqual({self.user_a_id: 3}, collection_summary.contributors_summary)
def add_question_id_to_skill(question_id, collection_id, skill_id, user_id): """Adds the question id to the question list of the appropriate skill. Args: question_id: str. The id of the question. collection_id: str. The id of the collection. skill_id: str. The id of the skill. user_id: str. The id of the user. """ collection_services.update_collection( user_id, collection_id, [{ 'cmd': collection_domain.CMD_ADD_QUESTION_ID_TO_SKILL, 'skill_id': skill_id, 'question_id': question_id }], 'Add a new question with ID %s to skill with ID %s' % (question_id, skill_id))
def remove_question_id_from_skill(question_id, collection_id, skill_id, user_id): """Removes the question id from the question list of the appropriate skill. Args: skill_id: str. The id of the skill. user_id: str. The id of the user. """ collection_services.update_collection( user_id, collection_id, [{ 'cmd': collection_domain.CMD_REMOVE_QUESTION_ID_FROM_SKILL, 'skill_id': skill_id, 'question_id': question_id }], 'Remove a question with ID %s from skill with ID: %s' % (question_id, skill_id))
def test_remove_question_id_from_skill(self): """Tests to verify remove_question_id_from_skill method.""" collection_id = 'col1' exp_id = '0_exploration_id' owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) # Create a new collection and exploration. self.save_new_valid_collection(collection_id, owner_id, exploration_id=exp_id) # Add a skill. collection_services.update_collection( owner_id, collection_id, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_SKILL, 'name': 'skill0' }], 'Add a new skill') state = exp_domain.State.create_default_state('ABC') question_data = state.to_dict() question_dict = { 'question_id': 'col1.random', 'title': 'abc', 'question_data': question_data, 'question_data_schema_version': 1, 'collection_id': 'col1', 'language_code': 'en' } collection = collection_services.get_collection_by_id(collection_id) skill_id = collection.get_skill_id_from_skill_name('skill0') question = question_domain.Question.from_dict(question_dict) question_services.add_question_id_to_skill(question.question_id, collection_id, skill_id, owner_id) collection = collection_services.get_collection_by_id(collection_id) self.assertIn(question.question_id, collection.skills[skill_id].question_ids) skill_id = collection.get_skill_id_from_skill_name('skill0') question_services.remove_question_id_from_skill( question.question_id, collection_id, skill_id, owner_id) collection = collection_services.get_collection_by_id(collection_id) self.assertEqual(len(collection.skills[skill_id].question_ids), 0)
def test_adding_exploration_to_collection(self): with self.swap( subscription_services, 'subscribe_to_thread', self._null_fn ), self.swap( subscription_services, 'subscribe_to_collection', self._null_fn ): # User B creates and saves a new collection. self.save_new_default_collection( self.COLLECTION_ID_1, self.user_b_id) # User B adds the exploration created by user A to the collection. collection_services.update_collection( self.user_b_id, self.COLLECTION_ID_1, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': self.EXP_ID_1 }], 'Add new exploration to collection.') # Users A and B have no subscriptions (to either explorations or # collections). user_a_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_a_id, strict=False) user_b_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_b_id, strict=False) self.assertEqual(user_a_subscriptions_model, None) self.assertEqual(user_b_subscriptions_model, None) self._run_one_off_job() user_a_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_a_id) user_b_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_b_id) # User B should be subscribed to the collection and user A to the # exploration. self.assertEqual( user_a_subscriptions_model.activity_ids, [self.EXP_ID_1]) self.assertEqual( user_a_subscriptions_model.collection_ids, []) self.assertEqual( user_b_subscriptions_model.activity_ids, []) self.assertEqual( user_b_subscriptions_model.collection_ids, [self.COLLECTION_ID_1])
def test_nonhuman_committers_not_counted(self): # Create a commit with the system user id. exploration = self.save_new_valid_exploration( self.EXP_ID, feconf.SYSTEM_COMMITTER_ID, title='Original Title') collection = self.save_new_valid_collection(self.COL_ID, self.user_a_id) # Create commits with all the system user ids. for system_id in constants.SYSTEM_USER_IDS: exp_services.update_exploration( system_id, self.EXP_ID, [exp_domain.ExplorationChange({ 'cmd': 'edit_exploration_property', 'property_name': 'title', 'new_value': 'Title changed by %s' % system_id })], 'Changed title.') collection_services.update_collection( system_id, self.COL_ID, [{ 'cmd': 'edit_collection_property', 'property_name': 'title', 'new_value': 'New Exploration Title' }], 'Changed title.') output = self._run_one_off_job() self.assertEqual([['SUCCESS', 3]], output) # Check that no system id was added to the exploration's # contributor's summary. exploration_summary = exp_fetchers.get_exploration_summary_by_id( exploration.id) collection_summary = collection_services.get_collection_summary_by_id( collection.id) for system_id in constants.SYSTEM_USER_IDS: self.assertNotIn( system_id, exploration_summary.contributors_summary) self.assertNotIn( system_id, exploration_summary.contributor_ids) self.assertNotIn( system_id, collection_summary.contributors_summary) self.assertNotIn( system_id, collection_summary.contributor_ids)
def test_adding_exploration_to_collection(self): with self.swap( subscription_services, 'subscribe_to_thread', self._null_fn ), self.swap( subscription_services, 'subscribe_to_collection', self._null_fn): # User B creates and saves a new collection. self.save_new_default_collection( self.COLLECTION_ID_1, self.user_b_id) # User B adds the exploration created by user A to the collection. collection_services.update_collection( self.user_b_id, self.COLLECTION_ID_1, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': self.EXP_ID_1 }], 'Add new exploration to collection.') # Users A and B have no subscriptions (to either explorations or # collections). user_a_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_a_id, strict=False) user_b_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_b_id, strict=False) self.assertEqual(user_a_subscriptions_model, None) self.assertEqual(user_b_subscriptions_model, None) self._run_one_off_job() user_a_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_a_id) user_b_subscriptions_model = user_models.UserSubscriptionsModel.get( self.user_b_id) # User B should be subscribed to the collection and user A to the # exploration. self.assertEqual( user_a_subscriptions_model.activity_ids, [self.EXP_ID_1]) self.assertEqual( user_a_subscriptions_model.collection_ids, []) self.assertEqual( user_b_subscriptions_model.activity_ids, []) self.assertEqual( user_b_subscriptions_model.collection_ids, [self.COLLECTION_ID_1])
def put(self, collection_id): """Updates properties of the given collection.""" collection = collection_services.get_collection_by_id(collection_id) version = self.normalized_payload.get('version') _require_valid_version(version, collection.version) commit_message = self.normalized_payload.get('commit_message') change_list = self.normalized_payload.get('change_list') collection_services.update_collection( self.user_id, collection_id, [change.to_dict() for change in change_list], commit_message) collection_dict = (summary_services.get_learner_collection_dict_by_id( collection_id, self.user, allow_invalid_explorations=True)) # Send the updated collection back to the frontend. self.values.update({'collection': collection_dict}) self.render_json(self.values)
def test_get_learner_dict_when_referencing_inaccessible_explorations(self): self.save_new_default_collection(self.COLLECTION_ID, self.owner_id) self.save_new_valid_exploration(self.EXP_ID, self.editor_id) collection_services.update_collection( self.owner_id, self.COLLECTION_ID, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': self.EXP_ID }], 'Added another creator\'s private exploration') # A collection cannot access someone else's private exploration. rights_manager.publish_collection(self.owner, self.COLLECTION_ID) with self.assertRaisesRegex( utils.ValidationError, 'Expected collection to only reference valid explorations, but ' 'found an exploration with ID: exploration_id'): summary_services.get_learner_collection_dict_by_id( self.COLLECTION_ID, self.owner) # After the exploration is published, the dict can now be created. rights_manager.publish_exploration(self.editor, self.EXP_ID) summary_services.get_learner_collection_dict_by_id( self.COLLECTION_ID, self.owner)
def test_get_learner_dict_when_referencing_inaccessible_explorations(self): self.save_new_default_collection(self.COLLECTION_ID, self.owner_id) self.save_new_valid_exploration(self.EXP_ID, self.editor_id) collection_services.update_collection( self.owner_id, self.COLLECTION_ID, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': self.EXP_ID }], 'Added another creator\'s private exploration') # A collection cannot access someone else's private exploration. rights_manager.publish_collection(self.owner_id, self.COLLECTION_ID) with self.assertRaisesRegexp( utils.ValidationError, 'Expected collection to only reference valid explorations, but ' 'found an exploration with ID: exploration_id'): summary_services.get_learner_collection_dict_by_id( self.COLLECTION_ID, self.owner_id) # After the exploration is published, the dict can now be created. rights_manager.publish_exploration(self.editor_id, self.EXP_ID) summary_services.get_learner_collection_dict_by_id( self.COLLECTION_ID, self.owner_id)
def test_get_learner_dict_with_allowed_private_exps(self): self.save_new_valid_collection( self.COLLECTION_ID, self.owner_id, exploration_id=self.EXP_ID) self.save_new_valid_exploration(self.EXP_ID_1, self.editor_id) collection_services.update_collection( self.owner_id, self.COLLECTION_ID, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': self.EXP_ID_1 }], 'Added another creator\'s private exploration') rights_manager.publish_collection(self.owner_id, self.COLLECTION_ID) collection_dict = summary_services.get_learner_collection_dict_by_id( self.COLLECTION_ID, self.owner_id, allow_invalid_explorations=True) # The author's private exploration will be contained in the public # collection since invalid explorations are being allowed, but the # private exploration of another author will not. collection_node_dicts = collection_dict['nodes'] self.assertEqual( collection_node_dicts[0]['exploration_summary']['id'], self.EXP_ID) self.assertIsNone(collection_node_dicts[1]['exploration_summary'])
def test_get_learner_dict_with_allowed_private_exps(self): self.save_new_valid_collection(self.COLLECTION_ID, self.owner_id, exploration_id=self.EXP_ID) self.save_new_valid_exploration(self.EXP_ID_1, self.editor_id) collection_services.update_collection( self.owner_id, self.COLLECTION_ID, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': self.EXP_ID_1 }], 'Added another creator\'s private exploration') rights_manager.publish_collection(self.owner, self.COLLECTION_ID) collection_dict = summary_services.get_learner_collection_dict_by_id( self.COLLECTION_ID, self.owner, allow_invalid_explorations=True) # The author's private exploration will be contained in the public # collection since invalid explorations are being allowed, but the # private exploration of another author will not. collection_node_dicts = collection_dict['nodes'] self.assertEqual(collection_node_dicts[0]['exploration_summary']['id'], self.EXP_ID) self.assertIsNone(collection_node_dicts[1]['exploration_summary'])
def test_delete_question(self): collection_id = 'col1' exp_id = '0_exploration_id' owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) # Create a new collection and exploration. self.save_new_valid_collection(collection_id, owner_id, exploration_id=exp_id) # Add a skill. collection_services.update_collection( owner_id, collection_id, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_SKILL, 'name': 'skill0' }], 'Add a new skill') question = question_domain.Question( 'dummy', 'A Question', exp_domain.State.create_default_state('ABC').to_dict(), 1, collection_id, 'en') question_id = question_services.add_question(self.owner_id, question) with self.assertRaisesRegexp( Exception, ('The question with ID %s is not present' ' in the given collection' % question_id)): question_services.delete_question(self.owner_id, 'random', question_id) question_services.delete_question(self.owner_id, collection_id, question_id) with self.assertRaisesRegexp( Exception, ('Entity for class QuestionModel with id %s not found' % (question_id))): question_models.QuestionModel.get(question_id)
def test_get_activity_progress(self): # Add activities to the completed section. learner_progress_services.mark_exploration_as_completed( self.user_id, self.EXP_ID_0) learner_progress_services.mark_collection_as_completed( self.user_id, self.COL_ID_0) # Add activities to the incomplete section. state_name = 'state name' version = 1 learner_progress_services.mark_exploration_as_incomplete( self.user_id, self.EXP_ID_1, state_name, version) learner_progress_services.mark_collection_as_incomplete( self.user_id, self.COL_ID_1) # Add activities to the playlist section. learner_progress_services.add_exp_to_learner_playlist( self.user_id, self.EXP_ID_3) learner_progress_services.add_collection_to_learner_playlist( self.user_id, self.COL_ID_3) # Get the progress of the user. activity_progress = learner_progress_services.get_activity_progress( self.user_id) incomplete_exp_summaries = ( activity_progress[0].incomplete_exp_summaries) incomplete_collection_summaries = ( activity_progress[0].incomplete_collection_summaries) completed_exp_summaries = ( activity_progress[0].completed_exp_summaries) completed_collection_summaries = ( activity_progress[0].completed_collection_summaries) exploration_playlist_summaries = ( activity_progress[0].exploration_playlist_summaries) collection_playlist_summaries = ( activity_progress[0].collection_playlist_summaries) self.assertEqual(len(incomplete_exp_summaries), 1) self.assertEqual(len(incomplete_collection_summaries), 1) self.assertEqual(len(completed_exp_summaries), 1) self.assertEqual(len(completed_collection_summaries), 1) self.assertEqual(len(exploration_playlist_summaries), 1) self.assertEqual(len(collection_playlist_summaries), 1) self.assertEqual(incomplete_exp_summaries[0].title, 'Sillat Suomi') self.assertEqual(incomplete_collection_summaries[0].title, 'Introduce Oppia') self.assertEqual(completed_exp_summaries[0].title, 'Bridges in England') self.assertEqual(completed_collection_summaries[0].title, 'Bridges') self.assertEqual(exploration_playlist_summaries[0].title, 'Welcome Oppia') self.assertEqual(collection_playlist_summaries[0].title, 'Welcome Oppia Collection') # Delete an exploration in the completed section. exp_services.delete_exploration(self.owner_id, self.EXP_ID_0) # Delete an exploration in the incomplete section. exp_services.delete_exploration(self.owner_id, self.EXP_ID_1) # Delete an exploration in the playlist section. exp_services.delete_exploration(self.owner_id, self.EXP_ID_3) # Add an exploration to a collection that has already been completed. collection_services.update_collection( self.owner_id, self.COL_ID_0, [{ 'cmd': collection_domain.CMD_ADD_COLLECTION_NODE, 'exploration_id': self.EXP_ID_2 }], 'Add new exploration') # Get the progress of the user. activity_progress = learner_progress_services.get_activity_progress( self.user_id) # Check that the exploration is no longer present in the incomplete # section. self.assertEqual(len(activity_progress[0].incomplete_exp_summaries), 0) # Check that the dashboard records the exploration deleted in the # completed section. self.assertEqual(activity_progress[1]['completed_explorations'], 1) # Check that the dashboard records the exploration deleted in the # incomplete section. self.assertEqual(activity_progress[1]['incomplete_explorations'], 1) # Check that the dashboard records the exploration deleted in the # playlist section. self.assertEqual(activity_progress[1]['exploration_playlist'], 1) incomplete_collection_summaries = ( activity_progress[0].incomplete_collection_summaries) # Check that the collection to which a new exploration has been added # has been moved to the incomplete section. self.assertEqual(len(incomplete_collection_summaries), 2) self.assertEqual(incomplete_collection_summaries[1].title, 'Bridges') # Check that the dashboard has recorded the change in the collection. self.assertEqual(activity_progress[2], ['Bridges']) # Now suppose the user has completed the collection. It should be added # back to the completed section. learner_progress_services.mark_collection_as_completed( self.user_id, self.COL_ID_0) # Delete a collection in the completed section. collection_services.delete_collection(self.owner_id, self.COL_ID_0) # Delete a collection in the incomplete section. collection_services.delete_collection(self.owner_id, self.COL_ID_1) # Delete a collection in the playlist section. collection_services.delete_collection(self.owner_id, self.COL_ID_3) # Get the progress of the user. activity_progress = learner_progress_services.get_activity_progress( self.user_id) # Check that the dashboard records the collection deleted in the # completed section. self.assertEqual(activity_progress[1]['completed_collections'], 1) # Check that the dashboard records the collection deleted in the # incomplete section. self.assertEqual(activity_progress[1]['incomplete_collections'], 1) # Check that the dashboard records the collection deleted in the # playlist section. self.assertEqual(activity_progress[1]['collection_playlist'], 1)