| import logging |
| import uuid |
| from typing import List, Dict, Any, Optional |
| from supabase import create_client, Client |
| from config import settings |
|
|
| logger = logging.getLogger("supabase_service") |
|
|
| |
| supabase_client: Optional[Client] = None |
| if settings.SUPABASE_URL and settings.SUPABASE_KEY: |
| try: |
| supabase_client = create_client(settings.SUPABASE_URL, settings.SUPABASE_KEY) |
| logger.info("Supabase client initialized successfully.") |
| except Exception as e: |
| logger.error(f"Error initializing Supabase client: {e}") |
| else: |
| logger.warning("Supabase URL or Key not set. Using mock in-memory database.") |
|
|
| |
| |
| MOCK_SHELTERS = [ |
| { |
| "id": "s1", |
| "name": "Refugio Polideportivo Los Naranjos", |
| "capacity": 150, |
| "occupancy": 45, |
| "latitude": 10.4678, |
| "longitude": -66.6210, |
| "resources": {"food_boxes": 200, "medical_kits": 50, "water_liters": 1000} |
| }, |
| { |
| "id": "s2", |
| "name": "Refugio U.E. Antonio José de Sucre", |
| "capacity": 100, |
| "occupancy": 80, |
| "latitude": 10.4585, |
| "longitude": -66.6025, |
| "resources": {"food_boxes": 80, "medical_kits": 20, "water_liters": 400} |
| }, |
| { |
| "id": "s3", |
| "name": "Refugio Centro Cultural Guatire", |
| "capacity": 200, |
| "occupancy": 110, |
| "latitude": 10.4722, |
| "longitude": -66.5412, |
| "resources": {"food_boxes": 300, "medical_kits": 100, "water_liters": 2500} |
| } |
| ] |
|
|
| MOCK_DAMAGE_REPORTS = [ |
| { |
| "id": "d1", |
| "severity": "high", |
| "latitude": 10.4621, |
| "longitude": -66.6185, |
| "photo_url": "https://images.unsplash.com/photo-1594897030264-ab7d87efc473?w=500", |
| "status": "pending", |
| "details": { |
| "owner_name": "Juan Perez", |
| "owner_contact": "+58 412 1234567", |
| "exact_address": "Sector Oropeza Castillo, Calle 3, Casa Nro 12, Guarenas", |
| "description": "Fallas estructurales graves en vigas principales y grietas en paredes de carga." |
| } |
| }, |
| { |
| "id": "d2", |
| "severity": "collapsed", |
| "latitude": 10.4690, |
| "longitude": -66.6102, |
| "photo_url": "https://images.unsplash.com/photo-1580618672591-eb180b1a973f?w=500", |
| "status": "verified", |
| "details": { |
| "owner_name": "Maria Rodriguez", |
| "owner_contact": "+58 414 7654321", |
| "exact_address": "Urbanización Vicente Emilio Sojo, Bloque 4, Guarenas", |
| "description": "Derrumbe parcial del segundo piso de la vivienda unifamiliar." |
| } |
| } |
| ] |
|
|
|
|
| |
|
|
| def save_damage_report( |
| severity: str, |
| latitude: float, |
| longitude: float, |
| photo_url: Optional[str], |
| status: str, |
| owner_name: str, |
| owner_contact: str, |
| exact_address: str, |
| description: Optional[str] |
| ) -> Dict[str, Any]: |
| """ |
| Saves a damage report. Connects to Supabase if available, otherwise writes to in-memory store. |
| """ |
| report_id = str(uuid.uuid4()) |
| |
| if supabase_client: |
| try: |
| |
| point_wkt = f"POINT({longitude} {latitude})" |
| |
| |
| report_data = { |
| "id": report_id, |
| "severity": severity, |
| "location": point_wkt, |
| "photo_url": photo_url, |
| "status": status |
| } |
| |
| res_report = supabase_client.table("damage_reports").insert(report_data).execute() |
| |
| |
| details_data = { |
| "id": report_id, |
| "owner_name": owner_name, |
| "owner_contact": owner_contact, |
| "exact_address": exact_address, |
| "description": description |
| } |
| res_details = supabase_client.table("damage_details").insert(details_data).execute() |
| |
| return { |
| "id": report_id, |
| "severity": severity, |
| "latitude": latitude, |
| "longitude": longitude, |
| "photo_url": photo_url, |
| "status": status, |
| "details": details_data |
| } |
| except Exception as e: |
| logger.error(f"Error saving to Supabase: {e}. Falling back to in-memory storage.") |
| |
| |
| |
| new_report = { |
| "id": report_id, |
| "severity": severity, |
| "latitude": latitude, |
| "longitude": longitude, |
| "photo_url": photo_url, |
| "status": status, |
| "details": { |
| "owner_name": owner_name, |
| "owner_contact": owner_contact, |
| "exact_address": exact_address, |
| "description": description |
| } |
| } |
| MOCK_DAMAGE_REPORTS.append(new_report) |
| logger.info(f"Saved damage report to in-memory store: {report_id}") |
| return new_report |
|
|
|
|
| def get_damage_reports_in_bbox( |
| min_lat: float, min_lng: float, max_lat: float, max_lng: float |
| ) -> List[Dict[str, Any]]: |
| """ |
| Retrieves public damage reports within a bounding box. |
| """ |
| if supabase_client: |
| try: |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| res = supabase_client.rpc( |
| "get_damage_in_bbox", |
| {"min_lat": min_lat, "min_lng": min_lng, "max_lat": max_lat, "max_lng": max_lng} |
| ).execute() |
| return res.data |
| except Exception as e: |
| logger.error(f"Supabase spatial query failed: {e}. Filtering in-memory.") |
|
|
| |
| filtered = [] |
| for r in MOCK_DAMAGE_REPORTS: |
| lat, lng = r["latitude"], r["longitude"] |
| if min_lat <= lat <= max_lat and min_lng <= lng <= max_lng: |
| |
| |
| filtered.append({ |
| "id": r["id"], |
| "severity": r["severity"], |
| "latitude": lat, |
| "longitude": lng, |
| "photo_url": r["photo_url"], |
| "status": r["status"] |
| }) |
| return filtered |
|
|
|
|
| def get_shelters_in_bbox( |
| min_lat: float, min_lng: float, max_lat: float, max_lng: float |
| ) -> List[Dict[str, Any]]: |
| """ |
| Retrieves shelters within a bounding box. |
| """ |
| if supabase_client: |
| try: |
| res = supabase_client.rpc( |
| "get_shelters_in_bbox", |
| {"min_lat": min_lat, "min_lng": min_lng, "max_lat": max_lat, "max_lng": max_lng} |
| ).execute() |
| return res.data |
| except Exception as e: |
| logger.error(f"Supabase spatial query for shelters failed: {e}. Filtering in-memory.") |
|
|
| |
| filtered = [] |
| for s in MOCK_SHELTERS: |
| lat, lng = s["latitude"], s["longitude"] |
| if min_lat <= lat <= max_lat and min_lng <= lng <= max_lng: |
| filtered.append(s) |
| return filtered |
|
|
|
|
| def save_shelter( |
| name: str, capacity: int, occupancy: int, latitude: float, longitude: float, resources: Dict[str, Any] |
| ) -> Dict[str, Any]: |
| """ |
| Saves a new shelter. |
| """ |
| shelter_id = str(uuid.uuid4()) |
| if supabase_client: |
| try: |
| point_wkt = f"POINT({longitude} {latitude})" |
| shelter_data = { |
| "id": shelter_id, |
| "name": name, |
| "capacity": capacity, |
| "occupancy": occupancy, |
| "location": point_wkt, |
| "resources": resources |
| } |
| supabase_client.table("shelters").insert(shelter_data).execute() |
| return shelter_data |
| except Exception as e: |
| logger.error(f"Error saving shelter to Supabase: {e}") |
| |
| new_shelter = { |
| "id": shelter_id, |
| "name": name, |
| "capacity": capacity, |
| "occupancy": occupancy, |
| "latitude": latitude, |
| "longitude": longitude, |
| "resources": resources |
| } |
| MOCK_SHELTERS.append(new_shelter) |
| return new_shelter |
|
|