From 2d075d25e691e1415a31f32998909290f1cfd015 Mon Sep 17 00:00:00 2001 From: aniketde Date: Sat, 7 Mar 2026 01:14:04 -0800 Subject: [PATCH] Fix GoingToCamp provider KeyError and broken site details endpoint The GoingToCamp API has changed its /api/maps endpoint to no longer provide per-facility mapId lookups, causing a KeyError when listing campgrounds. This fix: - Uses rootMapId from /api/resourceLocation response instead of looking up mapId from /api/maps (which no longer has it) - Adds root_map_id field to ResourceLocation model - Gracefully handles the now-404 /api/resource/details endpoint by returning fallback site data so availability searches still work Fixes #377 Co-Authored-By: Claude Opus 4.6 --- camply/containers/gtc_api_responses.py | 1 + .../going_to_camp/going_to_camp_provider.py | 26 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/camply/containers/gtc_api_responses.py b/camply/containers/gtc_api_responses.py index 0ba0d33f..5196910b 100644 --- a/camply/containers/gtc_api_responses.py +++ b/camply/containers/gtc_api_responses.py @@ -18,3 +18,4 @@ class ResourceLocation(CamplyModel): resource_location_id: Optional[int] resource_location_name: str region_name: str + root_map_id: Optional[int] diff --git a/camply/providers/going_to_camp/going_to_camp_provider.py b/camply/providers/going_to_camp/going_to_camp_provider.py index 506a70ff..7f48e4ca 100644 --- a/camply/providers/going_to_camp/going_to_camp_provider.py +++ b/camply/providers/going_to_camp/going_to_camp_provider.py @@ -166,9 +166,19 @@ def get_site_details(self, rec_area_id: int, resource_id: int): ) attribute_details = self._attribute_details - site_details = self._api_request( - rec_area_id, "SITE_DETAILS", {"resourceId": resource_id} - ) + try: + site_details = self._api_request( + rec_area_id, "SITE_DETAILS", {"resourceId": resource_id} + ) + except ConnectionError: + return { + "resourceId": resource_id, + "localizedValues": [{"name": f"Site {resource_id}"}], + "minCapacity": 1, + "maxCapacity": 1, + "definedAttributes": [], + "site_attributes": {}, + } site_attributes = {} for attribute in site_details["definedAttributes"]: attribute_detail = attribute_details[ @@ -387,6 +397,7 @@ def _filter_facilities_responses( resource_categories=facil.get("resourceCategoryIds"), resource_location_id=facil.get("resourceLocationId"), resource_location_name=location_name, + root_map_id=facil.get("rootMapId"), ) except ValidationError as ve: logger.error("That doesn't look like a valid Campground Facility") @@ -424,10 +435,11 @@ def _process_facilities_responses( ------- Tuple[dict, CampgroundFacility] """ - self.campground_details[facility.resource_location_id] - facility.id = _fetch_nested_key( - self.campground_details, facility.resource_location_id, "mapId" - ) + facility.id = facility.root_map_id + if facility.id is None: + facility.id = _fetch_nested_key( + self.campground_details, facility.resource_location_id, "mapId" + ) if facility.region_name: formatted_recreation_area = ( f"{rec_area.recreation_area}, {facility.region_name}"