Refactor code structure and remove redundant changes

This commit is contained in:
pacnpal
2025-08-26 13:19:04 -04:00
parent bf7e0c0f40
commit 831be6a2ee
151 changed files with 16260 additions and 9137 deletions

View File

@@ -0,0 +1,233 @@
"""
Media API views for ThrillWiki API v1.
This module provides API endpoints for media management including
photo uploads, captions, and media operations.
Consolidated from apps.media.views
"""
import json
import logging
from typing import Any, Dict
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.http import Http404
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter
from drf_spectacular.types import OpenApiTypes
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from rest_framework.parsers import MultiPartParser, FormParser
# Import domain-specific models and services instead of generic Photo model
from apps.parks.models import ParkPhoto
from apps.rides.models import RidePhoto
from apps.parks.services import ParkMediaService
from apps.rides.services import RideMediaService
from apps.core.services.media_service import MediaService
from .serializers import (
PhotoUploadInputSerializer,
PhotoUploadOutputSerializer,
PhotoDetailOutputSerializer,
PhotoUpdateInputSerializer,
PhotoListOutputSerializer,
)
from ..parks.serializers import ParkPhotoSerializer
from ..rides.serializers import RidePhotoSerializer
logger = logging.getLogger(__name__)
@extend_schema_view(
post=extend_schema(
summary="Upload photo",
description="Upload a photo and associate it with a content object (park, ride, etc.)",
request=PhotoUploadInputSerializer,
responses={
201: PhotoUploadOutputSerializer,
400: OpenApiTypes.OBJECT,
403: OpenApiTypes.OBJECT,
},
tags=["Media"],
),
)
class PhotoUploadAPIView(APIView):
"""API endpoint for photo uploads."""
permission_classes = [IsAuthenticated]
parser_classes = [MultiPartParser, FormParser]
def post(self, request: Request) -> Response:
"""Upload a photo and associate it with a content object."""
try:
serializer = PhotoUploadInputSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
validated_data = serializer.validated_data
# Get content object
try:
content_type = ContentType.objects.get(
app_label=validated_data["app_label"], model=validated_data["model"]
)
content_object = content_type.get_object_for_this_type(
pk=validated_data["object_id"]
)
except ContentType.DoesNotExist:
return Response(
{
"error": f"Invalid content type: {validated_data['app_label']}.{validated_data['model']}"
},
status=status.HTTP_400_BAD_REQUEST,
)
except content_type.model_class().DoesNotExist:
return Response(
{"error": "Content object not found"},
status=status.HTTP_404_NOT_FOUND,
)
# Determine which domain service to use based on content object
if hasattr(content_object, '_meta') and content_object._meta.app_label == 'parks':
# Check permissions for park photos
if not request.user.has_perm("parks.add_parkphoto"):
return Response(
{"error": "You do not have permission to upload park photos"},
status=status.HTTP_403_FORBIDDEN,
)
# Create park photo using park media service
photo = ParkMediaService.upload_photo(
park=content_object,
image_file=validated_data["photo"],
user=request.user,
caption=validated_data.get("caption", ""),
alt_text=validated_data.get("alt_text", ""),
is_primary=validated_data.get("is_primary", False),
)
elif hasattr(content_object, '_meta') and content_object._meta.app_label == 'rides':
# Check permissions for ride photos
if not request.user.has_perm("rides.add_ridephoto"):
return Response(
{"error": "You do not have permission to upload ride photos"},
status=status.HTTP_403_FORBIDDEN,
)
# Create ride photo using ride media service
photo = RideMediaService.upload_photo(
ride=content_object,
image_file=validated_data["photo"],
user=request.user,
caption=validated_data.get("caption", ""),
alt_text=validated_data.get("alt_text", ""),
is_primary=validated_data.get("is_primary", False),
photo_type=validated_data.get("photo_type", "general"),
)
else:
return Response(
{"error": f"Unsupported content type for media upload: {content_object._meta.label}"},
status=status.HTTP_400_BAD_REQUEST,
)
response_serializer = PhotoUploadOutputSerializer(
{
"id": photo.id,
"url": photo.image.url,
"caption": photo.caption,
"alt_text": photo.alt_text,
"is_primary": photo.is_primary,
"message": "Photo uploaded successfully",
}
)
return Response(response_serializer.data, status=status.HTTP_201_CREATED)
except Exception as e:
logger.error(f"Error in photo upload: {str(e)}", exc_info=True)
return Response(
{"error": f"An error occurred while uploading the photo: {str(e)}"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
@extend_schema_view(
list=extend_schema(
summary="List photos",
description="Retrieve a list of photos with optional filtering",
parameters=[
OpenApiParameter(
name="content_type",
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
description="Filter by content type (e.g., 'parks.park')",
),
OpenApiParameter(
name="object_id",
type=OpenApiTypes.INT,
location=OpenApiParameter.QUERY,
description="Filter by object ID",
),
],
responses={200: PhotoListOutputSerializer(many=True)},
tags=["Media"],
),
retrieve=extend_schema(
summary="Get photo details",
description="Retrieve detailed information about a specific photo",
responses={
200: PhotoDetailOutputSerializer,
404: OpenApiTypes.OBJECT,
},
tags=["Media"],
),
update=extend_schema(
summary="Update photo",
description="Update photo information (caption, alt text, etc.)",
request=PhotoUpdateInputSerializer,
responses={
200: PhotoDetailOutputSerializer,
400: OpenApiTypes.OBJECT,
403: OpenApiTypes.OBJECT,
404: OpenApiTypes.OBJECT,
},
tags=["Media"],
),
destroy=extend_schema(
summary="Delete photo",
description="Delete a photo (only by owner or admin)",
responses={
204: None,
403: OpenApiTypes.OBJECT,
404: OpenApiTypes.OBJECT,
},
tags=["Media"],
),
set_primary=extend_schema(
summary="Set photo as primary",
description="Set this photo as the primary photo for its content object",
responses={
200: OpenApiTypes.OBJECT,
403: OpenApiTypes.OBJECT,
404: OpenApiTypes.OBJECT,
},
tags=["Media"],
),
)
class PhotoViewSet(ModelViewSet):
"""ViewSet for managing photos."""
permission_classes = [IsAuthenticated]
lookup_field = "id"
def get_serializer_class(self):
"""Return appropriate serializer based on action."""
if self.action == "list":
return PhotoListOutputSerializer
elif self.action in ["update", "partial_update"]:
return PhotoUpdateInputSerializer
return PhotoDetailOutputSerializer