def post(self, analysis_id):
        # Obtiene el análisis.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para editar los
        # comentarios del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user, 'edit_comments'):
            return '', 403

        # Obtiene los valores de los argumentos recibidos en la petición.
        args = parser_post_auth.parse_args()
        comment = args['comment']

        # Crea el nuevo comentario de análisis.
        new_analysis_comment = AnalysisComment(datetime.utcnow(),
                                               comment,
                                               analysis.id,
                                               g.user.profile.id)
        db.session.add(new_analysis_comment)
        db.session.flush()

        # Verifica que el usuario autenticado no sea el dueño del análisis.
        if g.user.id != analysis.profile.user.first().id:
            # Crea la notificación dirigida al dueño del análisis.
            notification = NotificationNewAnalysisComment(analysis.profile.id,
                                                          g.user.profile.id,
                                                          new_analysis_comment.id
                                                          )
            db.session.add(notification)

        db.session.commit()
        return new_analysis_comment, 201
    def get(self, id):
        analysis_file = AnalysisFile.query.get_or_404(id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # archivos de análisis, del análisis asociado.
        if not permission.get_permission_by_user(analysis_file.analysis, g.user, 'view_analysis_files'):
            return '', 403

        file_path = analysis_file.path
        file_name = file_path.rsplit('/')[-1]
        user = g.user
        file_manager = FileManagerFactory().get_file_manager(analysis_file.analysis.profile.user.first())
        file_str = file_manager.download_file(file_path)

        if analysis_file.is_encrypted:
            # Obtiene la instancia de AnalysisFileEncryption, que fue generada
            # al encriptar el archivo.
            analysis_file_encryption = analysis_file.analysis_file_encryptions.first()
            # Obtiene la clave secreta encriptada.
            encrypted_secret_key = analysis_file_encryption.encrypted_secret_key
            # Obtiene la clave RSA privada del usuario que encriptó el archivo.
            rsa_private_key = analysis_file_encryption.profile.user.first().rsa_private_key
            # Desencripta la clave secreta con la clave RSA privada del usuario
            # que encriptó el archivo.
            secret_key = encryption.decrypt_secret_key(encrypted_secret_key,
                                                       rsa_private_key
                                                       )
            # Desencripta el archivo haciendo uso de la clave secreta.
            file_str = encryption.decrypt_file(file_str, secret_key)

        str_in_out = StringIO()
        str_in_out.write(file_str)
        str_in_out.seek(0)
        return send_file(str_in_out, attachment_filename=file_name, as_attachment=True)
示例#3
0
    def post(self):
        # Obtiene los valores de los argumentos recibidos en la petición.
        args = parser_post.parse_args()
        datetime = args['datetime']
        value = args['value']
        analysis_id = args['analysis_id']
        profile_id = args['profile_id']
        measurement_source_id = args['measurement_source_id']
        measurement_type_id = args['measurement_type_id']
        measurement_unit_id = args['measurement_unit_id']

        # Obtiene el análisis especificado.
        if analysis_id is not None:
            analysis = Analysis.query.get_or_404(analysis_id)
            # Verifica que el usuario autenticado tenga permiso para editar las
            # mediciones del análisis especificado, en caso de que exista.
            if not permission.get_permission_by_user(analysis, g.user, 'edit_measurements'):
                return '', 403

        new_measurement = Measurement(datetime,
                                      value,
                                      analysis_id,
                                      profile_id,
                                      measurement_source_id,
                                      measurement_type_id,
                                      measurement_unit_id)
        db.session.add(new_measurement)
        db.session.commit()
        return new_measurement, 201
示例#4
0
    def post(self):
        # Obtiene los valores de los argumentos recibidos en la petición.
        args = parser_post.parse_args()
        datetime = args['datetime']
        value = args['value']
        analysis_id = args['analysis_id']
        profile_id = args['profile_id']
        measurement_source_id = args['measurement_source_id']
        measurement_type_id = args['measurement_type_id']
        measurement_unit_id = args['measurement_unit_id']

        # Obtiene el análisis especificado.
        if analysis_id is not None:
            analysis = Analysis.query.get_or_404(analysis_id)
            # Verifica que el usuario autenticado tenga permiso para editar las
            # mediciones del análisis especificado, en caso de que exista.
            if not permission.get_permission_by_user(analysis, g.user,
                                                     'edit_measurements'):
                return '', 403

        new_measurement = Measurement(datetime, value, analysis_id, profile_id,
                                      measurement_source_id,
                                      measurement_type_id, measurement_unit_id)
        db.session.add(new_measurement)
        db.session.commit()
        return new_measurement, 201
    def post(self, analysis_id):
        # Obtiene el análisis.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para editar los
        # comentarios del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user,
                                                 'edit_comments'):
            return '', 403

        # Obtiene los valores de los argumentos recibidos en la petición.
        args = parser_post_auth.parse_args()
        comment = args['comment']

        # Crea el nuevo comentario de análisis.
        new_analysis_comment = AnalysisComment(datetime.utcnow(), comment,
                                               analysis.id, g.user.profile.id)
        db.session.add(new_analysis_comment)
        db.session.flush()

        # Verifica que el usuario autenticado no sea el dueño del análisis.
        if g.user.id != analysis.profile.user.first().id:
            # Crea la notificación dirigida al dueño del análisis.
            notification = NotificationNewAnalysisComment(
                analysis.profile.id, g.user.profile.id,
                new_analysis_comment.id)
            db.session.add(notification)

        db.session.commit()
        return new_analysis_comment, 201
示例#6
0
    def put(self, id):
        analysis_file = AnalysisFile.query.get_or_404(id)
        args = parser_put.parse_args()

        # Verifica que el usuario autenticado tenga permiso para editar los
        # archivos de análisis, del análisis asociado.
        if not permission.get_permission_by_user(analysis_file.analysis, g.user, 'edit_analysis_files'):
            return '', 403

        # Actualiza los atributos del objeto, en base a los argumentos
        # recibidos.

        # Actualiza la ruta del archivo, en caso de que haya sido modificada.
        if (args['path'] is not None and
              analysis_file.path != args['path']):
            analysis_file.path = args['path']
        # Actualiza la descripción, en caso de que haya sido modificada.
        if (args['description'] is not None and
              analysis_file.description != args['description']):
            analysis_file.description = args['description']
        # Actualiza el análisis asociado, en caso de que haya sido modificado.
        if (args['analysis_id'] is not None and
              analysis_file.analysis_id != args['analysis_id']):
            analysis_file.analysis_id = args['analysis_id']
        # Actualiza la ubicación de almacenamiento asociada, en caso de que
        # haya sido modificada.
        if (args['storage_location_id'] is not None and
              analysis_file.storage_location_id != args['storage_location_id']):
            analysis_file.storage_location_id = args['storage_location_id']

        db.session.commit()
        return analysis_file, 200
示例#7
0
    def post(self):
        # Obtiene los valores de los argumentos recibidos en la petición.
        args = parser_post.parse_args()
        image_file = args['image_file']
        description = args['description']
        is_encrypted = args['is_encrypted'] or False
        analysis_id = args['analysis_id']

        # Obtiene el análisis especificado.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para editar los
        # archivos de análisis, del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user, 'edit_analysis_files'):
            return '', 403

        # Verifica si el archivo debe ser encriptado.
        if is_encrypted:
            # Verifica que el usuario autenticado tenga generado su par de
            # claves RSA.
            if (g.user.rsa_public_key is None or
                    g.user.rsa_public_key == ''):
                # Crea el par de claves RSA del usuario.
                g.user.create_rsa_keys()
                db.session.add(g.user)
                db.session.flush()
            # Genera una nueva clave secreta para encriptar el archivo.
            secret_key = encryption.generate_secret_key(32)
            # Encripta la clave secreta con la clave RSA pública del usuario autenticado.
            encrypted_secret_key = encryption.encrypt_secret_key(secret_key, g.user.rsa_public_key)
            # Encripta el archivo haciendo uso de la clave secreta.
            image_file = encryption.encrypt_file(image_file, secret_key)

        file_manager = FileManagerFactory().get_file_manager(analysis.profile.user.first())
        res = file_manager.upload_file(image_file)
        storage_location = StorageLocation.query.filter_by(name=res['storage_location']).first()
        if storage_location is None:
            raise ValueError("No se encuentra una ubicación con la denominación especificada.")

        new_analysis_file = AnalysisFile(datetime.utcnow(),
                                         res['path'],
                                         description,
                                         analysis.id,
                                         storage_location.id,
                                         is_encrypted
                                         )
        db.session.add(new_analysis_file)

        if is_encrypted:
            db.session.flush()
            new_analysis_file_encryption = AnalysisFileEncryption(encrypted_secret_key,
                                                                  new_analysis_file.id,
                                                                  g.user.profile.id
                                                                  )
            db.session.add(new_analysis_file_encryption)

        db.session.commit()
        return new_analysis_file, 201
示例#8
0
    def post(self):
        # Obtiene los valores de los argumentos recibidos en la petición.
        args = parser_post.parse_args()
        image_file = args['image_file']
        description = args['description']
        is_encrypted = args['is_encrypted'] or False
        analysis_id = args['analysis_id']

        # Obtiene el análisis especificado.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para editar los
        # archivos de análisis, del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user,
                                                 'edit_analysis_files'):
            return '', 403

        # Verifica si el archivo debe ser encriptado.
        if is_encrypted:
            # Verifica que el usuario autenticado tenga generado su par de
            # claves RSA.
            if (g.user.rsa_public_key is None or g.user.rsa_public_key == ''):
                # Crea el par de claves RSA del usuario.
                g.user.create_rsa_keys()
                db.session.add(g.user)
                db.session.flush()
            # Genera una nueva clave secreta para encriptar el archivo.
            secret_key = encryption.generate_secret_key(32)
            # Encripta la clave secreta con la clave RSA pública del usuario autenticado.
            encrypted_secret_key = encryption.encrypt_secret_key(
                secret_key, g.user.rsa_public_key)
            # Encripta el archivo haciendo uso de la clave secreta.
            image_file = encryption.encrypt_file(image_file, secret_key)

        file_manager = FileManagerFactory().get_file_manager(
            analysis.profile.user.first())
        res = file_manager.upload_file(image_file)
        storage_location = StorageLocation.query.filter_by(
            name=res['storage_location']).first()
        if storage_location is None:
            raise ValueError(
                "No se encuentra una ubicación con la denominación especificada."
            )

        new_analysis_file = AnalysisFile(datetime.utcnow(), res['path'],
                                         description, analysis.id,
                                         storage_location.id, is_encrypted)
        db.session.add(new_analysis_file)

        if is_encrypted:
            db.session.flush()
            new_analysis_file_encryption = AnalysisFileEncryption(
                encrypted_secret_key, new_analysis_file.id, g.user.profile.id)
            db.session.add(new_analysis_file_encryption)

        db.session.commit()
        return new_analysis_file, 201
示例#9
0
    def get(self, id):
        analysis_file = AnalysisFile.query.get_or_404(id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # archivos de análisis, del análisis asociado.
        if not permission.get_permission_by_user(analysis_file.analysis, g.user, 'view_analysis_files'):
            return '', 403

        return analysis_file
示例#10
0
    def get(self, analysis_comment_id):
        # Obtiene el comentario de análisis.
        analysis_comment = AnalysisComment.query.get_or_404(analysis_comment_id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # comentarios del análisis asociado.
        if not permission.get_permission_by_user(analysis_comment.analysis, g.user, 'view_comments'):
            return '', 403

        return analysis_comment
示例#11
0
    def get(self, analysis_file_id):
        # Obtiene el archivo de análisis.
        analysis_file = AnalysisFile.query.get_or_404(analysis_file_id)

        # Obtiene los valores de los argumentos recibidos en la petición.
        args = parser.parse_args()
        download = args['download'] or False
        token = args['token']

        # Comprueba el token recibido.
        user = User.verify_auth_token(token)
        if user is None:
            return '', 401

        # Verifica que el usuario autenticado tenga permiso para ver los
        # archivos de análisis, del análisis asociado.
        if not permission.get_permission_by_user(analysis_file.analysis, user,
                                                 'view_analysis_files'):
            return '', 403

        file_path = analysis_file.path
        file_name = file_path.rsplit('/')[-1]
        file_manager = FileManagerFactory().get_file_manager(
            analysis_file.analysis.profile.user.first())

        # Verifica si el archivo de análisis está encriptado. De ser así,
        # recupera el archivo original. Sino, solicita su thumbnail a la
        # ubicación de almacenamiento.
        if analysis_file.is_encrypted:
            file_str = file_manager.download_file(file_path)
            # Obtiene la instancia de AnalysisFileEncryption, que fue generada
            # al encriptar el archivo.
            analysis_file_encryption = analysis_file.analysis_file_encryptions.first(
            )
            # Obtiene la clave secreta encriptada.
            encrypted_secret_key = analysis_file_encryption.encrypted_secret_key
            # Obtiene la clave RSA privada del usuario que encriptó el archivo.
            rsa_private_key = analysis_file_encryption.profile.user.first(
            ).rsa_private_key
            # Desencripta la clave secreta con la clave RSA privada del usuario
            # que encriptó el archivo.
            secret_key = encryption.decrypt_secret_key(encrypted_secret_key,
                                                       rsa_private_key)
            # Desencripta el archivo haciendo uso de la clave secreta.
            file_str = encryption.decrypt_file(file_str, secret_key)
        else:
            file_str = file_manager.get_thumbnail(file_path)

        str_in_out = StringIO()
        str_in_out.write(file_str)
        str_in_out.seek(0)
        return send_file(str_in_out,
                         attachment_filename=file_name,
                         as_attachment=download)
示例#12
0
    def get(self, analysis_id):
        # Obtiene el análisis.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # archivos de análisis, del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user, 'view_analysis_files'):
            return '', 403

        # Obtiene todos los archivos de análisis asociados al análisis.
        analysis_files = analysis.analysis_files.all()
        return analysis_files
示例#13
0
    def get(self, analysis_id):
        # Obtiene el análisis.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para ver las
        # mediciones del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user, 'view_measurements'):
            return '', 403

        # Obtiene todas las mediciones asociadas al análisis.
        measurements = analysis.measurements.all()
        return measurements
示例#14
0
    def get(self, analysis_comment_id):
        # Obtiene el comentario de análisis.
        analysis_comment = AnalysisComment.query.get_or_404(
            analysis_comment_id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # comentarios del análisis asociado.
        if not permission.get_permission_by_user(analysis_comment.analysis,
                                                 g.user, 'view_comments'):
            return '', 403

        return analysis_comment
    def get(self, analysis_id):
        # Obtiene el análisis.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # comentarios del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user, 'view_comments'):
            return '', 403

        # Obtiene todos los comentarios de análisis asociados al análisis, y
        # los ordena por fecha y hora.
        analysis_comments = analysis.analysis_comments.order_by(AnalysisComment.datetime).all()
        return analysis_comments
示例#16
0
    def put(self, id):
        measurement = Measurement.query.get_or_404(id)
        args = parser_put.parse_args()

        # Verifica que el usuario autenticado tenga permiso para editar las
        # mediciones del análisis asociado a la medición especificada, en caso
        # de que exista.
        if (measurement.analysis is not None
                and not permission.get_permission_by_user(
                    measurement.analysis, g.user, 'edit_measurements')):
            return '', 403

        # Actualiza los atributos y relaciones del objeto, en base a los
        # argumentos recibidos.

        # Actualiza la fecha y hora, en caso de que haya sido modificada.
        if (args['datetime'] is not None
                and measurement.datetime != args['datetime']):
            measurement.datetime = args['datetime']
        # Actualiza el valor, en caso de que haya sido modificado.
        if (args['value'] is not None and measurement.value != args['value']):
            measurement.value = args['value']
        # Actualiza el análisis asociado, en caso de que haya sido modificado.
        if (args['analysis_id'] is not None
                and measurement.analysis_id != args['analysis_id']):
            measurement.analysis_id = args['analysis_id']
        # Actualiza el perfil asociado, en caso de que haya sido modificado.
        if (args['profile_id'] is not None
                and measurement.profile_id != args['profile_id']):
            measurement.profile_id = args['profile_id']
        # Actualiza la fuente de la medición, en caso de que haya sido
        # modificada.
        if (args['measurement_source_id'] is not None
                and measurement.measurement_source_id !=
                args['measurement_source_id']):
            measurement.measurement_source_id = args['measurement_source_id']
        # Actualiza el tipo de medición, en caso de que haya sido modificado.
        if (args['measurement_type_id'] is not None
                and measurement.measurement_type_id !=
                args['measurement_type_id']):
            measurement.measurement_type_id = args['measurement_type_id']
        # Actualiza la unidad de medida asociada, en caso de que haya sido
        # modificada.
        if (args['measurement_unit_id'] is not None
                and measurement.measurement_unit_id !=
                args['measurement_unit_id']):
            measurement.measurement_unit_id = args['measurement_unit_id']

        db.session.commit()
        return measurement, 200
    def get(self, analysis_id):
        # Obtiene el análisis.
        analysis = Analysis.query.get_or_404(analysis_id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # comentarios del análisis especificado.
        if not permission.get_permission_by_user(analysis, g.user,
                                                 'view_comments'):
            return '', 403

        # Obtiene todos los comentarios de análisis asociados al análisis, y
        # los ordena por fecha y hora.
        analysis_comments = analysis.analysis_comments.order_by(
            AnalysisComment.datetime).all()
        return analysis_comments
示例#18
0
    def delete(self, id):
        # Obtiene la medición.
        measurement = Measurement.query.get_or_404(id)

        # Verifica que el usuario autenticado tenga permiso para editar las
        # mediciones del análisis asociado a la medición especificada, en caso
        # de que exista.
        if (measurement.analysis is not None and
                not permission.get_permission_by_user(measurement.analysis, g.user, 'edit_measurements')):
            return '', 403

        # Elimina la medición.
        db.session.delete(measurement)
        db.session.commit()

        return '', 204
示例#19
0
    def put(self, id):
        measurement = Measurement.query.get_or_404(id)
        args = parser_put.parse_args()

        # Verifica que el usuario autenticado tenga permiso para editar las
        # mediciones del análisis asociado a la medición especificada, en caso
        # de que exista.
        if (measurement.analysis is not None and
                not permission.get_permission_by_user(measurement.analysis, g.user, 'edit_measurements')):
            return '', 403

        # Actualiza los atributos y relaciones del objeto, en base a los
        # argumentos recibidos.

        # Actualiza la fecha y hora, en caso de que haya sido modificada.
        if (args['datetime'] is not None and
              measurement.datetime != args['datetime']):
            measurement.datetime = args['datetime']
        # Actualiza el valor, en caso de que haya sido modificado.
        if (args['value'] is not None and
              measurement.value != args['value']):
            measurement.value = args['value']
        # Actualiza el análisis asociado, en caso de que haya sido modificado.
        if (args['analysis_id'] is not None and
              measurement.analysis_id != args['analysis_id']):
            measurement.analysis_id = args['analysis_id']
        # Actualiza el perfil asociado, en caso de que haya sido modificado.
        if (args['profile_id'] is not None and
              measurement.profile_id != args['profile_id']):
            measurement.profile_id = args['profile_id']
        # Actualiza la fuente de la medición, en caso de que haya sido
        # modificada.
        if (args['measurement_source_id'] is not None and
              measurement.measurement_source_id != args['measurement_source_id']):
            measurement.measurement_source_id = args['measurement_source_id']
        # Actualiza el tipo de medición, en caso de que haya sido modificado.
        if (args['measurement_type_id'] is not None and
              measurement.measurement_type_id != args['measurement_type_id']):
            measurement.measurement_type_id = args['measurement_type_id']
        # Actualiza la unidad de medida asociada, en caso de que haya sido
        # modificada.
        if (args['measurement_unit_id'] is not None and
              measurement.measurement_unit_id != args['measurement_unit_id']):
            measurement.measurement_unit_id = args['measurement_unit_id']

        db.session.commit()
        return measurement, 200
示例#20
0
    def delete(self, id):
        # Obtiene la medición.
        measurement = Measurement.query.get_or_404(id)

        # Verifica que el usuario autenticado tenga permiso para editar las
        # mediciones del análisis asociado a la medición especificada, en caso
        # de que exista.
        if (measurement.analysis is not None
                and not permission.get_permission_by_user(
                    measurement.analysis, g.user, 'edit_measurements')):
            return '', 403

        # Elimina la medición.
        db.session.delete(measurement)
        db.session.commit()

        return '', 204
示例#21
0
    def delete(self, id):
        # Obtiene el archivo de análisis.
        analysis_file = AnalysisFile.query.get_or_404(id)

        # Verifica que el usuario autenticado tenga permiso para editar los
        # archivos de análisis, del análisis asociado.
        if not permission.get_permission_by_user(analysis_file.analysis, g.user, 'edit_analysis_files'):
            return '', 403

        # Elimina el archivo asociado de la ubicación de almacenamiento.
        analysisFile.delete_file(analysis_file)

        # Elimina el archivo de análisis.
        db.session.delete(analysis_file)
        db.session.commit()

        return '', 204
示例#22
0
    def get(self, id):
        analysis_file = AnalysisFile.query.get_or_404(id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # archivos de análisis, del análisis asociado.
        if not permission.get_permission_by_user(
                analysis_file.analysis, g.user, 'view_analysis_files'):
            return '', 403

        file_path = analysis_file.path
        file_name = file_path.rsplit('/')[-1]
        user = g.user
        file_manager = FileManagerFactory().get_file_manager(
            analysis_file.analysis.profile.user.first())
        file_str = file_manager.download_file(file_path)

        if analysis_file.is_encrypted:
            # Obtiene la instancia de AnalysisFileEncryption, que fue generada
            # al encriptar el archivo.
            analysis_file_encryption = analysis_file.analysis_file_encryptions.first(
            )
            # Obtiene la clave secreta encriptada.
            encrypted_secret_key = analysis_file_encryption.encrypted_secret_key
            # Obtiene la clave RSA privada del usuario que encriptó el archivo.
            rsa_private_key = analysis_file_encryption.profile.user.first(
            ).rsa_private_key
            # Desencripta la clave secreta con la clave RSA privada del usuario
            # que encriptó el archivo.
            secret_key = encryption.decrypt_secret_key(encrypted_secret_key,
                                                       rsa_private_key)
            # Desencripta el archivo haciendo uso de la clave secreta.
            file_str = encryption.decrypt_file(file_str, secret_key)

        str_in_out = StringIO()
        str_in_out.write(file_str)
        str_in_out.seek(0)
        return send_file(str_in_out,
                         attachment_filename=file_name,
                         as_attachment=True)
    def get(self, analysis_file_id):
        analysis_file = AnalysisFile.query.get_or_404(analysis_file_id)

        # Verifica que el usuario autenticado tenga permiso para ver los
        # archivos de análisis, del análisis asociado.
        if not permission.get_permission_by_user(analysis_file.analysis, g.user, 'view_analysis_files'):
            return '', 403

        file_path = analysis_file.path
        file_name = file_path.rsplit('/')[-1]
        file_manager = FileManagerFactory().get_file_manager(analysis_file.analysis.profile.user.first())

        # Verifica si el archivo de análisis está encriptado. De ser así,
        # recupera el archivo original. Sino, solicita su thumbnail a la
        # ubicación de almacenamiento.
        if analysis_file.is_encrypted:
            file_str = file_manager.download_file(file_path)
            # Obtiene la instancia de AnalysisFileEncryption, que fue generada
            # al encriptar el archivo.
            analysis_file_encryption = analysis_file.analysis_file_encryptions.first()
            # Obtiene la clave secreta encriptada.
            encrypted_secret_key = analysis_file_encryption.encrypted_secret_key
            # Obtiene la clave RSA privada del usuario que encriptó el archivo.
            rsa_private_key = analysis_file_encryption.profile.user.first().rsa_private_key
            # Desencripta la clave secreta con la clave RSA privada del usuario
            # que encriptó el archivo.
            secret_key = encryption.decrypt_secret_key(encrypted_secret_key,
                                                       rsa_private_key
                                                       )
            # Desencripta el archivo haciendo uso de la clave secreta.
            file_str = encryption.decrypt_file(file_str, secret_key)
        else:
            file_str = file_manager.get_thumbnail(file_path)

        str_in_out = StringIO()
        str_in_out.write(file_str)
        str_in_out.seek(0)
        return send_file(str_in_out, attachment_filename=file_name)