Example #1
0
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)
Example #2
0
 def test_that_domain_object_is_created_correctly(self) -> None:
     image_replacement_data = (
         takeout_domain.TakeoutImageReplacementInstruction(('exp1', ),
                                                           'test', 'key1'))
     self.assertEqual(image_replacement_data.dictionary_path, ('exp1', ))
     self.assertEqual(image_replacement_data.export_filename, 'test')
     self.assertEqual(image_replacement_data.new_key, 'key1')
Example #3
0
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)