"""Amazon S3 connector.""" import boto3 from botocore.errorfactory import ClientError from oto import response from sentry_sdk import capture_exception class S3FileNotFound(Exception): """ Exceptions that raises if provided key wasn't found in bucket. Attributes: key (str): Wrong provided key. bucket (str): S3 Bucket. """ def __init__(self, key, bucket): """Show exception message. Args: key (str): Key that wasn't found in provided bucket. bucket (str): Bucket where key had to exist. """ Exception.__init__(self, '{key} not found in bucket {bucket}!'.format( key=key, bucket=bucket)) def connect_to_s3(): """Connect to S3. Connect to S3 via AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env variables Returns: S3Connection: S3Connection object provides access to s3. """ conn = boto3.Session() s3_connection = conn.client('s3') return s3_connection def get_s3_file_url(s3_connection, bucket_name, file_key, expires_in=86400): """Generate download url for provided file in s3 bucket. Args: s3_connection (S3Connection): S3Connection object authorized in s3. bucket_name (str): name of bucket where file is stored. file_key (str): path to file for which url should be generated. expires_in (int): lifetime of url. Default is 1 day. Returns: Response: Response with url in message or with errors. """ try: s3_connection.head_bucket(Bucket=bucket_name) try: s3_connection.head_object(Bucket=bucket_name, Key=file_key) except ClientError: raise S3FileNotFound(key=file_key, bucket=bucket_name) url = s3_connection.generate_presigned_url( 'get_object', Params={'Bucket': bucket_name, 'Key': file_key}, ExpiresIn=expires_in) return response.Response(url) except ClientError as ex: capture_exception(ex) return response.create_error_response( code=ex.response['Error']['Code'], message=ex.response['Error']['Message'], status=ex.response['ResponseMetadata']['HTTPStatusCode']) except S3FileNotFound as ex: capture_exception(ex) return response.create_not_found_response( message=ex.args[0])