File: //home/arjun/projects/aigenerator/AI-LG-backend/Ai_logo_generation/User/views.py
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import UserProfileSerializer, BillingAddressSerializer
from rest_framework.decorators import permission_classes
from image_generation.utils.s3_handler import S3Handler
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import os
import logging
from django.conf import settings
from payment.models import Transaction, Product
from django.utils import timezone
from .models import BillingAddress
from django.utils.timezone import now
from payment.views import cancel_subscription
from django.http import HttpRequest
import stripe
logger = logging.getLogger('User')
@permission_classes([IsAuthenticated])
class UserProfileView(APIView):
def get(self, request):
user = request.user
serializer = UserProfileSerializer(user, request_method='GET')
s3_handler = S3Handler()
latest_subscription = Transaction.objects.filter(
customer=user,
is_subscription=True
).order_by('-subscription_start').first()
product_data = None
will_expire_soon = False
if latest_subscription:
# If there's a subscription, get the relevant details
subscription_status = latest_subscription.subscription_status
if latest_subscription.subscription_status == 'active' :
is_subscribed = True
subscription_start = latest_subscription.subscription_start
subscription_end = latest_subscription.subscription_end
will_expire_soon = self.check_subscription_expiry(subscription_end)
else:
is_subscribed = False
subscription_start = None
subscription_end = None
try:
product = Product.objects.get(id=latest_subscription.product_id)
product_data = {
"name": product.name,
"amount": product.amount,
"description": product.description,
"currency": product.currency,
"resolution": product.resolution,
"billing_period": product.billing_period,
}
except Product.DoesNotExist:
product_data = None
else:
# No subscription found
is_subscribed = False
subscription_status = None
subscription_start = None
subscription_end = None
response_data = {
"data": {
"id": str(user.uuid),
"email": user.email,
"first_name": user.first_name,
"last_name": user.last_name,
"date_joined": user.date_joined,
"profile_image":s3_handler.generate_presigned_url(user.profile_image) if user.profile_image else None,
"is_verified":user.is_verified,
"is_subscribed": is_subscribed,
"subscription_status": subscription_status,
"subscription_date": {
"start": subscription_start,
"end": subscription_end
} if subscription_start and subscription_end else None,
"subscription_plan": product_data,
"will_expire_soon": will_expire_soon
},
"success": True,
"message": "User profile retrieved successfully.",
"statusCode": 200
}
return Response(response_data, status=status.HTTP_200_OK)
def check_subscription_expiry(self, subscription_end):
if not subscription_end:
return False # No subscription end date
# Calculate the difference in days
days_remaining = (subscription_end - now()).days
return days_remaining <= 5
@swagger_auto_schema(
responses={200: UserProfileSerializer()},
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'first_name': openapi.Schema(type=openapi.TYPE_STRING, description='First Name'),
'last_name': openapi.Schema(type=openapi.TYPE_STRING, description='Last Name'),
'profile_image': openapi.Schema(type=openapi.TYPE_FILE, description='Profile Image'),
},
)
)
def patch(self, request):
logger.info(request)
user = request.user
serializer = UserProfileSerializer(user, data=request.data, partial=True, request_method='PATCH')
logger.info(request.data)
logger.info(f"Serializer Initial Data: {serializer.initial_data}") # Log serializer initial data
logger.info(f"Request Files: {request.FILES}") # Log uploaded files
if serializer.is_valid():
# Check if an image is uploaded
image_file = request.FILES.get('profile_image')
if image_file:
s3_handler = S3Handler()
file_extension = os.path.splitext(image_file.name)[1] # Get file extension
key = f"{user.uuid}/profile/avatar{file_extension}" # Create a unique key for S3
upload_success = s3_handler.upload_image(image_file, key) # Upload to S3
if upload_success:
# If upload is successful, store the key in the user profile_image field
serializer.validated_data['profile_image'] = key
elif 'profile_image' in request.data and request.data['profile_image'] is None:
# If no image is uploaded, delete the existing image from S3
if user.profile_image:
s3_handler = S3Handler()
s3_handler.delete_object(user.profile_image)
serializer.validated_data['profile_image'] = None
# Save the validated data (including the image key if it was uploaded)
serializer.save()
s3_handler = S3Handler()
response_data = {
"data": {
"id": str(user.uuid),
"email": user.email,
"first_name": serializer.validated_data.get('first_name', user.first_name),
"last_name": serializer.validated_data.get('last_name', user.last_name),
"profile_image": s3_handler.generate_presigned_url(user.profile_image) if user.profile_image else None,
},
"success": True,
"message": "User profile updated successfully.",
"statusCode": 200
}
return Response(response_data, status=status.HTTP_200_OK)
return Response({
"error": serializer.errors,
"success": False,
"message": "Failed to update user profile.",
"statusCode": 400
}, status=status.HTTP_400_BAD_REQUEST)
# def delete(self, request):
# user = request.user
# user.is_active = False
# user.save()
# logger.info(f"User {user.email} has been deactivated.")
# return Response({
# "success": True,
# "message": "User account has been deactivated.",
# "statusCode": 200
# }, status=status.HTTP_200_OK)
def delete(self, request):
user = request.user
logger.info(f"Attempting to delete account for user: {user.email}")
try:
latest_transaction = Transaction.objects.filter(customer=user, is_subscription=True).order_by('-created_at').first()
logger.info("Fetched latest transaction for user.")
if latest_transaction:
subscription_id = latest_transaction.subscription_id
logger.info(f"Found subscription to cancel with ID: {subscription_id}")
try:
stripe.Subscription.delete(subscription_id)
latest_transaction.subscription_status = 'cancelled'
latest_transaction.is_subscription = False
latest_transaction.save()
logger.info(f"Subscription {subscription_id} cancelled and transaction updated.")
except stripe.error.StripeError as e:
logger.error(f"Stripe error while deleting subscription: {e}")
return Response({
"success": False,
"message": "Failed to cancel subscription on Stripe.",
"statusCode": 500
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except Exception as e:
logger.error(f"Unexpected error when updating subscription status: {e}")
return Response({
"success": False,
"message": "An error occurred while canceling the subscription.",
"statusCode": 500
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
else:
logger.info("No active subscription found for user.")
# Mark the user as deleted
user.is_deleted = True
user.is_active = False
user.deleted_at = timezone.now()
user.save()
logger.info(f"User {user.email} has been marked as deleted.")
return Response({
"success": True,
"message": "User account deleted successfully.",
"statusCode": 200
}, status=status.HTTP_200_OK)
except Exception as e:
logger.error(f"An error occurred while deleting the user account: {e}")
return Response({
"success": False,
"message": "Failed to delete user account.",
"statusCode": 500
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
# Billing address
@permission_classes([IsAuthenticated])
class BillingAddressView(APIView):
@swagger_auto_schema(
responses={200: BillingAddressSerializer()},
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'first_name': openapi.Schema(type=openapi.TYPE_STRING, description='First Name'),
'last_name': openapi.Schema(type=openapi.TYPE_STRING, description='Last Name'),
'country_code': openapi.Schema(type=openapi.TYPE_STRING, description='Country Code, e.g., +1 or +91'),
'phone_number': openapi.Schema(type=openapi.TYPE_STRING, description='Phone Number'),
'address': openapi.Schema(type=openapi.TYPE_STRING, description='Street Address'),
'city': openapi.Schema(type=openapi.TYPE_STRING, description='City'),
'state': openapi.Schema(type=openapi.TYPE_STRING, description='state'),
'postal_code': openapi.Schema(type=openapi.TYPE_STRING, description='Postal Code'),
},
# required=['first_name', 'last_name', 'country_code', 'phone_number', 'address', 'city', 'state', 'postal_code']
)
)
def post(self, request):
user = request.user
try:
billing_address = BillingAddress.objects.get(user=user)
serializer = BillingAddressSerializer(billing_address, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({
"data": serializer.data,
"success": True,
"message": "Billing address updated successfully.",
"statusCode": 200
}, status=status.HTTP_200_OK)
return Response({
"error": serializer.errors,
"success": False,
"message": "Failed to update billing address.",
"statusCode": 400
}, status=status.HTTP_400_BAD_REQUEST)
except BillingAddress.DoesNotExist:
serializer = BillingAddressSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=user)
return Response({
"data": serializer.data,
"success": True,
"message": "Billing address created successfully.",
"statusCode": 201
}, status=status.HTTP_201_CREATED)
return Response({
"error": serializer.errors,
"success": False,
"message": "Failed to create billing address.",
"statusCode": 400
}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
responses={200: BillingAddressSerializer()}
)
def get(self, request):
"""Fetch the billing address for the logged-in user"""
user = request.user
try:
# Fetch the billing address if it exists
billing_address = BillingAddress.objects.get(user=user)
serializer = BillingAddressSerializer(billing_address)
return Response({
"data": serializer.data,
"success": True,
"message": "Billing address retrieved successfully.",
"statusCode": 200
}, status=status.HTTP_200_OK)
except BillingAddress.DoesNotExist:
return Response({
"data": [],
"success": True,
"message": "Billing address not found.",
"statusCode": 200
}, status=status.HTTP_200_OK)