from rest_framework import status from rest_framework.views import APIView from rest_framework.decorators import action from rest_framework.response import Response from rest_framework_simplejwt.tokens import RefreshToken import traceback from django.contrib.auth.models import User from django.conf import settings from django.db.utils import IntegrityError from django.db import IntegrityError, transaction from .serializers import ClientRegisterSerializer, UserResponseSerializer from api.utils.cookiesSet import AuthBaseViewSet from datetime import datetime class RegisterViewSet(AuthBaseViewSet): """Регистрация клиента""" @action(detail=False, methods=['post'], url_path="clients") def register_client(self, request): serializer = ClientRegisterSerializer(data=request.data) if serializer.is_valid(): try: with transaction.atomic(): user = serializer.save() refresh = RefreshToken.for_user(user) user_data = UserResponseSerializer(user).data response = Response( { "access": str(refresh.access_token), "refresh": str(refresh), "user": user_data }, status=status.HTTP_201_CREATED ) # используем метод из базового класса вместо прямой установки куки return self._set_auth_cookies(response, refresh) except IntegrityError as e: return Response( {"error": "Пользователь с таким email уже существует"}, status=status.HTTP_400_BAD_REQUEST ) except Exception as e: return Response( {"error": str(e)}, status=status.HTTP_400_BAD_REQUEST ) # ошибка валидации return Response( { "error": "Ошибка валидации", "details": serializer.errors }, status=status.HTTP_400_BAD_REQUEST ) class LoginViewSet(AuthBaseViewSet): """Логин для клиента""" @action(detail=False, methods=['post'], url_path="clients") def login_client(self, request): try: email = request.data.get("email") password = request.data.get("password") if not email or not password: return Response( {"error": "Email и пароль обязательны"}, status=status.HTTP_400_BAD_REQUEST ) try: user = User.objects.get(email=email) except User.DoesNotExist: return Response( {"error": "Пользователь не найден"}, status=status.HTTP_404_NOT_FOUND ) if not user.check_password(password): return Response( {"error": "Неверный пароль"}, status=status.HTTP_403_FORBIDDEN ) refresh = RefreshToken.for_user(user) user_data = UserResponseSerializer(user).data user_data["userType"] = "client" response = Response({ "message": "Успешная авторизация", "access": str(refresh.access_token), "refresh": str(refresh), "user": user_data }, status=status.HTTP_200_OK) # аналогично используем метод из базового класса return self._set_auth_cookies(response, refresh) except Exception as e: return Response( {"error": "Ошибка авторизации"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR ) class LogoutView(APIView): """Логаут""" def post(self, request): response = Response({'message': 'Logged out'}, status=status.HTTP_200_OK) # чистим куки и sessionID response.delete_cookie('access_token') response.delete_cookie('refresh_token') response.delete_cookie('sessionid') return response class RefreshTokenView(APIView): def post(self, request): try: refresh_token = request.data.get('refresh') if not refresh_token: return Response( {'error': 'Refresh token is required'}, status=status.HTTP_400_BAD_REQUEST ) try: token = RefreshToken(refresh_token) # Сохраняем user_type при обновлении токена if 'user_type' in token: token.access_token['user_type'] = token['user_type'] # Добавляем точное время истечения токена expires_at = datetime.now() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'] response_data = { 'access': str(token.access_token), 'refresh': str(token), 'expires_at': datetime.timestamp(expires_at) } return Response(response_data) except Exception as e: # Более подробное логирование ошибок print(f"Token refresh error: {str(e)}") print(traceback.format_exc()) return Response( {'error': f'Invalid refresh token: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST ) except Exception as e: return Response( {'error': f'Token refresh failed: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST )