Files
Iliyan Angelov c67067a2a4 Mail
2025-09-14 23:24:25 +03:00

231 lines
7.6 KiB
Python

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)