feat: Implement MFA authentication, add ride statistics model, and update various services, APIs, and tests across the application.

This commit is contained in:
pacnpal
2025-12-28 17:32:53 -05:00
parent aa56c46c27
commit c95f99ca10
452 changed files with 7948 additions and 6073 deletions

View File

@@ -1,18 +1,18 @@
"""
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 datetime import timedelta
from django.db.models import Count, Sum
from django.db.models.functions import Coalesce
from django.utils import timezone
from datetime import timedelta
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from apps.accounts.models import User
from apps.rides.models import RideCredit
from apps.reviews.models import Review
from apps.moderation.models import EditSubmission
from apps.reviews.models import Review
from apps.rides.models import RideCredit
@api_view(['GET'])
@@ -20,7 +20,7 @@ from apps.moderation.models import EditSubmission
def leaderboard(request):
"""
Get user leaderboard data.
Query params:
- category: 'credits' | 'reviews' | 'contributions' (default: credits)
- period: 'all' | 'monthly' | 'weekly' (default: all)
@@ -29,14 +29,14 @@ def leaderboard(request):
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':
@@ -50,16 +50,16 @@ def leaderboard(request):
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({
@@ -70,7 +70,7 @@ def _get_credits_leaderboard(date_filter, limit):
'total_credits': entry['total_credits'],
'unique_rides': entry['unique_rides'],
})
return Response({
'category': 'credits',
'results': results,
@@ -80,15 +80,15 @@ def _get_credits_leaderboard(date_filter, limit):
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({
@@ -98,7 +98,7 @@ def _get_reviews_leaderboard(date_filter, limit):
'display_name': entry['user__display_name'] or entry['user__username'],
'review_count': entry['review_count'],
})
return Response({
'category': 'reviews',
'results': results,
@@ -108,15 +108,15 @@ def _get_reviews_leaderboard(date_filter, limit):
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({
@@ -126,7 +126,7 @@ def _get_contributions_leaderboard(date_filter, limit):
'display_name': entry['submitted_by__display_name'] or entry['submitted_by__username'],
'contribution_count': entry['contribution_count'],
})
return Response({
'category': 'contributions',
'results': results,