diff --git a/CHANGES b/CHANGES index f468441..8258051 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.5.1 (2024-01-15) +================== +* Revised upload methods + 0.5.0 (2025-01-13) ================== * Refactored upload logic out of view code diff --git a/s3sign/utils.py b/s3sign/utils.py index fb3d8c1..72d726e 100644 --- a/s3sign/utils.py +++ b/s3sign/utils.py @@ -1,8 +1,22 @@ import logging +import os +import uuid from botocore.config import Config from botocore.exceptions import ClientError +DEFAULT_AWS_REGION = 'us-east-1' +PATH_STRING = ( + '{root}{now.year:04d}/{now.month:02d}/' + '{now.day:02d}/{basename}{extension}') + + +def get_object_name(now, extension, root=''): + basename = str(uuid.uuid4()) + return PATH_STRING.format( + now=now, basename=basename, extension=extension, root=root) + + s3_config = Config( signature_version='s3v4', s3={'addressing_style': 'path'}, @@ -103,10 +117,37 @@ def create_presigned_post(s3_client, bucket_name, object_name, return response -def upload_file( +def upload_file(s3_client, file_name, bucket, object_name=None) -> bool: + """Upload a file to an S3 bucket + + :param file_name: File to upload + :param bucket: Bucket to upload to + :param object_name: S3 object name. If not specified then file_name is used + :return: True if file was uploaded, else False + """ + + # If S3 object_name was not specified, use file_name + if object_name is None: + object_name = os.path.basename(file_name) + + # Upload the file + try: + s3_client.upload_file(file_name, bucket, object_name) + except ClientError as e: + logging.error(e) + return False + + return True + + +def prepare_presigned_post( s3_client, bucket, mime_type, object_name, max_file_size, acl, expiration_time, private ) -> dict: + """ + Prepare data necessary to make a POST request to upload a file to + S3 from JavaScript. + """ S3_BUCKET = bucket url = 'https://{}.s3.amazonaws.com/{}'.format( diff --git a/s3sign/views.py b/s3sign/views.py index f0f987c..238baf5 100644 --- a/s3sign/views.py +++ b/s3sign/views.py @@ -11,10 +11,9 @@ from django.views.generic import View from django.utils import timezone -from s3sign.utils import s3_config, upload_file - - -DEFAULT_AWS_REGION = 'us-east-1' +from s3sign.utils import ( + DEFAULT_AWS_REGION, s3_config, prepare_presigned_post +) class SignS3View(View): @@ -129,7 +128,7 @@ def get(self, request): aws_secret_access_key=self.get_aws_secret_key() ) - data = upload_file( + data = prepare_presigned_post( self.s3_client, self.get_bucket(), self.get_mimetype(request), self.get_object_name(request), self.max_file_size, self.acl, self.get_expiration_time(), self.private)