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

@@ -11,6 +11,7 @@ from django.core.cache import cache
from django.db import transaction
from ..models import ParkLocation
from apps.core.utils import capture_and_log
logger = logging.getLogger(__name__)
@@ -90,7 +91,7 @@ class ParkLocationService:
return result_data
except requests.RequestException as e:
logger.error(f"Error searching park locations: {str(e)}")
capture_and_log(e, 'Search park locations', source='service')
return {
"count": 0,
"results": [],
@@ -156,7 +157,7 @@ class ParkLocationService:
return result
except requests.RequestException as e:
logger.error(f"Error reverse geocoding park location: {str(e)}")
capture_and_log(e, 'Reverse geocode park location', source='service')
return {"error": "Reverse geocoding service temporarily unavailable"}
@classmethod

View File

@@ -12,6 +12,7 @@ from django.core.files.uploadedfile import UploadedFile
from django.db import transaction
from apps.core.services.media_service import MediaService
from apps.core.utils import capture_and_log
from ..models import Park, ParkPhoto
@@ -164,7 +165,7 @@ class ParkMediaService:
logger.info(f"Photo {photo.pk} approved by user {approved_by.username}")
return True
except Exception as e:
logger.error(f"Failed to approve photo {photo.pk}: {str(e)}")
capture_and_log(e, f'Approve park photo {photo.pk}', source='service')
return False
@staticmethod
@@ -191,7 +192,7 @@ class ParkMediaService:
logger.info(f"Photo {photo_id} deleted from park {park_slug} by user {deleted_by.username}")
return True
except Exception as e:
logger.error(f"Failed to delete photo {photo.pk}: {str(e)}")
capture_and_log(e, f'Delete park photo {photo.pk}', source='service')
return False
@staticmethod

View File

@@ -23,6 +23,7 @@ from django.contrib.gis.measure import Distance
from django.core.cache import cache
from apps.parks.models import Park
from apps.core.utils import capture_and_log
logger = logging.getLogger(__name__)
@@ -242,7 +243,7 @@ class RoadTripService:
return None
except Exception as e:
logger.error(f"Geocoding failed for '{address}': {e}")
capture_and_log(e, f"Geocode address '{address}'", source='service')
return None
def calculate_route(self, start_coords: Coordinates, end_coords: Coordinates) -> RouteInfo | None:
@@ -319,7 +320,7 @@ class RoadTripService:
return self._calculate_straight_line_route(start_coords, end_coords)
except Exception as e:
logger.error(f"Route calculation failed: {e}")
capture_and_log(e, 'Calculate route', source='service')
# Fallback to straight-line distance
return self._calculate_straight_line_route(start_coords, end_coords)
@@ -445,7 +446,7 @@ class RoadTripService:
return max(0, detour_distance) # Don't return negative detours
except Exception as e:
logger.error(f"Failed to calculate detour distance: {e}")
capture_and_log(e, 'Calculate detour distance', source='service', severity='low')
return None
def create_multi_park_trip(self, park_list: list["Park"]) -> RoadTrip | None: