schon/engine/vibes_auth/views.py
Egor fureunoir Gorbunov 943aa02cd3 Features: 1) Add test cases for DRF and GraphQL views in core, blog, payments, and vibes_auth applications; 2) Implement reusable GraphQL testing utilities in test classes; 3) Introduce test configuration scripts for Windows and Unix environments.
Fixes: 1) Correct entrypoint scripts by removing redundant `python` reference in `uv run` commands; 2) Resolve incorrect imports and adjust class renaming in vibes_auth tests; 3) Address typing errors and minor omissions in existing code.

Extra: 1) Improve formatting in settings and middleware files; 2) Update messaging test class names for clarity; 3) Cleanup unused imports and extra whitespaces, ensuring cleaner codebase.
2025-11-13 16:42:04 +03:00

92 lines
3.9 KiB
Python

import logging
from typing import Any, Type
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.permissions import AllowAny, BasePermission
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 engine.vibes_auth.docs.drf.views import TOKEN_OBTAIN_SCHEMA, TOKEN_REFRESH_SCHEMA, TOKEN_VERIFY_SCHEMA
from engine.vibes_auth.serializers import (
TokenObtainPairSerializer,
TokenRefreshSerializer,
TokenVerifySerializer,
)
logger = logging.getLogger(__name__)
@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]
permission_classes: list[Type[BasePermission]] = [
AllowAny,
]
authentication_classes: list[str] = []
@method_decorator(ratelimit(key="ip", rate="10/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]
permission_classes: list[Type[BasePermission]] = [
AllowAny,
]
authentication_classes: list[str] = []
@method_decorator(ratelimit(key="ip", rate="10/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]
permission_classes: list[Type[BasePermission]] = [
AllowAny,
]
authentication_classes: list[str] = []
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)