"""Connector for AWS S3.""" import boto3 from botocore.exceptions import ClientError from oto import response from sentry_sdk import capture_exception from blacklist_manager import config s3_client = None def get_s3_client(): """Connect to S3. Returns: botocore.client.S3 : Client object provides access to s3. """ global s3_client if not s3_client: s3_client = boto3.client('s3') return s3_client def check_if_file_exists(file_key): """File lookup in s3 bucket. Args: file_key (str): path to a file Returns: bool: Whether file exists """ if not file_key: return False try: get_s3_client().head_object( Bucket=config.EXPORT_BUCKET_NAME, Key=file_key) except ClientError as error: return int(error.response['Error']['Code']) != 404 return True def get_signed_url(file_key, expires_in=86400): """Generate generate a pre-signed URL for file on S3 for expires_in time. Args: file_key (str): path to file for which url should be generated. expires_in (int): lifetime of url in sec. Default is 1 day. Returns: Response: Response with url in message or with errors. """ bucket_name = config.EXPORT_BUCKET_NAME if not check_if_file_exists(file_key): return response.create_not_found_response( message=f'{file_key} not found in {bucket_name} bucket') url = get_s3_client().generate_presigned_url( 'get_object', Params={'Bucket': bucket_name, 'Key': file_key}, ExpiresIn=expires_in ) return response.Response(message=url) def upload_file_from_disk(file_key, disk_file_path): """Upload file from disk to S3. Args: file_key (str): key of a file that should be uploaded to s3 bucket. disk_file_path (str): file path that is to be uploaded. """ try: get_s3_client().upload_file( disk_file_path, config.EXPORT_BUCKET_NAME, file_key) return response.Response( f'Successfully uploaded to {config.EXPORT_BUCKET_NAME}/{file_key}') except FileNotFoundError as err: capture_exception(err) return response.create_not_found_response( f'Temp file {file_key} not found')