mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 17:31:09 -05:00
- Restructure API v1 with improved serializers organization - Add user deletion requests and moderation queue system - Implement bulk moderation operations and permissions - Add user profile enhancements with display names and avatars - Expand ride and park API endpoints with better filtering - Add manufacturer API with detailed ride relationships - Improve authentication flows and error handling - Update frontend documentation and API specifications
206 lines
6.7 KiB
Python
206 lines
6.7 KiB
Python
"""
|
|
Shared serializers and utilities for ThrillWiki API v1.
|
|
|
|
This module contains common serializers and helper classes used across multiple domains
|
|
to avoid code duplication and maintain consistency.
|
|
"""
|
|
|
|
from rest_framework import serializers
|
|
from drf_spectacular.utils import extend_schema_field
|
|
from django.contrib.auth import get_user_model
|
|
from django.conf import settings
|
|
|
|
# Import models inside class methods to avoid Django initialization issues
|
|
|
|
UserModel = get_user_model()
|
|
|
|
# Define constants to avoid import-time model loading
|
|
CATEGORY_CHOICES = [
|
|
("RC", "Roller Coaster"),
|
|
("FL", "Flat Ride"),
|
|
("DR", "Dark Ride"),
|
|
("WR", "Water Ride"),
|
|
("TR", "Transport"),
|
|
("OT", "Other"),
|
|
]
|
|
|
|
|
|
# Placeholder for dynamic model choices - will be populated at runtime
|
|
class ModelChoices:
|
|
@staticmethod
|
|
def get_ride_status_choices():
|
|
try:
|
|
from apps.rides.models import Ride
|
|
|
|
return Ride.STATUS_CHOICES
|
|
except ImportError:
|
|
return [("OPERATING", "Operating"), ("CLOSED", "Closed")]
|
|
|
|
@staticmethod
|
|
def get_park_status_choices():
|
|
try:
|
|
from apps.parks.models import Park
|
|
|
|
return Park.STATUS_CHOICES
|
|
except ImportError:
|
|
return [("OPERATING", "Operating"), ("CLOSED", "Closed")]
|
|
|
|
@staticmethod
|
|
def get_company_role_choices():
|
|
try:
|
|
from apps.parks.models import Company
|
|
|
|
return Company.CompanyRole.choices
|
|
except ImportError:
|
|
return [("OPERATOR", "Operator"), ("MANUFACTURER", "Manufacturer")]
|
|
|
|
@staticmethod
|
|
def get_coaster_track_choices():
|
|
try:
|
|
from apps.rides.models import RollerCoasterStats
|
|
|
|
return RollerCoasterStats.TRACK_MATERIAL_CHOICES
|
|
except ImportError:
|
|
return [("STEEL", "Steel"), ("WOOD", "Wood")]
|
|
|
|
@staticmethod
|
|
def get_coaster_type_choices():
|
|
try:
|
|
from apps.rides.models import RollerCoasterStats
|
|
|
|
return RollerCoasterStats.COASTER_TYPE_CHOICES
|
|
except ImportError:
|
|
return [("SITDOWN", "Sit Down"), ("INVERTED", "Inverted")]
|
|
|
|
@staticmethod
|
|
def get_launch_choices():
|
|
try:
|
|
from apps.rides.models import RollerCoasterStats
|
|
|
|
return RollerCoasterStats.LAUNCH_CHOICES
|
|
except ImportError:
|
|
return [("CHAIN", "Chain Lift"), ("LAUNCH", "Launch")]
|
|
|
|
@staticmethod
|
|
def get_top_list_categories():
|
|
try:
|
|
from apps.accounts.models import TopList
|
|
|
|
return TopList.Categories.choices
|
|
except ImportError:
|
|
return [("RC", "Roller Coasters"), ("PARKS", "Parks")]
|
|
|
|
@staticmethod
|
|
def get_ride_post_closing_choices():
|
|
try:
|
|
from apps.rides.models import Ride
|
|
|
|
return Ride.POST_CLOSING_STATUS_CHOICES
|
|
except ImportError:
|
|
return [
|
|
("DEMOLISHED", "Demolished"),
|
|
("RELOCATED", "Relocated"),
|
|
("SBNO", "Standing But Not Operating"),
|
|
]
|
|
|
|
@staticmethod
|
|
def get_ride_category_choices():
|
|
try:
|
|
from apps.rides.models import CATEGORY_CHOICES
|
|
|
|
return CATEGORY_CHOICES
|
|
except ImportError:
|
|
return [
|
|
("RC", "Roller Coaster"),
|
|
("DR", "Dark Ride"),
|
|
("FR", "Flat Ride"),
|
|
("WR", "Water Ride"),
|
|
("TR", "Transport"),
|
|
("OT", "Other"),
|
|
]
|
|
|
|
|
|
class LocationOutputSerializer(serializers.Serializer):
|
|
"""Shared serializer for location data."""
|
|
|
|
latitude = serializers.SerializerMethodField()
|
|
longitude = serializers.SerializerMethodField()
|
|
city = serializers.SerializerMethodField()
|
|
state = serializers.SerializerMethodField()
|
|
country = serializers.SerializerMethodField()
|
|
formatted_address = serializers.SerializerMethodField()
|
|
|
|
@extend_schema_field(serializers.FloatField(allow_null=True))
|
|
def get_latitude(self, obj) -> float | None:
|
|
if hasattr(obj, "location") and obj.location:
|
|
return obj.location.latitude
|
|
return None
|
|
|
|
@extend_schema_field(serializers.FloatField(allow_null=True))
|
|
def get_longitude(self, obj) -> float | None:
|
|
if hasattr(obj, "location") and obj.location:
|
|
return obj.location.longitude
|
|
return None
|
|
|
|
@extend_schema_field(serializers.CharField(allow_null=True))
|
|
def get_city(self, obj) -> str | None:
|
|
if hasattr(obj, "location") and obj.location:
|
|
return obj.location.city
|
|
return None
|
|
|
|
@extend_schema_field(serializers.CharField(allow_null=True))
|
|
def get_state(self, obj) -> str | None:
|
|
if hasattr(obj, "location") and obj.location:
|
|
return obj.location.state
|
|
return None
|
|
|
|
@extend_schema_field(serializers.CharField(allow_null=True))
|
|
def get_country(self, obj) -> str | None:
|
|
if hasattr(obj, "location") and obj.location:
|
|
return obj.location.country
|
|
return None
|
|
|
|
@extend_schema_field(serializers.CharField())
|
|
def get_formatted_address(self, obj) -> str:
|
|
if hasattr(obj, "location") and obj.location:
|
|
return obj.location.formatted_address
|
|
return ""
|
|
|
|
|
|
class CompanyOutputSerializer(serializers.Serializer):
|
|
"""Shared serializer for company data."""
|
|
|
|
id = serializers.IntegerField()
|
|
name = serializers.CharField()
|
|
slug = serializers.CharField()
|
|
roles = serializers.ListField(child=serializers.CharField(), required=False)
|
|
url = serializers.SerializerMethodField()
|
|
|
|
@extend_schema_field(serializers.URLField())
|
|
def get_url(self, obj) -> str:
|
|
"""Generate the frontend URL for this company based on their primary role.
|
|
|
|
CRITICAL DOMAIN SEPARATION:
|
|
- OPERATOR and PROPERTY_OWNER are for parks domain
|
|
- MANUFACTURER and DESIGNER are for rides domain
|
|
"""
|
|
# Use the URL field from the model if it exists (auto-generated on save)
|
|
if hasattr(obj, "url") and obj.url:
|
|
return obj.url
|
|
|
|
# Fallback URL generation (should not be needed if model save works correctly)
|
|
if hasattr(obj, "roles") and obj.roles:
|
|
frontend_domain = getattr(
|
|
settings, "FRONTEND_DOMAIN", "https://thrillwiki.com"
|
|
)
|
|
primary_role = obj.roles[0] if obj.roles else None
|
|
|
|
# Only generate URLs for rides domain roles here
|
|
if primary_role == "MANUFACTURER":
|
|
return f"{frontend_domain}/rides/manufacturers/{obj.slug}/"
|
|
elif primary_role == "DESIGNER":
|
|
return f"{frontend_domain}/rides/designers/{obj.slug}/"
|
|
# OPERATOR and PROPERTY_OWNER URLs are handled by parks domain
|
|
|
|
return ""
|