list a user's own support tickets, Persian digits in completion notifications, rewrite .env.example to match the code

GET /api/support/tickets returns the caller's last 20 tickets with their
support-reply count, on the read throttle so listing never spends the
30/hour create quota. Before it the app kept ticket ids only in one
browser's localStorage, so a ticket and its answer vanished with the device.

Completion notifications now use Persian digits and drop the
'with 0 stars ... 0 points' sentence when nothing was earned.

.env.example: NUM_PROXIES=2 (ArvanCloud + nginx), KAVENEGAR_OTP_TEMPLATE,
BAZAAR_PISHKHAN_API_SECRET, sandbox off by default; removed variables the
code no longer reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-29 21:18:12 +03:30
parent 8321dc22c3
commit 93b451d422
7 changed files with 192 additions and 163 deletions

View File

@@ -1,3 +1,4 @@
from django.db.models import Count, Q
from django.shortcuts import get_object_or_404
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import IsAuthenticated
@@ -12,6 +13,7 @@ from .serializers import (
TicketCreateRequestSerializer,
TicketCreateResponseSerializer,
TicketDetailResponseSerializer,
TicketListResponseSerializer,
TicketMessageCreateRequestSerializer,
TicketMessageCreateResponseSerializer,
)
@@ -88,7 +90,15 @@ class BugReportCreateView(APIView):
class TicketCreateView(APIView):
"""POST /api/support/tickets — ایجاد تیکت"""
"""
GET /api/support/tickets — تیکت‌های همین کاربر (۲۰ تای آخر)
POST /api/support/tickets — ایجاد تیکت
GET تا ۲۰۲۶-۰۹-۲۹ نبود و اپ شناسه‌ی تیکت‌ها را فقط در حافظه‌ی همان مرورگر
نگه می‌داشت؛ با عوض شدنِ دستگاه، تیکت و پاسخِ پشتیبانی از دید پنهان می‌شد.
"""
LIST_LIMIT = 20
permission_classes = [IsAuthenticated]
# مثلِ BugReportCreateView: هیچ idempotency ای نیست، پس این endpoint هم
@@ -99,6 +109,36 @@ class TicketCreateView(APIView):
throttle_scope = 'support_create'
throttle_classes = [GuestAwareSupportThrottle]
def get_throttles(self):
# GET سهمِ خواندن را می‌خورد، نه سقفِ ۳۰ در ساعتِ ساختِ رکورد.
if self.request.method == 'GET':
self.throttle_scope = 'read'
return super().get_throttles()
@extend_schema(
operation_id='support_tickets_list',
responses=TicketListResponseSerializer,
tags=['Support (support)'],
)
def get(self, request):
tickets = (
Ticket.objects.filter(user_id=request.user.id)
.annotate(support_replies=Count('messages', filter=Q(messages__sender='support')))
.order_by('-created_at')[: self.LIST_LIMIT]
)
data = {'tickets': [
{
'ticketId': str(t.pk),
'subject': t.subject,
'category': t.category,
'status': t.status,
'createdAt': t.created_at,
'supportReplies': t.support_replies,
}
for t in tickets
]}
return Response(TicketListResponseSerializer(data).data)
@extend_schema(
request=TicketCreateRequestSerializer,
responses=TicketCreateResponseSerializer,