89 lines
3.5 KiB
Python
89 lines
3.5 KiB
Python
|
|
from django.db import IntegrityError
|
||
|
|
from django.db.models import Count
|
||
|
|
from rest_framework import status
|
||
|
|
from rest_framework.exceptions import NotFound
|
||
|
|
from rest_framework.permissions import IsAuthenticated
|
||
|
|
from rest_framework.response import Response
|
||
|
|
from rest_framework.views import APIView
|
||
|
|
|
||
|
|
from apps.reviews.models import Review, ReviewLike
|
||
|
|
|
||
|
|
from .serializers import ReviewSerializer, ReviewWriteSerializer
|
||
|
|
|
||
|
|
|
||
|
|
class ReviewListView(APIView):
|
||
|
|
"""فهرستِ عمومیِ نظراتِ تاییدشده — پرلایکترینها اول."""
|
||
|
|
|
||
|
|
permission_classes = [IsAuthenticated]
|
||
|
|
|
||
|
|
def get(self, request):
|
||
|
|
reviews = (
|
||
|
|
Review.objects.filter(is_approved=True)
|
||
|
|
.select_related("user")
|
||
|
|
.annotate(like_count=Count("likes"))
|
||
|
|
.order_by("-like_count", "-created_at")
|
||
|
|
)
|
||
|
|
liked_ids = set(
|
||
|
|
ReviewLike.objects.filter(user=request.user, review__in=reviews).values_list(
|
||
|
|
"review_id", flat=True
|
||
|
|
)
|
||
|
|
)
|
||
|
|
serializer = ReviewSerializer(
|
||
|
|
reviews, many=True, context={"request": request, "liked_ids": liked_ids}
|
||
|
|
)
|
||
|
|
return Response(serializer.data)
|
||
|
|
|
||
|
|
|
||
|
|
class MyReviewView(APIView):
|
||
|
|
"""نظرِ خودِ کاربر — صرفنظر از تایید یا نبودنِ آن. یک کاربر همیشه دقیقا
|
||
|
|
صفر یا یک نظر دارد؛ نوشتنِ دوباره همان نظر را جایگزین و تاییدش را
|
||
|
|
ریست میکند."""
|
||
|
|
|
||
|
|
permission_classes = [IsAuthenticated]
|
||
|
|
|
||
|
|
def get(self, request):
|
||
|
|
review = Review.objects.filter(user=request.user).first()
|
||
|
|
if review is None:
|
||
|
|
return Response(None)
|
||
|
|
return Response(ReviewSerializer(review, context={"request": request}).data)
|
||
|
|
|
||
|
|
def patch(self, request):
|
||
|
|
serializer = ReviewWriteSerializer(data=request.data)
|
||
|
|
serializer.is_valid(raise_exception=True)
|
||
|
|
review, _created = Review.objects.update_or_create(
|
||
|
|
user=request.user,
|
||
|
|
defaults={
|
||
|
|
"body": serializer.validated_data["body"],
|
||
|
|
"is_approved": False,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
return Response(
|
||
|
|
ReviewSerializer(review, context={"request": request}).data,
|
||
|
|
status=status.HTTP_200_OK,
|
||
|
|
)
|
||
|
|
|
||
|
|
def delete(self, request):
|
||
|
|
Review.objects.filter(user=request.user).delete()
|
||
|
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||
|
|
|
||
|
|
|
||
|
|
class ReviewLikeToggleView(APIView):
|
||
|
|
"""لایک/آنلایکِ یک نظرِ تاییدشده — لایکِ نظرِ تاییدنشدهی خودِ کسی معنی
|
||
|
|
ندارد، چون در فهرستِ عمومی اصلا دیده نمیشود."""
|
||
|
|
|
||
|
|
permission_classes = [IsAuthenticated]
|
||
|
|
|
||
|
|
def post(self, request, pk):
|
||
|
|
review = Review.objects.filter(pk=pk, is_approved=True).first()
|
||
|
|
if review is None:
|
||
|
|
raise NotFound("نظر یافت نشد.")
|
||
|
|
deleted, _ = ReviewLike.objects.filter(review=review, user=request.user).delete()
|
||
|
|
if not deleted:
|
||
|
|
try:
|
||
|
|
ReviewLike.objects.create(review=review, user=request.user)
|
||
|
|
except IntegrityError:
|
||
|
|
pass # درخواستِ همزمانِ دوم — بیضرر، نتیجه هرحال «لایکشده» است.
|
||
|
|
like_count = review.likes.count()
|
||
|
|
liked_by_me = review.likes.filter(user=request.user).exists()
|
||
|
|
return Response({"like_count": like_count, "liked_by_me": liked_by_me})
|