mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-30 06:27:01 -05:00
feat: Implement MFA authentication, add ride statistics model, and update various services, APIs, and tests across the application.
This commit is contained in:
@@ -5,88 +5,88 @@ This module provides a unified interface to all serializers across different dom
|
||||
while maintaining the modular structure for better organization and maintainability.
|
||||
"""
|
||||
|
||||
import importlib
|
||||
from typing import Any
|
||||
|
||||
# --- Companies and ride models domain ---
|
||||
from .companies import (
|
||||
CompanyCreateInputSerializer,
|
||||
CompanyDetailOutputSerializer,
|
||||
CompanyUpdateInputSerializer,
|
||||
RideModelCreateInputSerializer,
|
||||
RideModelDetailOutputSerializer,
|
||||
RideModelUpdateInputSerializer,
|
||||
) # noqa: F401
|
||||
|
||||
# --- Parks domain ---
|
||||
from .parks import (
|
||||
ParkAreaCreateInputSerializer,
|
||||
ParkAreaDetailOutputSerializer,
|
||||
ParkAreaUpdateInputSerializer,
|
||||
ParkCreateInputSerializer,
|
||||
ParkDetailOutputSerializer,
|
||||
ParkFilterInputSerializer,
|
||||
ParkListOutputSerializer,
|
||||
ParkLocationCreateInputSerializer,
|
||||
ParkLocationOutputSerializer,
|
||||
ParkLocationUpdateInputSerializer,
|
||||
ParkSuggestionOutputSerializer,
|
||||
ParkSuggestionSerializer,
|
||||
ParkUpdateInputSerializer,
|
||||
) # noqa: F401
|
||||
|
||||
# --- Rides domain ---
|
||||
from .rides import (
|
||||
RideCreateInputSerializer,
|
||||
RideDetailOutputSerializer,
|
||||
RideFilterInputSerializer,
|
||||
RideListOutputSerializer,
|
||||
RideLocationCreateInputSerializer,
|
||||
RideLocationOutputSerializer,
|
||||
RideLocationUpdateInputSerializer,
|
||||
RideModelOutputSerializer,
|
||||
RideParkOutputSerializer,
|
||||
RideReviewCreateInputSerializer,
|
||||
RideReviewOutputSerializer,
|
||||
RideReviewUpdateInputSerializer,
|
||||
RideUpdateInputSerializer,
|
||||
RollerCoasterStatsCreateInputSerializer,
|
||||
RollerCoasterStatsOutputSerializer,
|
||||
RollerCoasterStatsUpdateInputSerializer,
|
||||
) # noqa: F401
|
||||
from .services import (
|
||||
HealthCheckOutputSerializer,
|
||||
PerformanceMetricsOutputSerializer,
|
||||
SimpleHealthOutputSerializer,
|
||||
EmailSendInputSerializer,
|
||||
EmailTemplateOutputSerializer,
|
||||
MapDataOutputSerializer,
|
||||
CoordinateInputSerializer,
|
||||
HistoryEventSerializer,
|
||||
HistoryEntryOutputSerializer,
|
||||
HistoryCreateInputSerializer,
|
||||
ModerationSubmissionSerializer,
|
||||
ModerationSubmissionOutputSerializer,
|
||||
RoadtripParkSerializer,
|
||||
RoadtripCreateInputSerializer,
|
||||
RoadtripOutputSerializer,
|
||||
GeocodeInputSerializer,
|
||||
GeocodeOutputSerializer,
|
||||
DistanceCalculationInputSerializer,
|
||||
DistanceCalculationOutputSerializer,
|
||||
EmailSendInputSerializer,
|
||||
EmailTemplateOutputSerializer,
|
||||
GeocodeInputSerializer,
|
||||
GeocodeOutputSerializer,
|
||||
HealthCheckOutputSerializer,
|
||||
HistoryCreateInputSerializer,
|
||||
HistoryEntryOutputSerializer,
|
||||
HistoryEventSerializer,
|
||||
MapDataOutputSerializer,
|
||||
ModerationSubmissionOutputSerializer,
|
||||
ModerationSubmissionSerializer,
|
||||
PerformanceMetricsOutputSerializer,
|
||||
RoadtripCreateInputSerializer,
|
||||
RoadtripOutputSerializer,
|
||||
RoadtripParkSerializer,
|
||||
SimpleHealthOutputSerializer,
|
||||
) # noqa: F401
|
||||
from typing import Any, Dict, List
|
||||
import importlib
|
||||
|
||||
# --- Shared utilities and base classes ---
|
||||
from .shared import (
|
||||
FilterOptionSerializer,
|
||||
FilterRangeSerializer,
|
||||
StandardizedFilterMetadataSerializer,
|
||||
validate_filter_metadata_contract,
|
||||
ensure_filter_option_format,
|
||||
) # noqa: F401
|
||||
|
||||
# --- Parks domain ---
|
||||
from .parks import (
|
||||
ParkListOutputSerializer,
|
||||
ParkDetailOutputSerializer,
|
||||
ParkCreateInputSerializer,
|
||||
ParkUpdateInputSerializer,
|
||||
ParkFilterInputSerializer,
|
||||
ParkAreaDetailOutputSerializer,
|
||||
ParkAreaCreateInputSerializer,
|
||||
ParkAreaUpdateInputSerializer,
|
||||
ParkLocationOutputSerializer,
|
||||
ParkLocationCreateInputSerializer,
|
||||
ParkLocationUpdateInputSerializer,
|
||||
ParkSuggestionSerializer,
|
||||
ParkSuggestionOutputSerializer,
|
||||
) # noqa: F401
|
||||
|
||||
# --- Companies and ride models domain ---
|
||||
from .companies import (
|
||||
CompanyDetailOutputSerializer,
|
||||
CompanyCreateInputSerializer,
|
||||
CompanyUpdateInputSerializer,
|
||||
RideModelDetailOutputSerializer,
|
||||
RideModelCreateInputSerializer,
|
||||
RideModelUpdateInputSerializer,
|
||||
) # noqa: F401
|
||||
|
||||
# --- Rides domain ---
|
||||
from .rides import (
|
||||
RideParkOutputSerializer,
|
||||
RideModelOutputSerializer,
|
||||
RideListOutputSerializer,
|
||||
RideDetailOutputSerializer,
|
||||
RideCreateInputSerializer,
|
||||
RideUpdateInputSerializer,
|
||||
RideFilterInputSerializer,
|
||||
RollerCoasterStatsOutputSerializer,
|
||||
RollerCoasterStatsCreateInputSerializer,
|
||||
RollerCoasterStatsUpdateInputSerializer,
|
||||
RideLocationOutputSerializer,
|
||||
RideLocationCreateInputSerializer,
|
||||
RideLocationUpdateInputSerializer,
|
||||
RideReviewOutputSerializer,
|
||||
RideReviewCreateInputSerializer,
|
||||
RideReviewUpdateInputSerializer,
|
||||
validate_filter_metadata_contract,
|
||||
) # noqa: F401
|
||||
|
||||
# --- Accounts domain: try multiple likely locations, fall back to placeholders ---
|
||||
_ACCOUNTS_SYMBOLS: List[str] = [
|
||||
_ACCOUNTS_SYMBOLS: list[str] = [
|
||||
"UserProfileOutputSerializer",
|
||||
"UserProfileCreateInputSerializer",
|
||||
"UserProfileUpdateInputSerializer",
|
||||
@@ -106,7 +106,7 @@ _ACCOUNTS_SYMBOLS: List[str] = [
|
||||
]
|
||||
|
||||
|
||||
def _import_accounts_symbols() -> Dict[str, Any]:
|
||||
def _import_accounts_symbols() -> dict[str, Any]:
|
||||
"""
|
||||
Try a list of candidate module paths and return a dict mapping expected symbol
|
||||
names to the objects found. If no candidate provides a symbol, the symbol maps to None.
|
||||
@@ -119,7 +119,7 @@ def _import_accounts_symbols() -> Dict[str, Any]:
|
||||
]
|
||||
|
||||
# Prepare default placeholders
|
||||
result: Dict[str, Any] = {name: None for name in _ACCOUNTS_SYMBOLS}
|
||||
result: dict[str, Any] = dict.fromkeys(_ACCOUNTS_SYMBOLS)
|
||||
|
||||
for modname in candidates:
|
||||
try:
|
||||
|
||||
@@ -5,21 +5,22 @@ This module contains all serializers related to user account management,
|
||||
profile settings, preferences, privacy, notifications, and security.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from django.contrib.auth import get_user_model
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
OpenApiExample,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.accounts.models import (
|
||||
User,
|
||||
UserProfile,
|
||||
UserNotification,
|
||||
NotificationPreference,
|
||||
User,
|
||||
UserNotification,
|
||||
UserProfile,
|
||||
)
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
from apps.lists.models import UserList
|
||||
from apps.rides.models.credits import RideCredit
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
|
||||
UserModel = get_user_model()
|
||||
|
||||
@@ -187,7 +188,7 @@ class PublicUserSerializer(serializers.ModelSerializer):
|
||||
Only exposes public information.
|
||||
"""
|
||||
profile = UserProfileSerializer(read_only=True)
|
||||
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
@@ -906,9 +907,10 @@ class AvatarUploadSerializer(serializers.Serializer):
|
||||
|
||||
# Try to validate with PIL
|
||||
try:
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
from PIL import Image
|
||||
|
||||
value.seek(0)
|
||||
image_data = value.read()
|
||||
value.seek(0) # Reset for later use
|
||||
|
||||
@@ -5,14 +5,14 @@ This module contains all serializers related to user authentication,
|
||||
registration, password management, and social authentication.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from django.contrib.auth import get_user_model, authenticate
|
||||
from django.contrib.auth import authenticate, get_user_model
|
||||
from django.contrib.auth.password_validation import validate_password
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
OpenApiExample,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
|
||||
UserModel = get_user_model()
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@ This module contains all serializers related to companies that operate parks
|
||||
or manufacture rides, as well as ride model serializers.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
extend_schema_field,
|
||||
OpenApiExample,
|
||||
extend_schema_field,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
|
||||
from .shared import ModelChoices
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
|
||||
from .shared import ModelChoices
|
||||
|
||||
# === COMPANY SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ This module contains serializers for history tracking and timeline functionality
|
||||
using django-pghistory.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class ParkHistoryEventSerializer(serializers.Serializer):
|
||||
|
||||
@@ -5,13 +5,12 @@ This module contains all serializers related to map functionality,
|
||||
including location data, search results, and clustering.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
extend_schema_field,
|
||||
OpenApiExample,
|
||||
extend_schema_field,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
# === MAP LOCATION SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -5,13 +5,12 @@ This module contains serializers for photo uploads, media management,
|
||||
and related media functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
extend_schema_field,
|
||||
OpenApiExample,
|
||||
extend_schema_field,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
# === MEDIA SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -5,13 +5,12 @@ This module contains serializers for statistics, health checks, and other
|
||||
miscellaneous functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_field,
|
||||
)
|
||||
from .shared import ModelChoices
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
|
||||
# === STATISTICS SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ Serializers for park review API endpoints.
|
||||
This module contains serializers for park review CRUD operations.
|
||||
"""
|
||||
|
||||
from drf_spectacular.utils import OpenApiExample, extend_schema_field, extend_schema_serializer
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import extend_schema_field, extend_schema_serializer, OpenApiExample
|
||||
from apps.parks.models.reviews import ParkReview
|
||||
|
||||
from apps.api.v1.serializers.reviews import ReviewUserSerializer
|
||||
from apps.parks.models.reviews import ParkReview
|
||||
|
||||
|
||||
@extend_schema_serializer(
|
||||
examples=[
|
||||
|
||||
@@ -5,18 +5,18 @@ This module contains all serializers related to parks, park areas, park location
|
||||
and park search functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
extend_schema_field,
|
||||
OpenApiExample,
|
||||
extend_schema_field,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
from apps.core.services.media_url_service import MediaURLService
|
||||
from config.django import base as settings
|
||||
|
||||
from .shared import LocationOutputSerializer, CompanyOutputSerializer, ModelChoices
|
||||
from apps.core.services.media_url_service import MediaURLService
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
|
||||
from .shared import CompanyOutputSerializer, LocationOutputSerializer, ModelChoices
|
||||
|
||||
# === PARK SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ This module contains serializers for park-specific media functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.parks.models import ParkPhoto
|
||||
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@ Serializers for review-related API endpoints.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.accounts.models import User
|
||||
from apps.parks.models.reviews import ParkReview
|
||||
from apps.rides.models.reviews import RideReview
|
||||
from apps.accounts.models import User
|
||||
|
||||
|
||||
class ReviewUserSerializer(serializers.ModelSerializer):
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from apps.rides.models.credits import RideCredit
|
||||
from apps.rides.models import Ride
|
||||
|
||||
from apps.api.v1.serializers.rides import RideListOutputSerializer
|
||||
from apps.rides.models import Ride
|
||||
from apps.rides.models.credits import RideCredit
|
||||
|
||||
|
||||
class RideCreditSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for user ride credits."""
|
||||
|
||||
|
||||
ride_id = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Ride.objects.all(), source='ride', write_only=True
|
||||
)
|
||||
ride = RideListOutputSerializer(read_only=True)
|
||||
|
||||
|
||||
class Meta:
|
||||
model = RideCredit
|
||||
fields = [
|
||||
@@ -23,6 +24,7 @@ class RideCreditSerializer(serializers.ModelSerializer):
|
||||
'first_ridden_at',
|
||||
'last_ridden_at',
|
||||
'notes',
|
||||
'display_order',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
]
|
||||
@@ -37,7 +39,7 @@ class RideCreditSerializer(serializers.ModelSerializer):
|
||||
last = attrs.get('last_ridden_at')
|
||||
if first and last and last < first:
|
||||
raise serializers.ValidationError("Last ridden date cannot be before first ridden date.")
|
||||
|
||||
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
|
||||
@@ -5,16 +5,17 @@ This module contains all serializers related to ride models, variants,
|
||||
technical specifications, and related functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
extend_schema_field,
|
||||
OpenApiExample,
|
||||
extend_schema_field,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
from config.django import base as settings
|
||||
|
||||
from .shared import ModelChoices
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
|
||||
# Use dynamic imports to avoid circular import issues
|
||||
|
||||
@@ -23,9 +24,9 @@ def get_ride_model_classes():
|
||||
"""Get ride model classes dynamically to avoid import issues."""
|
||||
from apps.rides.models import (
|
||||
RideModel,
|
||||
RideModelVariant,
|
||||
RideModelPhoto,
|
||||
RideModelTechnicalSpec,
|
||||
RideModelVariant,
|
||||
)
|
||||
|
||||
return RideModel, RideModelVariant, RideModelPhoto, RideModelTechnicalSpec
|
||||
|
||||
@@ -4,11 +4,11 @@ Serializers for ride review API endpoints.
|
||||
This module contains serializers for ride review CRUD operations with Rich Choice Objects compliance.
|
||||
"""
|
||||
|
||||
from drf_spectacular.utils import OpenApiExample, extend_schema_field, extend_schema_serializer
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import extend_schema_field, extend_schema_serializer, OpenApiExample
|
||||
from apps.rides.models.reviews import RideReview
|
||||
|
||||
from apps.accounts.models import User
|
||||
from apps.core.choices.serializers import RichChoiceSerializer
|
||||
from apps.rides.models.reviews import RideReview
|
||||
|
||||
|
||||
class ReviewUserSerializer(serializers.ModelSerializer):
|
||||
@@ -74,7 +74,7 @@ class RideReviewOutputSerializer(serializers.ModelSerializer):
|
||||
"""Output serializer for ride reviews."""
|
||||
|
||||
user = ReviewUserSerializer(read_only=True)
|
||||
|
||||
|
||||
# Ride information
|
||||
ride = serializers.SerializerMethodField()
|
||||
park = serializers.SerializerMethodField()
|
||||
|
||||
@@ -5,16 +5,17 @@ This module contains all serializers related to rides, roller coaster statistics
|
||||
ride locations, and ride reviews.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_serializer,
|
||||
extend_schema_field,
|
||||
OpenApiExample,
|
||||
extend_schema_field,
|
||||
extend_schema_serializer,
|
||||
)
|
||||
from config.django import base as settings
|
||||
from .shared import ModelChoices
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
from config.django import base as settings
|
||||
|
||||
from .shared import ModelChoices
|
||||
|
||||
# === RIDE SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ This module contains serializers for ride-specific media functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.rides.models import RidePhoto
|
||||
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@ and other search functionality.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from ..shared import ModelChoices
|
||||
|
||||
from apps.core.choices.serializers import RichChoiceFieldSerializer
|
||||
|
||||
from ..shared import ModelChoices
|
||||
|
||||
# === CORE ENTITY SEARCH SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -5,11 +5,10 @@ This module contains serializers for various services like email, maps,
|
||||
history tracking, moderation, and roadtrip planning.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema_field,
|
||||
)
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
# === HEALTH CHECK SERIALIZERS ===
|
||||
|
||||
|
||||
@@ -8,14 +8,15 @@ These serializers prevent contract violations by providing a single source of tr
|
||||
for common data structures used throughout the API.
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from rest_framework import serializers
|
||||
from typing import Dict, Any, List
|
||||
|
||||
|
||||
class FilterOptionSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard filter option format - matches frontend TypeScript exactly.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface FilterOption {
|
||||
value: string;
|
||||
@@ -31,7 +32,7 @@ class FilterOptionSerializer(serializers.Serializer):
|
||||
help_text="Human-readable display label"
|
||||
)
|
||||
count = serializers.IntegerField(
|
||||
required=False,
|
||||
required=False,
|
||||
allow_null=True,
|
||||
help_text="Number of items matching this filter option"
|
||||
)
|
||||
@@ -44,7 +45,7 @@ class FilterOptionSerializer(serializers.Serializer):
|
||||
class FilterRangeSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard range filter format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface FilterRange {
|
||||
min: number;
|
||||
@@ -66,7 +67,7 @@ class FilterRangeSerializer(serializers.Serializer):
|
||||
help_text="Step size for range inputs"
|
||||
)
|
||||
unit = serializers.CharField(
|
||||
required=False,
|
||||
required=False,
|
||||
allow_null=True,
|
||||
help_text="Unit of measurement (e.g., 'feet', 'mph', 'stars')"
|
||||
)
|
||||
@@ -75,7 +76,7 @@ class FilterRangeSerializer(serializers.Serializer):
|
||||
class BooleanFilterSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard boolean filter format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface BooleanFilter {
|
||||
key: string;
|
||||
@@ -97,7 +98,7 @@ class BooleanFilterSerializer(serializers.Serializer):
|
||||
class OrderingOptionSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard ordering option format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface OrderingOption {
|
||||
value: string;
|
||||
@@ -115,7 +116,7 @@ class OrderingOptionSerializer(serializers.Serializer):
|
||||
class StandardizedFilterMetadataSerializer(serializers.Serializer):
|
||||
"""
|
||||
Matches frontend TypeScript interface exactly.
|
||||
|
||||
|
||||
This serializer ensures all filter metadata responses follow the same structure
|
||||
that the frontend expects, preventing runtime type errors.
|
||||
"""
|
||||
@@ -131,7 +132,7 @@ class StandardizedFilterMetadataSerializer(serializers.Serializer):
|
||||
help_text="Total number of items in the filtered dataset"
|
||||
)
|
||||
ordering_options = FilterOptionSerializer(
|
||||
many=True,
|
||||
many=True,
|
||||
required=False,
|
||||
help_text="Available ordering options"
|
||||
)
|
||||
@@ -145,7 +146,7 @@ class StandardizedFilterMetadataSerializer(serializers.Serializer):
|
||||
class PaginationMetadataSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard pagination metadata format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface PaginationMetadata {
|
||||
count: number;
|
||||
@@ -183,7 +184,7 @@ class PaginationMetadataSerializer(serializers.Serializer):
|
||||
class ApiResponseSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard API response wrapper.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface ApiResponse<T> {
|
||||
success: boolean;
|
||||
@@ -214,7 +215,7 @@ class ApiResponseSerializer(serializers.Serializer):
|
||||
class ErrorResponseSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard error response format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface ApiError {
|
||||
status: "error";
|
||||
@@ -245,7 +246,7 @@ class ErrorResponseSerializer(serializers.Serializer):
|
||||
class LocationSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard location format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface Location {
|
||||
city: string;
|
||||
@@ -291,7 +292,7 @@ LocationOutputSerializer = LocationSerializer
|
||||
class CompanyOutputSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard company output format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface Company {
|
||||
id: number;
|
||||
@@ -322,24 +323,24 @@ class ModelChoices:
|
||||
"""
|
||||
Utility class to provide model choices for serializers using Rich Choice Objects.
|
||||
This prevents circular imports while providing access to model choices from the registry.
|
||||
|
||||
|
||||
NO FALLBACKS - All choices must be properly defined in Rich Choice Objects.
|
||||
"""
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_park_status_choices():
|
||||
"""Get park status choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("statuses", "parks")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_ride_status_choices():
|
||||
"""Get ride status choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("statuses", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_company_role_choices():
|
||||
"""Get company role choices from Rich Choice registry."""
|
||||
@@ -350,91 +351,91 @@ class ModelChoices:
|
||||
parks_choices = get_choices("company_roles", "parks")
|
||||
all_choices = list(rides_choices) + list(parks_choices)
|
||||
return [(choice.value, choice.label) for choice in all_choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_ride_category_choices():
|
||||
"""Get ride category choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("categories", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_ride_post_closing_choices():
|
||||
"""Get ride post-closing status choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("post_closing_statuses", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_coaster_track_choices():
|
||||
"""Get coaster track material choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("track_materials", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_coaster_type_choices():
|
||||
"""Get coaster type choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("coaster_types", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_launch_choices():
|
||||
"""Get launch system choices from Rich Choice registry (legacy method)."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("propulsion_systems", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_propulsion_system_choices():
|
||||
"""Get propulsion system choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("propulsion_systems", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_photo_type_choices():
|
||||
"""Get photo type choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("photo_types", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_spec_category_choices():
|
||||
"""Get technical specification category choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("spec_categories", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_technical_spec_category_choices():
|
||||
"""Get technical specification category choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("spec_categories", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_target_market_choices():
|
||||
"""Get target market choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("target_markets", "rides")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_entity_type_choices():
|
||||
"""Get entity type choices for search functionality."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("entity_types", "core")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_health_status_choices():
|
||||
"""Get health check status choices from Rich Choice registry."""
|
||||
from apps.core.choices.registry import get_choices
|
||||
choices = get_choices("health_statuses", "core")
|
||||
return [(choice.value, choice.label) for choice in choices]
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_simple_health_status_choices():
|
||||
"""Get simple health check status choices from Rich Choice registry."""
|
||||
@@ -446,7 +447,7 @@ class ModelChoices:
|
||||
class EntityReferenceSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard entity reference format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface Entity {
|
||||
id: number;
|
||||
@@ -468,7 +469,7 @@ class EntityReferenceSerializer(serializers.Serializer):
|
||||
class ImageVariantsSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard image variants format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface ImageVariants {
|
||||
thumbnail: string;
|
||||
@@ -495,7 +496,7 @@ class ImageVariantsSerializer(serializers.Serializer):
|
||||
class PhotoSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard photo format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface Photo {
|
||||
id: number;
|
||||
@@ -546,7 +547,7 @@ class PhotoSerializer(serializers.Serializer):
|
||||
class UserInfoSerializer(serializers.Serializer):
|
||||
"""
|
||||
Standard user info format.
|
||||
|
||||
|
||||
Frontend TypeScript interface:
|
||||
interface UserInfo {
|
||||
id: number;
|
||||
@@ -571,19 +572,19 @@ class UserInfoSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
|
||||
def validate_filter_metadata_contract(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def validate_filter_metadata_contract(data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
Validate that filter metadata follows the expected contract.
|
||||
|
||||
|
||||
This function can be used in views to ensure filter metadata
|
||||
matches the frontend TypeScript interface before returning it.
|
||||
|
||||
|
||||
Args:
|
||||
data: Filter metadata dictionary
|
||||
|
||||
|
||||
Returns:
|
||||
Validated and potentially transformed data
|
||||
|
||||
|
||||
Raises:
|
||||
serializers.ValidationError: If data doesn't match contract
|
||||
"""
|
||||
@@ -593,21 +594,21 @@ def validate_filter_metadata_contract(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
return serializer.validated_data
|
||||
|
||||
|
||||
def ensure_filter_option_format(options: List[Any]) -> List[Dict[str, Any]]:
|
||||
def ensure_filter_option_format(options: list[Any]) -> list[dict[str, Any]]:
|
||||
"""
|
||||
Ensure a list of filter options follows the expected format.
|
||||
|
||||
|
||||
This utility function converts various input formats to the standard
|
||||
FilterOption format expected by the frontend.
|
||||
|
||||
|
||||
Args:
|
||||
options: List of options in various formats
|
||||
|
||||
|
||||
Returns:
|
||||
List of options in standard format
|
||||
"""
|
||||
standardized = []
|
||||
|
||||
|
||||
for option in options:
|
||||
if isinstance(option, dict):
|
||||
# Already in correct format or close to it
|
||||
@@ -633,19 +634,19 @@ def ensure_filter_option_format(options: List[Any]) -> List[Dict[str, Any]]:
|
||||
'count': None,
|
||||
'selected': False
|
||||
}
|
||||
|
||||
|
||||
standardized.append(standardized_option)
|
||||
|
||||
|
||||
return standardized
|
||||
|
||||
|
||||
def ensure_range_format(range_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def ensure_range_format(range_data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
Ensure range data follows the expected format.
|
||||
|
||||
|
||||
Args:
|
||||
range_data: Range data dictionary
|
||||
|
||||
|
||||
Returns:
|
||||
Range data in standard format
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user