From 6c2d452684160df42b8e7dbc2ec389a07d66c6cc Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Sat, 7 Jun 2025 18:31:27 +0300 Subject: [PATCH] Fixes: OrderViewSet fixes --- core/docs/drf/viewsets.py | 29 +++++++++++++++++++++++++++++ core/permissions.py | 15 +++++++++++++-- core/viewsets.py | 25 ++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/core/docs/drf/viewsets.py b/core/docs/drf/viewsets.py index a5ace8a6..7bf75f96 100644 --- a/core/docs/drf/viewsets.py +++ b/core/docs/drf/viewsets.py @@ -21,6 +21,8 @@ from core.serializers import ( BuyUnregisteredOrderSerializer, CategoryDetailSerializer, CategorySimpleSerializer, + FeedbackDetailSerializer, + FeedbackSimpleSerializer, OrderDetailSerializer, OrderSimpleSerializer, ProductDetailSerializer, @@ -521,3 +523,30 @@ ADDRESS_SCHEMA = { }, ), } + +FEEDBACK_SCHEMA = { + "list": extend_schema( + summary=_("list all feedbacks (simple view)"), + responses={status.HTTP_200_OK: FeedbackSimpleSerializer(many=True), **BASE_ERRORS}, + ), + "retrieve": extend_schema( + summary=_("retrieve a single feedback (detailed view)"), + responses={status.HTTP_200_OK: FeedbackDetailSerializer, **BASE_ERRORS}, + ), + "create": extend_schema( + summary=_("create a feedback"), + responses={status.HTTP_201_CREATED: FeedbackDetailSerializer, **BASE_ERRORS}, + ), + "destroy": extend_schema( + summary=_("delete a feedback"), + responses={status.HTTP_204_NO_CONTENT: {}, **BASE_ERRORS}, + ), + "update": extend_schema( + summary=_("rewrite an existing feedback saving non-editables"), + responses={status.HTTP_200_OK: FeedbackDetailSerializer, **BASE_ERRORS}, + ), + "partial_update": extend_schema( + summary=_("rewrite some fields of an existing feedback saving non-editables"), + responses={status.HTTP_200_OK: FeedbackDetailSerializer, **BASE_ERRORS}, + ), +} diff --git a/core/permissions.py b/core/permissions.py index 0dbd3645..a189e7c3 100644 --- a/core/permissions.py +++ b/core/permissions.py @@ -51,7 +51,8 @@ class EvibesPermission(permissions.BasePermission): } def has_permission(self, request, view): - action = getattr(view, "action", None) + action = str(getattr(view, "action", None)) + model = view.queryset.model app_label = model._meta.app_label model_name = model._meta.model_name @@ -59,6 +60,9 @@ class EvibesPermission(permissions.BasePermission): if action == "create" and view.additional.get("create") == "ALLOW": return True + if action == 'retrieve' and view.additional.get("retrieve") == "ALLOW": + return True + if action in self.USER_SCOPED_ACTIONS: return True @@ -87,7 +91,14 @@ class EvibesPermission(permissions.BasePermission): model = view.queryset.model app_label = model._meta.app_label model_name = model._meta.model_name - action = getattr(view, "action", None) + action = str(getattr(view, "action", None)) + + if action == 'retrieve' and request.method in permissions.SAFE_METHODS and hasattr(obj, + 'user') and obj.user is None: + lookup_val = view.kwargs.get(view.lookup_field) + if str(obj.human_readable_id) == lookup_val or str(obj.uuid) == lookup_val: + return True + perm_prefix = self.ACTION_PERM_MAP.get(action) return bool(perm_prefix and request.user.has_perm(f"{app_label}.{perm_prefix}_{model_name}")) diff --git a/core/viewsets.py b/core/viewsets.py index 4ec3b357..f9c105f4 100644 --- a/core/viewsets.py +++ b/core/viewsets.py @@ -1,5 +1,6 @@ from uuid import UUID +from django.db.models import Q from django.http import Http404 from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ @@ -10,6 +11,7 @@ from drf_spectacular.utils import extend_schema_view from rest_framework import status from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied +from rest_framework.generics import get_object_or_404 from rest_framework.renderers import MultiPartRenderer from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet @@ -22,6 +24,7 @@ from core.docs.drf.viewsets import ( ATTRIBUTE_SCHEMA, ATTRIBUTE_VALUE_SCHEMA, CATEGORY_SCHEMA, + FEEDBACK_SCHEMA, ORDER_SCHEMA, PRODUCT_SCHEMA, WISHLIST_SCHEMA, @@ -218,6 +221,7 @@ class VendorViewSet(EvibesViewSet): } +@extend_schema_view(**FEEDBACK_SCHEMA) class FeedbackViewSet(EvibesViewSet): queryset = Feedback.objects.all() filter_backends = [DjangoFilterBackend] @@ -230,6 +234,7 @@ class FeedbackViewSet(EvibesViewSet): @extend_schema_view(**ORDER_SCHEMA) class OrderViewSet(EvibesViewSet): + lookup_field = 'lookup_value' queryset = Order.objects.prefetch_related("order_products").all() filter_backends = [DjangoFilterBackend] filterset_class = OrderFilter @@ -240,6 +245,12 @@ class OrderViewSet(EvibesViewSet): "add_order_product": AddOrderProductSerializer, "remove_order_product": RemoveOrderProductSerializer, } + additional = { + "retrieve": "ALLOW" + } + + def get_serializer_class(self): + return self.action_serializer_classes.get(self.action, super().get_serializer_class()) def get_queryset(self): qs = super().get_queryset() @@ -248,15 +259,23 @@ class OrderViewSet(EvibesViewSet): if user.has_perm("core.view_order"): return qs - return qs.filter(user=user) + return qs.filter(Q(user=user) | Q(user__isnull=True)) + + def get_object(self): + lookup_val = self.kwargs.get(self.lookup_field) + queryset = self.filter_queryset(self.get_queryset()) + obj = get_object_or_404( + queryset, + Q(uuid=lookup_val) | Q(human_readable_id=lookup_val) + ) + self.check_object_permissions(self.request, obj) + return obj @action(detail=False, methods=["get"], url_path="current") def current(self, request): if not request.user.is_authenticated: raise PermissionDenied(permission_denied_message) order = Order.objects.get(user=request.user, status="PENDING") - if not request.user == order.user: - raise PermissionDenied(permission_denied_message) return Response( status=status.HTTP_200_OK, data=OrderDetailSerializer(order).data,