from rest_framework import status, generics, permissions from rest_framework.decorators import api_view, permission_classes from rest_framework.response import Response from rest_framework.views import APIView from rest_framework_simplejwt.tokens import RefreshToken from django.contrib.auth import login from django.utils import timezone from django_ratelimit.decorators import ratelimit from django.db import transaction import uuid from .models import User, UserProfile, LoginAttempt, EmailVerification from .serializers import ( UserRegistrationSerializer, UserLoginSerializer, UserSerializer, UserProfileSerializer, EmailSettingsSerializer, PasswordChangeSerializer, EmailVerificationSerializer, LoginAttemptSerializer ) class UserRegistrationView(APIView): """User registration endpoint.""" permission_classes = [permissions.AllowAny] def post(self, request): serializer = UserRegistrationSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() # Generate tokens refresh = RefreshToken.for_user(user) access_token = refresh.access_token return Response({ 'message': 'User registered successfully. Please verify your email.', 'user': UserSerializer(user).data, 'tokens': { 'refresh': str(refresh), 'access': str(access_token), } }, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class UserLoginView(APIView): """User login endpoint.""" permission_classes = [permissions.AllowAny] def post(self, request): serializer = UserLoginSerializer(data=request.data) if serializer.is_valid(): user = serializer.validated_data['user'] # Log login attempt LoginAttempt.objects.create( user=user, email=user.email, ip_address=self.get_client_ip(request), user_agent=request.META.get('HTTP_USER_AGENT', ''), success=True ) # Generate tokens refresh = RefreshToken.for_user(user) access_token = refresh.access_token # Update last login IP user.last_login_ip = self.get_client_ip(request) user.save() return Response({ 'message': 'Login successful', 'user': UserSerializer(user).data, 'tokens': { 'refresh': str(refresh), 'access': str(access_token), } }, status=status.HTTP_200_OK) # Log failed login attempt email = request.data.get('email', '') LoginAttempt.objects.create( email=email, ip_address=self.get_client_ip(request), user_agent=request.META.get('HTTP_USER_AGENT', ''), success=False, failure_reason='Invalid credentials' ) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def get_client_ip(self, request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') return ip class UserProfileView(generics.RetrieveUpdateAPIView): """User profile management.""" serializer_class = UserSerializer permission_classes = [permissions.IsAuthenticated] def get_object(self): return self.request.user class UserProfileSettingsView(generics.RetrieveUpdateAPIView): """User profile settings management.""" serializer_class = UserProfileSerializer permission_classes = [permissions.IsAuthenticated] def get_object(self): profile, created = UserProfile.objects.get_or_create(user=self.request.user) return profile class EmailSettingsView(generics.RetrieveUpdateAPIView): """Email server settings management.""" serializer_class = EmailSettingsSerializer permission_classes = [permissions.IsAuthenticated] def get_object(self): return self.request.user class PasswordChangeView(APIView): """Password change endpoint.""" permission_classes = [permissions.IsAuthenticated] @ratelimit(key='user', rate='5/m', method=['POST']) def post(self, request): serializer = PasswordChangeSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): serializer.save() return Response({'message': 'Password changed successfully'}, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class EmailVerificationView(APIView): """Email verification endpoint.""" permission_classes = [permissions.AllowAny] def post(self, request): serializer = EmailVerificationSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() return Response({ 'message': 'Email verified successfully', 'user': UserSerializer(user).data }, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class ResendVerificationView(APIView): """Resend email verification.""" permission_classes = [permissions.IsAuthenticated] @ratelimit(key='user', rate='3/m', method=['POST']) def post(self, request): user = request.user if user.is_verified: return Response({'message': 'Email is already verified'}, status=status.HTTP_400_BAD_REQUEST) # Create new verification token token = str(uuid.uuid4()) EmailVerification.objects.create( user=user, token=token, expires_at=timezone.now() + timezone.timedelta(hours=24) ) # TODO: Send verification email return Response({'message': 'Verification email sent'}, status=status.HTTP_200_OK) class LoginAttemptsView(generics.ListAPIView): """View login attempts for security monitoring.""" serializer_class = LoginAttemptSerializer permission_classes = [permissions.IsAuthenticated] def get_queryset(self): return LoginAttempt.objects.filter(user=self.request.user).order_by('-timestamp')[:50] class LogoutView(APIView): """Logout endpoint.""" permission_classes = [permissions.IsAuthenticated] def post(self, request): try: refresh_token = request.data["refresh"] token = RefreshToken(refresh_token) token.blacklist() return Response({'message': 'Logout successful'}, status=status.HTTP_200_OK) except Exception as e: return Response({'error': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) @api_view(['GET']) @permission_classes([permissions.IsAuthenticated]) def user_stats(request): """Get user statistics.""" user = request.user stats = { 'total_emails': 0, # Will be implemented with emails app 'unread_emails': 0, # Will be implemented with emails app 'sent_emails': 0, # Will be implemented with emails app 'draft_emails': 0, # Will be implemented with emails app 'last_login': user.last_login, 'is_verified': user.is_verified, 'account_created': user.date_joined, } return Response(stats)