Initial commit
This commit is contained in:
109
progress/views.py
Normal file
109
progress/views.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .models import LeaderboardEntry, StreakRecord, UserHearts, UserStats
|
||||
from .serializers import (
|
||||
LeaderboardResponseSerializer,
|
||||
StreakCalendarResponseSerializer,
|
||||
UserHeartsResponseSerializer,
|
||||
UserSummaryResponseSerializer,
|
||||
)
|
||||
|
||||
|
||||
class UserSummaryView(APIView):
|
||||
"""GET /api/user/summary — پروفایل + آمار + استریک (ادغامشده)"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@extend_schema(responses=UserSummaryResponseSerializer, tags=['Progress & Gamification (progress)'])
|
||||
def get(self, request):
|
||||
user = request.user # accounts.User، از طریق TadrisinoTokenAuthentication
|
||||
stats = UserStats.objects.filter(user_id=user.id).first()
|
||||
streak = StreakRecord.objects.filter(user_id=user.id).first()
|
||||
|
||||
data = {
|
||||
'userId': str(user.id),
|
||||
'name': user.name,
|
||||
'avatar': user.avatar,
|
||||
'gradeId': user.grade_id,
|
||||
'xp': stats.xp if stats else 0,
|
||||
'coins': stats.coins if stats else 0,
|
||||
'streak': {
|
||||
'current': streak.current_streak if streak else 0,
|
||||
'longest': streak.longest_streak if streak else 0,
|
||||
},
|
||||
# اپ subscription هنوز در این فاز پیادهسازی نشده؛ فعلاً null.
|
||||
'subscription': None,
|
||||
}
|
||||
return Response(UserSummaryResponseSerializer(data).data)
|
||||
|
||||
|
||||
class StreakCalendarView(APIView):
|
||||
"""GET /api/user/streak/calendar — تقویم کامل روزهای فعال"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@extend_schema(responses=StreakCalendarResponseSerializer, tags=['Progress & Gamification (progress)'])
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
streak = StreakRecord.objects.filter(user_id=user.id).first()
|
||||
|
||||
data = {
|
||||
'currentStreak': streak.current_streak if streak else 0,
|
||||
'longestStreak': streak.longest_streak if streak else 0,
|
||||
'activeDays': list(streak.active_days.values_list('date', flat=True)) if streak else [],
|
||||
}
|
||||
return Response(StreakCalendarResponseSerializer(data).data)
|
||||
|
||||
|
||||
class LeaderboardView(APIView):
|
||||
"""GET /api/leaderboard?period= — رتبهبندی هفتگی/ماهانه"""
|
||||
|
||||
@extend_schema(
|
||||
parameters=[OpenApiParameter('period', OpenApiTypes.STR, required=False,
|
||||
enum=['weekly', 'all_time'])],
|
||||
responses=LeaderboardResponseSerializer,
|
||||
tags=['Progress & Gamification (progress)'],
|
||||
)
|
||||
def get(self, request):
|
||||
period = request.query_params.get('period', 'weekly')
|
||||
entries = LeaderboardEntry.objects.filter(period=period).order_by('rank')[:50]
|
||||
|
||||
# نام کاربر از accounts.User خونده میشه (فقط برای نمایش، بدون FK واقعی).
|
||||
from accounts.models import User as AccountUser
|
||||
user_ids = [e.user_id for e in entries]
|
||||
names = {u.id: u.name for u in AccountUser.objects.filter(id__in=user_ids)}
|
||||
|
||||
data = {
|
||||
'period': period,
|
||||
'entries': [
|
||||
{
|
||||
'rank': e.rank,
|
||||
'userId': str(e.user_id),
|
||||
'name': names.get(e.user_id, ''),
|
||||
'xpInPeriod': e.xp_in_period,
|
||||
}
|
||||
for e in entries
|
||||
],
|
||||
}
|
||||
return Response(LeaderboardResponseSerializer(data).data)
|
||||
|
||||
|
||||
class UserHeartsView(APIView):
|
||||
"""GET /api/user/hearts — وضعیت فعلی جانها (هارت)"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@extend_schema(responses=UserHeartsResponseSerializer, tags=['Progress & Gamification (progress)'])
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
hearts, _ = UserHearts.objects.get_or_create(user_id=user.id)
|
||||
data = {
|
||||
'currentHearts': hearts.current_hearts,
|
||||
'maxHearts': hearts.max_hearts,
|
||||
'nextRefillAt': hearts.next_refill_at,
|
||||
}
|
||||
return Response(UserHeartsResponseSerializer(data).data)
|
||||
Reference in New Issue
Block a user