def setUp(self): """Load a demo exploration and register self.EDITOR_EMAIL.""" super(AssetDevHandlerImageTests, self).setUp() exp_services.delete_demo('0') self.system_user = user_services.get_system_user() exp_services.load_demo('0') rights_manager.release_ownership_of_exploration(self.system_user, '0') self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME)
def reduce(exp_id, list_of_exps): """Saves and publishes the newly created copy of the existing exploration. Args: exp_id: str. The exploration id. list_of_exps: list(str). The list containing newly-created exploration copies in the YAML representation. """ for stringified_exp in list_of_exps: exploration = exp_domain.Exploration.from_untitled_yaml( exp_id, 'Copy', 'Copies', stringified_exp) exp_services.save_new_exploration(feconf.SYSTEM_COMMITTER_ID, exploration) system_user = user_services.get_system_user() rights_manager.publish_exploration(system_user, exp_id)
def test_get_item_similarity(self): exp_summaries = exp_services.get_all_exploration_summaries() self.assertEqual( recommendations_services.get_item_similarity( exp_summaries['exp_id_1'], exp_summaries['exp_id_2']), 4.5) self.assertEqual( recommendations_services.get_item_similarity( exp_summaries['exp_id_4'], exp_summaries['exp_id_4']), 9.0) system_user = user_services.get_system_user() rights_manager.unpublish_exploration(system_user, 'exp_id_2') exp_summaries = exp_services.get_all_exploration_summaries() self.assertEqual( recommendations_services.get_item_similarity( exp_summaries['exp_id_1'], exp_summaries['exp_id_2']), 0.0)
def setUp(self): super(AssetDevHandlerAudioTest, self).setUp() exp_services.delete_demo('0') self.system_user = user_services.get_system_user() exp_services.load_demo('0') rights_manager.release_ownership_of_exploration(self.system_user, '0') self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME) mock_accepted_audio_extensions = { 'mp3': ['audio/mp3'], 'flac': ['audio/flac'] } self.accepted_audio_extensions_swap = self.swap( feconf, 'ACCEPTED_AUDIO_EXTENSIONS', mock_accepted_audio_extensions)
def _reload_collection(self, collection_id): """Reloads the collection in dev_mode corresponding to the given collection id. Args: collection_id: str. The collection id. Raises: Exception: Cannot reload a collection in production. """ if constants.DEV_MODE: logging.info('[ADMIN] %s reloaded collection %s' % (self.user_id, collection_id)) collection_services.load_demo(unicode(collection_id)) rights_manager.release_ownership_of_collection( user_services.get_system_user(), unicode(collection_id)) else: raise Exception('Cannot reload a collection in production.')
def _reload_exploration(self, exploration_id): """Reloads the exploration in dev_mode corresponding to the given exploration id. Args: exploration_id: str. The exploration id. Raises: Exception. Cannot reload an exploration in production. """ if constants.DEV_MODE: logging.info('[ADMIN] %s reloaded exploration %s' % (self.user_id, exploration_id)) exp_services.load_demo(exploration_id) rights_manager.release_ownership_of_exploration( user_services.get_system_user(), exploration_id) else: raise Exception('Cannot reload an exploration in production.')
def post(self): username = self.payload.get('username') role = self.payload.get('role') topic_id = self.payload.get('topic_id') user_id = user_services.get_user_id_from_username(username) if user_id is None: raise self.InvalidInputException( 'User with given username does not exist.') user_services.update_user_role(user_id, role) role_services.log_role_query(self.user_id, feconf.ROLE_ACTION_UPDATE, role=role, username=username) if topic_id: user = user_services.UserActionsInfo(user_id) topic_services.assign_role(user_services.get_system_user(), user, topic_domain.ROLE_MANAGER, topic_id) self.render_json({})
def test_get_item_similarity(self) -> None: exp_summaries = exp_services.get_all_exploration_summaries( ) # type: ignore[no-untyped-call] self.assertEqual( recommendations_services.get_item_similarity( exp_summaries['exp_id_1'], exp_summaries['exp_id_2']), 4.5) self.assertEqual( recommendations_services.get_item_similarity( exp_summaries['exp_id_4'], exp_summaries['exp_id_4']), 9.0) system_user = user_services.get_system_user( ) # type: ignore[no-untyped-call] rights_manager.unpublish_exploration( system_user, 'exp_id_2') # type: ignore[no-untyped-call] exp_summaries = exp_services.get_all_exploration_summaries( ) # type: ignore[no-untyped-call] self.assertEqual( recommendations_services.get_item_similarity( exp_summaries['exp_id_1'], exp_summaries['exp_id_2']), 0.0)
def load_demo(collection_id): """Loads a demo collection. The resulting collection will have version 2 (one for its initial creation and one for its subsequent modification). Args: collection_id: str. ID of the collection to be loaded. """ delete_demo(collection_id) if not collection_domain.Collection.is_demo_collection_id(collection_id): raise Exception('Invalid demo collection id %s' % collection_id) demo_filepath = os.path.join( feconf.SAMPLE_COLLECTIONS_DIR, feconf.DEMO_COLLECTIONS[collection_id]) if demo_filepath.endswith('yaml'): yaml_content = utils.get_file_contents(demo_filepath) else: raise Exception('Unrecognized file path: %s' % demo_filepath) collection = save_new_collection_from_yaml( feconf.SYSTEM_COMMITTER_ID, yaml_content, collection_id) system_user = user_services.get_system_user() publish_collection_and_update_user_profiles(system_user, collection_id) index_collections_given_ids([collection_id]) # Now, load all of the demo explorations that are part of the collection. for collection_node in collection.nodes: exp_id = collection_node.exploration_id # Only load the demo exploration if it is not yet loaded. if exp_services.get_exploration_by_id(exp_id, strict=False) is None: exp_services.load_demo(exp_id) logging.info('Collection with id %s was loaded.' % collection_id)
def _remove_user_from_activities_with_associated_rights_models( user_id, use_user_subscriptions_ids): """Remove the user from exploration, collection, and topic models. Args: user_id: str. The ID of the user for which to remove the user from explorations, collections, and topics. use_user_subscriptions_ids: bool. Whether to use the IDs from user's UserSubscriptionsModel. When False the IDs are gathered via datastore queries. """ if use_user_subscriptions_ids: subscribed_exploration_summaries = ( exp_fetchers.get_exploration_summaries_subscribed_to(user_id)) else: subscribed_exploration_summaries = ( exp_fetchers.get_exploration_summaries_where_user_has_role(user_id) ) explorations_to_be_deleted_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if exp_summary.is_private() and exp_summary.is_solely_owned_by_user(user_id) ] exp_services.delete_explorations(user_id, explorations_to_be_deleted_ids, force_deletion=True) # Release ownership of explorations that are public and are solely owned # by the to-be-deleted user. explorations_to_release_ownership_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if not exp_summary.is_private() and exp_summary. is_solely_owned_by_user(user_id) and not exp_summary.community_owned ] for exp_id in explorations_to_release_ownership_ids: rights_manager.release_ownership_of_exploration( user_services.get_system_user(), exp_id) explorations_to_remove_user_from_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if not exp_summary.is_solely_owned_by_user(user_id) and exp_summary.does_user_have_any_role(user_id) ] for exp_id in explorations_to_remove_user_from_ids: rights_manager.deassign_role_for_exploration( user_services.get_system_user(), exp_id, user_id) if use_user_subscriptions_ids: subscribed_collection_summaries = ( collection_services.get_collection_summaries_subscribed_to(user_id) ) else: subscribed_collection_summaries = ( collection_services.get_collection_summaries_where_user_has_role( user_id)) collections_to_be_deleted_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if col_summary.is_private() and col_summary.is_solely_owned_by_user(user_id) ] collection_services.delete_collections(user_id, collections_to_be_deleted_ids, force_deletion=True) # Release ownership of collections that are public and are solely owned # by the to-be-deleted user. collections_to_release_ownership_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if not col_summary.is_private() and col_summary. is_solely_owned_by_user(user_id) and not col_summary.community_owned ] for col_id in collections_to_release_ownership_ids: rights_manager.release_ownership_of_collection( user_services.get_system_user(), col_id) collections_to_remove_user_from_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if not col_summary.is_solely_owned_by_user(user_id) and col_summary.does_user_have_any_role(user_id) ] for col_id in collections_to_remove_user_from_ids: rights_manager.deassign_role_for_collection( user_services.get_system_user(), col_id, user_id) topic_services.deassign_user_from_all_topics( user_services.get_system_user(), user_id)
def remove_user_from_activities_with_associated_rights_models(user_id): """Remove the user from exploration, collection, and topic models. Args: user_id: str. The ID of the user for which to remove the user from explorations, collections, and topics. """ subscribed_exploration_summaries = ( exp_fetchers.get_exploration_summaries_where_user_has_role(user_id)) explorations_to_be_deleted_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if exp_summary.is_private() and exp_summary.is_solely_owned_by_user(user_id) ] exp_services.delete_explorations( user_id, explorations_to_be_deleted_ids, force_deletion=True) # Release ownership of explorations that are public and are solely owned # by the to-be-deleted user. explorations_to_release_ownership_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if not exp_summary.is_private() and exp_summary.is_solely_owned_by_user(user_id) and not exp_summary.community_owned ] for exp_id in explorations_to_release_ownership_ids: rights_manager.release_ownership_of_exploration( user_services.get_system_user(), exp_id) explorations_to_remove_user_from_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if not exp_summary.is_solely_owned_by_user(user_id) and exp_summary.does_user_have_any_role(user_id) ] for exp_id in explorations_to_remove_user_from_ids: rights_manager.deassign_role_for_exploration( user_services.get_system_user(), exp_id, user_id) # To hard-delete explorations marked as deleted we are using the rights # model to retrieve the exploration as the summary model gets hard-deleted # while marking the exploration as deleted. explorations_rights = ( rights_manager.get_exploration_rights_where_user_is_owner(user_id)) explorations_to_be_deleted_ids = [ exploration_rights.id for exploration_rights in explorations_rights if exploration_rights.is_private() and exploration_rights.is_solely_owned_by_user(user_id) ] exp_services.delete_explorations( user_id, explorations_to_be_deleted_ids, force_deletion=True) subscribed_collection_summaries = ( collection_services.get_collection_summaries_where_user_has_role( user_id)) collections_to_be_deleted_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if col_summary.is_private() and col_summary.is_solely_owned_by_user(user_id) ] collection_services.delete_collections( user_id, collections_to_be_deleted_ids, force_deletion=True) # Release ownership of collections that are public and are solely owned # by the to-be-deleted user. collections_to_release_ownership_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if not col_summary.is_private() and col_summary.is_solely_owned_by_user(user_id) and not col_summary.community_owned ] for col_id in collections_to_release_ownership_ids: rights_manager.release_ownership_of_collection( user_services.get_system_user(), col_id) collections_to_remove_user_from_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if not col_summary.is_solely_owned_by_user(user_id) and col_summary.does_user_have_any_role(user_id) ] for col_id in collections_to_remove_user_from_ids: rights_manager.deassign_role_for_collection( user_services.get_system_user(), col_id, user_id) # To hard-delete collections marked as deleted we are using the rights # model to retrieve the collection as the summary model gets hard-deleted # while marking the collection as deleted. collection_rights = ( rights_manager.get_collection_rights_where_user_is_owner(user_id)) collections_to_be_deleted_ids = [ collection_rights.id for collection_rights in collection_rights if collection_rights.is_private() and collection_rights.is_solely_owned_by_user(user_id) ] collection_services.delete_collections( user_id, collections_to_be_deleted_ids, force_deletion=True) topic_services.deassign_user_from_all_topics( user_services.get_system_user(), user_id)
def post(self): """Generates structures for Android end-to-end tests. This handler generates structures for Android end-to-end tests in order to evaluate the integration of network requests from the Android client to the backend. This handler should only be called once (or otherwise raises an exception), and can only be used in development mode (this handler is unavailable in production). Note that the handler outputs an empty JSON dict when the request is successful. The specific structures that are generated: Topic: A topic with both a test story and a subtopic. Story: A story with 'android_interactions' as a exploration node. Exploration: 'android_interactions' from the local assets. Subtopic: A dummy subtopic to validate the topic. Skill: A dummy skill to validate the subtopic. Raises: Exception. When used in production mode. InvalidInputException. The topic is already created but not published. InvalidInputException. The topic is already published. """ if not constants.DEV_MODE: raise Exception('Cannot load new structures data in production.') if topic_services.does_topic_with_name_exist('Android test'): topic = topic_fetchers.get_topic_by_name('Android test') topic_rights = topic_fetchers.get_topic_rights(topic.id, strict=False) if topic_rights.topic_is_published: raise self.InvalidInputException( 'The topic is already published.') raise self.InvalidInputException( 'The topic exists but is not published.') exp_id = '26' user_id = feconf.SYSTEM_COMMITTER_ID # Generate new Structure id for topic, story, skill and question. topic_id = topic_fetchers.get_new_topic_id() story_id = story_services.get_new_story_id() skill_id = skill_services.get_new_skill_id() question_id = question_services.get_new_question_id() # Create dummy skill and question. skill = self._create_dummy_skill(skill_id, 'Dummy Skill for Android', '<p>Dummy Explanation 1</p>') question = self._create_dummy_question(question_id, 'Question 1', [skill_id]) question_services.add_question(user_id, question) question_services.create_new_question_skill_link( user_id, question_id, skill_id, 0.3) # Create and update topic to validate before publishing. topic = topic_domain.Topic.create_default_topic( topic_id, 'Android test', 'test-topic-one', 'description', 'fragm') topic.update_url_fragment('test-topic') topic.update_meta_tag_content('tag') topic.update_page_title_fragment_for_web('page title for topic') # Save the dummy image to the filesystem to be used as thumbnail. with utils.open_file(os.path.join(feconf.TESTS_DATA_DIR, 'test_svg.svg'), 'rb', encoding=None) as f: raw_image = f.read() fs = fs_services.GcsFileSystem(feconf.ENTITY_TYPE_TOPIC, topic_id) fs.commit('%s/test_svg.svg' % (constants.ASSET_TYPE_THUMBNAIL), raw_image, mimetype='image/svg+xml') # Update thumbnail properties. topic_services.update_thumbnail_filename(topic, 'test_svg.svg') topic.update_thumbnail_bg_color('#C6DCDA') # Add other structures to the topic. topic.add_canonical_story(story_id) topic.add_uncategorized_skill_id(skill_id) topic.add_subtopic(1, 'Test Subtopic Title', 'testsubtop') # Update and validate subtopic. topic_services.update_subtopic_thumbnail_filename( topic, 1, 'test_svg.svg') topic.update_subtopic_thumbnail_bg_color(1, '#FFFFFF') topic.update_subtopic_url_fragment(1, 'suburl') topic.move_skill_id_to_subtopic(None, 1, skill_id) subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, topic_id)) # Upload local exploration to the datastore and enable feedback. exp_services.load_demo(exp_id) rights_manager.release_ownership_of_exploration( user_services.get_system_user(), exp_id) exp_services.update_exploration( user_id, exp_id, [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'correctness_feedback_enabled', 'new_value': True }) ], 'Changed correctness_feedback_enabled.') # Add and update the exploration/node to the story. story = story_domain.Story.create_default_story( story_id, 'Android End to End testing', 'Description', topic_id, 'android-end-to-end-testing') story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'Testing with UI Automator') story.update_node_description( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'To test all Android interactions') story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), exp_id) # Save the dummy image to the filesystem to be used as thumbnail. with utils.open_file(os.path.join(feconf.TESTS_DATA_DIR, 'test_svg.svg'), 'rb', encoding=None) as f: raw_image = f.read() fs = fs_services.GcsFileSystem(feconf.ENTITY_TYPE_STORY, story_id) fs.commit('%s/test_svg.svg' % (constants.ASSET_TYPE_THUMBNAIL), raw_image, mimetype='image/svg+xml') story.update_node_thumbnail_filename( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'test_svg.svg') story.update_node_thumbnail_bg_color( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), '#F8BF74') # Update and validate the story. story.update_meta_tag_content('tag') story.update_thumbnail_filename('test_svg.svg') story.update_thumbnail_bg_color( constants.ALLOWED_THUMBNAIL_BG_COLORS['story'][0]) # Save the previously created structures # (skill, story, topic, subtopic). skill_services.save_new_skill(user_id, skill) story_services.save_new_story(user_id, story) topic_services.save_new_topic(user_id, topic) subtopic_page_services.save_subtopic_page( user_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Dummy Subtopic Title', 'url_fragment': 'dummy-fragment' }) ]) # Generates translation opportunities for the Contributor Dashboard. exp_ids_in_story = story.story_contents.get_all_linked_exp_ids() opportunity_services.add_new_exploration_opportunities( story_id, exp_ids_in_story) # Publish the story and topic. topic_services.publish_story(topic_id, story_id, user_id) topic_services.publish_topic(topic_id, user_id) # Upload thumbnails to be accessible through AssetsDevHandler. self._upload_thumbnail(topic_id, feconf.ENTITY_TYPE_TOPIC) self._upload_thumbnail(story_id, feconf.ENTITY_TYPE_STORY) self.render_json({})
def pre_delete_user(user_id): """Prepare user for the full deletion. 1. Mark all the activities that are private and solely owned by the user being deleted as deleted. 2. Disable all the email preferences. 3. Mark the user as to be deleted. 4. Create PendingDeletionRequestModel for the user. Args: user_id: str. The id of the user to be deleted. If the user_id corresponds to a profile user then only that profile is deleted. For a full user, all of its associated profile users are deleted too. """ pending_deletion_requests = [] user_settings = user_services.get_user_settings(user_id, strict=True) linked_profile_user_ids = [ user.user_id for user in user_services.get_all_profiles_auth_details_by_parent_user_id(user_id) ] profile_users_settings_list = user_services.get_users_settings( linked_profile_user_ids) for profile_user_settings in profile_users_settings_list: profile_id = profile_user_settings.user_id user_services.mark_user_for_deletion(profile_id) pending_deletion_requests.append( wipeout_domain.PendingDeletionRequest.create_default( profile_id, profile_user_settings.email, profile_user_settings.role, [], [])) explorations_to_be_deleted_ids = [] collections_to_be_deleted_ids = [] if user_settings.role != feconf.ROLE_ID_LEARNER: subscribed_exploration_summaries = ( exp_fetchers.get_exploration_summaries_subscribed_to(user_id)) explorations_to_be_deleted_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if exp_summary.is_private() and exp_summary.is_solely_owned_by_user(user_id) ] exp_services.delete_explorations(user_id, explorations_to_be_deleted_ids) # Release ownership of explorations that are public and are solely owned # by the to-be-deleted user. explorations_to_release_ownership_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if not exp_summary.is_private() and exp_summary.is_solely_owned_by_user(user_id) ] for exp_id in explorations_to_release_ownership_ids: rights_manager.release_ownership_of_exploration( user_services.get_system_user(), exp_id) explorations_to_remove_user_from_ids = [ exp_summary.id for exp_summary in subscribed_exploration_summaries if not exp_summary.is_solely_owned_by_user(user_id) ] for exp_id in explorations_to_remove_user_from_ids: rights_manager.deassign_role_for_exploration( user_services.get_system_user(), exp_id, user_id) subscribed_collection_summaries = ( collection_services.get_collection_summaries_subscribed_to(user_id) ) collections_to_be_deleted_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if col_summary.is_private() and col_summary.is_solely_owned_by_user(user_id) ] collection_services.delete_collections(user_id, collections_to_be_deleted_ids) # Release ownership of collections that are public and are solely owned # by the to-be-deleted user. collections_to_release_ownership_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if not col_summary.is_private() and col_summary.is_solely_owned_by_user(user_id) ] for col_id in collections_to_release_ownership_ids: rights_manager.release_ownership_of_collection( user_services.get_system_user(), col_id) collections_to_remove_user_from_ids = [ col_summary.id for col_summary in subscribed_collection_summaries if not col_summary.is_solely_owned_by_user(user_id) ] for col_id in collections_to_remove_user_from_ids: rights_manager.deassign_role_for_collection( user_services.get_system_user(), col_id, user_id) topic_services.deassign_user_from_all_topics( user_services.get_system_user(), user_id) # Set all the user's email preferences to False in order to disable all # ordinary emails that could be sent to the users. user_services.update_email_preferences(user_id, False, False, False, False) user_services.mark_user_for_deletion(user_id) pending_deletion_requests.append( wipeout_domain.PendingDeletionRequest.create_default( user_id, user_settings.email, user_settings.role, explorations_to_be_deleted_ids, collections_to_be_deleted_ids)) save_pending_deletion_requests(pending_deletion_requests)