feat: Implement initial schema and add various API, service, and management command enhancements across the application.

This commit is contained in:
pacnpal
2026-01-01 15:13:01 -05:00
parent c95f99ca10
commit b243b17af7
413 changed files with 11164 additions and 17433 deletions

View File

@@ -155,11 +155,7 @@ class RideRankingViewSet(ReadOnlyModelViewSet):
from apps.rides.models import RankingSnapshot
ranking = self.get_object()
history = RankingSnapshot.objects.filter(ride=ranking.ride).order_by(
"-snapshot_date"
)[
:90
] # Last 3 months
history = RankingSnapshot.objects.filter(ride=ranking.ride).order_by("-snapshot_date")[:90] # Last 3 months
serializer = self.get_serializer(history, many=True)
return Response(serializer.data)
@@ -180,11 +176,7 @@ class RideRankingViewSet(ReadOnlyModelViewSet):
top_rated = RideRanking.objects.select_related("ride", "ride__park").first()
# Get most compared ride
most_compared = (
RideRanking.objects.select_related("ride", "ride__park")
.order_by("-comparison_count")
.first()
)
most_compared = RideRanking.objects.select_related("ride", "ride__park").order_by("-comparison_count").first()
# Get biggest rank change (last 7 days)
from datetime import timedelta
@@ -197,9 +189,7 @@ class RideRankingViewSet(ReadOnlyModelViewSet):
current_rankings = RideRanking.objects.select_related("ride")
for ranking in current_rankings[:100]: # Check top 100 for performance
old_snapshot = (
RankingSnapshot.objects.filter(
ride=ranking.ride, snapshot_date__lte=week_ago
)
RankingSnapshot.objects.filter(ride=ranking.ride, snapshot_date__lte=week_ago)
.order_by("-snapshot_date")
.first()
)
@@ -232,11 +222,7 @@ class RideRankingViewSet(ReadOnlyModelViewSet):
"park": top_rated.ride.park.name,
"rank": top_rated.rank,
"winning_percentage": float(top_rated.winning_percentage),
"average_rating": (
float(top_rated.average_rating)
if top_rated.average_rating
else None
),
"average_rating": (float(top_rated.average_rating) if top_rated.average_rating else None),
}
if top_rated
else None
@@ -272,9 +258,7 @@ class RideRankingViewSet(ReadOnlyModelViewSet):
ranking = self.get_object()
comparisons = (
RidePairComparison.objects.filter(
Q(ride_a=ranking.ride) | Q(ride_b=ranking.ride)
)
RidePairComparison.objects.filter(Q(ride_a=ranking.ride) | Q(ride_b=ranking.ride))
.select_related("ride_a", "ride_b", "ride_a__park", "ride_b__park")
.order_by("-mutual_riders_count")[:50]
)
@@ -309,16 +293,8 @@ class RideRankingViewSet(ReadOnlyModelViewSet):
"ties": comp.ties,
"result": result,
"mutual_riders": comp.mutual_riders_count,
"ride_a_avg_rating": (
float(comp.ride_a_avg_rating)
if comp.ride_a_avg_rating
else None
),
"ride_b_avg_rating": (
float(comp.ride_b_avg_rating)
if comp.ride_b_avg_rating
else None
),
"ride_a_avg_rating": (float(comp.ride_a_avg_rating) if comp.ride_a_avg_rating else None),
"ride_b_avg_rating": (float(comp.ride_b_avg_rating) if comp.ride_b_avg_rating else None),
}
)
@@ -345,9 +321,7 @@ class TriggerRankingCalculationView(APIView):
def post(self, request):
"""Trigger ranking calculation."""
if not request.user.is_staff:
return Response(
{"error": "Admin access required"}, status=status.HTTP_403_FORBIDDEN
)
return Response({"detail": "Admin access required"}, status=status.HTTP_403_FORBIDDEN)
# Replace direct import with a guarded runtime import to avoid static-analysis/initialization errors
try:
@@ -367,7 +341,7 @@ class TriggerRankingCalculationView(APIView):
if not RideRankingService:
return Response(
{"error": "Ranking service unavailable"},
{"detail": "Ranking service unavailable"},
status=status.HTTP_503_SERVICE_UNAVAILABLE,
)