Add comprehensive API documentation for ThrillWiki integration and features

- Introduced Next.js integration guide for ThrillWiki API, detailing authentication, core domain APIs, data structures, and implementation patterns.
- Documented the migration to Rich Choice Objects, highlighting changes for frontend developers and enhanced metadata availability.
- Fixed the missing `get_by_slug` method in the Ride model, ensuring proper functionality of ride detail endpoints.
- Created a test script to verify manufacturer syncing with ride models, ensuring data integrity across related models.
This commit is contained in:
pacnpal
2025-09-16 11:29:17 -04:00
parent 61d73a2147
commit c2c26cfd1d
98 changed files with 11476 additions and 4803 deletions

View File

@@ -483,15 +483,111 @@ class RideModelFilterOptionsAPIView(APIView):
tags=["Ride Models"],
)
def get(self, request: Request) -> Response:
"""Return filter options for ride models."""
"""Return filter options for ride models with Rich Choice Objects metadata."""
# Import Rich Choice registry
from apps.core.choices.registry import get_choices
if not MODELS_AVAILABLE:
return Response(
{
"categories": [("RC", "Roller Coaster"), ("FR", "Flat Ride")],
"target_markets": [("THRILL", "Thrill"), ("FAMILY", "Family")],
"manufacturers": [{"id": 1, "name": "Bolliger & Mabillard"}],
}
)
# Use Rich Choice Objects for fallback options
try:
# Get rich choice objects from registry
categories = get_choices('categories', 'rides')
target_markets = get_choices('target_markets', 'rides')
# Convert Rich Choice Objects to frontend format with metadata
categories_data = [
{
"value": choice.value,
"label": choice.label,
"description": choice.description,
"color": choice.metadata.get('color'),
"icon": choice.metadata.get('icon'),
"css_class": choice.metadata.get('css_class'),
"sort_order": choice.metadata.get('sort_order', 0)
}
for choice in categories
]
target_markets_data = [
{
"value": choice.value,
"label": choice.label,
"description": choice.description,
"color": choice.metadata.get('color'),
"icon": choice.metadata.get('icon'),
"css_class": choice.metadata.get('css_class'),
"sort_order": choice.metadata.get('sort_order', 0)
}
for choice in target_markets
]
except Exception:
# Ultimate fallback with basic structure
categories_data = [
{"value": "RC", "label": "Roller Coaster", "description": "High-speed thrill rides with tracks", "color": "red", "icon": "roller-coaster", "css_class": "bg-red-100 text-red-800", "sort_order": 1},
{"value": "DR", "label": "Dark Ride", "description": "Indoor themed experiences", "color": "purple", "icon": "dark-ride", "css_class": "bg-purple-100 text-purple-800", "sort_order": 2},
{"value": "FR", "label": "Flat Ride", "description": "Spinning and rotating attractions", "color": "blue", "icon": "flat-ride", "css_class": "bg-blue-100 text-blue-800", "sort_order": 3},
{"value": "WR", "label": "Water Ride", "description": "Water-based attractions and slides", "color": "cyan", "icon": "water-ride", "css_class": "bg-cyan-100 text-cyan-800", "sort_order": 4},
{"value": "TR", "label": "Transport", "description": "Transportation systems within parks", "color": "green", "icon": "transport", "css_class": "bg-green-100 text-green-800", "sort_order": 5},
{"value": "OT", "label": "Other", "description": "Miscellaneous attractions", "color": "gray", "icon": "other", "css_class": "bg-gray-100 text-gray-800", "sort_order": 6},
]
target_markets_data = [
{"value": "FAMILY", "label": "Family", "description": "Suitable for all family members", "color": "green", "icon": "family", "css_class": "bg-green-100 text-green-800", "sort_order": 1},
{"value": "THRILL", "label": "Thrill", "description": "High-intensity thrill experience", "color": "orange", "icon": "thrill", "css_class": "bg-orange-100 text-orange-800", "sort_order": 2},
{"value": "EXTREME", "label": "Extreme", "description": "Maximum intensity experience", "color": "red", "icon": "extreme", "css_class": "bg-red-100 text-red-800", "sort_order": 3},
{"value": "KIDDIE", "label": "Kiddie", "description": "Designed for young children", "color": "pink", "icon": "kiddie", "css_class": "bg-pink-100 text-pink-800", "sort_order": 4},
{"value": "ALL_AGES", "label": "All Ages", "description": "Enjoyable for all age groups", "color": "blue", "icon": "all-ages", "css_class": "bg-blue-100 text-blue-800", "sort_order": 5},
]
return Response({
"categories": categories_data,
"target_markets": target_markets_data,
"manufacturers": [{"id": 1, "name": "Bolliger & Mabillard", "slug": "bolliger-mabillard"}],
"ordering_options": [
{"value": "name", "label": "Name A-Z"},
{"value": "-name", "label": "Name Z-A"},
{"value": "manufacturer__name", "label": "Manufacturer A-Z"},
{"value": "-manufacturer__name", "label": "Manufacturer Z-A"},
{"value": "first_installation_year", "label": "Oldest First"},
{"value": "-first_installation_year", "label": "Newest First"},
{"value": "total_installations", "label": "Fewest Installations"},
{"value": "-total_installations", "label": "Most Installations"},
],
})
# Get static choice definitions from Rich Choice Objects (primary source)
# Get dynamic data from database queries
# Get rich choice objects from registry
categories = get_choices('categories', 'rides')
target_markets = get_choices('target_markets', 'rides')
# Convert Rich Choice Objects to frontend format with metadata
categories_data = [
{
"value": choice.value,
"label": choice.label,
"description": choice.description,
"color": choice.metadata.get('color'),
"icon": choice.metadata.get('icon'),
"css_class": choice.metadata.get('css_class'),
"sort_order": choice.metadata.get('sort_order', 0)
}
for choice in categories
]
target_markets_data = [
{
"value": choice.value,
"label": choice.label,
"description": choice.description,
"color": choice.metadata.get('color'),
"icon": choice.metadata.get('icon'),
"css_class": choice.metadata.get('css_class'),
"sort_order": choice.metadata.get('sort_order', 0)
}
for choice in target_markets
]
# Get actual data from database
manufacturers = (
@@ -502,48 +598,22 @@ class RideModelFilterOptionsAPIView(APIView):
.values("id", "name", "slug")
)
(
RideModel.objects.exclude(category="")
.values_list("category", flat=True)
.distinct()
)
return Response({
"categories": categories_data,
"target_markets": target_markets_data,
"manufacturers": list(manufacturers),
"ordering_options": [
{"value": "name", "label": "Name A-Z"},
{"value": "-name", "label": "Name Z-A"},
{"value": "manufacturer__name", "label": "Manufacturer A-Z"},
{"value": "-manufacturer__name", "label": "Manufacturer Z-A"},
{"value": "first_installation_year", "label": "Oldest First"},
{"value": "-first_installation_year", "label": "Newest First"},
{"value": "total_installations", "label": "Fewest Installations"},
{"value": "-total_installations", "label": "Most Installations"},
],
})
(
RideModel.objects.exclude(target_market="")
.values_list("target_market", flat=True)
.distinct()
)
return Response(
{
"categories": [
("RC", "Roller Coaster"),
("DR", "Dark Ride"),
("FR", "Flat Ride"),
("WR", "Water Ride"),
("TR", "Transport"),
("OT", "Other"),
],
"target_markets": [
("FAMILY", "Family"),
("THRILL", "Thrill"),
("EXTREME", "Extreme"),
("KIDDIE", "Kiddie"),
("ALL_AGES", "All Ages"),
],
"manufacturers": list(manufacturers),
"ordering_options": [
("name", "Name A-Z"),
("-name", "Name Z-A"),
("manufacturer__name", "Manufacturer A-Z"),
("-manufacturer__name", "Manufacturer Z-A"),
("first_installation_year", "Oldest First"),
("-first_installation_year", "Newest First"),
("total_installations", "Fewest Installations"),
("-total_installations", "Most Installations"),
],
}
)
# === RIDE MODEL STATISTICS ===