feat(viewsets): add endpoint to retrieve products by identifier
introduce `exact_list` action in `viewsets.py` to retrieve products by `uuid`, `slug`, or `sku` identifiers. Includes input validation and ratelimiting. Adds corresponding schema documentation and a GraphQL mutation for similar functionality.
This commit is contained in:
parent
ce689ee754
commit
ff99177139
3 changed files with 69 additions and 1 deletions
|
|
@ -750,6 +750,20 @@ PRODUCT_SCHEMA = {
|
||||||
**BASE_ERRORS,
|
**BASE_ERRORS,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
"exact_list": extend_schema(
|
||||||
|
tags=[
|
||||||
|
"products",
|
||||||
|
],
|
||||||
|
summary=_("retrieve exact products by identifier"),
|
||||||
|
description=_(
|
||||||
|
"retrieve a list of products by identifier type (uuid, slug, or sku). "
|
||||||
|
"Send a POST request with `identificator_type` and `identificators` (list of values)."
|
||||||
|
),
|
||||||
|
responses={
|
||||||
|
status.HTTP_200_OK: ProductSimpleSerializer(many=True),
|
||||||
|
**BASE_ERRORS,
|
||||||
|
},
|
||||||
|
),
|
||||||
"seo_meta": extend_schema(
|
"seo_meta": extend_schema(
|
||||||
tags=[
|
tags=[
|
||||||
"products",
|
"products",
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,11 @@ from engine.core.graphene.object_types import (
|
||||||
BulkProductInput,
|
BulkProductInput,
|
||||||
FeedbackType,
|
FeedbackType,
|
||||||
OrderType,
|
OrderType,
|
||||||
|
ProductType,
|
||||||
SearchResultsType,
|
SearchResultsType,
|
||||||
WishlistType,
|
WishlistType,
|
||||||
)
|
)
|
||||||
from engine.core.models import Address, Order, OrderProduct, Wishlist
|
from engine.core.models import Address, Order, OrderProduct, Product, Wishlist
|
||||||
from engine.core.utils import format_attributes, is_url_safe
|
from engine.core.utils import format_attributes, is_url_safe
|
||||||
from engine.core.utils.caching import web_cache
|
from engine.core.utils.caching import web_cache
|
||||||
from engine.core.utils.emailing import contact_us_email
|
from engine.core.utils.emailing import contact_us_email
|
||||||
|
|
@ -574,6 +575,31 @@ class BuyProduct(Mutation):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RetrieveExactProducts(Mutation):
|
||||||
|
class Meta:
|
||||||
|
description = _("retrieve exact products by identificator")
|
||||||
|
|
||||||
|
class Arguments:
|
||||||
|
identificator_type = String(required=True)
|
||||||
|
identificators = List(String, required=True)
|
||||||
|
|
||||||
|
products = List(ProductType, required=True)
|
||||||
|
|
||||||
|
def mutate(self, info, identificator_type: str, identificators: list[str]):
|
||||||
|
match identificator_type:
|
||||||
|
case "uuid":
|
||||||
|
products = Product.objects.filter(uuid__in=identificators)
|
||||||
|
case "slug":
|
||||||
|
products = Product.objects.filter(slug__in=identificators)
|
||||||
|
case "sku":
|
||||||
|
products = Product.objects.filter(sku__in=identificators)
|
||||||
|
case _:
|
||||||
|
raise BadRequest(
|
||||||
|
_("identificator_type must be one of: uuid, slug, sku")
|
||||||
|
)
|
||||||
|
return RetrieveExactProducts(products=products) # ty: ignore[unknown-argument]
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyTypeChecker
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class FeedbackProductAction(Mutation):
|
class FeedbackProductAction(Mutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -530,6 +530,34 @@ class ProductViewSet(SchonViewSet):
|
||||||
self.check_object_permissions(self.request, obj)
|
self.check_object_permissions(self.request, obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
@action(detail=False, methods=("POST",), url_path="retrieve-exact")
|
||||||
|
@method_decorator(ratelimit(key="ip", rate="8/s" if not settings.DEBUG else "44/s"))
|
||||||
|
def exact_list(self, request: Request, *args, **kwargs) -> Response:
|
||||||
|
identificator_type = request.data.get("identificator_type")
|
||||||
|
identificators = request.data.get("identificators", [])
|
||||||
|
|
||||||
|
if not identificator_type or not identificators:
|
||||||
|
return Response(
|
||||||
|
{"detail": _("identificator_type and identificators are required")},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
match identificator_type:
|
||||||
|
case "uuid":
|
||||||
|
qs = self.get_queryset().filter(uuid__in=identificators)
|
||||||
|
case "slug":
|
||||||
|
qs = self.get_queryset().filter(slug__in=identificators)
|
||||||
|
case "sku":
|
||||||
|
qs = self.get_queryset().filter(sku__in=identificators)
|
||||||
|
case _:
|
||||||
|
return Response(
|
||||||
|
{"detail": _("identificator_type must be one of: uuid, slug, sku")},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
serializer = ProductSimpleSerializer(qs, many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
@action(detail=True, methods=("GET",), url_path="feedbacks")
|
@action(detail=True, methods=("GET",), url_path="feedbacks")
|
||||||
@method_decorator(ratelimit(key="ip", rate="2/s" if not settings.DEBUG else "44/s"))
|
@method_decorator(ratelimit(key="ip", rate="2/s" if not settings.DEBUG else "44/s"))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue