from django.shortcuts import get_object_or_404 from drf_spectacular.utils import extend_schema from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.throttling import ScopedRateThrottle from rest_framework.views import APIView from .models import Notification from .serializers import MarkReadResponseSerializer, NotificationListResponseSerializer # سقفِ تعدادِ اعلانِ برگشتی؛ جلوی رشدِ نامحدودِ پاسخ برای کاربرِ قدیمی رو # می‌گیره. صفحه‌بندیِ واقعی (cursor) وقتی فرانت infinite-scroll اضافه کنه. NOTIFICATIONS_MAX = 100 class GuestAwareReadThrottle(ScopedRateThrottle): """همون الگوی GuestAware*Throttle: مهمان با IP کلید می‌خوره.""" def get_cache_key(self, request, view): user = request.user if user and user.is_authenticated and getattr(user, 'is_guest', False): ident = f'guest-ip:{self.get_ident(request)}' elif user and user.is_authenticated: ident = user.pk else: ident = self.get_ident(request) return self.cache_format % {'scope': self.scope, 'ident': ident} class NotificationListView(APIView): """GET /api/notifications — فهرست اعلان‌های کاربر (جدیدترین اول)""" permission_classes = [IsAuthenticated] throttle_scope = 'read' throttle_classes = [GuestAwareReadThrottle] @extend_schema(responses=NotificationListResponseSerializer, tags=['Notifications (notifications)']) def get(self, request): qs = Notification.objects.filter(user_id=request.user.id) # Meta.ordering: جدیدترین اول unread_count = qs.filter(is_read=False).count() data = {'items': list(qs[:NOTIFICATIONS_MAX]), 'unreadCount': unread_count} return Response(NotificationListResponseSerializer(data).data) class NotificationMarkReadView(APIView): """PATCH /api/notifications/{id}/read — علامت‌گذاری یک اعلان به‌عنوان خوانده‌شده""" permission_classes = [IsAuthenticated] @extend_schema(responses=MarkReadResponseSerializer, tags=['Notifications (notifications)']) def patch(self, request, id): notification = get_object_or_404(Notification, pk=id, user_id=request.user.id) if not notification.is_read: notification.is_read = True notification.save(update_fields=['is_read']) return Response(MarkReadResponseSerializer({'success': True}).data)