From 653f0a219e1bffda409ad7e24707b536eb9dbcc3 Mon Sep 17 00:00:00 2001 From: vickytechkey Date: Sun, 4 Oct 2026 10:20:25 +0530 Subject: [PATCH] feat: add user management, WhatsApp OTP authentication, and core API URL routing --- api/views.py | 81 +++++++++++++++++++++++++++++++--- customerwebsitebackend/urls.py | 3 +- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/api/views.py b/api/views.py index e97f5ad..da2b5f6 100644 --- a/api/views.py +++ b/api/views.py @@ -1,11 +1,15 @@ import logging -audit_logger = logging.getLogger('audit') +import requests +from django.conf import settings +from django.core.cache import cache from rest_framework import status, permissions from rest_framework.response import Response from rest_framework.views import APIView from django.contrib.auth.models import User from .serializers import UserRegisterSerializer +audit_logger = logging.getLogger('audit') + class UserRegisterView(APIView): permission_classes = [permissions.AllowAny] @@ -47,13 +51,78 @@ class SendWhatsAppOTPView(APIView): def post(self, request): mobile_number = request.data.get('mobile_number') otp_code = request.data.get('otp_code') + template_name = request.data.get('template_name', 'mobile_number_verification') if not mobile_number or not otp_code: return Response({"error": "mobile_number and otp_code are required"}, status=status.HTTP_400_BAD_REQUEST) audit_logger.info(f"AUDIT - Send WhatsApp OTP: mobile '{mobile_number}', OTP '{otp_code}'") - return Response({ - "status": "success", - "message": f"WhatsApp OTP dispatched to {mobile_number}", - "mobile_number": mobile_number - }, status=status.HTTP_200_OK) + + # Store OTP in backend cache for 5 minutes (300 seconds) + clean_phone = str(mobile_number).replace('+', '').strip() + cache.set(f"whatsapp_otp_{clean_phone}", str(otp_code), timeout=300) + + whatsapp_service_url = getattr(settings, 'WHATSAPP_SERVICE_URL', 'http://betawhatsapp.tradhox.com/api/send/') + payload = { + "mobile_number": mobile_number, + "otp_code": otp_code, + "template_name": template_name + } + + try: + res = requests.post(whatsapp_service_url, json=payload, timeout=10) + try: + res_data = res.json() + except Exception: + res_data = {"text": res.text} + + if res.status_code == 200 and res_data.get('status') != 'error': + return Response({ + "status": "success", + "message": f"WhatsApp OTP dispatched to {mobile_number}", + "mobile_number": mobile_number, + "gateway_response": res_data + }, status=status.HTTP_200_OK) + else: + audit_logger.warning(f"WhatsApp gateway response for {mobile_number}: {res.status_code} {res_data}") + return Response({ + "status": "success", + "message": f"WhatsApp OTP request submitted for {mobile_number}", + "mobile_number": mobile_number, + "gateway_response": res_data + }, status=status.HTTP_200_OK) + except Exception as e: + audit_logger.error(f"WhatsApp service connection error for {mobile_number}: {e}") + return Response({ + "status": "error", + "message": f"Could not reach WhatsApp service gateway: {str(e)}", + "mobile_number": mobile_number + }, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + +class VerifyOTPView(APIView): + permission_classes = [permissions.AllowAny] + + def post(self, request): + mobile_number = request.data.get('mobile_number') + otp_code = request.data.get('otp_code') + + if not mobile_number or not otp_code: + return Response({"error": "mobile_number and otp_code are required"}, status=status.HTTP_400_BAD_REQUEST) + + clean_phone = str(mobile_number).replace('+', '').strip() + stored_otp = cache.get(f"whatsapp_otp_{clean_phone}") + + if stored_otp and str(stored_otp).strip() == str(otp_code).strip(): + audit_logger.info(f"AUDIT - OTP Verification SUCCESS: mobile '{mobile_number}'") + return Response({ + "status": "success", + "message": "OTP verified successfully" + }, status=status.HTTP_200_OK) + else: + audit_logger.warning(f"AUDIT - OTP Verification FAILED: mobile '{mobile_number}', submitted '{otp_code}', expected '{stored_otp}'") + return Response({ + "status": "error", + "message": "Invalid or expired OTP verification code. Access denied." + }, status=status.HTTP_400_BAD_REQUEST) + + diff --git a/customerwebsitebackend/urls.py b/customerwebsitebackend/urls.py index 3aa4a8a..c8fbb59 100644 --- a/customerwebsitebackend/urls.py +++ b/customerwebsitebackend/urls.py @@ -6,7 +6,7 @@ def home_view(request): from django.contrib import admin from django.urls import path from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView -from api.views import UserRegisterView, UserProfileView, SendWhatsAppOTPView +from api.views import UserRegisterView, UserProfileView, SendWhatsAppOTPView, VerifyOTPView from products.views import CategoryListView, ProductListView, ProductDetailView from orders.views import CartView, CartItemDetailView, CheckoutView, PaymentSuccessView, OrderHistoryView, OrderDetailView @@ -16,6 +16,7 @@ urlpatterns = [ # Auth APIs path('api/v1/customer/auth/send-whatsapp/', SendWhatsAppOTPView.as_view(), name='send_whatsapp'), + path('api/v1/customer/auth/verify-otp/', VerifyOTPView.as_view(), name='verify_otp'), path('api/v1/customer/auth/register/', UserRegisterView.as_view(), name='register'), path('api/v1/customer/auth/login/', TokenObtainPairView.as_view(), name='login'), path('api/v1/customer/auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),