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

@@ -9,19 +9,20 @@ This service implements the filtering design specified in:
backend/docs/ride_filtering_design.md
"""
from typing import Any
from django.contrib.postgres.search import (
SearchVector,
SearchQuery,
SearchRank,
SearchVector,
TrigramSimilarity,
)
from django.db import models
from django.db.models import Q, F, Value
from django.db.models import F, Q, Value
from django.db.models.functions import Greatest
from typing import Dict, List, Optional, Any
from apps.rides.models import Ride
from apps.parks.models import Park
from apps.rides.models import Ride
from apps.rides.models.company import Company
@@ -104,11 +105,11 @@ class RideSearchService:
def search_and_filter(
self,
filters: Dict[str, Any],
filters: dict[str, Any],
sort_by: str = "relevance",
page: int = 1,
page_size: int = 20,
) -> Dict[str, Any]:
) -> dict[str, Any]:
"""
Main search and filter method that combines all capabilities.
@@ -219,7 +220,7 @@ class RideSearchService:
return queryset, final_rank
def _apply_basic_info_filters(
self, queryset, filters: Dict[str, Any]
self, queryset, filters: dict[str, Any]
) -> models.QuerySet:
"""Apply basic information filters."""
@@ -267,7 +268,7 @@ class RideSearchService:
return queryset
def _apply_date_filters(self, queryset, filters: Dict[str, Any]) -> models.QuerySet:
def _apply_date_filters(self, queryset, filters: dict[str, Any]) -> models.QuerySet:
"""Apply date range filters."""
# Opening date range
@@ -297,7 +298,7 @@ class RideSearchService:
return queryset
def _apply_height_safety_filters(
self, queryset, filters: Dict[str, Any]
self, queryset, filters: dict[str, Any]
) -> models.QuerySet:
"""Apply height and safety requirement filters."""
@@ -320,7 +321,7 @@ class RideSearchService:
return queryset
def _apply_performance_filters(
self, queryset, filters: Dict[str, Any]
self, queryset, filters: dict[str, Any]
) -> models.QuerySet:
"""Apply performance metric filters."""
@@ -355,7 +356,7 @@ class RideSearchService:
return queryset
def _apply_relationship_filters(
self, queryset, filters: Dict[str, Any]
self, queryset, filters: dict[str, Any]
) -> models.QuerySet:
"""Apply relationship filters (manufacturer, designer, ride model)."""
@@ -398,7 +399,7 @@ class RideSearchService:
return queryset
def _apply_roller_coaster_filters(
self, queryset, filters: Dict[str, Any]
self, queryset, filters: dict[str, Any]
) -> models.QuerySet:
"""Apply roller coaster specific filters."""
queryset = self._apply_numeric_range_filter(
@@ -448,7 +449,7 @@ class RideSearchService:
def _apply_numeric_range_filter(
self,
queryset,
filters: Dict[str, Any],
filters: dict[str, Any],
filter_key: str,
field_name: str,
) -> models.QuerySet:
@@ -466,7 +467,7 @@ class RideSearchService:
return queryset
def _apply_company_filters(
self, queryset, filters: Dict[str, Any]
self, queryset, filters: dict[str, Any]
) -> models.QuerySet:
"""Apply company-related filters."""
@@ -522,8 +523,8 @@ class RideSearchService:
) # Always add name as secondary sort
def _add_search_highlights(
self, results: List[Ride], search_term: str
) -> List[Ride]:
self, results: list[Ride], search_term: str
) -> list[Ride]:
"""Add search highlights to results using SearchHeadline."""
if not search_term or not results:
@@ -536,12 +537,12 @@ class RideSearchService:
# (note: highlights would need to be processed at query time)
for ride in results:
# Store highlighted versions as dynamic attributes (for template use)
setattr(ride, "highlighted_name", ride.name)
setattr(ride, "highlighted_description", ride.description)
ride.highlighted_name = ride.name
ride.highlighted_description = ride.description
return results
def _get_applied_filters_summary(self, filters: Dict[str, Any]) -> Dict[str, Any]:
def _get_applied_filters_summary(self, filters: dict[str, Any]) -> dict[str, Any]:
"""Generate a summary of applied filters for the frontend."""
applied = {}
@@ -602,7 +603,7 @@ class RideSearchService:
def get_search_suggestions(
self, query: str, limit: int = 10
) -> List[Dict[str, Any]]:
) -> list[dict[str, Any]]:
"""
Get search suggestions for autocomplete functionality.
"""
@@ -672,8 +673,8 @@ class RideSearchService:
return suggestions[:limit]
def get_filter_options(
self, filter_type: str, context_filters: Optional[Dict[str, Any]] = None
) -> List[Dict[str, Any]]:
self, filter_type: str, context_filters: dict[str, Any] | None = None
) -> list[dict[str, Any]]:
"""
Get available options for a specific filter type.
Optionally filter options based on current context.
@@ -716,7 +717,7 @@ class RideSearchService:
# Add more filter options as needed
return []
def _apply_all_filters(self, queryset, filters: Dict[str, Any]) -> models.QuerySet:
def _apply_all_filters(self, queryset, filters: dict[str, Any]) -> models.QuerySet:
"""Apply all filters except search ranking."""
queryset = self._apply_basic_info_filters(queryset, filters)