Files
thrillwiki_django_no_react/backend/apps/api/v1/serializers/shared.py
pacnpal bb7da85516 Refactor API structure and add comprehensive user management features
- 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
2025-08-29 16:03:51 -04:00

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 ""