Features: 1) Add async and sync capabilities to CamelCaseMiddleWare; 2) Include OpenAPI support for Enum name overrides in DRF settings; 3) Integrate OpenAPI types in DRF views for improved schema accuracy.
Fixes: 1) Correct `lookup_field` to `uuid` in various viewsets; 2) Replace `type=str` with `OpenApiTypes.STR` in path parameters of multiple DRF endpoints; 3) Add missing import `iscoroutinefunction` and `markcoroutinefunction`. Extra: 1) Refactor `__call__` method in `CamelCaseMiddleWare` to separate sync and async logic; 2) Enhance documentation schema responses with precise types in multiple DRF views.
This commit is contained in:
parent
dc7f8be926
commit
29fb56be89
5 changed files with 41 additions and 17 deletions
|
|
@ -1,6 +1,6 @@
|
|||
from django.conf import settings
|
||||
from django.http import FileResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema, inline_serializer
|
||||
from rest_framework import status
|
||||
from rest_framework.fields import CharField, DictField, JSONField, ListField
|
||||
|
|
@ -32,6 +32,9 @@ CUSTOM_OPENAPI_SCHEMA = {
|
|||
"OpenApi3 schema for this API. Format can be selected via content negotiation. "
|
||||
"Language can be selected with Accept-Language and query parameter both."
|
||||
),
|
||||
responses={
|
||||
status.HTTP_200_OK: OpenApiTypes.OBJECT,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +179,7 @@ DOWNLOAD_DIGITAL_ASSET_SCHEMA = {
|
|||
],
|
||||
summary=_("download a digital asset from purchased digital order"),
|
||||
responses={
|
||||
status.HTTP_200_OK: FileResponse,
|
||||
status.HTTP_200_OK: OpenApiTypes.BINARY,
|
||||
status.HTTP_400_BAD_REQUEST: error,
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ CATEGORY_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Category UUID or slug"),
|
||||
type=str,
|
||||
type=OpenApiTypes.STR,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||
|
|
@ -284,7 +284,7 @@ CATEGORY_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Category UUID or slug"),
|
||||
type=str,
|
||||
type=OpenApiTypes.STR,
|
||||
),
|
||||
],
|
||||
responses={
|
||||
|
|
@ -369,7 +369,7 @@ ORDER_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Order UUID or human-readable id"),
|
||||
type=str,
|
||||
type=OpenApiTypes.STR,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: OrderDetailSerializer(), **BASE_ERRORS},
|
||||
|
|
@ -1006,7 +1006,7 @@ BRAND_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Brand UUID or slug"),
|
||||
type=str,
|
||||
type=OpenApiTypes.STR,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: BrandDetailSerializer(), **BASE_ERRORS},
|
||||
|
|
@ -1049,7 +1049,7 @@ BRAND_SCHEMA = {
|
|||
name="lookup_value",
|
||||
location="path",
|
||||
description=_("Brand UUID or slug"),
|
||||
type=str,
|
||||
type=OpenApiTypes.STR,
|
||||
),
|
||||
],
|
||||
responses={status.HTTP_200_OK: SeoSnapshotSerializer(), **BASE_ERRORS},
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ class CategoryViewSet(EvibesViewSet):
|
|||
action_serializer_classes = {
|
||||
"list": CategorySimpleSerializer,
|
||||
}
|
||||
lookup_field = "lookup_value"
|
||||
lookup_field = "uuid"
|
||||
lookup_url_kwarg = "lookup_value"
|
||||
additional = {"seo_meta": "ALLOW"}
|
||||
|
||||
|
|
@ -356,7 +356,7 @@ class BrandViewSet(EvibesViewSet):
|
|||
action_serializer_classes = {
|
||||
"list": BrandSimpleSerializer,
|
||||
}
|
||||
lookup_field = "lookup_value"
|
||||
lookup_field = "uuid"
|
||||
lookup_url_kwarg = "lookup_value"
|
||||
additional = {"seo_meta": "ALLOW"}
|
||||
|
||||
|
|
@ -658,7 +658,7 @@ class OrderViewSet(EvibesViewSet):
|
|||
"performed and enforces permissions accordingly while interacting with order data."
|
||||
)
|
||||
|
||||
lookup_field = "lookup_value"
|
||||
lookup_field = "uuid"
|
||||
lookup_url_kwarg = "lookup_value"
|
||||
queryset = Order.objects.prefetch_related("order_products").all()
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
|
|
@ -690,7 +690,7 @@ class OrderViewSet(EvibesViewSet):
|
|||
return qs.filter(user=user)
|
||||
|
||||
def get_object(self):
|
||||
lookup_val = self.kwargs[self.lookup_field]
|
||||
lookup_val = self.kwargs[self.lookup_url_kwarg]
|
||||
qs = self.get_queryset()
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import traceback
|
|||
from os import getenv
|
||||
from typing import Any, Callable, cast
|
||||
|
||||
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.core.exceptions import (
|
||||
BadRequest,
|
||||
|
|
@ -81,11 +82,11 @@ class GrapheneJWTAuthorizationMiddleware:
|
|||
return next(root, info, **args)
|
||||
|
||||
@staticmethod
|
||||
def get_jwt_user(request: HttpRequest) -> "User" | AnonymousUser:
|
||||
def get_jwt_user(request: HttpRequest) -> User | AnonymousUser:
|
||||
jwt_authenticator = JWTAuthentication()
|
||||
try:
|
||||
user_obj, _ = jwt_authenticator.authenticate(request) # type: ignore[assignment]
|
||||
user: "User" | AnonymousUser = cast(User, user_obj)
|
||||
user: User | AnonymousUser = cast(User, user_obj)
|
||||
except InvalidToken:
|
||||
user = AnonymousUser()
|
||||
except TypeError:
|
||||
|
|
@ -175,10 +176,27 @@ class RateLimitMiddleware:
|
|||
|
||||
|
||||
class CamelCaseMiddleWare:
|
||||
async_capable = True
|
||||
sync_capable = True
|
||||
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
if iscoroutinefunction(get_response):
|
||||
markcoroutinefunction(self) # ty:ignore[invalid-argument-type]
|
||||
|
||||
def __call__(self, request):
|
||||
async def __call__(self, request):
|
||||
if iscoroutinefunction(self.get_response):
|
||||
self._underscoreize_request(request)
|
||||
response = await self.get_response(request)
|
||||
return response
|
||||
return self._sync_call(request)
|
||||
|
||||
def _sync_call(self, request):
|
||||
self._underscoreize_request(request)
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
def _underscoreize_request(self, request):
|
||||
underscoreized_get = underscoreize(
|
||||
{k: v for k, v in request.GET.lists()},
|
||||
**JSON_UNDERSCOREIZE,
|
||||
|
|
@ -194,6 +212,3 @@ class CamelCaseMiddleWare:
|
|||
|
||||
new_get._mutable = False
|
||||
request.GET = new_get
|
||||
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
|
|
|||
|
|
@ -143,4 +143,10 @@ SPECTACULAR_SETTINGS = {
|
|||
"email": "contact@fureunoir.com",
|
||||
"URL": "https://t.me/fureunoir",
|
||||
},
|
||||
"ENUM_NAME_OVERRIDES": {
|
||||
"OrderStatusEnum": "engine.core.choices.ORDER_STATUS_CHOICES",
|
||||
"OrderProductStatusEnum": "engine.core.choices.ORDER_PRODUCT_STATUS_CHOICES",
|
||||
"TransactionStatusEnum": "engine.core.choices.TRANSACTION_STATUS_CHOICES",
|
||||
"ThreadStatusEnum": "engine.vibes_auth.choices.ThreadStatus",
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue