from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUEST, HTTP_401_UNAUTHORIZED from rest_framework.viewsets import ReadOnlyModelViewSet from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.permissions import IsAuthenticatedOrReadOnly, AllowAny, IsAuthenticated from django.contrib.auth import authenticate, login, logout from apps.users.models import User from apps.users.serializers import UserSerializer class UserViewSet(ReadOnlyModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [IsAuthenticatedOrReadOnly] lookup_field = 'uuid' @action(detail=False, methods=['post'], permission_classes=[AllowAny]) def login(self, request): email_address = request.data.get('email_address') password = request.data.get('password') if not email_address or not password: return Response({'error': 'Email and password are required'}, status=HTTP_400_BAD_REQUEST) email_address = User.objects.normalize_email(email_address) user = authenticate(request, username=email_address, password=password) if user is None: return Response({'error': 'Invalid credentials'}, status=HTTP_401_UNAUTHORIZED) login(request, user) return Response({'user': UserSerializer(user).data, 'message': 'Login successful', 'success': True}, status=HTTP_200_OK) @action(detail=False, methods=['post'], permission_classes=[IsAuthenticated]) def logout(self, request): logout(request) return Response({'message': 'Logout successful', 'success': True}, status=HTTP_200_OK) @action(detail=False, methods=['get'], permission_classes=[IsAuthenticated]) def me(self, request): user_data = UserSerializer(request.user).data user_data['success'] = True return Response(user_data) @action(detail=False, methods=['get'], permission_classes=[AllowAny]) def session(self, request): return Response({'isAuthenticated': request.user.is_authenticated, 'isStaff': request.user.is_staff if request.user.is_authenticated else False}) @action(detail=False, methods=['post'], permission_classes=[AllowAny]) def signup(self, request): try: data = request.data except: return Response({'detail': 'Invalid data provided.', 'success': False}, status=HTTP_400_BAD_REQUEST) email_address = data.get('email_address') if not email_address: return Response({'detail': 'Email address is required.', 'success': False}, status=HTTP_400_BAD_REQUEST) email_address = User.objects.normalize_email(email_address) if User.objects.filter(email_address=email_address).exists(): return Response({'detail': 'Email address already exists.', 'success': False}, status=HTTP_400_BAD_REQUEST) if not data.get('first_name') or not data.get('last_name'): return Response({'detail': 'First and last name(s) must be provided.', 'success': False}, status=HTTP_400_BAD_REQUEST) if data.get('password') != data.get('confirm_password'): return Response({'detail': 'Passwords do not match.', 'success': False}, status=HTTP_400_BAD_REQUEST) try: user = User.objects.create_user( email_address=email_address, password=data.get('password'), first_name=data.get('first_name'), last_name=data.get('last_name'), date_of_birth=data.get('date_of_birth') ) return Response({'detail': 'User account created successfully.', 'success': True}, status=HTTP_201_CREATED) except Exception as e: return Response({'detail': str(e), 'success': False}, status=HTTP_400_BAD_REQUEST) @action(detail=False, methods=['post'], permission_classes=[IsAuthenticated]) def change_password(self, request): data = request.data required_fields = ['old_password', 'password', 'confirm_password'] for field in required_fields: if not data.get(field): return Response({'detail': f'"{field}" not provided', 'success': False}, status=HTTP_400_BAD_REQUEST) if data.get('password') != data.get('confirm_password'): return Response({'detail': 'Passwords do not match', 'success': False}, status=HTTP_400_BAD_REQUEST) user = request.user if not user.check_password(data.get('old_password')): return Response({'detail': 'Old password is incorrect', 'success': False}, status=HTTP_401_UNAUTHORIZED) user.set_password(data.get('password')) user.save() return Response({'detail': 'Password changed successfully', 'success': True}, status=HTTP_200_OK)