def test_export_nonexistent_user(self): """Setup for nonexistent user test of export_data functionality.""" with self.assertRaisesRegexp( user_models.UserSettingsModel.EntityNotFoundError, 'Entity for class UserSettingsModel with id fake_user_id ' 'not found'): takeout_service.export_data_for_user('fake_user_id')
def get(self): """Handles GET requests.""" # Retrieve user data. user_takeout_object = takeout_service.export_data_for_user( self.user_id) user_data = user_takeout_object.user_data user_images = user_takeout_object.user_images # Ensure that the exported data does not contain a user ID. user_data_json_string = json.dumps(user_data) if re.search(feconf.USER_ID_REGEX, user_data_json_string): logging.error( '[TAKEOUT] User ID found in the JSON generated for user %s' % self.user_id) user_data_json_string = ( 'There was an error while exporting ' + 'data. Please contact %s to export your data.' % feconf.ADMIN_EMAIL_ADDRESS) user_images = [] # Create zip file. temp_file = io.BytesIO() with zipfile.ZipFile( temp_file, mode='w', compression=zipfile.ZIP_DEFLATED ) as zfile: zfile.writestr('oppia_takeout_data.json', user_data_json_string) for image in user_images: decoded_png = utils.convert_png_data_url_to_binary( image.b64_image_data) zfile.writestr('images/' + image.image_export_path, decoded_png) # Render file for download. self.render_downloadable_file( temp_file, 'oppia_takeout_data.zip', 'text/plain')
def get(self): """Handles GET requests.""" if not constants.ENABLE_ACCOUNT_EXPORT: raise self.PageNotFoundException # Retrieve user data. user_takeout_object = takeout_service.export_data_for_user( self.user_id) user_data = user_takeout_object.user_data user_images = user_takeout_object.user_images # Create zip file. temp_file = python_utils.string_io() with zipfile.ZipFile(temp_file, mode='w', compression=zipfile.ZIP_DEFLATED) as zfile: zfile.writestr('oppia_takeout_data.json', json.dumps(user_data)) for image in user_images: b64_png_no_header = image.b64_image_data.split(',')[1] decoded_png = base64.b64decode( python_utils.url_unquote_plus(b64_png_no_header)) zfile.writestr('images/' + image.image_export_path, decoded_png) # Render file for download. self.render_downloadable_file(temp_file.getvalue(), 'oppia_takeout_data.zip', 'text/plain')
def get(self): """Handles GET requests.""" if not constants.ENABLE_ACCOUNT_EXPORT: raise self.PageNotFoundException user_data = takeout_service.export_data_for_user(self.user_id) self.render_json(user_data)
def test_export_data_nontrivial(self): """Nontrivial test of export_data functionality.""" self.set_up_non_trivial() # We set up the feedback_thread_model here so that we can easily # access it when computing the expected data later. feedback_thread_model = feedback_models.GeneralFeedbackThreadModel( entity_type=self.THREAD_ENTITY_TYPE, entity_id=self.THREAD_ENTITY_ID, original_author_id=self.USER_ID_1, status=self.THREAD_STATUS, subject=self.THREAD_SUBJECT, has_suggestion=self.THREAD_HAS_SUGGESTION, summary=self.THREAD_SUMMARY, message_count=self.THREAD_MESSAGE_COUNT) feedback_thread_model.put() expected_stats_data = { 'impact_score': self.USER_1_IMPACT_SCORE, 'total_plays': self.USER_1_TOTAL_PLAYS, 'average_ratings': self.USER_1_AVERAGE_RATINGS, 'num_ratings': self.USER_1_NUM_RATINGS, 'weekly_creator_stats_list': self.USER_1_WEEKLY_CREATOR_STATS_LIST } expected_skill_data = { self.SKILL_ID_1: self.DEGREE_OF_MASTERY, self.SKILL_ID_2: self.DEGREE_OF_MASTERY } expected_contribution_data = { 'created_exploration_ids': [self.EXPLORATION_IDS[0]], 'edited_exploration_ids': [self.EXPLORATION_IDS[0]] } expected_exploration_data = { self.EXPLORATION_IDS[0]: { 'rating': 2, 'rated_on': self.GENERIC_DATE, 'draft_change_list': { 'new_content': {} }, 'draft_change_list_last_updated': self.GENERIC_DATE, 'draft_change_list_exp_version': 3, 'draft_change_list_id': 1, 'mute_suggestion_notifications': (feconf.DEFAULT_SUGGESTION_NOTIFICATIONS_MUTED_PREFERENCE), 'mute_feedback_notifications': (feconf.DEFAULT_SUGGESTION_NOTIFICATIONS_MUTED_PREFERENCE) } } expected_completed_activities_data = { 'completed_exploration_ids': self.EXPLORATION_IDS, 'completed_collection_ids': self.COLLECTION_IDS } expected_incomplete_activities_data = { 'incomplete_exploration_ids': self.EXPLORATION_IDS, 'incomplete_collection_ids': self.COLLECTION_IDS } expected_last_playthrough_data = { self.EXPLORATION_IDS[0]: { 'exp_version': self.EXP_VERSION, 'state_name': self.STATE_NAME } } expected_learner_playlist_data = { 'playlist_exploration_ids': self.EXPLORATION_IDS, 'playlist_collection_ids': self.COLLECTION_IDS } expected_collection_progress_data = { self.COLLECTION_IDS[0]: self.EXPLORATION_IDS } expected_story_progress_data = { self.STORY_ID_1: self.COMPLETED_NODE_IDS_1 } thread_id = feedback_services.create_thread(self.THREAD_ENTITY_TYPE, self.THREAD_ENTITY_ID, self.USER_ID_1, self.THREAD_SUBJECT, self.MESSAGE_TEXT) feedback_services.create_message(thread_id, self.USER_ID_1, self.THREAD_STATUS, self.THREAD_SUBJECT, self.MESSAGE_TEXT) expected_general_feedback_thread_data = { feedback_thread_model.id: { 'entity_type': self.THREAD_ENTITY_TYPE, 'entity_id': self.THREAD_ENTITY_ID, 'status': self.THREAD_STATUS, 'subject': self.THREAD_SUBJECT, 'has_suggestion': self.THREAD_HAS_SUGGESTION, 'summary': self.THREAD_SUMMARY, 'message_count': self.THREAD_MESSAGE_COUNT, 'last_updated': feedback_thread_model.last_updated }, thread_id: { 'entity_type': self.THREAD_ENTITY_TYPE, 'entity_id': self.THREAD_ENTITY_ID, 'status': self.THREAD_STATUS, 'subject': self.THREAD_SUBJECT, 'has_suggestion': False, 'summary': None, 'message_count': 2, 'last_updated': (feedback_models.GeneralFeedbackThreadModel.get( thread_id).last_updated) } } expected_general_feedback_thread_user_data = { thread_id: self.MESSAGE_IDS_READ_BY_USER } expected_general_feedback_message_data = { thread_id + '.0': { 'thread_id': thread_id, 'message_id': 0, 'updated_status': self.THREAD_STATUS, 'updated_subject': self.THREAD_SUBJECT, 'text': self.MESSAGE_TEXT, 'received_via_email': self.MESSAGE_RECEIEVED_VIA_EMAIL }, thread_id + '.1': { 'thread_id': thread_id, 'message_id': 1, 'updated_status': self.THREAD_STATUS, 'updated_subject': self.THREAD_SUBJECT, 'text': self.MESSAGE_TEXT, 'received_via_email': self.MESSAGE_RECEIEVED_VIA_EMAIL } } expected_collection_rights_data = { 'owned_collection_ids': ([self.COLLECTION_IDS[0]]), 'editable_collection_ids': ([self.COLLECTION_IDS[0]]), 'voiced_collection_ids': ([self.COLLECTION_IDS[0]]), 'viewable_collection_ids': [self.COLLECTION_IDS[0]] } expected_general_suggestion_data = { 'exploration.exp1.thread_1': { 'suggestion_type': (suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT), 'target_type': suggestion_models.TARGET_TYPE_EXPLORATION, 'target_id': self.EXPLORATION_IDS[0], 'target_version_at_submission': 1, 'status': suggestion_models.STATUS_IN_REVIEW, 'change_cmd': self.CHANGE_CMD } } expected_exploration_rights_data = { 'owned_exploration_ids': ([self.EXPLORATION_IDS[0]]), 'editable_exploration_ids': ([self.EXPLORATION_IDS[0]]), 'voiced_exploration_ids': ([self.EXPLORATION_IDS[0]]), 'viewable_exploration_ids': [self.EXPLORATION_IDS[0]] } expected_settings_data = { 'email': self.USER_1_EMAIL, 'role': feconf.ROLE_ID_ADMIN, 'username': self.GENERIC_USERNAME, 'normalized_username': self.GENERIC_USERNAME, 'last_agreed_to_terms': self.GENERIC_DATE, 'last_started_state_editor_tutorial': self.GENERIC_DATE, 'last_started_state_translation_tutorial': self.GENERIC_DATE, 'last_logged_in': self.GENERIC_DATE, 'last_edited_an_exploration': self.GENERIC_DATE, 'profile_picture_data_url': self.GENERIC_IMAGE_URL, 'default_dashboard': 'learner', 'creator_dashboard_display_pref': 'card', 'user_bio': self.GENERIC_USER_BIO, 'subject_interests': self.GENERIC_SUBJECT_INTERESTS, 'first_contribution_msec': 1, 'preferred_language_codes': self.GENERIC_LANGUAGE_CODES, 'preferred_site_language_code': self.GENERIC_LANGUAGE_CODES[0], 'preferred_audio_language_code': self.GENERIC_LANGUAGE_CODES[0] } expected_reply_to_data = { self.THREAD_ID_1: self.USER_1_REPLY_TO_ID_1, self.THREAD_ID_2: self.USER_1_REPLY_TO_ID_2 } expected_subscriptions_data = { 'creator_ids': self.CREATOR_IDS, 'collection_ids': self.COLLECTION_IDS, 'activity_ids': self.ACTIVITY_IDS + self.EXPLORATION_IDS, 'general_feedback_thread_ids': self.GENERAL_FEEDBACK_THREAD_IDS + [thread_id], 'last_checked': None } expected_topic_data = { 'managed_topic_ids': [self.TOPIC_ID_1, self.TOPIC_ID_2] } expected_export = { 'user_stats_data': expected_stats_data, 'user_settings_data': expected_settings_data, 'user_subscriptions_data': expected_subscriptions_data, 'user_skill_mastery_data': expected_skill_data, 'user_contributions_data': expected_contribution_data, 'exploration_user_data_data': expected_exploration_data, 'completed_activities_data': expected_completed_activities_data, 'incomplete_activities_data': expected_incomplete_activities_data, 'exp_user_last_playthrough_data': expected_last_playthrough_data, 'learner_playlist_data': expected_learner_playlist_data, 'topic_rights_data': expected_topic_data, 'collection_progress_data': expected_collection_progress_data, 'story_progress_data': expected_story_progress_data, 'general_feedback_thread_data': expected_general_feedback_thread_data, 'general_feedback_thread_user_data': expected_general_feedback_thread_user_data, 'general_feedback_message_data': expected_general_feedback_message_data, 'collection_rights_data': expected_collection_rights_data, 'general_suggestion_data': expected_general_suggestion_data, 'exploration_rights_data': expected_exploration_rights_data, 'general_feedback_email_reply_to_id_data': expected_reply_to_data } exported_data = takeout_service.export_data_for_user(self.USER_ID_1) self.assertEqual(exported_data, expected_export)
def test_export_data_trivial(self): """Trivial test of export_data functionality.""" self.set_up_trivial() # Generate expected output. collection_progress_data = {} collection_rights_data = { 'editable_collection_ids': [], 'owned_collection_ids': [], 'viewable_collection_ids': [], 'voiced_collection_ids': [] } completed_activities_data = {} contribution_data = {} exploration_rights_data = { 'editable_exploration_ids': [], 'owned_exploration_ids': [], 'viewable_exploration_ids': [], 'voiced_exploration_ids': [] } exploration_data = {} reply_to_data = {} general_feedback_message_data = {} general_feedback_thread_data = {} general_feedback_thread_user_data = {} general_suggestion_data = {} last_playthrough_data = {} learner_playlist_data = {} incomplete_activities_data = {} settings_data = { 'email': '*****@*****.**', 'role': feconf.ROLE_ID_ADMIN, 'username': None, 'normalized_username': None, 'last_agreed_to_terms': None, 'last_started_state_editor_tutorial': None, 'last_started_state_translation_tutorial': None, 'last_logged_in': None, 'last_edited_an_exploration': None, 'profile_picture_data_url': None, 'default_dashboard': 'learner', 'creator_dashboard_display_pref': 'card', 'user_bio': None, 'subject_interests': [], 'first_contribution_msec': None, 'preferred_language_codes': [], 'preferred_site_language_code': None, 'preferred_audio_language_code': None } skill_data = {} stats_data = {} story_progress_data = {} subscriptions_data = { 'activity_ids': [], 'collection_ids': [], 'creator_ids': [], 'general_feedback_thread_ids': [], 'last_checked': None } topic_rights_data = {'managed_topic_ids': []} expected_export = { 'user_stats_data': stats_data, 'user_settings_data': settings_data, 'user_subscriptions_data': subscriptions_data, 'user_skill_mastery_data': skill_data, 'user_contributions_data': contribution_data, 'exploration_user_data_data': exploration_data, 'completed_activities_data': completed_activities_data, 'incomplete_activities_data': incomplete_activities_data, 'exp_user_last_playthrough_data': last_playthrough_data, 'learner_playlist_data': learner_playlist_data, 'topic_rights_data': topic_rights_data, 'collection_progress_data': collection_progress_data, 'story_progress_data': story_progress_data, 'general_feedback_thread_data': general_feedback_thread_data, 'general_feedback_thread_user_data': general_feedback_thread_user_data, 'general_feedback_message_data': general_feedback_message_data, 'collection_rights_data': collection_rights_data, 'general_suggestion_data': general_suggestion_data, 'exploration_rights_data': exploration_rights_data, 'general_feedback_email_reply_to_id_data': reply_to_data } # Perform export and compare. exported_data = takeout_service.export_data_for_user(self.USER_ID_1) self.assertEqual(expected_export, exported_data)
def test_export_data_nontrivial(self): """Nontrivial test of export_data functionality.""" self.set_up_non_trivial() # We set up the feedback_thread_model here so that we can easily # access it when computing the expected data later. feedback_thread_model = feedback_models.GeneralFeedbackThreadModel( entity_type=self.THREAD_ENTITY_TYPE, entity_id=self.THREAD_ENTITY_ID, original_author_id=self.USER_ID_1, status=self.THREAD_STATUS, subject=self.THREAD_SUBJECT, has_suggestion=self.THREAD_HAS_SUGGESTION, summary=self.THREAD_SUMMARY, message_count=self.THREAD_MESSAGE_COUNT) feedback_thread_model.put() expected_stats_data = { 'impact_score': self.USER_1_IMPACT_SCORE, 'total_plays': self.USER_1_TOTAL_PLAYS, 'average_ratings': self.USER_1_AVERAGE_RATINGS, 'num_ratings': self.USER_1_NUM_RATINGS, 'weekly_creator_stats_list': self.USER_1_WEEKLY_CREATOR_STATS_LIST } expected_skill_data = { self.SKILL_ID_1: self.DEGREE_OF_MASTERY, self.SKILL_ID_2: self.DEGREE_OF_MASTERY } expected_contribution_data = { 'created_exploration_ids': [self.EXPLORATION_IDS[0]], 'edited_exploration_ids': [self.EXPLORATION_IDS[0]] } expected_exploration_data = { self.EXPLORATION_IDS[0]: { 'rating': 2, 'rated_on': self.GENERIC_EPOCH, 'draft_change_list': { 'new_content': {} }, 'draft_change_list_last_updated': self.GENERIC_EPOCH, 'draft_change_list_exp_version': 3, 'draft_change_list_id': 1, 'mute_suggestion_notifications': (feconf.DEFAULT_SUGGESTION_NOTIFICATIONS_MUTED_PREFERENCE), 'mute_feedback_notifications': (feconf.DEFAULT_SUGGESTION_NOTIFICATIONS_MUTED_PREFERENCE) } } expected_completed_activities_data = { 'completed_exploration_ids': self.EXPLORATION_IDS, 'completed_collection_ids': self.COLLECTION_IDS } expected_incomplete_activities_data = { 'incomplete_exploration_ids': self.EXPLORATION_IDS, 'incomplete_collection_ids': self.COLLECTION_IDS } expected_last_playthrough_data = { self.EXPLORATION_IDS[0]: { 'exp_version': self.EXP_VERSION, 'state_name': self.STATE_NAME } } expected_learner_playlist_data = { 'playlist_exploration_ids': self.EXPLORATION_IDS, 'playlist_collection_ids': self.COLLECTION_IDS } expected_collection_progress_data = { self.COLLECTION_IDS[0]: self.EXPLORATION_IDS } expected_story_progress_data = { self.STORY_ID_1: self.COMPLETED_NODE_IDS_1 } thread_id = feedback_services.create_thread(self.THREAD_ENTITY_TYPE, self.THREAD_ENTITY_ID, self.USER_ID_1, self.THREAD_SUBJECT, self.MESSAGE_TEXT) feedback_services.create_message(thread_id, self.USER_ID_1, self.THREAD_STATUS, self.THREAD_SUBJECT, self.MESSAGE_TEXT) expected_general_feedback_thread_data = { feedback_thread_model.id: { 'entity_type': self.THREAD_ENTITY_TYPE, 'entity_id': self.THREAD_ENTITY_ID, 'status': self.THREAD_STATUS, 'subject': self.THREAD_SUBJECT, 'has_suggestion': self.THREAD_HAS_SUGGESTION, 'summary': self.THREAD_SUMMARY, 'message_count': self.THREAD_MESSAGE_COUNT, 'last_updated_msec': utils.get_time_in_millisecs(feedback_thread_model.last_updated) }, thread_id: { 'entity_type': self.THREAD_ENTITY_TYPE, 'entity_id': self.THREAD_ENTITY_ID, 'status': self.THREAD_STATUS, 'subject': self.THREAD_SUBJECT, 'has_suggestion': False, 'summary': None, 'message_count': 2, 'last_updated_msec': utils.get_time_in_millisecs( feedback_models.GeneralFeedbackThreadModel.get_by_id( thread_id).last_updated) } } expected_general_feedback_thread_user_data = { thread_id: self.MESSAGE_IDS_READ_BY_USER } expected_general_feedback_message_data = { thread_id + '.0': { 'thread_id': thread_id, 'message_id': 0, 'updated_status': self.THREAD_STATUS, 'updated_subject': self.THREAD_SUBJECT, 'text': self.MESSAGE_TEXT, 'received_via_email': self.MESSAGE_RECEIEVED_VIA_EMAIL }, thread_id + '.1': { 'thread_id': thread_id, 'message_id': 1, 'updated_status': self.THREAD_STATUS, 'updated_subject': self.THREAD_SUBJECT, 'text': self.MESSAGE_TEXT, 'received_via_email': self.MESSAGE_RECEIEVED_VIA_EMAIL } } expected_collection_rights_data = { 'owned_collection_ids': ([self.COLLECTION_IDS[0]]), 'editable_collection_ids': ([self.COLLECTION_IDS[0]]), 'voiced_collection_ids': ([self.COLLECTION_IDS[0]]), 'viewable_collection_ids': [self.COLLECTION_IDS[0]] } expected_general_suggestion_data = { 'exploration.exp1.thread_1': { 'suggestion_type': (suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT), 'target_type': suggestion_models.TARGET_TYPE_EXPLORATION, 'target_id': self.EXPLORATION_IDS[0], 'target_version_at_submission': 1, 'status': suggestion_models.STATUS_IN_REVIEW, 'change_cmd': self.CHANGE_CMD } } expected_exploration_rights_data = { 'owned_exploration_ids': ([self.EXPLORATION_IDS[0]]), 'editable_exploration_ids': ([self.EXPLORATION_IDS[0]]), 'voiced_exploration_ids': ([self.EXPLORATION_IDS[0]]), 'viewable_exploration_ids': [self.EXPLORATION_IDS[0]] } expected_settings_data = { 'email': self.USER_1_EMAIL, 'role': feconf.ROLE_ID_ADMIN, 'username': self.GENERIC_USERNAME, 'normalized_username': self.GENERIC_USERNAME, 'last_agreed_to_terms': self.GENERIC_EPOCH, 'last_started_state_editor_tutorial': self.GENERIC_EPOCH, 'last_started_state_translation_tutorial': self.GENERIC_EPOCH, 'last_logged_in': self.GENERIC_EPOCH, 'last_edited_an_exploration': self.GENERIC_EPOCH, 'profile_picture_filename': 'user_settings_profile_picture.png', 'default_dashboard': 'learner', 'creator_dashboard_display_pref': 'card', 'user_bio': self.GENERIC_USER_BIO, 'subject_interests': self.GENERIC_SUBJECT_INTERESTS, 'first_contribution_msec': 1, 'preferred_language_codes': self.GENERIC_LANGUAGE_CODES, 'preferred_site_language_code': self.GENERIC_LANGUAGE_CODES[0], 'preferred_audio_language_code': self.GENERIC_LANGUAGE_CODES[0] } expected_reply_to_data = { self.THREAD_ID_1: self.USER_1_REPLY_TO_ID_1, self.THREAD_ID_2: self.USER_1_REPLY_TO_ID_2 } expected_subscriptions_data = { 'creator_usernames': self.CREATOR_USERNAMES, 'collection_ids': self.COLLECTION_IDS, 'activity_ids': self.ACTIVITY_IDS + self.EXPLORATION_IDS, 'general_feedback_thread_ids': self.GENERAL_FEEDBACK_THREAD_IDS + [thread_id], 'last_checked': self.GENERIC_EPOCH } expected_task_entry_data = { 'task_ids_resolved_by_user': [self.GENERIC_MODEL_ID] } expected_topic_data = { 'managed_topic_ids': [self.TOPIC_ID_1, self.TOPIC_ID_2] } expected_voiceover_application_data = { 'application_1_id': { 'target_type': 'exploration', 'target_id': 'exp_id', 'status': 'review', 'language_code': 'en', 'filename': 'application_audio.mp3', 'content': '<p>Some content</p>', 'rejection_message': None }, 'application_2_id': { 'target_type': 'exploration', 'target_id': 'exp_id', 'status': 'review', 'language_code': 'en', 'filename': 'application_audio.mp3', 'content': '<p>Some content</p>', 'rejection_message': None } } expected_community_rights_data = { 'can_review_translation_for_language_codes': ['hi', 'en'], 'can_review_voiceover_for_language_codes': ['hi'], 'can_review_questions': True } expected_contrib_score_data = { self.SCORE_CATEGORY_1: { 'has_email_been_sent': False, 'score': 1.5 }, self.SCORE_CATEGORY_2: { 'has_email_been_sent': False, 'score': 2 } } expected_collection_rights_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_collection_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_skill_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_subtopic_page_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_topic_rights_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_topic_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_story_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_question_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_config_property_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_exploration_rights_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_exploration_sm = { 'exp_1-1': { 'commit_type': 'create', 'commit_cmds': [{ 'category': 'A category', 'cmd': 'create_new', 'title': 'A title' }], 'commit_message': 'New exploration created with title \'A title\'.' }, 'exp_1-2': { 'commit_type': 'edit', 'commit_cmds': [{ 'new_value': 'the objective', 'cmd': 'edit_exploration_property', 'old_value': None, 'property_name': 'objective' }], 'commit_message': 'Test edit' } } expected_platform_parameter_sm = { self.GENERIC_MODEL_ID: { 'commit_type': self.COMMIT_TYPE, 'commit_message': self.COMMIT_MESSAGE, 'commit_cmds': self.COMMIT_CMDS } } expected_data = { 'user_stats': expected_stats_data, 'user_settings': expected_settings_data, 'user_subscriptions': expected_subscriptions_data, 'user_skill_mastery': expected_skill_data, 'user_contributions': expected_contribution_data, 'exploration_user_data': expected_exploration_data, 'completed_activities': expected_completed_activities_data, 'incomplete_activities': expected_incomplete_activities_data, 'exp_user_last_playthrough': expected_last_playthrough_data, 'learner_playlist': expected_learner_playlist_data, 'task_entry': expected_task_entry_data, 'topic_rights': expected_topic_data, 'collection_progress': expected_collection_progress_data, 'story_progress': expected_story_progress_data, 'general_feedback_thread': expected_general_feedback_thread_data, 'general_feedback_thread_user': expected_general_feedback_thread_user_data, 'general_feedback_message': expected_general_feedback_message_data, 'collection_rights': expected_collection_rights_data, 'general_suggestion': expected_general_suggestion_data, 'exploration_rights': expected_exploration_rights_data, 'general_feedback_email_reply_to_id': expected_reply_to_data, 'general_voiceover_application': expected_voiceover_application_data, 'user_contribution_scoring': expected_contrib_score_data, 'user_community_rights': expected_community_rights_data, 'collection_rights_snapshot_metadata': expected_collection_rights_sm, 'collection_snapshot_metadata': expected_collection_sm, 'skill_snapshot_metadata': expected_skill_sm, 'subtopic_page_snapshot_metadata': expected_subtopic_page_sm, 'topic_rights_snapshot_metadata': expected_topic_rights_sm, 'topic_snapshot_metadata': expected_topic_sm, 'story_snapshot_metadata': expected_story_sm, 'question_snapshot_metadata': expected_question_sm, 'config_property_snapshot_metadata': expected_config_property_sm, 'exploration_rights_snapshot_metadata': expected_exploration_rights_sm, 'exploration_snapshot_metadata': expected_exploration_sm, 'platform_parameter_snapshot_metadata': expected_platform_parameter_sm, } user_takeout_object = takeout_service.export_data_for_user( self.USER_ID_1) observed_data = user_takeout_object.user_data observed_images = user_takeout_object.user_images self.assertEqual(observed_data, expected_data) observed_json = json.dumps(observed_data) expected_json = json.dumps(expected_data) self.assertEqual(json.loads(observed_json), json.loads(expected_json)) expected_images = [ takeout_domain.TakeoutImage(self.GENERIC_IMAGE_URL, 'user_settings_profile_picture.png') ] self.assertEqual(len(expected_images), len(observed_images)) for i, _ in enumerate(expected_images): self.assertEqual(expected_images[i].b64_image_data, observed_images[i].b64_image_data) self.assertEqual(expected_images[i].image_export_path, observed_images[i].image_export_path)
def test_export_data_trivial(self): """Trivial test of export_data functionality.""" self.set_up_trivial() # Generate expected output. collection_progress_data = {} collection_rights_data = { 'editable_collection_ids': [], 'owned_collection_ids': [], 'viewable_collection_ids': [], 'voiced_collection_ids': [] } completed_activities_data = {} contribution_data = {} exploration_rights_data = { 'editable_exploration_ids': [], 'owned_exploration_ids': [], 'viewable_exploration_ids': [], 'voiced_exploration_ids': [] } exploration_data = {} reply_to_data = {} general_feedback_message_data = {} general_feedback_thread_data = {} general_feedback_thread_user_data = {} general_suggestion_data = {} last_playthrough_data = {} learner_playlist_data = {} incomplete_activities_data = {} settings_data = { 'email': '*****@*****.**', 'role': feconf.ROLE_ID_ADMIN, 'username': None, 'normalized_username': None, 'last_agreed_to_terms': None, 'last_started_state_editor_tutorial': None, 'last_started_state_translation_tutorial': None, 'last_logged_in': None, 'last_edited_an_exploration': None, 'profile_picture_filename': None, 'default_dashboard': 'learner', 'creator_dashboard_display_pref': 'card', 'user_bio': None, 'subject_interests': [], 'first_contribution_msec': None, 'preferred_language_codes': [], 'preferred_site_language_code': None, 'preferred_audio_language_code': None } skill_data = {} stats_data = {} story_progress_data = {} subscriptions_data = { 'activity_ids': [], 'collection_ids': [], 'creator_usernames': [], 'general_feedback_thread_ids': [], 'last_checked': None } task_entry_data = {'task_ids_resolved_by_user': []} topic_rights_data = {'managed_topic_ids': []} expected_voiceover_application_data = {} expected_contrib_score_data = {} expected_community_rights_data = {} expected_collection_rights_sm = {} expected_collection_sm = {} expected_skill_sm = {} expected_subtopic_page_sm = {} expected_topic_rights_sm = {} expected_topic_sm = {} expected_story_sm = {} expected_question_sm = {} expected_config_property_sm = {} expected_exploration_rights_sm = {} expected_exploration_sm = {} expected_platform_parameter_sm = {} expected_data = { 'user_stats': stats_data, 'user_settings': settings_data, 'user_subscriptions': subscriptions_data, 'user_skill_mastery': skill_data, 'user_contributions': contribution_data, 'exploration_user_data': exploration_data, 'completed_activities': completed_activities_data, 'incomplete_activities': incomplete_activities_data, 'exp_user_last_playthrough': last_playthrough_data, 'learner_playlist': learner_playlist_data, 'task_entry': task_entry_data, 'topic_rights': topic_rights_data, 'collection_progress': collection_progress_data, 'story_progress': story_progress_data, 'general_feedback_thread': general_feedback_thread_data, 'general_feedback_thread_user': general_feedback_thread_user_data, 'general_feedback_message': general_feedback_message_data, 'collection_rights': collection_rights_data, 'general_suggestion': general_suggestion_data, 'exploration_rights': exploration_rights_data, 'general_feedback_email_reply_to_id': reply_to_data, 'general_voiceover_application': expected_voiceover_application_data, 'user_contribution_scoring': expected_contrib_score_data, 'user_community_rights': expected_community_rights_data, 'collection_rights_snapshot_metadata': expected_collection_rights_sm, 'collection_snapshot_metadata': expected_collection_sm, 'skill_snapshot_metadata': expected_skill_sm, 'subtopic_page_snapshot_metadata': expected_subtopic_page_sm, 'topic_rights_snapshot_metadata': expected_topic_rights_sm, 'topic_snapshot_metadata': expected_topic_sm, 'story_snapshot_metadata': expected_story_sm, 'question_snapshot_metadata': expected_question_sm, 'config_property_snapshot_metadata': expected_config_property_sm, 'exploration_rights_snapshot_metadata': expected_exploration_rights_sm, 'exploration_snapshot_metadata': expected_exploration_sm, 'platform_parameter_snapshot_metadata': expected_platform_parameter_sm, } # Perform export and compare. user_takeout_object = takeout_service.export_data_for_user( self.USER_ID_1) observed_data = user_takeout_object.user_data observed_images = user_takeout_object.user_images self.assertEqual(expected_data, observed_data) observed_json = json.dumps(observed_data) expected_json = json.dumps(expected_data) self.assertEqual(json.loads(expected_json), json.loads(observed_json)) expected_images = [] self.assertEqual(expected_images, observed_images)