1) Add new `test_graphene` test module for expanded testing coverage; 2) Introduce `test_drf` module in `engine/blog` for improved API testing; Fixes: 1) Remove unnecessary `--extra testing` flag from Dockerfile to streamline dependencies; 2) Update `uv.lock` with newer versions of dependencies (`certifi`, `coverage`, `django-constance`) for enhanced security and functionality; Extra: 1) Remove deprecated packages (`bandit`, `cfgv`, `distlib`) from `uv.lock` for cleanup; 2) Adjust `uv.lock` content and formatting to be consistent with updated dependencies.
93 lines
3.9 KiB
Python
93 lines
3.9 KiB
Python
import logging
|
|
from typing import Any, Type
|
|
|
|
from django.conf import settings
|
|
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)
|