Ajuste 24 Horas

This commit is contained in:
2026-03-27 00:14:30 -03:00
parent 09a31f42e0
commit 464f9d4426

View File

@@ -1,15 +1,19 @@
import os import os
import requests
import smtplib import smtplib
from email.mime.text import MIMEText
from datetime import datetime from datetime import datetime
from email.mime.text import MIMEText
from pathlib import Path
import pytz import pytz
import requests
from dotenv import load_dotenv from dotenv import load_dotenv
# Carregar variáveis de ambiente
load_dotenv()
# Configurações # Carrega .env sempre pelo caminho do projeto (independente do CWD)
BASE_DIR = Path(__file__).resolve().parent
load_dotenv(dotenv_path=BASE_DIR / ".env")
EVOLUTION_API_URL = os.getenv("EVOLUTION_API_URL") EVOLUTION_API_URL = os.getenv("EVOLUTION_API_URL")
EVOLUTION_INSTANCE_ID = os.getenv("EVOLUTION_INSTANCE_ID") EVOLUTION_INSTANCE_ID = os.getenv("EVOLUTION_INSTANCE_ID")
EVOLUTION_API_TOKEN = os.getenv("EVOLUTION_API_TOKEN") EVOLUTION_API_TOKEN = os.getenv("EVOLUTION_API_TOKEN")
@@ -22,34 +26,59 @@ SMTP_EMAIL = os.getenv("SMTP_EMAIL")
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD") SMTP_PASSWORD = os.getenv("SMTP_PASSWORD")
EMAIL_TO = os.getenv("EMAIL_TO") EMAIL_TO = os.getenv("EMAIL_TO")
# Timezone configurável via variável de ambiente
TIMEZONE = os.getenv("TIMEZONE", "America/Sao_Paulo") TIMEZONE = os.getenv("TIMEZONE", "America/Sao_Paulo")
tz = pytz.timezone(TIMEZONE) tz = pytz.timezone(TIMEZONE)
def _normalize_env(value):
if value is None:
return None
cleaned = value.strip()
return cleaned if cleaned else None
def _required_env_missing():
required = {
"EVOLUTION_API_URL": _normalize_env(EVOLUTION_API_URL),
"EVOLUTION_API_TOKEN": _normalize_env(EVOLUTION_API_TOKEN),
"EVOLUTION_SENDER_INSTANCE": _normalize_env(EVOLUTION_SENDER_INSTANCE),
"N8N_WEBHOOK_URL": _normalize_env(N8N_WEBHOOK_URL),
"SMTP_EMAIL": _normalize_env(SMTP_EMAIL),
"SMTP_PASSWORD": _normalize_env(SMTP_PASSWORD),
"EMAIL_TO": _normalize_env(EMAIL_TO),
"WHATSAPP_NUMBER": _normalize_env(WHATSAPP_NUMBER),
}
return [name for name, value in required.items() if not value]
def get_now(): def get_now():
"""Retorna datetime atual com timezone configurado."""
return datetime.now(tz) return datetime.now(tz)
def get_headers(): def get_headers():
token = _normalize_env(EVOLUTION_API_TOKEN) or ""
return { return {
"apikey": EVOLUTION_API_TOKEN, "apikey": token,
"Authorization": f"Bearer {EVOLUTION_API_TOKEN}", "Authorization": f"Bearer {token}",
"Content-Type": "application/json" "Content-Type": "application/json",
} }
def send_email_error(error_details): def send_email_error(error_details):
"""Envia email de erro caso algo falhe."""
try: try:
now = get_now() now = get_now()
subject = "🚨 ERRO - Monitor Evolution API" subject = "ERRO - Monitor Evolution API"
body = f"Falha no monitoramento.\nHorário: {now.strftime('%d/%m/%Y %H:%M:%S')}\n\nDetalhes do Erro:\n{error_details}" body = (
"Falha no monitoramento.\n"
f"Horario: {now.strftime('%d/%m/%Y %H:%M:%S')}\n\n"
f"Detalhes do Erro:\n{error_details}"
)
msg = MIMEText(body) msg = MIMEText(body)
msg['Subject'] = subject msg["Subject"] = subject
msg['From'] = SMTP_EMAIL msg["From"] = SMTP_EMAIL
msg['To'] = EMAIL_TO msg["To"] = EMAIL_TO
# Ler configuração de segurança (Default: STARTTLS)
smtp_security = os.getenv("SMTP_SECURITY", "STARTTLS").upper() smtp_security = os.getenv("SMTP_SECURITY", "STARTTLS").upper()
if smtp_security == "SSL": if smtp_security == "SSL":
@@ -64,194 +93,160 @@ def send_email_error(error_details):
server.send_message(msg) server.send_message(msg)
return True, "Email de erro enviado com sucesso." return True, "Email de erro enviado com sucesso."
except Exception as e: except Exception as exc:
return False, f"Falha ao enviar email: {str(e)}" return False, f"Falha ao enviar email: {exc}"
def send_whatsapp_success(): def send_whatsapp_success():
"""Envia mensagem de sucesso via Evolution API."""
try: try:
url = f"{EVOLUTION_API_URL}/message/sendText/{EVOLUTION_SENDER_INSTANCE}" base_url = (_normalize_env(EVOLUTION_API_URL) or "").rstrip("/")
sender_instance = _normalize_env(EVOLUTION_SENDER_INSTANCE) or "Wander"
url = f"{base_url}/message/sendText/{sender_instance}"
now = get_now() now = get_now()
message_text = ( message_text = (
f"✅ *MONITOR OK*\n\n" "MONITOR OK\n\n"
f"📅 Data: {now.strftime('%d/%m/%Y')}\n" f"Data: {now.strftime('%d/%m/%Y')}\n"
f"🕐 Horário: {now.strftime('%H:%M:%S')}\n\n" f"Horario: {now.strftime('%H:%M:%S')}\n\n"
f"• Evolution API: Online\n" "• Evolution API: Online\n"
f"• Webhook Instância: Habilitado\n" "• Webhook Instancia: Habilitado\n"
f"• Webhook N8N: Funcionando\n\n" "• Webhook N8N: Funcionando\n\n"
f"Todos os serviços operacionais." "Todos os servicos operacionais."
) )
payload = { payload = {"number": WHATSAPP_NUMBER, "text": message_text}
"number": WHATSAPP_NUMBER,
"text": message_text
}
# A Evolution API às vezes aceita apikey no header ou como query param,
# mas o padrão aqui é usar o header configurado.
response = requests.post(url, json=payload, headers=get_headers(), timeout=10) response = requests.post(url, json=payload, headers=get_headers(), timeout=10)
if response.status_code == 200 or response.status_code == 201: if response.status_code in (200, 201):
return True, "WhatsApp de sucesso enviado." return True, "WhatsApp de sucesso enviado."
else:
return False, f"Falha ao enviar WhatsApp: {response.text}" return False, f"Falha ao enviar WhatsApp: {response.text}"
except Exception as exc:
return False, f"Erro na requisicao WhatsApp: {exc}"
except Exception as e:
return False, f"Erro na requisição WhatsApp: {str(e)}"
def run_monitor_check(): def run_monitor_check():
"""Executa o fluxo de verificação completo."""
log_messages = [] log_messages = []
whatsapp_status = "-" whatsapp_status = "-"
email_status = "-" email_status = "-"
# Passo 1: Verificar Health Evolution API missing_env = _required_env_missing()
if missing_env:
log_messages.append(f"❌ Configuracao ausente no .env: {', '.join(missing_env)}")
return False, log_messages, whatsapp_status, email_status
base_url = (_normalize_env(EVOLUTION_API_URL) or "").rstrip("/")
sender_instance = _normalize_env(EVOLUTION_SENDER_INSTANCE) or "Wander"
webhook_n8n_url = _normalize_env(N8N_WEBHOOK_URL)
# Passo 1: Health Evolution API
try: try:
# Endpoint correto: /instance/connectionState/{instanceName} health_url = f"{base_url}/instance/connectionState/{sender_instance}"
# Usa o nome da instância (EVOLUTION_SENDER_INSTANCE) e não o ID
health_url = f"{EVOLUTION_API_URL}/instance/connectionState/{EVOLUTION_SENDER_INSTANCE}"
resp_health = requests.get(health_url, headers=get_headers(), timeout=10) resp_health = requests.get(health_url, headers=get_headers(), timeout=10)
if resp_health.status_code == 200: if resp_health.status_code == 200:
# Validar se a instância está realmente conectada (state: open)
try: try:
data = resp_health.json() data = resp_health.json()
instance_data = data.get('instance', {}) instance_data = data.get("instance", {})
state = instance_data.get('state') or data.get('state') state = instance_data.get("state") or data.get("state")
if state == 'open': if state == "open":
log_messages.append("✅ Evolution API Online") log_messages.append("✅ Evolution API Online")
else: else:
# Estado não é 'open' (ex: close, closed, connecting) = ERRO!
error_msg = f"Evolution API Desconectada (State: {state})" error_msg = f"Evolution API Desconectada (State: {state})"
log_messages.append(f"{error_msg}") log_messages.append(f"{error_msg}")
# Enviar email de erro
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
except Exception:
except Exception as json_err: raw_text = (resp_health.text or "").strip().lower()
# Se falhar ler JSON mas deu 200 OK, verificar se é HTML if raw_text.startswith("<!doctype") or raw_text.startswith("<html"):
raw_text = resp_health.text.strip() error_msg = "Evolution API retornou HTML (possivel erro de autenticacao)"
if raw_text.startswith('<!doctype') or raw_text.startswith('<html'):
error_msg = "Evolution API retornou HTML (possível erro de autenticação)"
elif raw_text: elif raw_text:
error_msg = "Evolution API retornou JSON inválido" error_msg = "Evolution API retornou JSON invalido"
else: else:
error_msg = "Evolution API retornou resposta vazia" error_msg = "Evolution API retornou resposta vazia"
log_messages.append(f"{error_msg}") log_messages.append(f"{error_msg}")
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
else: else:
error_msg = f"Evolution API Offline. Status: {resp_health.status_code}" error_msg = f"Evolution API Offline. Status: {resp_health.status_code}"
log_messages.append(f"{error_msg}") log_messages.append(f"{error_msg}")
# Tenta enviar email de erro
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
except Exception as exc:
except Exception as e: error_msg = f"Erro ao conectar na Evolution API: {exc}"
error_msg = f"Erro ao conectar na Evolution API: {str(e)}"
log_messages.append(f"{error_msg}") log_messages.append(f"{error_msg}")
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
# Passo 1.5: Verificar se o Webhook da Instância está habilitado # Passo 1.5: Webhook da instancia
try: try:
webhook_url = f"{EVOLUTION_API_URL}/webhook/find/{EVOLUTION_SENDER_INSTANCE}" webhook_url = f"{base_url}/webhook/find/{sender_instance}"
resp_webhook_config = requests.get(webhook_url, headers=get_headers(), timeout=15) resp_webhook_config = requests.get(webhook_url, headers=get_headers(), timeout=15)
if resp_webhook_config.status_code == 200: if resp_webhook_config.status_code == 200:
webhook_data = resp_webhook_config.json() webhook_data = resp_webhook_config.json()
# Verificar se enabled é True webhook_enabled = webhook_data.get("enabled", False)
webhook_enabled = webhook_data.get('enabled', False)
webhook_url_configured = webhook_data.get('url', 'N/A')
if webhook_enabled: if webhook_enabled:
log_messages.append("✅ Webhook Instância OK") log_messages.append("✅ Webhook Instancia OK")
else: else:
error_msg = f"Webhook da Instância DESABILITADO" error_msg = "Webhook da Instancia DESABILITADO"
log_messages.append(f"{error_msg}") log_messages.append(f"{error_msg}")
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
else: else:
# Se não conseguir verificar, apenas loga aviso mas continua log_messages.append(
log_messages.append(f"⚠️ Não foi possível verificar webhook da instância (Status: {resp_webhook_config.status_code})") f"⚠️ Nao foi possivel verificar webhook da instancia "
f"(Status: {resp_webhook_config.status_code})"
)
except Exception as exc:
log_messages.append(f"⚠️ Erro ao verificar webhook da instancia: {str(exc)[:80]}")
except Exception as e: # Passo 2: Teste webhook N8N
# Se falhar a verificação do webhook, loga aviso mas continua
log_messages.append(f"⚠️ Erro ao verificar webhook da instância: {str(e)[:50]}")
# Passo 2: Testar Webhook N8N
try: try:
# Nota: O fluxo original faz um POST simples resp_webhook = requests.post(webhook_n8n_url, json={"check": "ping"}, timeout=10)
resp_webhook = requests.post(N8N_WEBHOOK_URL, json={"check": "ping"}, timeout=10)
if resp_webhook.status_code == 200: if resp_webhook.status_code == 200:
log_messages.append("✅ Webhook N8N OK") log_messages.append("✅ Webhook N8N OK")
else: else:
error_msg = f"Webhook N8N falhou. Status: {resp_webhook.status_code}" error_msg = f"Webhook N8N falhou. Status: {resp_webhook.status_code}"
log_messages.append(f"{error_msg}") log_messages.append(f"{error_msg}")
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
except Exception as exc:
except Exception as e: error_msg = f"Erro ao conectar no Webhook N8N: {exc}"
error_msg = f"Erro ao conectar no Webhook N8N: {str(e)}"
log_messages.append(f"{error_msg}") log_messages.append(f"{error_msg}")
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
# Passo 3: Se chegou aqui, tudo OK -> Enviar WhatsApp # Passo 3: Notificacao de sucesso via WhatsApp
# Se está tudo OK, email de erro não é enviado, então mantemos email_status como "-" ou podemos por "N/A"
# O usuário pediu "Sucesso ou Error". Se não enviou nada, talvez "-" seja melhor que "Error".
success, msg = send_whatsapp_success() success, msg = send_whatsapp_success()
if success: if success:
log_messages.append(f"{msg}") log_messages.append(f"{msg}")
whatsapp_status = "Sucesso" whatsapp_status = "Sucesso"
return True, log_messages, whatsapp_status, email_status return True, log_messages, whatsapp_status, email_status
else:
# Se falhar enviar o whats, é um erro também?
whatsapp_status = "Erro" whatsapp_status = "Erro"
error_msg = f"Servicos online, mas falha ao enviar WhatsApp: {msg}"
# O fluxo original manda email de erro se o check falhar.
# Se o envio do whats falhar, vamos mandar email
error_msg = f"Serviços Online, mas falha ao enviar WhatsApp: {msg}"
log_messages.append(f"⚠️ {error_msg}") log_messages.append(f"⚠️ {error_msg}")
email_ok, _ = send_email_error(error_msg) email_ok, _ = send_email_error(error_msg)
email_status = "Sucesso" if email_ok else "Erro" email_status = "Sucesso" if email_ok else "Erro"
return False, log_messages, whatsapp_status, email_status return False, log_messages, whatsapp_status, email_status
def diagnose_n8n_webhook(): def diagnose_n8n_webhook():
"""Realiza um teste detalhado do Webhook N8N para diagnóstico."""
try: try:
url = N8N_WEBHOOK_URL url = _normalize_env(N8N_WEBHOOK_URL)
now = get_now() now = get_now()
payload = {"check": "diagnosis_ping", "timestamp": str(now)} payload = {"check": "diagnosis_ping", "timestamp": str(now)}
# Preparar log
log = { log = {
"url": url, "url": url,
"method": "POST", "method": "POST",
@@ -259,26 +254,31 @@ def diagnose_n8n_webhook():
"status_code": None, "status_code": None,
"response_body": None, "response_body": None,
"headers_received": None, "headers_received": None,
"error": None "error": None,
} }
response = requests.post(url, json=payload, timeout=10) if not url:
log["error"] = "N8N_WEBHOOK_URL nao configurada no .env"
return False, log
response = requests.post(url, json=payload, timeout=10)
log["status_code"] = response.status_code log["status_code"] = response.status_code
log["response_body"] = response.text log["response_body"] = response.text
log["headers_received"] = dict(response.headers) log["headers_received"] = dict(response.headers)
return response.status_code == 200, log
except Exception as exc:
return False, {
"url": _normalize_env(N8N_WEBHOOK_URL),
"method": "POST",
"payload_sent": None,
"status_code": None,
"response_body": None,
"headers_received": None,
"error": str(exc),
}
if response.status_code == 200:
return True, log
else:
return False, log
except Exception as e:
log["error"] = str(e)
return False, log
if __name__ == "__main__": if __name__ == "__main__":
# Teste rápido se rodar direto
status, logs, wa_status, em_status = run_monitor_check() status, logs, wa_status, em_status = run_monitor_check()
print(f"Status: {status}") print(f"Status: {status}")
print(f"WhatsApp: {wa_status} | Email: {em_status}") print(f"WhatsApp: {wa_status} | Email: {em_status}")