Skip to content

Commit

Permalink
Merge pull request #230 from healthy-food-and-dietary-products/featur…
Browse files Browse the repository at this point in the history
…e/reviews_new_endpoints

Feature/reviews new endpoints
  • Loading branch information
juliana-str authored Dec 30, 2023
2 parents 7bc5f24 + 1aa3e8d commit 1d23751
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 17 deletions.
2 changes: 1 addition & 1 deletion backend/api/orders_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
)
from .products_views import STATUS_200_RESPONSE_ON_DELETE_IN_DOCS
from core.loggers import logger
from good_food.utils import generate_order_number
from core.utils import generate_order_number
from orders.models import Delivery, Order, OrderProduct, ShoppingCart
from orders.shopping_carts import ShopCart
from products.models import Product
Expand Down
8 changes: 8 additions & 0 deletions backend/api/products_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,14 @@ class Meta(ProductSerializer.Meta):
fields = ("name",)


class ProductUserOrderCheckSerializer(serializers.Serializer):
"""Serializer to check if the user has ordered a product."""

product = serializers.IntegerField(read_only=True)
user = serializers.IntegerField(read_only=True)
ordered = serializers.BooleanField(read_only=True)


class FavoriteProductSerializer(serializers.ModelSerializer):
"""Serializer for favorite products list representation."""

Expand Down
49 changes: 45 additions & 4 deletions backend/api/products_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
ValidationErrorResponseSerializer,
)
from drf_yasg.utils import swagger_auto_schema
from rest_framework import decorators, filters, permissions, response, status, viewsets
from rest_framework import filters, permissions, response, status, viewsets
from rest_framework.decorators import action

from .filters import ProductFilter
from .mixins import MESSAGE_ON_DELETE, DestroyWithPayloadMixin
Expand All @@ -26,10 +27,12 @@
ProductCreateSerializer,
ProductSerializer,
ProductUpdateSerializer,
ProductUserOrderCheckSerializer,
PromotionSerializer,
SubcategorySerializer,
TagSerializer,
)
from orders.models import OrderProduct
from products.models import (
Category,
Component,
Expand Down Expand Up @@ -134,7 +137,7 @@ def get_queryset(self):
responses={200: CategoryBriefSerializer},
),
)
@decorators.action(methods=["get"], detail=False, url_path="category-brief-list")
@action(methods=["get"], detail=False, url_path="category-brief-list")
def category_brief_list(self, request):
"""
Shows brief information about categories without indicating subcategories
Expand All @@ -159,7 +162,7 @@ def category_brief_list(self, request):
responses={200: CategoryBriefSerializer, 404: ErrorResponse404Serializer},
),
)
@decorators.action(methods=["get"], detail=True, url_path="category-brief-detail")
@action(methods=["get"], detail=True, url_path="category-brief-detail")
def category_brief_detail(self, request, pk):
"""
Shows brief information about a category without indicating subcategories
Expand Down Expand Up @@ -579,6 +582,8 @@ def get_serializer_class(self):
return ProductUpdateSerializer
if self.action == "favorite":
return FavoriteProductCreateSerializer
if self.action == "order_user_check":
return ProductUserOrderCheckSerializer
return ProductSerializer

def get_queryset(self):
Expand Down Expand Up @@ -666,7 +671,7 @@ def retrieve(self, request, *args, **kwargs):
404: ErrorResponse404Serializer,
},
)
@decorators.action(
@action(
methods=["post", "delete"],
detail=True,
permission_classes=[permissions.IsAuthenticated],
Expand All @@ -675,6 +680,42 @@ def favorite(self, request, pk):
product = get_object_or_404(Product, id=pk)
return self.create_delete_or_scold(FavoriteProduct, product, request)

# TODO: test this endpoint
@method_decorator(
name="retrieve",
decorator=swagger_auto_schema(
operation_summary="Check user product order",
responses={
200: ProductUserOrderCheckSerializer,
404: ErrorResponse404Serializer,
},
),
)
@action(
methods=["get"],
detail=True,
url_path="order-user-check",
permission_classes=[permissions.IsAuthenticated],
)
def order_user_check(self, request, pk):
"""Shows whether the request.user has ordered this product."""
product = get_object_or_404(Product, id=int(pk))
serializer = self.get_serializer_class()
payload = {
"product": pk,
"user": self.request.user.pk,
"ordered": OrderProduct.objects.filter(
product=product, order__user=self.request.user
).exists(),
}
return response.Response(
serializer(
payload,
context={"request": request, "format": self.format_kwarg, "view": self},
).data,
status=status.HTTP_200_OK,
)


@method_decorator(
name="list",
Expand Down
11 changes: 10 additions & 1 deletion backend/api/reviews_serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from rest_framework import serializers

from api.users_serializers import UserLightSerializer
from orders.models import OrderProduct
from products.models import Product
from reviews.models import Review
Expand All @@ -13,7 +14,7 @@
class ReviewSerializer(serializers.ModelSerializer):
"""Serializer for reviews representation."""

author = serializers.SlugRelatedField(slug_field="username", read_only=True)
author = UserLightSerializer(read_only=True)
product = serializers.SlugRelatedField(slug_field="name", read_only=True)
was_edited = serializers.BooleanField(read_only=True)

Expand All @@ -33,3 +34,11 @@ def validate(self, data):
if not OrderProduct.objects.filter(product=product, order__user=user).exists():
raise serializers.ValidationError(REVIEW_NO_ORDER_ERROR_MESSAGE)
return data


class ReviewUserCheckSerializer(serializers.Serializer):
"""Serializer to check if the user has reviewed a product."""

product = serializers.IntegerField(read_only=True)
user = serializers.IntegerField(read_only=True)
reviewed = serializers.BooleanField(read_only=True)
42 changes: 40 additions & 2 deletions backend/api/reviews_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
ValidationErrorResponseSerializer,
)
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets
from rest_framework import permissions, response, status, viewsets
from rest_framework.decorators import action

from .mixins import DestroyWithPayloadMixin
from .permissions import IsAuthorOrAdminOrReadOnly
from .products_views import STATUS_200_RESPONSE_ON_DELETE_IN_DOCS
from .reviews_serializers import ReviewSerializer
from .reviews_serializers import ReviewSerializer, ReviewUserCheckSerializer
from products.models import Product
from reviews.models import Review

Expand Down Expand Up @@ -82,6 +83,11 @@ class ReviewViewSet(DestroyWithPayloadMixin, viewsets.ModelViewSet):
serializer_class = ReviewSerializer
permission_classes = [IsAuthorOrAdminOrReadOnly]

def get_serializer_class(self):
if self.action == "review_user_check":
return ReviewUserCheckSerializer
return ReviewSerializer

def get_queryset(self):
return Review.objects.filter(
product__id=self.kwargs.get("product_id")
Expand All @@ -94,3 +100,35 @@ def perform_create(self, serializer):
def perform_update(self, serializer):
serializer.save(pub_date=timezone.now(), was_edited=True)
return super().perform_update(serializer)

@method_decorator(
name="retrieve",
decorator=swagger_auto_schema(
operation_summary="Check user product review",
responses={200: ReviewUserCheckSerializer, 404: ErrorResponse404Serializer},
),
)
@action(
methods=["get"],
detail=False,
url_path="review-user-check",
permission_classes=[permissions.IsAuthenticated],
)
def review_user_check(self, request, product_id):
"""Shows whether the request.user has reviewed this product."""
product = get_object_or_404(Product, id=int(product_id))
serializer = self.get_serializer_class()
payload = {
"product": product_id,
"user": self.request.user.pk,
"reviewed": Review.objects.filter(
author=self.request.user, product=product
).exists(),
}
return response.Response(
serializer(
payload,
context={"request": request, "format": self.format_kwarg, "view": self},
).data,
status=status.HTTP_200_OK,
)
2 changes: 1 addition & 1 deletion backend/api/users_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class UserLightSerializer(UserSerializer):
"""Serializer to represent user in favorite products serializers."""

class Meta(UserSerializer.Meta):
fields = ("username", "email")
fields = ("id", "username")


class CustomUserDeleteSerializer(DjoserUserDeleteSerializer):
Expand Down
8 changes: 3 additions & 5 deletions backend/good_food/utils.py → backend/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@


def generate_order_number():
"""
Generates random ID.
"""
time = str(timezone.localdate())
"""Generates random ID."""
time = timezone.localdate()
random_int = random.randrange(100000, 1000000)
return str(time) + '-' + str(random_int)
return str(time) + "-" + str(random_int)
6 changes: 3 additions & 3 deletions backend/tests/api_tests/test_favorites.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def test_get_favorite_list(auth_admin, favorites, user, products):

assert response.status_code == 200
assert len(response.data) == 2
assert response.data[0]["user"]["id"] == user.pk
assert response.data[0]["user"]["username"] == user.username
assert response.data[0]["user"]["email"] == user.email
assert response.data[0]["product"]["name"] == products[0].name


Expand All @@ -29,8 +29,8 @@ def test_get_favorite_by_id(auth_admin, favorites, user, products):
)

assert response.status_code == 200
assert response.data["user"]["id"] == user.pk
assert response.data["user"]["username"] == user.username
assert response.data["user"]["email"] == user.email
assert response.data["product"]["name"] == products[0].name


Expand Down Expand Up @@ -92,8 +92,8 @@ def test_create_favorite(auth_client, products, user):
)

assert response.status_code == 201
assert response.data["user"]["id"] == user.pk
assert response.data["user"]["username"] == user.username
assert response.data["user"]["email"] == user.email
assert response.data["product"]["name"] == products[0].name


Expand Down

0 comments on commit 1d23751

Please sign in to comment.