def export_data_for_user(user_id): """Exports selected models according to model defined export_data functions. Args: user_id: str. The user_id of the user whose data is being exported. Returns: dict. Dictionary containing all user data in the following format: { <MODEL_NAME>_data: <dict of data in format as specified by model export policy> }. """ user_settings = user_services.get_user_settings(user_id) if user_settings is not None and ( user_settings.role == feconf.ROLE_ID_LEARNER): raise NotImplementedError( 'Takeout for profile users is not yet supported.') exported_data = dict() models_to_export = get_models_which_should_be_exported() for model in models_to_export: split_name = re.findall('[A-Z][^A-Z]*', model.__name__)[:-1] # Join the split name with underscores and add _data for final name. final_name = ('_').join([x.lower() for x in split_name]) exported_data[final_name] = model.export_data(user_id) # Separate out images. We store the images that need to be separated here # as a dictionary mapping tuples to strings. The tuple value indicates the # "path" to take to the image in the user's data dictionary, and the string # indicates the filename that the exported image will be saved to. replacement_instructions = [ takeout_domain.TakeoutImageReplacementInstruction( ('user_settings', 'profile_picture_data_url'), 'user_settings_profile_picture.png', 'profile_picture_filename' ) ] takeout_image_files = [] for replacement_instruction in replacement_instructions: dictionary_path = replacement_instruction.dictionary_path replacement_filename = replacement_instruction.export_filename replacement_key = replacement_instruction.new_key # Move pointer to the position indicated by the tuple. pointer = exported_data for key in dictionary_path[:-1]: pointer = pointer[key] # Swap out data with replacement filename. image_key = dictionary_path[-1] image_data = pointer[image_key] if image_data is not None: takeout_image_files.append( takeout_domain.TakeoutImage(image_data, replacement_filename)) pointer[image_key] = replacement_filename # Rename the key. pointer[replacement_key] = pointer.pop(image_key) return takeout_domain.TakeoutData(exported_data, takeout_image_files)
def test_that_domain_object_is_created_correctly(self) -> None: user_data = { 'model_name': { 'property1': 'value1', 'property2': 'value2' } } takeout_data = takeout_domain.TakeoutData(user_data, []) self.assertEqual(takeout_data.user_data, user_data) self.assertEqual(takeout_data.user_images, [])
def export_data_for_user(user_id: str) -> takeout_domain.TakeoutData: """Exports selected models according to model defined export_data functions. Args: user_id: str. The user_id of the user whose data is being exported. Returns: dict. Dictionary containing all user data in the following format: { <MODEL_NAME>_data: <dict of data in format as specified by model export policy> }. Raises: NotImplementedError. Takeout for profile users is not implemented. """ user_settings = user_services.get_user_settings(user_id, strict=False) if user_settings is not None and ( feconf.ROLE_ID_MOBILE_LEARNER in user_settings.roles): raise NotImplementedError( 'Takeout for profile users is not yet supported.') exported_data = {} models_to_export = get_models_which_should_be_exported() for model in models_to_export: split_name = re.findall('[A-Z][^A-Z]*', model.__name__)[:-1] # Join the split name with underscores and add _data for final name. exported_model_data = model.export_data(user_id) exported_model_data_json_string = json.dumps(exported_model_data) user_id_match_object = re.search( feconf.USER_ID_REGEX, exported_model_data_json_string) if user_id_match_object: logging.error( '[TAKEOUT] User ID (%s) found in the JSON generated ' 'for %s and user with ID %s' % ( user_id_match_object.group(0), model.__name__, user_id ) ) final_name = ('_').join([x.lower() for x in split_name]) exported_data[final_name] = exported_model_data # Separate out images. We store the images that need to be separated here # as a dictionary mapping tuples to strings. The tuple value indicates the # "path" to take to the image in the user's data dictionary, and the string # indicates the filename that the exported image will be saved to. replacement_instructions = [ takeout_domain.TakeoutImageReplacementInstruction( ('user_settings', 'profile_picture_data_url'), 'user_settings_profile_picture.png', 'profile_picture_filename' ) ] takeout_image_files: List[takeout_domain.TakeoutImage] = [] for replacement_instruction in replacement_instructions: dictionary_path = replacement_instruction.dictionary_path replacement_filename = replacement_instruction.export_filename replacement_key = replacement_instruction.new_key # Move pointer to the position indicated by the tuple. pointer = exported_data for key in dictionary_path[:-1]: pointer = pointer[key] # Swap out data with replacement filename. image_key = dictionary_path[-1] image_data = pointer[image_key] if image_data is not None: # Ruling out the possibility of Any for mypy type checking. assert isinstance(image_data, str) takeout_image_files.append( takeout_domain.TakeoutImage(image_data, replacement_filename)) pointer[image_key] = replacement_filename # Rename the key. pointer[replacement_key] = pointer.pop(image_key) return takeout_domain.TakeoutData(exported_data, takeout_image_files)