from rest_framework import status from rest_framework.decorators import action from rest_framework.response import Response from rest_framework_simplejwt.tokens import RefreshToken from rest_framework.views import APIView from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample from drf_spectacular.types import OpenApiTypes from django.contrib.auth.models import User from .serializers import ( UserResponseSerializer, LoginRequestSerializer, LoginResponseSerializer ) from api.utils.cookies import AuthBaseViewSet from api.types import User class LoginViewSet(AuthBaseViewSet): """ViewSet для авторизации пользователей""" serializer_class = LoginRequestSerializer @extend_schema( summary="Авторизация пользователя", description="Эндпоинт для авторизации пользователя по логину и паролю", request=LoginRequestSerializer, responses={ 200: OpenApiResponse( response=LoginResponseSerializer, description="Успешная авторизация", examples=[ OpenApiExample( 'Успешный ответ', value={ "message": "Успешная авторизация", "access": "eyJ0eXAiOiJKV1QiLCJhbGc...", "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...", "user": { "id": 1, "email": "user@example.com", "account_type": "engieneer", "name": "Иван", "surname": "Иванов", "imageURL": "https://example.com/avatar.jpg", "uuid": "abc123" } } ) ] ), 400: OpenApiResponse( description="Неверные параметры запроса", response=OpenApiTypes.OBJECT, examples=[ OpenApiExample( 'Отсутствуют обязательные поля', value={"error": "Логин и пароль обязательны"} ) ] ), 403: OpenApiResponse( description="Неверный пароль", response=OpenApiTypes.OBJECT, examples=[ OpenApiExample( 'Неверный пароль', value={"error": "Неверный пароль"} ) ] ), 404: OpenApiResponse( description="Пользователь не найден", response=OpenApiTypes.OBJECT, examples=[ OpenApiExample( 'Пользователь не найден', value={"error": "Пользователь не найден"} ) ] ), 500: OpenApiResponse( description="Внутренняя ошибка сервера", response=OpenApiTypes.OBJECT, examples=[ OpenApiExample( 'Ошибка сервера', value={"error": "Ошибка авторизации"} ) ] ) } ) @action(detail=False, methods=['post'], url_path="login") def login_client(self, request): try: login = request.data.get("login") password = request.data.get("password") if not login or not password: return Response( {"error": "Логин и пароль обязательны"}, status=status.HTTP_400_BAD_REQUEST ) try: user = User.objects.get(login=login) 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 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): """ViewSet для выхода из системы""" @extend_schema( summary="Выход из системы", description="Эндпоинт для выхода из системы, очищает все токены и куки", responses={ 200: OpenApiResponse( description="Успешный выход", response=OpenApiTypes.OBJECT, examples=[ OpenApiExample( 'Успешный выход', value={"message": "Logged out"} ) ] ) } ) 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