"""Géolocalisation asynchrone des IP bannies (hors du chemin d'ingestion MQTT). Fallback API externe (ip-api.com, sans clé) tant qu'aucune base GeoLite2 locale (MaxMind) n'est configurée — voir ROADMAP.md, Phase 2.a. """ import requests from celery import shared_task from django.utils import timezone from .models import BanEvent GEOLOCATION_API_URL = 'http://ip-api.com/json/{ip}' @shared_task(bind=True, max_retries=3, default_retry_delay=10) def geolocate_ip(self, ban_event_id: int) -> None: try: event = BanEvent.objects.get(pk=ban_event_id) except BanEvent.DoesNotExist: return try: response = requests.get(GEOLOCATION_API_URL.format(ip=event.ip_address), timeout=5) response.raise_for_status() data = response.json() except requests.RequestException as e: raise self.retry(exc=e) if data.get('status') != 'success': return event.latitude = data.get('lat') event.longitude = data.get('lon') event.country = data.get('country', '') event.country_code = data.get('countryCode', '') event.city = data.get('city', '') event.geolocated_at = timezone.now() event.save(update_fields=[ 'latitude', 'longitude', 'country', 'country_code', 'city', 'geolocated_at', ])