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

@@ -14,9 +14,10 @@ Forms for the comprehensive ride filtering system with 8 categories:
Each form handles validation and provides clean data for the RideSearchService.
"""
from typing import Any
from django import forms
from django.core.exceptions import ValidationError
from typing import Dict, Any
from apps.parks.models import Park, ParkArea
from apps.rides.models.company import Company
@@ -95,14 +96,14 @@ class BasicInfoForm(BaseFilterForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Get choices from Rich Choice registry
from apps.core.choices.registry import get_choices
# Get choices - let exceptions propagate if registry fails
category_choices = [(choice.value, choice.label) for choice in get_choices("categories", "rides")]
status_choices = [(choice.value, choice.label) for choice in get_choices("statuses", "rides")]
# Update field choices dynamically
self.fields['category'].choices = category_choices
self.fields['status'].choices = status_choices
@@ -189,9 +190,8 @@ class DateRangeField(forms.MultiValueField):
def validate(self, value):
super().validate(value)
if value and value.get("start") and value.get("end"):
if value["start"] > value["end"]:
raise ValidationError("Start date must be before end date.")
if value and value.get("start") and value.get("end") and value["start"] > value["end"]:
raise ValidationError("Start date must be before end date.")
class DateFiltersForm(BaseFilterForm):
@@ -340,15 +340,15 @@ class RollerCoasterForm(BaseFilterForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Get choices from Rich Choice registry
from apps.core.choices.registry import get_choices
# Get choices - let exceptions propagate if registry fails
track_material_choices = [(choice.value, choice.label) for choice in get_choices("track_materials", "rides")]
coaster_type_choices = [(choice.value, choice.label) for choice in get_choices("coaster_types", "rides")]
propulsion_system_choices = [(choice.value, choice.label) for choice in get_choices("propulsion_systems", "rides")]
# Update field choices dynamically
self.fields['track_material'].choices = track_material_choices
self.fields['coaster_type'].choices = coaster_type_choices
@@ -398,15 +398,15 @@ class CompanyForm(BaseFilterForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Get choices from Rich Choice registry
from apps.core.choices.registry import get_choices
# Get both rides and parks company roles - let exceptions propagate if registry fails
rides_roles = [(choice.value, choice.label) for choice in get_choices("company_roles", "rides")]
parks_roles = [(choice.value, choice.label) for choice in get_choices("company_roles", "parks")]
role_choices = rides_roles + parks_roles
# Update field choices dynamically
self.fields['manufacturer_roles'].choices = role_choices
self.fields['designer_roles'].choices = role_choices
@@ -434,7 +434,7 @@ class SortingForm(BaseFilterForm):
# Static sorting choices - these are UI-specific and don't need Rich Choice Objects
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Static sort choices for UI functionality
sort_choices = [
("relevance", "Relevance"),
@@ -451,7 +451,7 @@ class SortingForm(BaseFilterForm):
("capacity_asc", "Capacity (Lowest)"),
("capacity_desc", "Capacity (Highest)"),
]
self.fields['sort_by'].choices = sort_choices
sort_by = forms.ChoiceField(
@@ -524,7 +524,7 @@ class MasterFilterForm(BaseFilterForm):
return cleaned_data
def get_filter_dict(self) -> Dict[str, Any]:
def get_filter_dict(self) -> dict[str, Any]:
"""Convert form data to search service filter format."""
if not self.is_valid():
return {}
@@ -538,11 +538,11 @@ class MasterFilterForm(BaseFilterForm):
return filters
def get_search_filters(self) -> Dict[str, Any]:
def get_search_filters(self) -> dict[str, Any]:
"""Alias for get_filter_dict for backward compatibility."""
return self.get_filter_dict()
def get_filter_summary(self) -> Dict[str, Any]:
def get_filter_summary(self) -> dict[str, Any]:
"""Get summary of active filters for display."""
active_filters = {}
@@ -588,7 +588,7 @@ class MasterFilterForm(BaseFilterForm):
return active_filters
def get_active_filters_summary(self) -> Dict[str, Any]:
def get_active_filters_summary(self) -> dict[str, Any]:
"""Alias for get_filter_summary for backward compatibility."""
return self.get_filter_summary()
@@ -597,8 +597,4 @@ class MasterFilterForm(BaseFilterForm):
if not self.is_valid():
return False
for field_name, value in self.cleaned_data.items():
if value: # If any field has a value, we have active filters
return True
return False
return any(value for field_name, value in self.cleaned_data.items())