adding the s3 and cloudfront
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 34s
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 34s
This commit is contained in:
parent
05e313b837
commit
f1ee0b5774
6 changed files with 117 additions and 1 deletions
|
|
@ -14,11 +14,29 @@ class CategoryListField(serializers.RelatedField):
|
|||
class SupplierProfileSerializer(serializers.ModelSerializer):
|
||||
onboarding_step = serializers.SerializerMethodField()
|
||||
categories = CategoryListField(many=True, queryset=Category.objects.all(), required=False)
|
||||
aadhar_url = serializers.SerializerMethodField()
|
||||
pan_url = serializers.SerializerMethodField()
|
||||
logo_url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = SupplierProfile
|
||||
exclude = ('user',)
|
||||
|
||||
def get_aadhar_url(self, obj):
|
||||
from .views import get_document_url
|
||||
request = self.context.get('request')
|
||||
return get_document_url(obj.aadhar_s3_key, request)
|
||||
|
||||
def get_pan_url(self, obj):
|
||||
from .views import get_document_url
|
||||
request = self.context.get('request')
|
||||
return get_document_url(obj.pan_s3_key, request)
|
||||
|
||||
def get_logo_url(self, obj):
|
||||
from .views import get_document_url
|
||||
request = self.context.get('request')
|
||||
return get_document_url(obj.logo_s3_key, request)
|
||||
|
||||
def get_onboarding_step(self, obj):
|
||||
if obj.is_profile_complete:
|
||||
return 7
|
||||
|
|
|
|||
49
api/tests.py
49
api/tests.py
|
|
@ -190,3 +190,52 @@ def test_wallet_withdrawal(api_client, create_user):
|
|||
# Invalid amount (exceeds outstanding)
|
||||
response = api_client.post(url, {'amount': '1500.00'}, format='json')
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_document_cloudfront_url_generation(api_client, create_user):
|
||||
from django.conf import settings
|
||||
from api.views import get_document_url
|
||||
|
||||
profile = create_user.profile
|
||||
profile.aadhar_s3_key = 'suppliers/123/aadhar.pdf'
|
||||
profile.save()
|
||||
|
||||
# Case 1: CloudFront Domain set
|
||||
settings.AWS_CLOUDFRONT_DOMAIN = 'd12345.cloudfront.net'
|
||||
url = get_document_url(profile.aadhar_s3_key)
|
||||
assert url == 'https://d12345.cloudfront.net/suppliers/123/aadhar.pdf'
|
||||
|
||||
# Case 2: CloudFront Domain set with protocol prefix
|
||||
settings.AWS_CLOUDFRONT_DOMAIN = 'https://d98765.cloudfront.net/'
|
||||
url = get_document_url(profile.aadhar_s3_key)
|
||||
assert url == 'https://d98765.cloudfront.net/suppliers/123/aadhar.pdf'
|
||||
|
||||
# Case 3: CloudFront Domain empty, fallback to Local Mock
|
||||
settings.AWS_CLOUDFRONT_DOMAIN = ''
|
||||
url = get_document_url(profile.aadhar_s3_key)
|
||||
assert 'mock-download' in url
|
||||
|
||||
# Case 4: API Response includes aadhar_url, pan_url, logo_url
|
||||
url = reverse('profile')
|
||||
api_client.force_authenticate(user=create_user)
|
||||
response = api_client.get(url)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert 'aadhar_url' in response.data['profile']
|
||||
assert 'pan_url' in response.data['profile']
|
||||
assert 'logo_url' in response.data['profile']
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_mock_download_view(api_client, create_user):
|
||||
api_client.force_authenticate(user=create_user)
|
||||
|
||||
# 1. Upload mock file first using PUT request
|
||||
upload_url = reverse('mock-upload') + '?key=test_key.pdf'
|
||||
file_content = b'PDF content'
|
||||
upload_resp = api_client.put(upload_url, data=file_content, content_type='application/octet-stream')
|
||||
assert upload_resp.status_code == status.HTTP_200_OK
|
||||
|
||||
# 2. Download it
|
||||
download_url = reverse('mock-download') + '?key=test_key.pdf'
|
||||
download_resp = api_client.get(download_url)
|
||||
assert download_resp.status_code == status.HTTP_200_OK
|
||||
assert b"".join(download_resp.streaming_content) == file_content
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from rest_framework_simplejwt.views import TokenRefreshView
|
|||
from .views import (
|
||||
RegisterView, LoginView, LogoutView, VerifyOtpView, ProfileView,
|
||||
ProductViewSet, BulkUploadView, OrderViewSet, ReturnRequestViewSet,
|
||||
WalletView, WithdrawView, SubmitGstinView, PresignedUrlView, MockUploadView
|
||||
WalletView, WithdrawView, SubmitGstinView, PresignedUrlView, MockUploadView, MockDownloadView
|
||||
)
|
||||
|
||||
router = DefaultRouter()
|
||||
|
|
@ -22,6 +22,7 @@ urlpatterns = [
|
|||
path('profile/submit-gstin/', SubmitGstinView.as_view(), name='submit-gstin'),
|
||||
path('profile/presigned-url/', PresignedUrlView.as_view(), name='presigned-url'),
|
||||
path('profile/mock-upload/', MockUploadView.as_view(), name='mock-upload'),
|
||||
path('profile/mock-download/', MockDownloadView.as_view(), name='mock-download'),
|
||||
path('products/bulk-upload/', BulkUploadView.as_view(), name='bulk-upload'),
|
||||
path('wallet/', WalletView.as_view(), name='wallet'),
|
||||
path('wallet/withdraw/', WithdrawView.as_view(), name='withdraw'),
|
||||
|
|
|
|||
43
api/views.py
43
api/views.py
|
|
@ -7,6 +7,7 @@ import io
|
|||
import os
|
||||
import zipfile
|
||||
from django.conf import settings
|
||||
from django.http import FileResponse, Http404
|
||||
from datetime import date, datetime, timedelta
|
||||
from django.utils import timezone
|
||||
from django.contrib.auth import authenticate
|
||||
|
|
@ -286,6 +287,48 @@ class MockUploadView(APIView):
|
|||
except Exception as e:
|
||||
return Response({"error": f"Failed to save file locally: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
def get_document_url(s3_key, request=None):
|
||||
if not s3_key:
|
||||
return None
|
||||
|
||||
# 1. CloudFront distribution
|
||||
cloudfront_domain = getattr(settings, 'AWS_CLOUDFRONT_DOMAIN', None)
|
||||
if cloudfront_domain:
|
||||
domain = cloudfront_domain.replace('https://', '').replace('http://', '').strip('/')
|
||||
return f"https://{domain}/{s3_key}"
|
||||
|
||||
# 2. AWS S3 fallback
|
||||
aws_access = os.environ.get('AWS_ACCESS_KEY_ID') or os.environ.get('AWS_ACCESS_KEY')
|
||||
aws_secret = os.environ.get('AWS_SECRET_ACCESS_KEY') or os.environ.get('AWS_SECRET_KEY')
|
||||
bucket_name = os.environ.get('AWS_STORAGE_BUCKET_NAME') or os.environ.get('AWS_BUCKET_NAME') or 'betasupplierdocument-764709663363-ap-south-2-an'
|
||||
region_name = os.environ.get('AWS_REGION', 'ap-south-2')
|
||||
|
||||
if aws_access and aws_secret:
|
||||
return f"https://{bucket_name}.s3.{region_name}.amazonaws.com/{s3_key}"
|
||||
|
||||
# 3. Local Mock fallback
|
||||
path = f"/api/profile/mock-download/?key={s3_key}"
|
||||
if request:
|
||||
return request.build_absolute_uri(path)
|
||||
return path
|
||||
|
||||
class MockDownloadView(APIView):
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
def get(self, request):
|
||||
s3_key = request.query_params.get('key')
|
||||
if not s3_key:
|
||||
return Response({"error": "key query param is required"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
base_dir = os.environ.get('UPLOAD_MOUNT_DIR', '/home/ubuntu/mnt/s3files/supplierdocuments')
|
||||
if not os.path.exists('/home/ubuntu/mnt/s3files/supplierdocuments') and not os.environ.get('UPLOAD_MOUNT_DIR'):
|
||||
base_dir = os.path.join(settings.BASE_DIR, 'mnt/s3files/supplierdocuments')
|
||||
|
||||
file_path = os.path.join(base_dir, s3_key)
|
||||
if os.path.exists(file_path):
|
||||
return FileResponse(open(file_path, 'rb'))
|
||||
raise Http404("File not found")
|
||||
|
||||
class PresignedUrlView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
|
|
|
|||
|
|
@ -314,3 +314,7 @@ LOGGING = {
|
|||
# Media files (uploads)
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
# CloudFront Domain Configuration
|
||||
AWS_CLOUDFRONT_DOMAIN = os.environ.get('AWS_CLOUDFRONT_DOMAIN', '')
|
||||
|
||||
|
|
|
|||
1
mnt/s3files/supplierdocuments/test_key.pdf
Normal file
1
mnt/s3files/supplierdocuments/test_key.pdf
Normal file
|
|
@ -0,0 +1 @@
|
|||
PDF content
|
||||
Loading…
Reference in a new issue