mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-03 16:41:27 +01:00
127 lines
4.9 KiB
Python
127 lines
4.9 KiB
Python
from django.utils.decorators import method_decorator
|
|
from django_ratelimit.decorators import ratelimit
|
|
from rest_framework import permissions, serializers, status, viewsets
|
|
from rest_framework.decorators import action
|
|
from rest_framework.exceptions import PermissionDenied
|
|
from rest_framework.request import Request
|
|
from rest_framework.response import Response
|
|
|
|
from api.models import Notification, Rating, Reply
|
|
from api.serializers import RatingSerializer, ReplySerializer
|
|
from api.services.mentions import parse_mentions
|
|
from api.utils.auth import current_user
|
|
from api.views._pagination import FeedPagination
|
|
|
|
|
|
class RatingViewSet(viewsets.ModelViewSet):
|
|
queryset = Rating.objects.all()
|
|
serializer_class = RatingSerializer
|
|
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
|
|
|
|
@method_decorator(ratelimit(key="user", rate="10/m", method="POST", block=True))
|
|
def create(self, request, *args, **kwargs):
|
|
return super().create(request, *args, **kwargs)
|
|
|
|
def perform_create(self, serializer):
|
|
me = current_user(self.request)
|
|
flavor = serializer.validated_data["flavor"]
|
|
if Rating.objects.filter(user=me, flavor=flavor).exists():
|
|
raise serializers.ValidationError("You have already rated this flavor.")
|
|
rating = serializer.save(user=me)
|
|
if rating.comment:
|
|
parse_mentions(rating.comment, me, rating=rating)
|
|
|
|
def get_queryset(self):
|
|
return (
|
|
Rating.objects.select_related("user", "flavor", "flavor__category")
|
|
.prefetch_related("replies", "replies__user")
|
|
.order_by("-created_at")
|
|
)
|
|
|
|
@action(detail=False, methods=["get"], permission_classes=[permissions.IsAuthenticated])
|
|
def feed(self, request: Request) -> Response:
|
|
me = current_user(request)
|
|
followed_users = me.following.all()
|
|
feed_ratings = (
|
|
Rating.objects.filter(user__in=followed_users)
|
|
.select_related("user", "flavor", "flavor__category")
|
|
.prefetch_related("replies", "replies__user")
|
|
.order_by("-created_at")
|
|
)
|
|
|
|
paginator = FeedPagination()
|
|
page = paginator.paginate_queryset(feed_ratings, request)
|
|
if page is not None:
|
|
serializer = self.get_serializer(page, many=True)
|
|
return paginator.get_paginated_response(serializer.data)
|
|
|
|
return Response(self.get_serializer(feed_ratings, many=True).data)
|
|
|
|
def check_object_permissions(self, request, obj):
|
|
super().check_object_permissions(request, obj)
|
|
if (
|
|
request.method in ["PUT", "PATCH", "DELETE"]
|
|
and obj.user != request.user
|
|
and not request.user.is_superuser
|
|
):
|
|
self.permission_denied(request, message="You cannot edit/delete this rating.")
|
|
|
|
@action(detail=False, methods=["get"], permission_classes=[permissions.AllowAny])
|
|
def recent(self, request: Request) -> Response:
|
|
recent_ratings = (
|
|
Rating.objects.filter(comment__isnull=False)
|
|
.exclude(comment="")
|
|
.select_related("user", "flavor")
|
|
.order_by("-created_at")[:10]
|
|
)
|
|
return Response(self.get_serializer(recent_ratings, many=True).data)
|
|
|
|
@action(detail=True, methods=["post"], permission_classes=[permissions.IsAuthenticated])
|
|
def reply(self, request: Request, pk=None) -> Response:
|
|
me = current_user(request)
|
|
rating = self.get_object()
|
|
text = request.data.get("text")
|
|
if not text:
|
|
return Response({"error": "Text is required"}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
reply = Reply.objects.create(user=me, rating=rating, text=text)
|
|
|
|
if rating.user != me:
|
|
Notification.objects.create(
|
|
recipient=rating.user,
|
|
actor=me,
|
|
notification_type="reply",
|
|
rating=rating,
|
|
reply=reply,
|
|
)
|
|
|
|
parse_mentions(text, me, rating=rating, reply=reply)
|
|
|
|
return Response(
|
|
ReplySerializer(reply, context={"request": request}).data,
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
|
|
|
|
class ReplyViewSet(viewsets.ModelViewSet):
|
|
queryset = Reply.objects.all()
|
|
serializer_class = ReplySerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return Reply.objects.select_related("user", "rating").order_by("created_at")
|
|
|
|
def perform_update(self, serializer):
|
|
me = current_user(self.request)
|
|
reply = self.get_object()
|
|
if reply.user != me and not me.is_superuser:
|
|
raise PermissionDenied("You cannot edit this reply.")
|
|
new_reply = serializer.save()
|
|
parse_mentions(new_reply.text, me, rating=new_reply.rating, reply=new_reply)
|
|
|
|
def perform_destroy(self, instance):
|
|
me = current_user(self.request)
|
|
if instance.user != me and not me.is_superuser:
|
|
raise PermissionDenied("You cannot delete this reply.")
|
|
instance.delete()
|