mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-29 03:26:59 -05:00
feat: Add user leaderboard API, Cloudflare Turnstile integration, and support ticket categorization.
This commit is contained in:
133
backend/apps/api/v1/views/leaderboard.py
Normal file
133
backend/apps/api/v1/views/leaderboard.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
Leaderboard views for user rankings
|
||||
"""
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.response import Response
|
||||
from django.db.models import Count, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
|
||||
from apps.accounts.models import User
|
||||
from apps.rides.models import RideCredit
|
||||
from apps.reviews.models import Review
|
||||
from apps.moderation.models import EditSubmission
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([AllowAny])
|
||||
def leaderboard(request):
|
||||
"""
|
||||
Get user leaderboard data.
|
||||
|
||||
Query params:
|
||||
- category: 'credits' | 'reviews' | 'contributions' (default: credits)
|
||||
- period: 'all' | 'monthly' | 'weekly' (default: all)
|
||||
- limit: int (default: 25, max: 100)
|
||||
"""
|
||||
category = request.query_params.get('category', 'credits')
|
||||
period = request.query_params.get('period', 'all')
|
||||
limit = min(int(request.query_params.get('limit', 25)), 100)
|
||||
|
||||
# Calculate date filter based on period
|
||||
date_filter = None
|
||||
if period == 'weekly':
|
||||
date_filter = timezone.now() - timedelta(days=7)
|
||||
elif period == 'monthly':
|
||||
date_filter = timezone.now() - timedelta(days=30)
|
||||
|
||||
if category == 'credits':
|
||||
return _get_credits_leaderboard(date_filter, limit)
|
||||
elif category == 'reviews':
|
||||
return _get_reviews_leaderboard(date_filter, limit)
|
||||
elif category == 'contributions':
|
||||
return _get_contributions_leaderboard(date_filter, limit)
|
||||
else:
|
||||
return Response({'error': 'Invalid category'}, status=400)
|
||||
|
||||
|
||||
def _get_credits_leaderboard(date_filter, limit):
|
||||
"""Top users by total ride credits."""
|
||||
queryset = RideCredit.objects.all()
|
||||
|
||||
if date_filter:
|
||||
queryset = queryset.filter(created_at__gte=date_filter)
|
||||
|
||||
# Aggregate credits per user
|
||||
users_data = queryset.values('user_id', 'user__username', 'user__display_name').annotate(
|
||||
total_credits=Coalesce(Sum('count'), 0),
|
||||
unique_rides=Count('ride', distinct=True),
|
||||
).order_by('-total_credits')[:limit]
|
||||
|
||||
results = []
|
||||
for rank, entry in enumerate(users_data, 1):
|
||||
results.append({
|
||||
'rank': rank,
|
||||
'user_id': entry['user_id'],
|
||||
'username': entry['user__username'],
|
||||
'display_name': entry['user__display_name'] or entry['user__username'],
|
||||
'total_credits': entry['total_credits'],
|
||||
'unique_rides': entry['unique_rides'],
|
||||
})
|
||||
|
||||
return Response({
|
||||
'category': 'credits',
|
||||
'results': results,
|
||||
})
|
||||
|
||||
|
||||
def _get_reviews_leaderboard(date_filter, limit):
|
||||
"""Top users by review count."""
|
||||
queryset = Review.objects.all()
|
||||
|
||||
if date_filter:
|
||||
queryset = queryset.filter(created_at__gte=date_filter)
|
||||
|
||||
# Count reviews per user
|
||||
users_data = queryset.values('user_id', 'user__username', 'user__display_name').annotate(
|
||||
review_count=Count('id'),
|
||||
).order_by('-review_count')[:limit]
|
||||
|
||||
results = []
|
||||
for rank, entry in enumerate(users_data, 1):
|
||||
results.append({
|
||||
'rank': rank,
|
||||
'user_id': entry['user_id'],
|
||||
'username': entry['user__username'],
|
||||
'display_name': entry['user__display_name'] or entry['user__username'],
|
||||
'review_count': entry['review_count'],
|
||||
})
|
||||
|
||||
return Response({
|
||||
'category': 'reviews',
|
||||
'results': results,
|
||||
})
|
||||
|
||||
|
||||
def _get_contributions_leaderboard(date_filter, limit):
|
||||
"""Top users by approved contributions."""
|
||||
queryset = EditSubmission.objects.filter(status='approved')
|
||||
|
||||
if date_filter:
|
||||
queryset = queryset.filter(created_at__gte=date_filter)
|
||||
|
||||
# Count contributions per user
|
||||
users_data = queryset.values('submitted_by_id', 'submitted_by__username', 'submitted_by__display_name').annotate(
|
||||
contribution_count=Count('id'),
|
||||
).order_by('-contribution_count')[:limit]
|
||||
|
||||
results = []
|
||||
for rank, entry in enumerate(users_data, 1):
|
||||
results.append({
|
||||
'rank': rank,
|
||||
'user_id': entry['submitted_by_id'],
|
||||
'username': entry['submitted_by__username'],
|
||||
'display_name': entry['submitted_by__display_name'] or entry['submitted_by__username'],
|
||||
'contribution_count': entry['contribution_count'],
|
||||
})
|
||||
|
||||
return Response({
|
||||
'category': 'contributions',
|
||||
'results': results,
|
||||
})
|
||||
Reference in New Issue
Block a user