darkor

s3

Aug 11th, 2023
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.42 KB | None | 0 0
  1. from http import HTTPStatus
  2. from io import BytesIO
  3. from typing import Dict, Optional
  4.  
  5. import boto3
  6. from botocore.client import BaseClient
  7. from botocore.exceptions import ClientError
  8.  
  9. from app import config
  10. from app.common import common_api
  11. from app.common.utils import Base64File, InMemoryFile
  12.  
  13.  
  14. class AwsS3Processor:
  15.     """A class that provides all the work with AWS S3"""
  16.  
  17.     def __init__(self, boto_client: BaseClient, bucket_name: str):
  18.         self._client = boto_client
  19.         self.bucket_name = bucket_name
  20.  
  21.     @classmethod
  22.     def create_from_credentials(
  23.         cls, aws_access_key_id: str, aws_secret_access_key: str, bucket_name: str
  24.     ) -> "AwsS3Processor":
  25.         client = boto3.client(
  26.             "s3",
  27.             aws_access_key_id=aws_access_key_id,
  28.             aws_secret_access_key=aws_secret_access_key,
  29.         )
  30.  
  31.         return cls(boto_client=client, bucket_name=bucket_name)
  32.  
  33.     @staticmethod
  34.     def _generate_acl(is_private: bool) -> Dict:
  35.         if is_private:
  36.             return {"ACL": "private"}
  37.  
  38.         return {"ACL": "public-read"}
  39.  
  40.     def upload_in_memory_file(
  41.         self, file: InMemoryFile, upload_to: str, is_private=False
  42.     ):
  43.         upload_to_key = f"{upload_to}/{file.full_filename}"
  44.  
  45.         try:
  46.             extra_args = self._generate_acl(is_private=is_private)
  47.             if file.content_type is not None:
  48.                 extra_args["ContentType"] = file.content_type
  49.  
  50.             self._client.upload_fileobj(
  51.                 Fileobj=file.file,
  52.                 Bucket=self.bucket_name,
  53.                 ExtraArgs=extra_args,
  54.                 Key=upload_to_key,
  55.             )
  56.         except Exception as e:
  57.             raise ValueError("An error occurred while uploading: ", e)
  58.  
  59.         return upload_to_key
  60.  
  61.     def download_in_memory_file(self, key: str) -> Optional[BytesIO]:
  62.         try:
  63.             response = self._client.get_object(Bucket=self.bucket_name, Key=key)
  64.  
  65.             return BytesIO(response['Body'].read())
  66.         except Exception as e:
  67.             print(f"[ERROR] During downloading the file {key}. Error: ", e)
  68.             return None
  69.  
  70.     @staticmethod
  71.     def generate_url_to_file(file_name: str, bucket_name: str = "", is_private: bool = True):
  72.         s3_client = boto3.client('s3')
  73.  
  74.         if is_private:
  75.             try:
  76.                 response = s3_client.generate_presigned_url(
  77.                     "get_object", Params={"Bucket": bucket_name, "Key": file_name}, ExpiresIn=3600
  78.                 )
  79.             except ClientError as e:
  80.                 print(str(e))
  81.                 return None
  82.  
  83.             return response
  84.  
  85.         return f"https://{bucket_name}.s3.amazonaws.com/{file_name}" if file_name else ""
  86.  
  87.     def generate_url_to_cloudfront(self, file_name: str, bucket_name: str = ""):
  88.         raise NotImplemented
  89.  
  90.  
  91. def get_aws_s3_processor() -> AwsS3Processor:
  92.     return AwsS3Processor.create_from_credentials(
  93.         aws_access_key_id=config.AWS_ACCESS_KEY,
  94.         aws_secret_access_key=config.AWS_ACCOUNT_SECRET_KEY,
  95.         bucket_name=config.AWS_IMAGES_S3_BUCKET,
  96.     )
  97.  
  98.  
  99. def upload_file_by_credentials_from_config(
  100.     base64_image: str, upload_to: str, is_image: bool = False, is_private=True, filename_prefix: str = None
  101. ) -> str:
  102.     filename = Base64File.generate_file_name()
  103.     if filename_prefix is not None:
  104.         filename = f"{filename_prefix}{filename}"
  105.  
  106.     try:
  107.         file = Base64File.create_from_b64_string(b64string=base64_image, filename=filename)
  108.  
  109.     except ValueError:
  110.         raise common_api.abort(message="Can not detect the mime type", code=HTTPStatus.BAD_REQUEST)
  111.  
  112.     allowed_extensions = config.ALLOWED_IMAGE_EXTENSIONS if is_image else config.ALLOWED_FILE_EXTENSIONS
  113.  
  114.     if not file.validate_file_extension(list_of_allowed_extensions=allowed_extensions):
  115.         raise common_api.abort(
  116.             message=f"Invalid file extension. Supported file types: {', '.join(allowed_extensions)}",
  117.             code=HTTPStatus.BAD_REQUEST,
  118.         )
  119.  
  120.     # Upload image to the s3 bucket
  121.     s3_processor = get_aws_s3_processor()
  122.     uploaded_to_path = s3_processor.upload_in_memory_file(
  123.         file=file, upload_to=upload_to, is_private=is_private
  124.     )
  125.  
  126.     return uploaded_to_path
  127.  
  128.  
  129. def download_file_by_credentials_from_config(key: str) -> Optional[BytesIO]:
  130.     # download image from the s3 bucket
  131.     return get_aws_s3_processor().download_in_memory_file(key)
  132.  
Add Comment
Please, Sign In to add comment