import logging 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.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(__name__) @extend_schema_view(**TOKEN_OBTAIN_SCHEMA) class TokenObtainPairView(TokenViewBase): """ Represents a view for obtaining a pair of access and refresh tokens. This view manages the process of handling token-based authentication where clients can obtain 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. Attributes: serializer_class: Serializer class used for processing request data and returning response data. _serializer_class: Internal serializer class reference. Usage: This view should be used in authentication-related APIs where clients need to obtain new sets of tokens. It incorporates both a serializer for processing incoming data and also rate limiting to enforce request limits. Methods: post: Handles HTTP POST requests for token retrieval. This method is subject to rate limiting depending on the global DEBUG setting. """ serializer_class = TokenObtainPairSerializer # type: ignore _serializer_class = TokenObtainPairSerializer # type: ignore @method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h")) def post(self, request, *args, **kwargs): return super().post(request, *args, **kwargs) @extend_schema_view(**TOKEN_REFRESH_SCHEMA) class TokenRefreshView(TokenViewBase): """ 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. Attributes: serializer_class (Serializer): The serializer used to handle token refresh operations. This establishes the validation and processing logic for incoming requests. _serializer_class (Serializer): Internal reference to the serializer, typically used for ensuring consistent processing for refresh-related logic. Methods: post: Handles HTTP POST requests to refresh the token. Rate limits requests based on the IP of the client submitting the request. Rate limit settings are defined depending on whether the application is in DEBUG mode or not. """ serializer_class = TokenRefreshSerializer # type: ignore _serializer_class = TokenRefreshSerializer # type: ignore @method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h")) def post(self, request, *args, **kwargs): return super().post(request, *args, **kwargs) @extend_schema_view(**TOKEN_VERIFY_SCHEMA) class TokenVerifyView(TokenViewBase): """ Represents a view for verifying JSON Web Tokens (JWT) using specific serialization and validation logic. This class inherits from the `TokenViewBase` and is designed to handle the POST request for verifying JWT tokens. Tokens are validated using the associated `TokenVerifySerializer`. The view processes incoming requests, validates tokens, and returns a response indicating whether the token is valid. If valid, associated user data can also be returned. Errors during token validation result in an appropriate error response. """ serializer_class = TokenVerifySerializer # type: ignore _serializer_class = TokenVerifySerializer # type: ignore def post(self, request, *args, **kwargs): 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)