adding the s3 and cloudfront
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 34s

This commit is contained in:
vickytechkey 2026-08-20 11:21:14 +05:30
parent 05e313b837
commit f1ee0b5774
6 changed files with 117 additions and 1 deletions

View file

@ -14,11 +14,29 @@ class CategoryListField(serializers.RelatedField):
class SupplierProfileSerializer(serializers.ModelSerializer): class SupplierProfileSerializer(serializers.ModelSerializer):
onboarding_step = serializers.SerializerMethodField() onboarding_step = serializers.SerializerMethodField()
categories = CategoryListField(many=True, queryset=Category.objects.all(), required=False) categories = CategoryListField(many=True, queryset=Category.objects.all(), required=False)
aadhar_url = serializers.SerializerMethodField()
pan_url = serializers.SerializerMethodField()
logo_url = serializers.SerializerMethodField()
class Meta: class Meta:
model = SupplierProfile model = SupplierProfile
exclude = ('user',) 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): def get_onboarding_step(self, obj):
if obj.is_profile_complete: if obj.is_profile_complete:
return 7 return 7

View file

@ -190,3 +190,52 @@ def test_wallet_withdrawal(api_client, create_user):
# Invalid amount (exceeds outstanding) # Invalid amount (exceeds outstanding)
response = api_client.post(url, {'amount': '1500.00'}, format='json') response = api_client.post(url, {'amount': '1500.00'}, format='json')
assert response.status_code == status.HTTP_400_BAD_REQUEST 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

View file

@ -4,7 +4,7 @@ from rest_framework_simplejwt.views import TokenRefreshView
from .views import ( from .views import (
RegisterView, LoginView, LogoutView, VerifyOtpView, ProfileView, RegisterView, LoginView, LogoutView, VerifyOtpView, ProfileView,
ProductViewSet, BulkUploadView, OrderViewSet, ReturnRequestViewSet, ProductViewSet, BulkUploadView, OrderViewSet, ReturnRequestViewSet,
WalletView, WithdrawView, SubmitGstinView, PresignedUrlView, MockUploadView WalletView, WithdrawView, SubmitGstinView, PresignedUrlView, MockUploadView, MockDownloadView
) )
router = DefaultRouter() router = DefaultRouter()
@ -22,6 +22,7 @@ urlpatterns = [
path('profile/submit-gstin/', SubmitGstinView.as_view(), name='submit-gstin'), path('profile/submit-gstin/', SubmitGstinView.as_view(), name='submit-gstin'),
path('profile/presigned-url/', PresignedUrlView.as_view(), name='presigned-url'), path('profile/presigned-url/', PresignedUrlView.as_view(), name='presigned-url'),
path('profile/mock-upload/', MockUploadView.as_view(), name='mock-upload'), 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('products/bulk-upload/', BulkUploadView.as_view(), name='bulk-upload'),
path('wallet/', WalletView.as_view(), name='wallet'), path('wallet/', WalletView.as_view(), name='wallet'),
path('wallet/withdraw/', WithdrawView.as_view(), name='withdraw'), path('wallet/withdraw/', WithdrawView.as_view(), name='withdraw'),

View file

@ -7,6 +7,7 @@ import io
import os import os
import zipfile import zipfile
from django.conf import settings from django.conf import settings
from django.http import FileResponse, Http404
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from django.utils import timezone from django.utils import timezone
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
@ -286,6 +287,48 @@ class MockUploadView(APIView):
except Exception as e: except Exception as e:
return Response({"error": f"Failed to save file locally: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) 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): class PresignedUrlView(APIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]

View file

@ -314,3 +314,7 @@ LOGGING = {
# Media files (uploads) # Media files (uploads)
MEDIA_URL = '/media/' MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# CloudFront Domain Configuration
AWS_CLOUDFRONT_DOMAIN = os.environ.get('AWS_CLOUDFRONT_DOMAIN', '')

View file

@ -0,0 +1 @@
PDF content