mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 02:35:18 -05:00
feat: add passkey authentication and enhance user preferences - Add passkey login security event type with fingerprint icon - Include request and site context in email confirmation for backend - Add user_id exact match filter to prevent incorrect user lookups - Enable PATCH method for updating user preferences via API - Add moderation_preferences support to user settings - Optimize ticket queries with select_related and prefetch_related This commit introduces passkey authentication tracking, improves user profile filtering accuracy, and extends the preferences API to support updates. Query optimizations reduce database hits for ticket listings.
234 lines
8.4 KiB
Python
234 lines
8.4 KiB
Python
"""
|
|
Companies and ride models domain serializers for ThrillWiki API v1.
|
|
|
|
This module contains all serializers related to companies that operate parks
|
|
or manufacture rides, as well as ride model serializers.
|
|
"""
|
|
|
|
from drf_spectacular.utils import (
|
|
OpenApiExample,
|
|
extend_schema_field,
|
|
extend_schema_serializer,
|
|
)
|
|
from rest_framework import serializers
|
|
|
|
from apps.core.choices.serializers import RichChoiceFieldSerializer, RichChoiceSerializerField
|
|
|
|
from .shared import ModelChoices
|
|
|
|
# === COMPANY SERIALIZERS ===
|
|
|
|
|
|
@extend_schema_serializer(
|
|
examples=[
|
|
OpenApiExample(
|
|
"Company Example",
|
|
summary="Example company response",
|
|
description="A company that operates parks or manufactures rides",
|
|
value={
|
|
"id": 1,
|
|
"name": "Cedar Fair",
|
|
"slug": "cedar-fair",
|
|
"roles": ["OPERATOR", "PROPERTY_OWNER"],
|
|
"description": "Theme park operator based in Ohio",
|
|
"website": "https://cedarfair.com",
|
|
"person_type": "CORPORATION",
|
|
"status": "ACTIVE",
|
|
"founded_year": 1983,
|
|
"founded_date": "1983-05-01",
|
|
"founded_date_precision": "MONTH",
|
|
"logo_url": "https://example.com/logo.png",
|
|
"banner_image_url": "https://example.com/banner.jpg",
|
|
"card_image_url": "https://example.com/card.jpg",
|
|
"average_rating": 4.5,
|
|
"review_count": 150,
|
|
"parks_count": 11,
|
|
"rides_count": 0,
|
|
},
|
|
)
|
|
]
|
|
)
|
|
class CompanyDetailOutputSerializer(serializers.Serializer):
|
|
"""Output serializer for company details."""
|
|
|
|
# Core fields
|
|
id = serializers.IntegerField()
|
|
name = serializers.CharField()
|
|
slug = serializers.CharField()
|
|
roles = serializers.ListField(child=serializers.CharField())
|
|
description = serializers.CharField(allow_blank=True)
|
|
website = serializers.URLField(required=False, allow_blank=True, allow_null=True)
|
|
|
|
# Founding information
|
|
founded_date = serializers.DateField(allow_null=True, required=False)
|
|
|
|
# Counts (from model)
|
|
rides_count = serializers.IntegerField(required=False, default=0)
|
|
coasters_count = serializers.IntegerField(required=False, default=0)
|
|
|
|
# Frontend URL
|
|
url = serializers.URLField(required=False, allow_blank=True, allow_null=True)
|
|
|
|
# Metadata
|
|
created_at = serializers.DateTimeField()
|
|
updated_at = serializers.DateTimeField()
|
|
|
|
|
|
|
|
|
|
class CompanyCreateInputSerializer(serializers.Serializer):
|
|
"""Input serializer for creating companies."""
|
|
|
|
name = serializers.CharField(max_length=255)
|
|
roles = serializers.ListField(
|
|
child=serializers.ChoiceField(choices=ModelChoices.get_company_role_choices()),
|
|
allow_empty=False,
|
|
)
|
|
description = serializers.CharField(allow_blank=True, default="")
|
|
website = serializers.URLField(required=False, allow_blank=True)
|
|
|
|
# Entity type and status - using RichChoiceSerializerField
|
|
person_type = RichChoiceSerializerField(
|
|
choice_group="person_types",
|
|
domain="parks",
|
|
required=False,
|
|
allow_blank=True,
|
|
)
|
|
status = RichChoiceSerializerField(
|
|
choice_group="company_statuses",
|
|
domain="parks",
|
|
default="ACTIVE",
|
|
)
|
|
|
|
# Founding information
|
|
founded_year = serializers.IntegerField(required=False, allow_null=True)
|
|
founded_date = serializers.DateField(required=False, allow_null=True)
|
|
founded_date_precision = RichChoiceSerializerField(
|
|
choice_group="date_precision",
|
|
domain="parks",
|
|
required=False,
|
|
allow_blank=True,
|
|
)
|
|
|
|
# Image URLs (legacy - prefer using image IDs)
|
|
logo_url = serializers.URLField(required=False, allow_blank=True)
|
|
banner_image_url = serializers.URLField(required=False, allow_blank=True)
|
|
card_image_url = serializers.URLField(required=False, allow_blank=True)
|
|
|
|
# Cloudflare image IDs (preferred for new submissions)
|
|
logo_image_id = serializers.CharField(max_length=255, required=False, allow_blank=True)
|
|
banner_image_id = serializers.CharField(max_length=255, required=False, allow_blank=True)
|
|
card_image_id = serializers.CharField(max_length=255, required=False, allow_blank=True)
|
|
|
|
|
|
class CompanyUpdateInputSerializer(serializers.Serializer):
|
|
"""Input serializer for updating companies."""
|
|
|
|
name = serializers.CharField(max_length=255, required=False)
|
|
roles = serializers.ListField(
|
|
child=serializers.ChoiceField(choices=ModelChoices.get_company_role_choices()),
|
|
required=False,
|
|
)
|
|
description = serializers.CharField(allow_blank=True, required=False)
|
|
website = serializers.URLField(required=False, allow_blank=True)
|
|
|
|
# Entity type and status - using RichChoiceSerializerField
|
|
person_type = RichChoiceSerializerField(
|
|
choice_group="person_types",
|
|
domain="parks",
|
|
required=False,
|
|
allow_blank=True,
|
|
)
|
|
status = RichChoiceSerializerField(
|
|
choice_group="company_statuses",
|
|
domain="parks",
|
|
required=False,
|
|
)
|
|
|
|
# Founding information
|
|
founded_year = serializers.IntegerField(required=False, allow_null=True)
|
|
founded_date = serializers.DateField(required=False, allow_null=True)
|
|
founded_date_precision = RichChoiceSerializerField(
|
|
choice_group="date_precision",
|
|
domain="parks",
|
|
required=False,
|
|
allow_blank=True,
|
|
)
|
|
|
|
# Image URLs (legacy - prefer using image IDs)
|
|
logo_url = serializers.URLField(required=False, allow_blank=True)
|
|
banner_image_url = serializers.URLField(required=False, allow_blank=True)
|
|
card_image_url = serializers.URLField(required=False, allow_blank=True)
|
|
|
|
# Cloudflare image IDs (preferred for new submissions)
|
|
logo_image_id = serializers.CharField(max_length=255, required=False, allow_blank=True)
|
|
banner_image_id = serializers.CharField(max_length=255, required=False, allow_blank=True)
|
|
card_image_id = serializers.CharField(max_length=255, required=False, allow_blank=True)
|
|
|
|
|
|
# === RIDE MODEL SERIALIZERS ===
|
|
|
|
|
|
@extend_schema_serializer(
|
|
examples=[
|
|
OpenApiExample(
|
|
"Ride Model Example",
|
|
summary="Example ride model response",
|
|
description="A specific model/type of ride manufactured by a company",
|
|
value={
|
|
"id": 1,
|
|
"name": "Dive Coaster",
|
|
"description": "A roller coaster featuring a near-vertical drop",
|
|
"category": "RC",
|
|
"manufacturer": {
|
|
"id": 1,
|
|
"name": "Bolliger & Mabillard",
|
|
"slug": "bolliger-mabillard",
|
|
},
|
|
},
|
|
)
|
|
]
|
|
)
|
|
class RideModelDetailOutputSerializer(serializers.Serializer):
|
|
"""Output serializer for ride model details."""
|
|
|
|
id = serializers.IntegerField()
|
|
name = serializers.CharField()
|
|
description = serializers.CharField()
|
|
category = RichChoiceFieldSerializer(choice_group="categories", domain="rides")
|
|
|
|
# Manufacturer info
|
|
manufacturer = serializers.SerializerMethodField()
|
|
|
|
# Metadata
|
|
created_at = serializers.DateTimeField()
|
|
updated_at = serializers.DateTimeField()
|
|
|
|
@extend_schema_field(serializers.DictField(allow_null=True))
|
|
def get_manufacturer(self, obj) -> dict | None:
|
|
if obj.manufacturer:
|
|
return {
|
|
"id": obj.manufacturer.id,
|
|
"name": obj.manufacturer.name,
|
|
"slug": obj.manufacturer.slug,
|
|
}
|
|
return None
|
|
|
|
|
|
class RideModelCreateInputSerializer(serializers.Serializer):
|
|
"""Input serializer for creating ride models."""
|
|
|
|
name = serializers.CharField(max_length=255)
|
|
description = serializers.CharField(allow_blank=True, default="")
|
|
category = serializers.ChoiceField(choices=ModelChoices.get_ride_category_choices(), required=False)
|
|
manufacturer_id = serializers.IntegerField(required=False, allow_null=True)
|
|
|
|
|
|
class RideModelUpdateInputSerializer(serializers.Serializer):
|
|
"""Input serializer for updating ride models."""
|
|
|
|
name = serializers.CharField(max_length=255, required=False)
|
|
description = serializers.CharField(allow_blank=True, required=False)
|
|
category = serializers.ChoiceField(choices=ModelChoices.get_ride_category_choices(), required=False)
|
|
manufacturer_id = serializers.IntegerField(required=False, allow_null=True)
|