mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-28 06:27:02 -05:00
134 lines
4.4 KiB
Python
134 lines
4.4 KiB
Python
"""
|
|
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,
|
|
})
|