From 2108e1be4fa8e978ebd315dd064901e89a655d6d Mon Sep 17 00:00:00 2001 From: valenti Date: Wed, 8 Apr 2026 15:48:58 -0400 Subject: [PATCH] fixes 2 --- .../dequienes/dux_int_dequenes.sh | 2 +- .../dequienes/requirements_fastapi.txt | 6 - .../dequienes/setup_venv.sh | 29 + .../equifax/dux_equifax_int.sh | 2 +- .../equifax/requirements.txt | 5 +- .../equifax/requirements_fastapi.txt | 6 - .../external_providers/equifax/setup_venv.sh | 29 + .../sheriff_v2 copy 2/.env.example | 7 - .../Sheriff+API+v2.postman_collection.json | 708 ----------------- .../sheriff_v2 copy 2/dux_int_sher_v2.sh | 5 - .../sheriff_v2 copy 2/main.py | 723 ------------------ .../sheriff_v2 copy 2/requirements.txt | 7 - .../requirements_fastapi.txt | 6 - .../sheriff_v2 copy/.env.example | 7 - .../Sheriff+API+v2.postman_collection.json | 708 ----------------- .../sheriff_v2 copy/dux_int_sher_v2.sh | 5 - .../sheriff_v2 copy/main.py | 637 --------------- .../sheriff_v2 copy/requirements.txt | 7 - .../sheriff_v2 copy/requirements_fastapi.txt | 6 - .../sheriff_v2/dux_int_sher_v2.sh | 2 +- .../sheriff_v2/requirements_fastapi.txt | 6 - .../sheriff_v2/setup_venv.sh | 29 + 22 files changed, 93 insertions(+), 2849 deletions(-) delete mode 100644 server/external_providers/dequienes/requirements_fastapi.txt create mode 100755 server/external_providers/dequienes/setup_venv.sh delete mode 100644 server/external_providers/equifax/requirements_fastapi.txt create mode 100755 server/external_providers/equifax/setup_venv.sh delete mode 100644 server/external_providers/sheriff_v2 copy 2/.env.example delete mode 100644 server/external_providers/sheriff_v2 copy 2/Sheriff+API+v2.postman_collection.json delete mode 100755 server/external_providers/sheriff_v2 copy 2/dux_int_sher_v2.sh delete mode 100644 server/external_providers/sheriff_v2 copy 2/main.py delete mode 100644 server/external_providers/sheriff_v2 copy 2/requirements.txt delete mode 100644 server/external_providers/sheriff_v2 copy 2/requirements_fastapi.txt delete mode 100644 server/external_providers/sheriff_v2 copy/.env.example delete mode 100644 server/external_providers/sheriff_v2 copy/Sheriff+API+v2.postman_collection.json delete mode 100755 server/external_providers/sheriff_v2 copy/dux_int_sher_v2.sh delete mode 100644 server/external_providers/sheriff_v2 copy/main.py delete mode 100644 server/external_providers/sheriff_v2 copy/requirements.txt delete mode 100644 server/external_providers/sheriff_v2 copy/requirements_fastapi.txt delete mode 100644 server/external_providers/sheriff_v2/requirements_fastapi.txt create mode 100755 server/external_providers/sheriff_v2/setup_venv.sh diff --git a/server/external_providers/dequienes/dux_int_dequenes.sh b/server/external_providers/dequienes/dux_int_dequenes.sh index ffad227..0c2fe14 100755 --- a/server/external_providers/dequienes/dux_int_dequenes.sh +++ b/server/external_providers/dequienes/dux_int_dequenes.sh @@ -1,5 +1,5 @@ -venv/bin/python main.py +.venv/bin/python main.py diff --git a/server/external_providers/dequienes/requirements_fastapi.txt b/server/external_providers/dequienes/requirements_fastapi.txt deleted file mode 100644 index 3135b80..0000000 --- a/server/external_providers/dequienes/requirements_fastapi.txt +++ /dev/null @@ -1,6 +0,0 @@ -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.8.0 -requests==2.31.0 -python-dotenv==1.0.0 -python-multipart==0.0.6 diff --git a/server/external_providers/dequienes/setup_venv.sh b/server/external_providers/dequienes/setup_venv.sh new file mode 100755 index 0000000..ddeb276 --- /dev/null +++ b/server/external_providers/dequienes/setup_venv.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Check if the .venv directory exists +if [ ! -d ".venv" ]; then + echo ".venv directory does not exist. Creating a virtual environment..." + + # Create a virtual environment + python3 -m venv .venv + + echo "Virtual environment created." +else + echo ".venv directory already exists." +fi + +# Activate the virtual environment +source .venv/bin/activate + +# Upgrade pip (optional) +pip install --upgrade pip + +# Install requirements from requirements.txt +if [ -f "requirements.txt" ]; then + echo "Installing requirements from requirements.txt..." + pip install -r requirements.txt +else + echo "No requirements.txt file found." +fi + +echo "Setup complete." diff --git a/server/external_providers/equifax/dux_equifax_int.sh b/server/external_providers/equifax/dux_equifax_int.sh index ffad227..0c2fe14 100755 --- a/server/external_providers/equifax/dux_equifax_int.sh +++ b/server/external_providers/equifax/dux_equifax_int.sh @@ -1,5 +1,5 @@ -venv/bin/python main.py +.venv/bin/python main.py diff --git a/server/external_providers/equifax/requirements.txt b/server/external_providers/equifax/requirements.txt index ab81fbc..33dc3de 100644 --- a/server/external_providers/equifax/requirements.txt +++ b/server/external_providers/equifax/requirements.txt @@ -1,6 +1,7 @@ +pymongo==4.6.0 fastapi==0.104.1 uvicorn[standard]==0.24.0 +pydantic==2.8.0 requests==2.31.0 python-dotenv==1.0.0 -pymongo==4.6.0 -pydantic==2.8.0 +python-multipart==0.0.6 diff --git a/server/external_providers/equifax/requirements_fastapi.txt b/server/external_providers/equifax/requirements_fastapi.txt deleted file mode 100644 index 3135b80..0000000 --- a/server/external_providers/equifax/requirements_fastapi.txt +++ /dev/null @@ -1,6 +0,0 @@ -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.8.0 -requests==2.31.0 -python-dotenv==1.0.0 -python-multipart==0.0.6 diff --git a/server/external_providers/equifax/setup_venv.sh b/server/external_providers/equifax/setup_venv.sh new file mode 100755 index 0000000..ddeb276 --- /dev/null +++ b/server/external_providers/equifax/setup_venv.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Check if the .venv directory exists +if [ ! -d ".venv" ]; then + echo ".venv directory does not exist. Creating a virtual environment..." + + # Create a virtual environment + python3 -m venv .venv + + echo "Virtual environment created." +else + echo ".venv directory already exists." +fi + +# Activate the virtual environment +source .venv/bin/activate + +# Upgrade pip (optional) +pip install --upgrade pip + +# Install requirements from requirements.txt +if [ -f "requirements.txt" ]; then + echo "Installing requirements from requirements.txt..." + pip install -r requirements.txt +else + echo "No requirements.txt file found." +fi + +echo "Setup complete." diff --git a/server/external_providers/sheriff_v2 copy 2/.env.example b/server/external_providers/sheriff_v2 copy 2/.env.example deleted file mode 100644 index a34352a..0000000 --- a/server/external_providers/sheriff_v2 copy 2/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -SHERIFF_V2_BASE_URL=sheriff.example.com -SHERIFF_V2_ACCESS_KEY=your_access_key -SHERIFF_V2_ACCESS_SECRET=your_access_secret -SHERIFF_V2_CLIENT_IDENTIFIER=SheriffSecureClient-v1 -SHERIFF_V2_MONGODB_URI=mongodb://localhost:27017/duxiter -SHERIFF_V2_CACHE_TTL_SECONDS=604800 -SHERIFF_V2_TOKEN_TTL_SECONDS=1800 diff --git a/server/external_providers/sheriff_v2 copy 2/Sheriff+API+v2.postman_collection.json b/server/external_providers/sheriff_v2 copy 2/Sheriff+API+v2.postman_collection.json deleted file mode 100644 index 7f9d5a3..0000000 --- a/server/external_providers/sheriff_v2 copy 2/Sheriff+API+v2.postman_collection.json +++ /dev/null @@ -1,708 +0,0 @@ -{ - "info": { - "_postman_id": "db3f9c3b-5e0b-4dc4-bdb8-665fab04b4b9", - "name": "Sheriff API v2", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "31069565" - }, - "item": [ - { - "name": "🔒 Autenticación y Tokens", - "item": [ - { - "name": "🔑 getToken (Obtener Token de Acceso)", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var response = pm.response.json(); // Utiliza el método moderno para obtener el JSON", - "", - "if (response && response.data) {", - " // La respuesta contiene el token en la propiedad 'data'", - " pm.environment.set(\"bearer_token\", response.data);", - " ", - " // Opcional: Imprime el token en la Consola de Postman", - " console.log(\"Token guardado automáticamente en 'bearer_token': \" + response.data);", - "} else {", - " console.log(\"Error: No se pudo obtener el token de la respuesta. Verifica la estructura JSON.\");", - "}" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "auth": { - "type": "noauth" - }, - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"accessKey\": \"{{accessKey}}\",\n \"accessSecret\": \"{{accessSecret}}\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://{{base_url}}/api/clients/v2/apiCredentials/getToken", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "apiCredentials", - "getToken" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "👤 Plataforma", - "item": [ - { - "name": "Perfil - Detalle", - "item": [ - { - "name": "⚖️ Judiciales", - "item": [ - { - "name": "civil (Causas Civiles)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/judicial/{{rut}}/civil", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "judicial", - "{{rut}}", - "civil" - ] - } - }, - "response": [] - }, - { - "name": "cobranza (Causas Cobranza)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/judicial/{{rut}}/cobranza", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "judicial", - "{{rut}}", - "cobranza" - ] - } - }, - "response": [] - }, - { - "name": "laboral (Causas Laborales)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/judicial/{{rut}}/laboral", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "judicial", - "{{rut}}", - "laboral" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "💼 Cobranza Laboral", - "item": [ - { - "name": "multaLaboral (Multas Laborales)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/cobranzaLaboral/{{rut}}/multaLaboral", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "cobranzaLaboral", - "{{rut}}", - "multaLaboral" - ] - } - }, - "response": [] - }, - { - "name": "moraPrevisional (Mora Previsional)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/cobranzaLaboral/{{rut}}/moraPrevisional", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "cobranzaLaboral", - "{{rut}}", - "moraPrevisional" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "🛡️ Compliance", - "item": [ - { - "name": "compliance (Detalle de Cumplimiento)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/compliance/{{rut}}", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "compliance", - "{{rut}}" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "🔗 Legal", - "item": [ - { - "name": "mallaSocietaria (Malla Societaria)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/legal/{{rut}}/mallaSocietaria", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "legal", - "{{rut}}", - "mallaSocietaria" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "💯 Score", - "item": [ - { - "name": "💳 creditScore (Puntaje Crediticio)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/creditScore/{{rut}}", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "creditScore", - "{{rut}}" - ] - } - }, - "response": [] - } - ] - } - ] - }, - { - "name": "📈 Uso y Plan", - "item": [ - { - "name": "usage (Consumo de la Cuenta)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/usage", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "usage" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "↩️ Webhooks/Callbacks (Asíncronos)", - "item": [ - { - "name": "📋 Reportes (summaryByRut)", - "item": [ - { - "name": "summaryByRut (PDF de Resumen por RUT)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/pdf" - }, - { - "key": "Content-Disposition", - "value": "attachment; filename={{rut}}.pdf" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/webhook/profile/{{rut}}/resumen?format=pdf", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "webhook", - "profile", - "{{rut}}", - "resumen" - ], - "query": [ - { - "key": "format", - "value": "pdf" - } - ] - } - }, - "response": [] - } - ] - }, - { - "name": "🛡️ Compliance (Asíncrono)", - "item": [ - { - "name": "complianceByName (Cargar Perfil Compliance por Nombre)", - "request": { - "method": "POST", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"fullName\": \"Nombre Empresa\",\n \"isMonitoring\": true,\n \"isJuridicalPerson\": true,\n \"searchErrors\": 0\n }", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://{{base_url}}/api/clients/v2/webhook/compliance/cargarPerfil", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "webhook", - "compliance", - "cargarPerfil" - ] - } - }, - "response": [] - } - ] - } - ] - }, - { - "name": "📄 resumen (Obtener Resumen del Perfil)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/resumen?rut={{rut}}", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "resumen" - ], - "query": [ - { - "key": "rut", - "value": "{{rut}}" - } - ] - } - }, - "response": [] - }, - { - "name": "📜 loadedProfiles (Perfiles Cargados)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/profiles", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "profiles" - ] - } - }, - "response": [] - }, - { - "name": "➕ cargarRut (Cargar Perfil)", - "request": { - "method": "POST", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - }, - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"rut\": \"{{rut}}\",\n \"isMonitoring\": false,\n \"includeEquifax\": false\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/cargarRut", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "cargarRut" - ] - } - }, - "response": [] - } - ] - } - ], - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{bearer_token}}", - "type": "string" - } - ] - }, - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ] -} \ No newline at end of file diff --git a/server/external_providers/sheriff_v2 copy 2/dux_int_sher_v2.sh b/server/external_providers/sheriff_v2 copy 2/dux_int_sher_v2.sh deleted file mode 100755 index ffad227..0000000 --- a/server/external_providers/sheriff_v2 copy 2/dux_int_sher_v2.sh +++ /dev/null @@ -1,5 +0,0 @@ - -venv/bin/python main.py - - - diff --git a/server/external_providers/sheriff_v2 copy 2/main.py b/server/external_providers/sheriff_v2 copy 2/main.py deleted file mode 100644 index e5bbaa7..0000000 --- a/server/external_providers/sheriff_v2 copy 2/main.py +++ /dev/null @@ -1,723 +0,0 @@ -#!/usr/bin/env python3 -""" -FastAPI Sheriff v2 Provider -""" - -import os -import json -import time -import asyncio -import logging -import hashlib -import glob -import shutil -import threading -import re -from pathlib import Path -from typing import Dict, Any, Optional -from datetime import datetime, timedelta - -import requests -from fastapi import FastAPI, HTTPException, Header -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse -from pydantic import BaseModel -from dotenv import load_dotenv - -# Configure logging -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' -) -logger = logging.getLogger(__name__) - -load_dotenv() - -CACHE_TTL_SECONDS = int(os.getenv("SHERIFF_V2_CACHE_TTL_SECONDS", "604800")) -SHERIFF_RESPONSES_DIR = Path(__file__).resolve().parents[2] / "sheriff_v2_response" - -# Json Cache Manager Implementation -class JsonCacheManager: - def __init__(self, directory: Path): - self.directory = directory - self.backup_directory = directory / "backups" - self.directory.mkdir(parents=True, exist_ok=True) - self.backup_directory.mkdir(parents=True, exist_ok=True) - self.lock = threading.RLock() - - def _get_safe_filename_prefix(self, key: str) -> str: - return hashlib.sha256(key.encode()).hexdigest() - - def get(self, key: str) -> Optional[Dict[str, Any]]: - with self.lock: - try: - safe_prefix = self._get_safe_filename_prefix(key) - pattern = str(self.directory / f"{safe_prefix}_v*.json") - files = glob.glob(pattern) - - if not files: - return None - - # Filter and parse valid files - valid_files = [] - for f_path in files: - try: - name = Path(f_path).name - # Regex to parse: hash_v(\d+)_(\d+)_(\d+).json - match = re.match(r"^[0-9a-f]+_v(\d+)_(\d+)_(\d+)\.json$", name) - if match: - version = int(match.group(1)) - ts = int(match.group(2)) - exp = int(match.group(3)) - valid_files.append((version, ts, exp, f_path)) - except Exception: - continue - - if not valid_files: - return None - - # Pick latest version - valid_files.sort(key=lambda x: (x[0], x[1]), reverse=True) - latest = valid_files[0] - version, ts, exp, f_path = latest - - # Check expiry - if exp < time.time(): - # logger.info(f"Cache expired for key: {key}") - return None - - # Read file - with open(f_path, 'r', encoding='utf-8') as f: - data = json.load(f) - logger.info(f"Cache hit for key: {key} (file: {Path(f_path).name})") - return data.get("result") - - except Exception as e: - logger.error(f"Error reading from file cache: {e}") - return None - - def save(self, key: str, result: Dict[str, Any], ttl_seconds: int) -> None: - with self.lock: - try: - safe_prefix = self._get_safe_filename_prefix(key) - pattern = str(self.directory / f"{safe_prefix}_v*.json") - files = glob.glob(pattern) - - next_version = 1 - - # Handle backups and versioning - if files: - # Parse to find existing versions - current_versions = [] - for f_path in files: - name = Path(f_path).name - match = re.match(r"^[0-9a-f]+_v(\d+)_(\d+)_(\d+)\.json$", name) - if match: - current_versions.append((int(match.group(1)), f_path)) - - if current_versions: - current_versions.sort(key=lambda x: x[0], reverse=True) - last_ver, last_path = current_versions[0] - next_version = last_ver + 1 - - # Backup previous files - for _, path in current_versions: - try: - dest = self.backup_directory / Path(path).name - shutil.move(path, dest) - logger.info(f"Backed up {Path(path).name}") - except Exception as e: - logger.error(f"Failed to backup {path}: {e}") - - now_ts = int(time.time()) - exp_ts = now_ts + ttl_seconds - filename = f"{safe_prefix}_v{next_version}_{now_ts}_{exp_ts}.json" - filepath = self.directory / filename - - data = { - "_id": key, - "result": result, - "cached_at": datetime.utcnow().isoformat(), - "expires_at": (datetime.utcnow() + timedelta(seconds=ttl_seconds)).isoformat(), - "version": next_version - } - - # Atomic write - temp_path = filepath.with_suffix('.tmp') - with open(temp_path, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - - os.replace(temp_path, filepath) - logger.info(f"Transaction result cached with key: {key}, file: {filename}") - - except Exception as e: - logger.error(f"Error saving to file cache: {e}") - - def clear(self) -> int: - with self.lock: - try: - pattern = str(self.directory / "*_v*_*.json") - files = glob.glob(pattern) - count = 0 - for f in files: - try: - name = Path(f).name - if re.match(r"^[0-9a-f]+_v\d+_\d+_\d+\.json$", name): - os.remove(f) - count += 1 - except Exception: - pass - logger.info(f"Cleared {count} cached transactions") - return count - except Exception as e: - logger.error(f"Error clearing cache: {e}") - return 0 - - def stats(self) -> Dict[str, Any]: - with self.lock: - try: - total = 0 - expired = 0 - pattern = str(self.directory / "*_v*_*.json") - files = glob.glob(pattern) - - now_ts = time.time() - - for f in files: - name = Path(f).name - match = re.match(r"^[0-9a-f]+_v\d+_\d+_(\d+)\.json$", name) - if match: - total += 1 - exp = int(match.group(1)) - if exp < now_ts: - expired += 1 - - return { - "total_cached_transactions": total, - "expired_transactions": expired, - "active_transactions": total - expired, - "cache_ttl_seconds": CACHE_TTL_SECONDS, - "backend": "json_file" - } - except Exception as e: - logger.error(f"Error getting cache stats: {e}") - return {"error": str(e), "backend": "json_file"} - -# Initialize Cache Manager -cache_manager = JsonCacheManager(SHERIFF_RESPONSES_DIR) - -TOKEN_CACHE_FILE = Path(".token_cache.json") -SHERIFF_TOKEN_TTL_SECONDS = int(os.getenv("SHERIFF_V2_TOKEN_TTL_SECONDS", "1800")) - -# Pydantic Models -class TokenResponse(BaseModel): - token: str - cached: bool - -class HealthResponse(BaseModel): - status: str - timestamp: str - version: str - -class ErrorResponse(BaseModel): - error: str - detail: str - timestamp: str - -# FastAPI App -app = FastAPI( - title="Sheriff v2 Provider API", - description="REST API for Sheriff v2 client endpoints", - version="1.0.0", - docs_url="/docs", - redoc_url="/redoc" -) - -# CORS middleware -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], # Configure appropriately for production - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -class QueryRutRequest(BaseModel): - rut: str - isMonitoring: bool = False - includeEquifax: bool = False - -def generate_cache_key(env_key: str, payload: Dict[str, Any]) -> str: - payload_str = json.dumps(payload, sort_keys=True, separators=(',', ':')) - payload_hash = hashlib.sha256(payload_str.encode()).hexdigest() - return f"sheriff_v2_cache:{env_key}:{payload_hash}" - -def get_cached_transaction(cache_key: str) -> Optional[Dict[str, Any]]: - return cache_manager.get(cache_key) - -def save_transaction_to_cache(cache_key: str, result: Dict[str, Any]) -> None: - cache_manager.save(cache_key, result, CACHE_TTL_SECONDS) - -def clear_cache() -> int: - return cache_manager.clear() - -def get_cache_stats() -> Dict[str, Any]: - return cache_manager.stats() - -def now() -> float: - return time.time() - -def read_cache() -> Optional[dict]: - if TOKEN_CACHE_FILE.exists(): - try: - with TOKEN_CACHE_FILE.open("r", encoding="utf-8") as f: - return json.load(f) - except Exception: - return None - return None - -def write_cache(data: dict) -> None: - try: - with TOKEN_CACHE_FILE.open("w", encoding="utf-8") as f: - json.dump(data, f, indent=2) - except Exception: - pass - -def sheriff_base_url() -> str: - base_url = os.getenv("SHERIFF_V2_BASE_URL", "").strip() - if not base_url: - raise HTTPException(status_code=500, detail="Missing SHERIFF_V2_BASE_URL") - return base_url - -def get_client_identifier() -> str: - return os.getenv("SHERIFF_V2_CLIENT_IDENTIFIER", "SheriffSecureClient-v1").strip() - -def get_api_credentials() -> Dict[str, str]: - access_key = os.getenv("SHERIFF_V2_ACCESS_KEY", "").strip() - access_secret = os.getenv("SHERIFF_V2_ACCESS_SECRET", "").strip() - if not access_key or not access_secret: - raise HTTPException(status_code=500, detail="Missing Sheriff API credentials") - return {"accessKey": access_key, "accessSecret": access_secret} - -def get_cached_token(env_key: str) -> Optional[str]: - cache = read_cache() - if not cache: - return None - item = cache.get(env_key) - if not item: - return None - token = item.get("token") - expires_at = item.get("expires_at", 0) - if not token: - return None - current_time = now() - if current_time < (expires_at - 60): - return token - return None - -def save_cached_token(env_key: str, token: str, ttl_secs: int) -> None: - cache = read_cache() or {} - current_time = now() - cache[env_key] = { - "token": token, - "expires_at": current_time + int(ttl_secs), - "saved_at": current_time, - } - write_cache(cache) - -def fetch_token(base_url: str, access_key: str, access_secret: str) -> str: - url = base_url + "/api/clients/v2/apiCredentials/getToken" - client_id = get_client_identifier() - headers = {"Content-Type": "application/json","x-client-identifier": client_id } - body_data = {"accessKey": access_key, "accessSecret": access_secret} - body_json = json.dumps(body_data) - - # Print headers as JSON to show double quotes in logs - print(f"headers {headers}") - print(f"body {body_json}") - logger.info(f"Fetching token from {url}") - - resp = requests.post(url, headers=headers, data=body_json, timeout=30) - if resp.status_code == 200: - payload = resp.json() - token = payload.get("data") or payload.get("token") or "" - if not token: - raise HTTPException(status_code=502, detail="Token response invalid") - save_cached_token(base_url, token, SHERIFF_TOKEN_TTL_SECONDS) - return token - raise HTTPException(status_code=resp.status_code, detail=resp.text) - -def get_token() -> str: - base_url = sheriff_base_url() - cached = get_cached_token(base_url) - if cached: - return cached - creds = get_api_credentials() - return fetch_token(base_url, creds["accessKey"], creds["accessSecret"]) - -def execute_sheriff_get(path: str, query: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: - base_url = sheriff_base_url() - token = get_token() - client_id = get_client_identifier() - if base_url.startswith("http"): - url = f"{base_url}{path}" - else: - url = f"https://{base_url}{path}" - params = query or {} - cache_key = generate_cache_key("sheriff_v2_get", {"url": url, "params": params}) - cached = get_cached_transaction(cache_key) - if cached: - cached["_cache_info"] = {"cached": True, "cache_key": cache_key, "retrieved_at": datetime.utcnow().isoformat()} - return cached - headers = { - "accept": "application/json", - "Authorization": f"Bearer {token}", - "x-client-identifier": client_id, - } - print(f"Executing GET {url} with headers {headers} and params {params}") - resp = requests.get(url, headers=headers, params=params, timeout=60) - if resp.status_code == 200: - try: - data = resp.json() - except Exception: - data = {"raw": resp.text} - save_transaction_to_cache(cache_key, data) - data["_cache_info"] = {"cached": False, "cache_key": cache_key, "cached_at": datetime.utcnow().isoformat()} - return data - if resp.status_code == 401: - token = fetch_token(base_url, get_api_credentials()["accessKey"], get_api_credentials()["accessSecret"]) - headers["Authorization"] = f"Bearer {token}" - resp = requests.get(url, headers=headers, params=params, timeout=60) - if resp.status_code == 200: - try: - data = resp.json() - except Exception: - data = {"raw": resp.text} - save_transaction_to_cache(cache_key, data) - data["_cache_info"] = {"cached": False, "cache_key": cache_key, "cached_at": datetime.utcnow().isoformat()} - return data - raise HTTPException(status_code=resp.status_code, detail=resp.text) - if resp.status_code == 403: - raise HTTPException(status_code=403, detail="Forbidden") - if resp.status_code == 404: - raise HTTPException(status_code=404, detail="Not Found") - if resp.status_code >= 500: - raise HTTPException(status_code=502, detail=f"Upstream error {resp.status_code}") - raise HTTPException(status_code=resp.status_code, detail=resp.text) - -def execute_sheriff_post(path: str, body: Dict[str, Any]) -> Dict[str, Any]: - base_url = sheriff_base_url() - token = get_token() - client_id = get_client_identifier() - if base_url.startswith("http"): - url = f"{base_url}{path}" - else: - url = f"https://{base_url}{path}" - headers = { - "accept": "application/json", - "Authorization": f"Bearer {token}", - "x-client-identifier": client_id, - "Content-Type": "application/json", - } - resp = requests.post(url, headers=headers, json=body, timeout=60) - if resp.status_code == 200: - try: - return resp.json() - except Exception: - return {"raw": resp.text} - if resp.status_code == 401: - token = fetch_token(base_url, get_api_credentials()["accessKey"], get_api_credentials()["accessSecret"]) - headers["Authorization"] = f"Bearer {token}" - resp = requests.post(url, headers=headers, json=body, timeout=60) - if resp.status_code == 200: - try: - return resp.json() - except Exception: - return {"raw": resp.text} - raise HTTPException(status_code=resp.status_code, detail=resp.text) - if resp.status_code == 403: - raise HTTPException(status_code=403, detail="Forbidden") - if resp.status_code == 404: - raise HTTPException(status_code=404, detail="Not Found") - if resp.status_code >= 500: - raise HTTPException(status_code=502, detail=f"Upstream error {resp.status_code}") - raise HTTPException(status_code=resp.status_code, detail=resp.text) - -def persist_response(rut: str, result: Dict[str, Any]) -> str: - dest_dir = SHERIFF_RESPONSES_DIR - dest_dir.mkdir(parents=True, exist_ok=True) - ts = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") - fp = dest_dir / f"{rut}_{ts}.json" - with fp.open("w", encoding="utf-8") as f: - json.dump(result, f, ensure_ascii=False, indent=2) - return str(fp) - - -# Rimuoviamo completamente flusso POST/Equifax - - -def _clear_cached_token(env_key: str) -> None: - try: - cache_data = read_cache() - if cache_data and env_key in cache_data: - del cache_data[env_key] - write_cache(cache_data) - except Exception: - pass - -# API Endpoints -@app.get("/", response_model=HealthResponse) -async def root(): - return HealthResponse(status="healthy", timestamp=datetime.now().isoformat(), version="1.0.0") - -@app.get("/health", response_model=HealthResponse) -async def health_check(): - return HealthResponse(status="healthy", timestamp=datetime.now().isoformat(), version="1.0.0") - -@app.get("/token", response_model=TokenResponse) -async def get_token_endpoint(): - base_url = sheriff_base_url() - token = get_token() - cached = bool(get_cached_token(base_url)) - return TokenResponse(token=token, cached=cached) - -@app.get("/judicial/{rut}/civil") -async def get_civil_cases(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/judicial/{rut_sanitized}/civil" - return execute_sheriff_get(path) - -@app.get("/judicial/{rut}/cobranza") -async def get_cobranza_cases(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/judicial/{rut_sanitized}/cobranza" - return execute_sheriff_get(path) - -@app.get("/judicial/{rut}/laboral") -async def get_laboral_cases(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/judicial/{rut_sanitized}/laboral" - return execute_sheriff_get(path) - -@app.get("/cobranzaLaboral/{rut}/multaLaboral") -async def get_multa_laboral(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/multaLaboral" - return execute_sheriff_get(path) - -@app.get("/cobranzaLaboral/{rut}/moraPrevisional") -async def get_mora_previsional(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/moraPrevisional" - return execute_sheriff_get(path) - -@app.get("/compliance/{rut}") -async def get_compliance(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/compliance/{rut_sanitized}" - return execute_sheriff_get(path) - -@app.get("/legal/{rut}/mallaSocietaria") -async def get_malla_societaria(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/legal/{rut_sanitized}/mallaSocietaria" - return execute_sheriff_get(path) - -@app.get("/creditScore/{rut}") -async def get_credit_score(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/creditScore/{rut_sanitized}" - return execute_sheriff_get(path) - -@app.post("/queryRut") -async def query_rut(payload: QueryRutRequest): - cargar_body = { - "rut": payload.rut.strip(), - "isMonitoring": False, - "includeEquifax": False, - } - cargar = execute_sheriff_post("/api/clients/v2/helper/cargarRut", cargar_body) - time.sleep(2) - rut_sanitized = payload.rut.strip() - logger.info(f"Querying resumen for RUT {rut_sanitized}") - url = f"/api/clients/v2/helper/resumen?rut={rut_sanitized}&complete=True" - resumen = execute_sheriff_get(url) - - result: Dict[str, Any] = {"success": True, "cargarRut": cargar, "resumen": resumen} - ok = True - if isinstance(cargar, dict) and ("success" in cargar) and (not bool(cargar.get("success"))): - ok = False - if isinstance(resumen, dict) and ("success" in resumen) and (not bool(resumen.get("success"))): - ok = False - if ok: - judicial_civil = execute_sheriff_get(f"/api/clients/v2/helper/judicial/{rut_sanitized}/civil") - judicial_cobranza = execute_sheriff_get(f"/api/clients/v2/helper/judicial/{rut_sanitized}/cobranza") - judicial_laboral = execute_sheriff_get(f"/api/clients/v2/helper/judicial/{rut_sanitized}/laboral") - multa_laboral = execute_sheriff_get(f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/multaLaboral") - mora_previsional = execute_sheriff_get(f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/moraPrevisional") - compliance = execute_sheriff_get(f"/api/clients/v2/helper/compliance/{rut_sanitized}") - malla_societaria = execute_sheriff_get(f"/api/clients/v2/helper/legal/{rut_sanitized}/mallaSocietaria") - credit_score = execute_sheriff_get(f"/api/clients/v2/creditScore/{rut_sanitized}") - result.update({ - "judicial": { - "civil": judicial_civil, - "cobranza": judicial_cobranza, - "laboral": judicial_laboral, - }, - "cobranzaLaboral": { - "multaLaboral": multa_laboral, - "moraPrevisional": mora_previsional, - }, - "compliance": compliance, - "legal": { - "mallaSocietaria": malla_societaria, - }, - "creditScore": credit_score, - }) - saved_path = persist_response(rut_sanitized, result) - result["_saved_file"] = saved_path - return result - -@app.delete("/cache") -async def clear_sheriff_cache(): - try: - deleted_count = clear_cache() - return {"message": "Cache cleared successfully", "deleted_count": deleted_count} - except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to clear cache: {str(e)}") - -@app.get("/cache/stats") -async def get_sheriff_cache_stats(): - try: - stats = get_cache_stats() - return stats - except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to get cache stats: {str(e)}") - -# Rimuoviamo endpoints legacy transaction-cache - -@app.get("/config") -async def get_environment_config(): - try: - base_url = os.getenv("SHERIFF_V2_BASE_URL", "") - access_key = os.getenv("SHERIFF_V2_ACCESS_KEY", "") - access_secret = os.getenv("SHERIFF_V2_ACCESS_SECRET", "") - client_identifier = get_client_identifier() - return { - "base_url_set": bool(base_url), - "access_key_set": bool(access_key), - "access_secret_set": bool(access_secret), - "client_identifier": client_identifier, - "cache_ttl_seconds": CACHE_TTL_SECONDS, - "token_ttl_seconds": SHERIFF_TOKEN_TTL_SECONDS, - } - except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to get config: {str(e)}") - -# Error handlers -@app.exception_handler(HTTPException) -async def http_exception_handler(request, exc): - return JSONResponse( - status_code=exc.status_code, - content=ErrorResponse( - error=str(exc.detail), - detail=str(exc.detail), - timestamp=datetime.now().isoformat() - ).model_dump() - ) - -@app.exception_handler(Exception) -async def general_exception_handler(request, exc): - logger.error(f"Unhandled exception: {exc}") - return JSONResponse( - status_code=500, - content=ErrorResponse( - error="Internal server error", - detail=str(exc), - timestamp=datetime.now().isoformat() - ).model_dump() - ) - -async def cleanup_old_responses(): - """ - Periodically cleans up old response files: - 1. Deletes files older than 1 week. - 2. For remaining files, keeps only the most recent one for each RUT. - Runs every 10 minutes. - """ - while True: - try: - logger.info("Starting cleanup of old Sheriff V2 responses...") - if not SHERIFF_RESPONSES_DIR.exists(): - logger.info(f"Directory {SHERIFF_RESPONSES_DIR} does not exist. Skipping cleanup.") - else: - files_by_group: Dict[str, list] = {} - one_week_ago = datetime.utcnow() - timedelta(weeks=1) - deleted_count = 0 - - for file_path in SHERIFF_RESPONSES_DIR.glob("*.json"): - try: - filename = file_path.stem - # Format: {rut}_{timestamp} - parts = filename.rsplit('_', 1) - if len(parts) != 2: - continue - - rut, timestamp_str = parts - - try: - # Parse timestamp: YYYYMMDDTHHMMSSZ - file_dt = datetime.strptime(timestamp_str, "%Y%m%dT%H%M%SZ") - except ValueError: - continue - - # Check if older than 1 week - if file_dt < one_week_ago: - try: - file_path.unlink() - deleted_count += 1 - logger.info(f"Deleted old response file (older than 1 week): {file_path.name}") - except Exception as e: - logger.error(f"Failed to delete {file_path}: {e}") - continue - - if rut not in files_by_group: - files_by_group[rut] = [] - - files_by_group[rut].append((file_dt, file_path)) - except Exception as e: - logger.warning(f"Error processing file {file_path}: {e}") - - # Process groups - for rut, file_list in files_by_group.items(): - # Sort by timestamp descending (newest first) - file_list.sort(key=lambda x: x[0], reverse=True) - - # Keep the first one, delete the rest - for _, file_to_delete in file_list[1:]: - try: - file_to_delete.unlink() - deleted_count += 1 - logger.info(f"Deleted old response file (duplicate): {file_to_delete.name}") - except Exception as e: - logger.error(f"Failed to delete {file_to_delete}: {e}") - - if deleted_count > 0: - logger.info(f"Cleanup finished. Deleted {deleted_count} old files.") - else: - logger.info("Cleanup finished. No files to delete.") - - except Exception as e: - logger.error(f"Error during cleanup: {e}") - - # Wait for 10 minutes (600 seconds) - await asyncio.sleep(600) - -@app.on_event("startup") -async def startup_event(): - asyncio.create_task(cleanup_old_responses()) - -if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8024) diff --git a/server/external_providers/sheriff_v2 copy 2/requirements.txt b/server/external_providers/sheriff_v2 copy 2/requirements.txt deleted file mode 100644 index 53e41ac..0000000 --- a/server/external_providers/sheriff_v2 copy 2/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -pymongo==4.6.0 -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.5.0 -requests==2.31.0 -python-dotenv==1.0.0 -python-multipart==0.0.6 \ No newline at end of file diff --git a/server/external_providers/sheriff_v2 copy 2/requirements_fastapi.txt b/server/external_providers/sheriff_v2 copy 2/requirements_fastapi.txt deleted file mode 100644 index 11e652f..0000000 --- a/server/external_providers/sheriff_v2 copy 2/requirements_fastapi.txt +++ /dev/null @@ -1,6 +0,0 @@ -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.5.0 -requests==2.31.0 -python-dotenv==1.0.0 -python-multipart==0.0.6 diff --git a/server/external_providers/sheriff_v2 copy/.env.example b/server/external_providers/sheriff_v2 copy/.env.example deleted file mode 100644 index a34352a..0000000 --- a/server/external_providers/sheriff_v2 copy/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -SHERIFF_V2_BASE_URL=sheriff.example.com -SHERIFF_V2_ACCESS_KEY=your_access_key -SHERIFF_V2_ACCESS_SECRET=your_access_secret -SHERIFF_V2_CLIENT_IDENTIFIER=SheriffSecureClient-v1 -SHERIFF_V2_MONGODB_URI=mongodb://localhost:27017/duxiter -SHERIFF_V2_CACHE_TTL_SECONDS=604800 -SHERIFF_V2_TOKEN_TTL_SECONDS=1800 diff --git a/server/external_providers/sheriff_v2 copy/Sheriff+API+v2.postman_collection.json b/server/external_providers/sheriff_v2 copy/Sheriff+API+v2.postman_collection.json deleted file mode 100644 index 7f9d5a3..0000000 --- a/server/external_providers/sheriff_v2 copy/Sheriff+API+v2.postman_collection.json +++ /dev/null @@ -1,708 +0,0 @@ -{ - "info": { - "_postman_id": "db3f9c3b-5e0b-4dc4-bdb8-665fab04b4b9", - "name": "Sheriff API v2", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "31069565" - }, - "item": [ - { - "name": "🔒 Autenticación y Tokens", - "item": [ - { - "name": "🔑 getToken (Obtener Token de Acceso)", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var response = pm.response.json(); // Utiliza el método moderno para obtener el JSON", - "", - "if (response && response.data) {", - " // La respuesta contiene el token en la propiedad 'data'", - " pm.environment.set(\"bearer_token\", response.data);", - " ", - " // Opcional: Imprime el token en la Consola de Postman", - " console.log(\"Token guardado automáticamente en 'bearer_token': \" + response.data);", - "} else {", - " console.log(\"Error: No se pudo obtener el token de la respuesta. Verifica la estructura JSON.\");", - "}" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "auth": { - "type": "noauth" - }, - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"accessKey\": \"{{accessKey}}\",\n \"accessSecret\": \"{{accessSecret}}\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://{{base_url}}/api/clients/v2/apiCredentials/getToken", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "apiCredentials", - "getToken" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "👤 Plataforma", - "item": [ - { - "name": "Perfil - Detalle", - "item": [ - { - "name": "⚖️ Judiciales", - "item": [ - { - "name": "civil (Causas Civiles)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/judicial/{{rut}}/civil", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "judicial", - "{{rut}}", - "civil" - ] - } - }, - "response": [] - }, - { - "name": "cobranza (Causas Cobranza)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/judicial/{{rut}}/cobranza", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "judicial", - "{{rut}}", - "cobranza" - ] - } - }, - "response": [] - }, - { - "name": "laboral (Causas Laborales)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/judicial/{{rut}}/laboral", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "judicial", - "{{rut}}", - "laboral" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "💼 Cobranza Laboral", - "item": [ - { - "name": "multaLaboral (Multas Laborales)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/cobranzaLaboral/{{rut}}/multaLaboral", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "cobranzaLaboral", - "{{rut}}", - "multaLaboral" - ] - } - }, - "response": [] - }, - { - "name": "moraPrevisional (Mora Previsional)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/cobranzaLaboral/{{rut}}/moraPrevisional", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "cobranzaLaboral", - "{{rut}}", - "moraPrevisional" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "🛡️ Compliance", - "item": [ - { - "name": "compliance (Detalle de Cumplimiento)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/compliance/{{rut}}", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "compliance", - "{{rut}}" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "🔗 Legal", - "item": [ - { - "name": "mallaSocietaria (Malla Societaria)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/legal/{{rut}}/mallaSocietaria", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "legal", - "{{rut}}", - "mallaSocietaria" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "💯 Score", - "item": [ - { - "name": "💳 creditScore (Puntaje Crediticio)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/creditScore/{{rut}}", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "creditScore", - "{{rut}}" - ] - } - }, - "response": [] - } - ] - } - ] - }, - { - "name": "📈 Uso y Plan", - "item": [ - { - "name": "usage (Consumo de la Cuenta)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/usage", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "usage" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "↩️ Webhooks/Callbacks (Asíncronos)", - "item": [ - { - "name": "📋 Reportes (summaryByRut)", - "item": [ - { - "name": "summaryByRut (PDF de Resumen por RUT)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/pdf" - }, - { - "key": "Content-Disposition", - "value": "attachment; filename={{rut}}.pdf" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/webhook/profile/{{rut}}/resumen?format=pdf", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "webhook", - "profile", - "{{rut}}", - "resumen" - ], - "query": [ - { - "key": "format", - "value": "pdf" - } - ] - } - }, - "response": [] - } - ] - }, - { - "name": "🛡️ Compliance (Asíncrono)", - "item": [ - { - "name": "complianceByName (Cargar Perfil Compliance por Nombre)", - "request": { - "method": "POST", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"fullName\": \"Nombre Empresa\",\n \"isMonitoring\": true,\n \"isJuridicalPerson\": true,\n \"searchErrors\": 0\n }", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://{{base_url}}/api/clients/v2/webhook/compliance/cargarPerfil", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "webhook", - "compliance", - "cargarPerfil" - ] - } - }, - "response": [] - } - ] - } - ] - }, - { - "name": "📄 resumen (Obtener Resumen del Perfil)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/resumen?rut={{rut}}", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "resumen" - ], - "query": [ - { - "key": "rut", - "value": "{{rut}}" - } - ] - } - }, - "response": [] - }, - { - "name": "📜 loadedProfiles (Perfiles Cargados)", - "request": { - "method": "GET", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - } - ], - "url": { - "raw": "https://{{base_url}}/api/clients/v2/profiles", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "profiles" - ] - } - }, - "response": [] - }, - { - "name": "➕ cargarRut (Cargar Perfil)", - "request": { - "method": "POST", - "header": [ - { - "key": "accept", - "value": "application/json" - }, - { - "key": "Authorization", - "value": "Bearer {{bearer_token}}" - }, - { - "key": "x-client-identifier", - "value": "SheriffSecureClient-v1" - }, - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"rut\": \"{{rut}}\",\n \"isMonitoring\": false,\n \"includeEquifax\": false\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://{{base_url}}/api/clients/v2/helper/cargarRut", - "protocol": "https", - "host": [ - "{{base_url}}" - ], - "path": [ - "api", - "clients", - "v2", - "helper", - "cargarRut" - ] - } - }, - "response": [] - } - ] - } - ], - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{bearer_token}}", - "type": "string" - } - ] - }, - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ] -} \ No newline at end of file diff --git a/server/external_providers/sheriff_v2 copy/dux_int_sher_v2.sh b/server/external_providers/sheriff_v2 copy/dux_int_sher_v2.sh deleted file mode 100755 index ffad227..0000000 --- a/server/external_providers/sheriff_v2 copy/dux_int_sher_v2.sh +++ /dev/null @@ -1,5 +0,0 @@ - -venv/bin/python main.py - - - diff --git a/server/external_providers/sheriff_v2 copy/main.py b/server/external_providers/sheriff_v2 copy/main.py deleted file mode 100644 index 8e007a9..0000000 --- a/server/external_providers/sheriff_v2 copy/main.py +++ /dev/null @@ -1,637 +0,0 @@ -#!/usr/bin/env python3 -""" -FastAPI Sheriff v2 Provider -""" - -import os -import json -import time -import asyncio -import logging -import hashlib -from pathlib import Path -from typing import Dict, Any, Optional -from datetime import datetime, timedelta - -import requests -from fastapi import FastAPI, HTTPException, Header -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse -from pydantic import BaseModel -from dotenv import load_dotenv -from pymongo import MongoClient -from pymongo.errors import ConnectionFailure - -# Configure logging -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' -) -logger = logging.getLogger(__name__) - -load_dotenv() - -MONGODB_URI = os.getenv("MONGODB_URI", "mongodb://localhost:27017/duxiter") -print(MONGODB_URI) -CACHE_TTL_SECONDS = int(os.getenv("SHERIFF_V2_CACHE_TTL_SECONDS", "604800")) - -try: - mongo_client = MongoClient(MONGODB_URI) - # Test connection - mongo_client.admin.command('ping') - db = mongo_client.get_database() - cache_collection = db.sheriff_v2_cache - - # Create TTL index for automatic document expiration (ignore auth errors) - try: - cache_collection.create_index("expires_at", expireAfterSeconds=0) - except Exception as e: - logger.warning(f"Could not create TTL index (possibly requires auth): {e}") - logger.info(f"MongoDB connected successfully. Cache TTL: {CACHE_TTL_SECONDS} seconds") -except ConnectionFailure as e: - logger.error(f"MongoDB connection failed: {e}") - mongo_client = None - db = None - cache_collection = None - -TOKEN_CACHE_FILE = Path(".token_cache.json") -SHERIFF_TOKEN_TTL_SECONDS = int(os.getenv("SHERIFF_V2_TOKEN_TTL_SECONDS", "1800")) -SHERIFF_RESPONSES_DIR = Path(__file__).resolve().parents[2] / "sheriff_v2_response" - -# Pydantic Models -class TokenResponse(BaseModel): - token: str - cached: bool - -class HealthResponse(BaseModel): - status: str - timestamp: str - version: str - -class ErrorResponse(BaseModel): - error: str - detail: str - timestamp: str - -# FastAPI App -app = FastAPI( - title="Sheriff v2 Provider API", - description="REST API for Sheriff v2 client endpoints", - version="1.0.0", - docs_url="/docs", - redoc_url="/redoc" -) - -# CORS middleware -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], # Configure appropriately for production - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -class QueryRutRequest(BaseModel): - rut: str - isMonitoring: bool = False - includeEquifax: bool = False - -def generate_cache_key(env_key: str, payload: Dict[str, Any]) -> str: - payload_str = json.dumps(payload, sort_keys=True, separators=(',', ':')) - payload_hash = hashlib.sha256(payload_str.encode()).hexdigest() - return f"sheriff_v2_cache:{env_key}:{payload_hash}" - -def get_cached_transaction(cache_key: str) -> Optional[Dict[str, Any]]: - if cache_collection is None: - return None - - try: - cached_doc = cache_collection.find_one({"_id": cache_key}) - if cached_doc: - logger.info(f"Cache hit for key: {cache_key}") - return cached_doc.get("result") - else: -# logger.info(f"Cache miss for key: {cache_key}") - return None - except Exception as e: - logger.error(f"Error retrieving from cache: {e}") - return None - -def save_transaction_to_cache(cache_key: str, result: Dict[str, Any]) -> None: - if cache_collection is None: - return - - try: - expires_at = datetime.utcnow() + timedelta(seconds=CACHE_TTL_SECONDS) - cache_doc = { - "_id": cache_key, - "result": result, - "cached_at": datetime.utcnow(), - "expires_at": expires_at - } - - # Use upsert to replace existing cache entry - cache_collection.replace_one( - {"_id": cache_key}, - cache_doc, - upsert=True - ) - logger.info(f"Transaction result cached with key: {cache_key}, expires at: {expires_at}") - except Exception as e: - logger.error(f"Error saving to cache: {e}") - -def clear_cache() -> int: - if cache_collection is None: - return 0 - - try: - result = cache_collection.delete_many({}) - logger.info(f"Cleared {result.deleted_count} cached transactions") - return result.deleted_count - except Exception as e: - logger.error(f"Error clearing cache: {e}") - return 0 - -def get_cache_stats() -> Dict[str, Any]: - if cache_collection is None: - return {"error": "Cache not available"} - - try: - total_docs = cache_collection.count_documents({}) - expired_docs = cache_collection.count_documents({ - "expires_at": {"$lt": datetime.utcnow()} - }) - - return { - "total_cached_transactions": total_docs, - "expired_transactions": expired_docs, - "active_transactions": total_docs - expired_docs, - "cache_ttl_seconds": CACHE_TTL_SECONDS, - "mongodb_connected": True - } - except Exception as e: - logger.error(f"Error getting cache stats: {e}") - return {"error": str(e), "mongodb_connected": False} - -def now() -> float: - return time.time() - -def read_cache() -> Optional[dict]: - if TOKEN_CACHE_FILE.exists(): - try: - with TOKEN_CACHE_FILE.open("r", encoding="utf-8") as f: - return json.load(f) - except Exception: - return None - return None - -def write_cache(data: dict) -> None: - try: - with TOKEN_CACHE_FILE.open("w", encoding="utf-8") as f: - json.dump(data, f, indent=2) - except Exception: - pass - -def sheriff_base_url() -> str: - base_url = os.getenv("SHERIFF_V2_BASE_URL", "").strip() - if not base_url: - raise HTTPException(status_code=500, detail="Missing SHERIFF_V2_BASE_URL") - return base_url - -def get_client_identifier() -> str: - return os.getenv("SHERIFF_V2_CLIENT_IDENTIFIER", "SheriffSecureClient-v1").strip() - -def get_api_credentials() -> Dict[str, str]: - access_key = os.getenv("SHERIFF_V2_ACCESS_KEY", "").strip() - access_secret = os.getenv("SHERIFF_V2_ACCESS_SECRET", "").strip() - if not access_key or not access_secret: - raise HTTPException(status_code=500, detail="Missing Sheriff API credentials") - return {"accessKey": access_key, "accessSecret": access_secret} - -def get_cached_token(env_key: str) -> Optional[str]: - cache = read_cache() - if not cache: - return None - item = cache.get(env_key) - if not item: - return None - token = item.get("token") - expires_at = item.get("expires_at", 0) - if not token: - return None - current_time = now() - if current_time < (expires_at - 60): - return token - return None - -def save_cached_token(env_key: str, token: str, ttl_secs: int) -> None: - cache = read_cache() or {} - current_time = now() - cache[env_key] = { - "token": token, - "expires_at": current_time + int(ttl_secs), - "saved_at": current_time, - } - write_cache(cache) - -def fetch_token(base_url: str, access_key: str, access_secret: str) -> str: - url = base_url + "/api/clients/v2/apiCredentials/getToken" - client_id = get_client_identifier() - headers = {"Content-Type": "application/json","x-client-identifier": client_id } - body_data = {"accessKey": access_key, "accessSecret": access_secret} - body_json = json.dumps(body_data) - - # Print headers as JSON to show double quotes in logs - print(f"headers {headers}") - print(f"body {body_json}") - logger.info(f"Fetching token from {url}") - - resp = requests.post(url, headers=headers, data=body_json, timeout=30) - if resp.status_code == 200: - payload = resp.json() - token = payload.get("data") or payload.get("token") or "" - if not token: - raise HTTPException(status_code=502, detail="Token response invalid") - save_cached_token(base_url, token, SHERIFF_TOKEN_TTL_SECONDS) - return token - raise HTTPException(status_code=resp.status_code, detail=resp.text) - -def get_token() -> str: - base_url = sheriff_base_url() - cached = get_cached_token(base_url) - if cached: - return cached - creds = get_api_credentials() - return fetch_token(base_url, creds["accessKey"], creds["accessSecret"]) - -def execute_sheriff_get(path: str, query: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: - base_url = sheriff_base_url() - token = get_token() - client_id = get_client_identifier() - if base_url.startswith("http"): - url = f"{base_url}{path}" - else: - url = f"https://{base_url}{path}" - params = query or {} - cache_key = generate_cache_key("sheriff_v2_get", {"url": url, "params": params}) - cached = get_cached_transaction(cache_key) - if cached: - cached["_cache_info"] = {"cached": True, "cache_key": cache_key, "retrieved_at": datetime.utcnow().isoformat()} - return cached - headers = { - "accept": "application/json", - "Authorization": f"Bearer {token}", - "x-client-identifier": client_id, - } - print(f"Executing GET {url} with headers {headers} and params {params}") - resp = requests.get(url, headers=headers, params=params, timeout=60) - if resp.status_code == 200: - try: - data = resp.json() - except Exception: - data = {"raw": resp.text} - save_transaction_to_cache(cache_key, data) - data["_cache_info"] = {"cached": False, "cache_key": cache_key, "cached_at": datetime.utcnow().isoformat()} - return data - if resp.status_code == 401: - token = fetch_token(base_url, get_api_credentials()["accessKey"], get_api_credentials()["accessSecret"]) - headers["Authorization"] = f"Bearer {token}" - resp = requests.get(url, headers=headers, params=params, timeout=60) - if resp.status_code == 200: - try: - data = resp.json() - except Exception: - data = {"raw": resp.text} - save_transaction_to_cache(cache_key, data) - data["_cache_info"] = {"cached": False, "cache_key": cache_key, "cached_at": datetime.utcnow().isoformat()} - return data - raise HTTPException(status_code=resp.status_code, detail=resp.text) - if resp.status_code == 403: - raise HTTPException(status_code=403, detail="Forbidden") - if resp.status_code == 404: - raise HTTPException(status_code=404, detail="Not Found") - if resp.status_code >= 500: - raise HTTPException(status_code=502, detail=f"Upstream error {resp.status_code}") - raise HTTPException(status_code=resp.status_code, detail=resp.text) - -def execute_sheriff_post(path: str, body: Dict[str, Any]) -> Dict[str, Any]: - base_url = sheriff_base_url() - token = get_token() - client_id = get_client_identifier() - if base_url.startswith("http"): - url = f"{base_url}{path}" - else: - url = f"https://{base_url}{path}" - headers = { - "accept": "application/json", - "Authorization": f"Bearer {token}", - "x-client-identifier": client_id, - "Content-Type": "application/json", - } - resp = requests.post(url, headers=headers, json=body, timeout=60) - if resp.status_code == 200: - try: - return resp.json() - except Exception: - return {"raw": resp.text} - if resp.status_code == 401: - token = fetch_token(base_url, get_api_credentials()["accessKey"], get_api_credentials()["accessSecret"]) - headers["Authorization"] = f"Bearer {token}" - resp = requests.post(url, headers=headers, json=body, timeout=60) - if resp.status_code == 200: - try: - return resp.json() - except Exception: - return {"raw": resp.text} - raise HTTPException(status_code=resp.status_code, detail=resp.text) - if resp.status_code == 403: - raise HTTPException(status_code=403, detail="Forbidden") - if resp.status_code == 404: - raise HTTPException(status_code=404, detail="Not Found") - if resp.status_code >= 500: - raise HTTPException(status_code=502, detail=f"Upstream error {resp.status_code}") - raise HTTPException(status_code=resp.status_code, detail=resp.text) - -def persist_response(rut: str, result: Dict[str, Any]) -> str: - server_dir = Path(__file__).resolve().parents[2] - dest_dir = server_dir / "sheriff_v2_response" - dest_dir.mkdir(parents=True, exist_ok=True) - ts = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") - fp = dest_dir / f"{rut}_{ts}.json" - with fp.open("w", encoding="utf-8") as f: - json.dump(result, f, ensure_ascii=False, indent=2) - return str(fp) - - -# Rimuoviamo completamente flusso POST/Equifax - - -def _clear_cached_token(env_key: str) -> None: - try: - cache_data = read_cache() - if cache_data and env_key in cache_data: - del cache_data[env_key] - write_cache(cache_data) - except Exception: - pass - -# API Endpoints -@app.get("/", response_model=HealthResponse) -async def root(): - return HealthResponse(status="healthy", timestamp=datetime.now().isoformat(), version="1.0.0") - -@app.get("/health", response_model=HealthResponse) -async def health_check(): - return HealthResponse(status="healthy", timestamp=datetime.now().isoformat(), version="1.0.0") - -@app.get("/token", response_model=TokenResponse) -async def get_token_endpoint(): - base_url = sheriff_base_url() - token = get_token() - cached = bool(get_cached_token(base_url)) - return TokenResponse(token=token, cached=cached) - -@app.get("/judicial/{rut}/civil") -async def get_civil_cases(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/judicial/{rut_sanitized}/civil" - return execute_sheriff_get(path) - -@app.get("/judicial/{rut}/cobranza") -async def get_cobranza_cases(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/judicial/{rut_sanitized}/cobranza" - return execute_sheriff_get(path) - -@app.get("/judicial/{rut}/laboral") -async def get_laboral_cases(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/judicial/{rut_sanitized}/laboral" - return execute_sheriff_get(path) - -@app.get("/cobranzaLaboral/{rut}/multaLaboral") -async def get_multa_laboral(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/multaLaboral" - return execute_sheriff_get(path) - -@app.get("/cobranzaLaboral/{rut}/moraPrevisional") -async def get_mora_previsional(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/moraPrevisional" - return execute_sheriff_get(path) - -@app.get("/compliance/{rut}") -async def get_compliance(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/compliance/{rut_sanitized}" - return execute_sheriff_get(path) - -@app.get("/legal/{rut}/mallaSocietaria") -async def get_malla_societaria(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/helper/legal/{rut_sanitized}/mallaSocietaria" - return execute_sheriff_get(path) - -@app.get("/creditScore/{rut}") -async def get_credit_score(rut: str): - rut_sanitized = str(rut).strip() - path = f"/api/clients/v2/creditScore/{rut_sanitized}" - return execute_sheriff_get(path) - -@app.post("/queryRut") -async def query_rut(payload: QueryRutRequest): - cargar_body = { - "rut": payload.rut.strip(), - "isMonitoring": False, - "includeEquifax": False, - } - cargar = execute_sheriff_post("/api/clients/v2/helper/cargarRut", cargar_body) - time.sleep(2) - rut_sanitized = payload.rut.strip() - logger.info(f"Querying resumen for RUT {rut_sanitized}") - url = f"/api/clients/v2/helper/resumen?rut={rut_sanitized}&complete=True" - resumen = execute_sheriff_get(url) - - result: Dict[str, Any] = {"success": True, "cargarRut": cargar, "resumen": resumen} - ok = True - if isinstance(cargar, dict) and ("success" in cargar) and (not bool(cargar.get("success"))): - ok = False - if isinstance(resumen, dict) and ("success" in resumen) and (not bool(resumen.get("success"))): - ok = False - if ok: - judicial_civil = execute_sheriff_get(f"/api/clients/v2/helper/judicial/{rut_sanitized}/civil") - judicial_cobranza = execute_sheriff_get(f"/api/clients/v2/helper/judicial/{rut_sanitized}/cobranza") - judicial_laboral = execute_sheriff_get(f"/api/clients/v2/helper/judicial/{rut_sanitized}/laboral") - multa_laboral = execute_sheriff_get(f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/multaLaboral") - mora_previsional = execute_sheriff_get(f"/api/clients/v2/helper/cobranzaLaboral/{rut_sanitized}/moraPrevisional") - compliance = execute_sheriff_get(f"/api/clients/v2/helper/compliance/{rut_sanitized}") - malla_societaria = execute_sheriff_get(f"/api/clients/v2/helper/legal/{rut_sanitized}/mallaSocietaria") - credit_score = execute_sheriff_get(f"/api/clients/v2/creditScore/{rut_sanitized}") - result.update({ - "judicial": { - "civil": judicial_civil, - "cobranza": judicial_cobranza, - "laboral": judicial_laboral, - }, - "cobranzaLaboral": { - "multaLaboral": multa_laboral, - "moraPrevisional": mora_previsional, - }, - "compliance": compliance, - "legal": { - "mallaSocietaria": malla_societaria, - }, - "creditScore": credit_score, - }) - saved_path = persist_response(rut_sanitized, result) - result["_saved_file"] = saved_path - return result - -@app.delete("/cache") -async def clear_sheriff_cache(): - try: - deleted_count = clear_cache() - return {"message": "Cache cleared successfully", "deleted_count": deleted_count} - except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to clear cache: {str(e)}") - -@app.get("/cache/stats") -async def get_sheriff_cache_stats(): - try: - stats = get_cache_stats() - return stats - except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to get cache stats: {str(e)}") - -# Rimuoviamo endpoints legacy transaction-cache - -@app.get("/config") -async def get_environment_config(): - try: - base_url = os.getenv("SHERIFF_V2_BASE_URL", "") - access_key = os.getenv("SHERIFF_V2_ACCESS_KEY", "") - access_secret = os.getenv("SHERIFF_V2_ACCESS_SECRET", "") - client_identifier = get_client_identifier() - return { - "base_url_set": bool(base_url), - "access_key_set": bool(access_key), - "access_secret_set": bool(access_secret), - "client_identifier": client_identifier, - "cache_ttl_seconds": CACHE_TTL_SECONDS, - "token_ttl_seconds": SHERIFF_TOKEN_TTL_SECONDS, - } - except Exception as e: - raise HTTPException(status_code=500, detail=f"Failed to get config: {str(e)}") - -# Error handlers -@app.exception_handler(HTTPException) -async def http_exception_handler(request, exc): - return JSONResponse( - status_code=exc.status_code, - content=ErrorResponse( - error=str(exc.detail), - detail=str(exc.detail), - timestamp=datetime.now().isoformat() - ).model_dump() - ) - -@app.exception_handler(Exception) -async def general_exception_handler(request, exc): - logger.error(f"Unhandled exception: {exc}") - return JSONResponse( - status_code=500, - content=ErrorResponse( - error="Internal server error", - detail=str(exc), - timestamp=datetime.now().isoformat() - ).model_dump() - ) - -async def cleanup_old_responses(): - """ - Periodically cleans up old response files: - 1. Deletes files older than 1 week. - 2. For remaining files, keeps only the most recent one for each RUT. - Runs every 10 minutes. - """ - while True: - try: - logger.info("Starting cleanup of old Sheriff V2 responses...") - if not SHERIFF_RESPONSES_DIR.exists(): - logger.info(f"Directory {SHERIFF_RESPONSES_DIR} does not exist. Skipping cleanup.") - else: - files_by_group: Dict[str, list] = {} - one_week_ago = datetime.utcnow() - timedelta(weeks=1) - deleted_count = 0 - - for file_path in SHERIFF_RESPONSES_DIR.glob("*.json"): - try: - filename = file_path.stem - # Format: {rut}_{timestamp} - parts = filename.rsplit('_', 1) - if len(parts) != 2: - continue - - rut, timestamp_str = parts - - try: - # Parse timestamp: YYYYMMDDTHHMMSSZ - file_dt = datetime.strptime(timestamp_str, "%Y%m%dT%H%M%SZ") - except ValueError: - continue - - # Check if older than 1 week - if file_dt < one_week_ago: - try: - file_path.unlink() - deleted_count += 1 - logger.info(f"Deleted old response file (older than 1 week): {file_path.name}") - except Exception as e: - logger.error(f"Failed to delete {file_path}: {e}") - continue - - if rut not in files_by_group: - files_by_group[rut] = [] - - files_by_group[rut].append((file_dt, file_path)) - except Exception as e: - logger.warning(f"Error processing file {file_path}: {e}") - - # Process groups - for rut, file_list in files_by_group.items(): - # Sort by timestamp descending (newest first) - file_list.sort(key=lambda x: x[0], reverse=True) - - # Keep the first one, delete the rest - for _, file_to_delete in file_list[1:]: - try: - file_to_delete.unlink() - deleted_count += 1 - logger.info(f"Deleted old response file (duplicate): {file_to_delete.name}") - except Exception as e: - logger.error(f"Failed to delete {file_to_delete}: {e}") - - if deleted_count > 0: - logger.info(f"Cleanup finished. Deleted {deleted_count} old files.") - else: - logger.info("Cleanup finished. No files to delete.") - - except Exception as e: - logger.error(f"Error during cleanup: {e}") - - # Wait for 10 minutes (600 seconds) - await asyncio.sleep(600) - -@app.on_event("startup") -async def startup_event(): - asyncio.create_task(cleanup_old_responses()) - -if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8024) -class QueryRutRequest(BaseModel): - rut: str - isMonitoring: bool = False - includeEquifax: bool = False diff --git a/server/external_providers/sheriff_v2 copy/requirements.txt b/server/external_providers/sheriff_v2 copy/requirements.txt deleted file mode 100644 index 53e41ac..0000000 --- a/server/external_providers/sheriff_v2 copy/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -pymongo==4.6.0 -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.5.0 -requests==2.31.0 -python-dotenv==1.0.0 -python-multipart==0.0.6 \ No newline at end of file diff --git a/server/external_providers/sheriff_v2 copy/requirements_fastapi.txt b/server/external_providers/sheriff_v2 copy/requirements_fastapi.txt deleted file mode 100644 index 11e652f..0000000 --- a/server/external_providers/sheriff_v2 copy/requirements_fastapi.txt +++ /dev/null @@ -1,6 +0,0 @@ -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.5.0 -requests==2.31.0 -python-dotenv==1.0.0 -python-multipart==0.0.6 diff --git a/server/external_providers/sheriff_v2/dux_int_sher_v2.sh b/server/external_providers/sheriff_v2/dux_int_sher_v2.sh index ffad227..0c2fe14 100755 --- a/server/external_providers/sheriff_v2/dux_int_sher_v2.sh +++ b/server/external_providers/sheriff_v2/dux_int_sher_v2.sh @@ -1,5 +1,5 @@ -venv/bin/python main.py +.venv/bin/python main.py diff --git a/server/external_providers/sheriff_v2/requirements_fastapi.txt b/server/external_providers/sheriff_v2/requirements_fastapi.txt deleted file mode 100644 index 3135b80..0000000 --- a/server/external_providers/sheriff_v2/requirements_fastapi.txt +++ /dev/null @@ -1,6 +0,0 @@ -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.8.0 -requests==2.31.0 -python-dotenv==1.0.0 -python-multipart==0.0.6 diff --git a/server/external_providers/sheriff_v2/setup_venv.sh b/server/external_providers/sheriff_v2/setup_venv.sh new file mode 100755 index 0000000..ddeb276 --- /dev/null +++ b/server/external_providers/sheriff_v2/setup_venv.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Check if the .venv directory exists +if [ ! -d ".venv" ]; then + echo ".venv directory does not exist. Creating a virtual environment..." + + # Create a virtual environment + python3 -m venv .venv + + echo "Virtual environment created." +else + echo ".venv directory already exists." +fi + +# Activate the virtual environment +source .venv/bin/activate + +# Upgrade pip (optional) +pip install --upgrade pip + +# Install requirements from requirements.txt +if [ -f "requirements.txt" ]; then + echo "Installing requirements from requirements.txt..." + pip install -r requirements.txt +else + echo "No requirements.txt file found." +fi + +echo "Setup complete."