feat: Implement centralized error capture and handling with new middleware, services, and API endpoints, and add new admin and statistics API views.

This commit is contained in:
pacnpal
2026-01-02 15:55:42 -05:00
parent 1adba1b804
commit 95700c7d7b
43 changed files with 2477 additions and 158 deletions

View File

@@ -32,6 +32,7 @@ from apps.core.exceptions import (
ServiceError,
ValidationException,
)
from apps.core.utils import capture_and_log
from apps.core.utils.error_handling import ErrorHandler
from apps.parks.models import Park, ParkPhoto
from apps.parks.services import ParkMediaService
@@ -188,7 +189,7 @@ class ParkPhotoViewSet(ModelViewSet):
logger.warning(f"Validation error creating park photo: {e}")
raise ValidationError(str(e)) from None
except ServiceError as e:
logger.error(f"Service error creating park photo: {e}")
capture_and_log(e, 'Create park photo', source='api')
raise ValidationError(f"Failed to create photo: {str(e)}") from None
def perform_update(self, serializer):
@@ -210,7 +211,7 @@ class ParkPhotoViewSet(ModelViewSet):
logger.warning(f"Validation error setting primary photo: {e}")
raise ValidationError(str(e)) from None
except ServiceError as e:
logger.error(f"Service error setting primary photo: {e}")
capture_and_log(e, 'Set primary park photo', source='api')
raise ValidationError(f"Failed to set primary photo: {str(e)}") from None
def perform_destroy(self, instance):
@@ -232,13 +233,13 @@ class ParkPhotoViewSet(ModelViewSet):
except ImportError:
logger.warning("CloudflareImagesService not available")
except ServiceError as e:
logger.error(f"Service error deleting from Cloudflare: {str(e)}")
capture_and_log(e, 'Delete park photo from Cloudflare', source='api', severity='low')
# Continue with database deletion even if Cloudflare deletion fails
try:
ParkMediaService().delete_photo(instance.id, deleted_by=cast(UserModel, self.request.user))
except ServiceError as e:
logger.error(f"Service error deleting park photo: {e}")
capture_and_log(e, 'Delete park photo', source='api')
raise ValidationError(f"Failed to delete photo: {str(e)}") from None
@extend_schema(
@@ -539,14 +540,14 @@ class ParkPhotoViewSet(ModelViewSet):
try:
ParkMediaService().set_primary_photo(park_id=park.id, photo_id=photo.id)
except ServiceError as e:
logger.error(f"Error setting primary photo: {e}")
capture_and_log(e, 'Set primary park photo for saved image', source='api', severity='low')
# Don't fail the entire operation, just log the error
serializer = ParkPhotoOutputSerializer(photo, context={"request": request})
return Response(serializer.data, status=status.HTTP_201_CREATED)
except ImportError:
logger.error("CloudflareImagesService not available")
except ImportError as e:
capture_and_log(e, 'Cloudflare service import', source='api')
return ErrorHandler.handle_api_error(
ServiceError("Cloudflare Images service not available"),
user_message="Image upload service not available",