""" Ride media serializers for ThrillWiki API v1. This module contains serializers for ride-specific media functionality. """ from rest_framework import serializers from drf_spectacular.utils import extend_schema_field, extend_schema_serializer, OpenApiExample from apps.rides.models import Ride, RidePhoto @extend_schema_serializer( examples=[ OpenApiExample( name='Ride Photo with Cloudflare Images', summary='Complete ride photo response', description='Example response showing all fields including Cloudflare Images URLs and variants', value={ 'id': 123, 'image': 'https://imagedelivery.net/account-hash/abc123def456/public', 'image_url': 'https://imagedelivery.net/account-hash/abc123def456/public', 'image_variants': { 'thumbnail': 'https://imagedelivery.net/account-hash/abc123def456/thumbnail', 'medium': 'https://imagedelivery.net/account-hash/abc123def456/medium', 'large': 'https://imagedelivery.net/account-hash/abc123def456/large', 'public': 'https://imagedelivery.net/account-hash/abc123def456/public' }, 'caption': 'Amazing roller coaster photo', 'alt_text': 'Steel roller coaster with multiple inversions', 'is_primary': True, 'is_approved': True, 'photo_type': 'exterior', 'created_at': '2023-01-01T12:00:00Z', 'updated_at': '2023-01-01T12:00:00Z', 'date_taken': '2023-01-01T10:00:00Z', 'uploaded_by_username': 'photographer123', 'file_size': 2048576, 'dimensions': [1920, 1080], 'ride_slug': 'steel-vengeance', 'ride_name': 'Steel Vengeance', 'park_slug': 'cedar-point', 'park_name': 'Cedar Point' } ) ] ) class RidePhotoOutputSerializer(serializers.ModelSerializer): """Output serializer for ride photos with Cloudflare Images support.""" uploaded_by_username = serializers.CharField( source="uploaded_by.username", read_only=True ) file_size = serializers.SerializerMethodField() dimensions = serializers.SerializerMethodField() image_url = serializers.SerializerMethodField() image_variants = serializers.SerializerMethodField() @extend_schema_field( serializers.IntegerField(allow_null=True, help_text="File size in bytes") ) def get_file_size(self, obj): """Get file size in bytes.""" return obj.file_size @extend_schema_field( serializers.ListField( child=serializers.IntegerField(), min_length=2, max_length=2, allow_null=True, help_text="Image dimensions as [width, height] in pixels", ) ) def get_dimensions(self, obj): """Get image dimensions as [width, height].""" return obj.dimensions @extend_schema_field( serializers.URLField( help_text="Full URL to the Cloudflare Images asset", allow_null=True ) ) def get_image_url(self, obj): """Get the full Cloudflare Images URL.""" if obj.image: return obj.image.url return None @extend_schema_field( serializers.DictField( child=serializers.URLField(), help_text="Available Cloudflare Images variants with their URLs" ) ) def get_image_variants(self, obj): """Get available image variants from Cloudflare Images.""" if not obj.image: return {} # Common variants for ride photos variants = { 'thumbnail': f"{obj.image.url}/thumbnail", 'medium': f"{obj.image.url}/medium", 'large': f"{obj.image.url}/large", 'public': f"{obj.image.url}/public" } return variants ride_slug = serializers.CharField(source="ride.slug", read_only=True) ride_name = serializers.CharField(source="ride.name", read_only=True) park_slug = serializers.CharField(source="ride.park.slug", read_only=True) park_name = serializers.CharField(source="ride.park.name", read_only=True) class Meta: model = RidePhoto fields = [ "id", "image", "image_url", "image_variants", "caption", "alt_text", "is_primary", "is_approved", "photo_type", "created_at", "updated_at", "date_taken", "uploaded_by_username", "file_size", "dimensions", "ride_slug", "ride_name", "park_slug", "park_name", ] read_only_fields = [ "id", "image_url", "image_variants", "created_at", "updated_at", "uploaded_by_username", "file_size", "dimensions", "ride_slug", "ride_name", "park_slug", "park_name", ] class RidePhotoCreateInputSerializer(serializers.ModelSerializer): """Input serializer for creating ride photos.""" class Meta: model = RidePhoto fields = [ "image", "caption", "alt_text", "photo_type", "is_primary", ] class RidePhotoUpdateInputSerializer(serializers.ModelSerializer): """Input serializer for updating ride photos.""" class Meta: model = RidePhoto fields = [ "caption", "alt_text", "photo_type", "is_primary", ] class RidePhotoListOutputSerializer(serializers.ModelSerializer): """Simplified output serializer for ride photo lists.""" uploaded_by_username = serializers.CharField( source="uploaded_by.username", read_only=True ) class Meta: model = RidePhoto fields = [ "id", "image", "caption", "photo_type", "is_primary", "is_approved", "created_at", "uploaded_by_username", ] read_only_fields = fields class RidePhotoApprovalInputSerializer(serializers.Serializer): """Input serializer for photo approval operations.""" photo_ids = serializers.ListField( child=serializers.IntegerField(), help_text="List of photo IDs to approve" ) approve = serializers.BooleanField( default=True, help_text="Whether to approve (True) or reject (False) the photos" ) class RidePhotoStatsOutputSerializer(serializers.Serializer): """Output serializer for ride photo statistics.""" total_photos = serializers.IntegerField() approved_photos = serializers.IntegerField() pending_photos = serializers.IntegerField() has_primary = serializers.BooleanField() recent_uploads = serializers.IntegerField() by_type = serializers.DictField( child=serializers.IntegerField(), help_text="Photo counts by type" ) class RidePhotoTypeFilterSerializer(serializers.Serializer): """Serializer for filtering photos by type.""" photo_type = serializers.ChoiceField( choices=[ ("exterior", "Exterior View"), ("queue", "Queue Area"), ("station", "Station"), ("onride", "On-Ride"), ("construction", "Construction"), ("other", "Other"), ], required=False, help_text="Filter photos by type", ) class RidePhotoSerializer(serializers.ModelSerializer): """Legacy serializer for backward compatibility.""" class Meta: model = RidePhoto fields = [ "id", "image", "caption", "alt_text", "is_primary", "photo_type", "uploaded_at", "uploaded_by", ] class RideSerializer(serializers.ModelSerializer): """Serializer for the Ride model.""" class Meta: model = Ride fields = [ "id", "name", "slug", "park", "manufacturer", "designer", "type", "status", "opening_date", "closing_date", ]