views.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. from django.shortcuts import render
  2. # Create your views here.
  3. import time
  4. from rest_framework import permissions, status, authentication
  5. from rest_framework.response import Response
  6. from rest_framework.views import APIView
  7. from .config_aws import (
  8. AWS_UPLOAD_BUCKET,
  9. AWS_UPLOAD_REGION,
  10. AWS_UPLOAD_ACCESS_KEY_ID,
  11. AWS_UPLOAD_SECRET_KEY
  12. )
  13. from .models import FileItem
  14. class FilePolicyAPI(APIView):
  15. """
  16. This view is to get the AWS Upload Policy for our s3 bucket.
  17. What we do here is first create a FileItem object instance in our
  18. Django backend. This is to include the FileItem instance in the path
  19. we will use within our bucket as you'll see below.
  20. """
  21. permission_classes = [permissions.IsAuthenticated]
  22. authentication_classes = [authentication.SessionAuthentication]
  23. def post(self, request, *args, **kwargs):
  24. """
  25. The initial post request includes the filename
  26. and auth credientails. In our case, we'll use
  27. Session Authentication but any auth should work.
  28. """
  29. filename_req = request.data.get('filename')
  30. if not filename_req:
  31. return Response({"message": "A filename is required"}, status=status.HTTP_400_BAD_REQUEST)
  32. policy_expires = int(time.time()+5000)
  33. user = request.user
  34. username_str = str(request.user.username)
  35. """
  36. Below we create the Django object. We'll use this
  37. in our upload path to AWS.
  38. Example:
  39. To-be-uploaded file's name: Some Random File.mp4
  40. Eventual Path on S3: <bucket>/username/2312/2312.mp4
  41. """
  42. file_obj = FileItem.objects.create(user=user, name=filename_req)
  43. file_obj_id = file_obj.id
  44. upload_start_path = "{username}/{file_obj_id}/".format(
  45. username = username_str,
  46. file_obj_id=file_obj_id
  47. )
  48. _, file_extension = os.path.splitext(filename_req)
  49. filename_final = "{file_obj_id}{file_extension}".format(
  50. file_obj_id= file_obj_id,
  51. file_extension=file_extension
  52. )
  53. """
  54. Eventual file_upload_path includes the renamed file to the
  55. Django-stored FileItem instance ID. Renaming the file is
  56. done to prevent issues with user generated formatted names.
  57. """
  58. final_upload_path = "{upload_start_path}{filename_final}".format(
  59. upload_start_path=upload_start_path,
  60. filename_final=filename_final,
  61. )
  62. if filename_req and file_extension:
  63. """
  64. Save the eventual path to the Django-stored FileItem instance
  65. """
  66. file_obj.path = final_upload_path
  67. file_obj.save()
  68. policy_document_context = {
  69. "expire": policy_expires,
  70. "bucket_name": AWS_UPLOAD_BUCKET,
  71. "key_name": "",
  72. "acl_name": "private",
  73. "content_name": "",
  74. "content_length": 524288000,
  75. "upload_start_path": upload_start_path,
  76. }
  77. policy_document = """
  78. {"expiration": "2019-01-01T00:00:00Z",
  79. "conditions": [
  80. {"bucket": "%(bucket_name)s"},
  81. ["starts-with", "$key", "%(upload_start_path)s"],
  82. {"acl": "%(acl_name)s"},
  83. ["starts-with", "$Content-Type", "%(content_name)s"],
  84. ["starts-with", "$filename", ""],
  85. ["content-length-range", 0, %(content_length)d]
  86. ]
  87. }
  88. """ % policy_document_context
  89. aws_secret = str.encode(AWS_UPLOAD_SECRET_KEY)
  90. policy_document_str_encoded = str.encode(policy_document.replace(" ", ""))
  91. url = 'https://{bucket}.s3-{region}.amazonaws.com/'.format(
  92. bucket=AWS_UPLOAD_BUCKET,
  93. region=AWS_UPLOAD_REGION
  94. )
  95. policy = base64.b64encode(policy_document_str_encoded)
  96. signature = base64.b64encode(hmac.new(aws_secret, policy, hashlib.sha1).digest())
  97. data = {
  98. "policy": policy,
  99. "signature": signature,
  100. "key": AWS_UPLOAD_ACCESS_KEY_ID,
  101. "file_bucket_path": upload_start_path,
  102. "file_id": file_obj_id,
  103. "filename": filename_final,
  104. "url": url,
  105. "username": username_str,
  106. }
  107. return Response(data, status=status.HTTP_200_OK)