import logging from typing import Any from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ from django_ratelimit.decorators import ratelimit from drf_spectacular.utils import ( extend_schema_view, ) from rest_framework import status from rest_framework.request import Request from rest_framework.response import Response from rest_framework_simplejwt.exceptions import TokenError from rest_framework_simplejwt.views import TokenViewBase from evibes.settings import DEBUG from vibes_auth.docs.drf.views import TOKEN_OBTAIN_SCHEMA, TOKEN_REFRESH_SCHEMA, TOKEN_VERIFY_SCHEMA from vibes_auth.serializers import ( TokenObtainPairSerializer, TokenRefreshSerializer, TokenVerifySerializer, ) logger = logging.getLogger("django") @extend_schema_view(**TOKEN_OBTAIN_SCHEMA) class TokenObtainPairView(TokenViewBase): __doc__ = _( # type: ignore [assignment] "Represents a view for getting a pair of access and refresh tokens and user's data. " "This view manages the process of handling token-based authentication where " "clients can get a pair of JWT tokens (access and refresh) using provided " "credentials. It is built on top of a base token view and ensures proper " "rate limiting to protect against brute force attacks." ) serializer_class = TokenObtainPairSerializer # type: ignore [assignment] _serializer_class = TokenObtainPairSerializer # type: ignore [assignment] @method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h")) def post(self, request: Request, *args: list[Any], **kwargs: dict[Any, Any]) -> Response: return super().post(request, *args, **kwargs) @extend_schema_view(**TOKEN_REFRESH_SCHEMA) class TokenRefreshView(TokenViewBase): __doc__ = _( # type: ignore [assignment] "Handles refreshing of tokens for authentication purposes. " "This class is used to provide functionality for token refresh " "operations as part of an authentication system. It ensures that " "clients can request a refreshed token within defined rate limits. " "The view relies on the associated serializer to validate token " "refresh inputs and produce appropriate outputs." ) serializer_class = TokenRefreshSerializer # type: ignore [assignment] _serializer_class = TokenRefreshSerializer # type: ignore [assignment] @method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h")) def post(self, request: Request, *args: list[Any], **kwargs: dict[Any, Any]) -> Response: return super().post(request, *args, **kwargs) @extend_schema_view(**TOKEN_VERIFY_SCHEMA) class TokenVerifyView(TokenViewBase): __doc__ = _( # type: ignore [assignment] "Represents a view for verifying JSON Web Tokens (JWT) using specific serialization and validation logic. " ) serializer_class = TokenVerifySerializer # type: ignore [assignment] _serializer_class = TokenVerifySerializer # type: ignore [assignment] def post(self, request: Request, *args: list[Any], **kwargs: dict[Any, Any]) -> Response: try: serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user_data = serializer.validated_data.pop("user", None) return Response({"token": _("the token is valid"), "user": user_data}) except TokenError: return Response({"detail": _("the token is invalid")}, status=status.HTTP_400_BAD_REQUEST)