From 18a6c428c1a92142317bcf367501a63b231ba650 Mon Sep 17 00:00:00 2001 From: Marlon Alkan Date: Sun, 8 Jun 2025 19:26:34 +0200 Subject: [PATCH] core: api_views.py: add fallback IP geo provider Fixes #127 - add ip-api.com as fallback geo provider - fix silent JSONException by parsing only if HTTP 200 OK - add logger and log error if IP geo can't be fetched --- core/api_views.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/core/api_views.py b/core/api_views.py index 77473b5d..9efefe12 100644 --- a/core/api_views.py +++ b/core/api_views.py @@ -1,5 +1,6 @@ # core/api_views.py +import logging from rest_framework import viewsets, status from rest_framework.response import Response from django.shortcuts import get_object_or_404 @@ -13,6 +14,8 @@ import requests import os from core.tasks import rehash_streams +logger = logging.getLogger(__name__) + class UserAgentViewSet(viewsets.ModelViewSet): """ API endpoint that allows user agents to be viewed, created, edited, or deleted. @@ -77,14 +80,32 @@ def environment(request): except Exception as e: local_ip = f"Error: {e}" - # 3) If we got a valid public_ip, fetch geo info from ipapi.co + # 3) If we got a valid public_ip, fetch geo info from ipapi.co or ip-api.com if public_ip and "Error" not in public_ip: try: - geo = requests.get(f"https://ipapi.co/{public_ip}/json/", timeout=5).json() - # ipapi returns fields like country_code, country_name, etc. - country_code = geo.get("country_code", "") # e.g. "US" - country_name = geo.get("country_name", "") # e.g. "United States" - except requests.RequestException as e: + # Attempt to get geo information from ipapi.co first + r = requests.get(f"https://ipapi.co/{public_ip}/json/", timeout=5) + + if r.status_code == requests.codes.ok: + geo = r.json() + country_code = geo.get("country_code") # e.g. "US" + country_name = geo.get("country_name") # e.g. "United States" + + else: + # If ipapi.co fails, fallback to ip-api.com + # only supports http requests for free tier + r = requests.get("http://ip-api.com/json/", timeout=5) + + if r.status_code == requests.codes.ok: + geo = r.json() + country_code = geo.get("countryCode") # e.g. "US" + country_name = geo.get("country") # e.g. "United States" + + else: + raise Exception("Geo lookup failed with both services") + + except Exception as e: + logger.error(f"Error during geo lookup: {e}") country_code = None country_name = None