HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
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)