Tirando env do commit

This commit is contained in:
Joao Monezi
2025-06-21 16:19:21 +00:00
parent e51648489b
commit 5feb9db6c0
2549 changed files with 397274 additions and 0 deletions
View File
Binary file not shown.
Binary file not shown.
+168
View File
@@ -0,0 +1,168 @@
# app/api/webhook.py
from fastapi import APIRouter, Request, HTTPException, status
from fastapi.responses import PlainTextResponse, JSONResponse, Response
from pydantic import BaseModel
import json
from config import VERIFY_TOKEN
from models.webhook_model import WebhookEvent
from services.webhook_service import (
handle_message_type, mark_message_as_read,
encrypt_flow_response_data, decrypt_flow_request_data, send_whatsapp_flow # <--- ADICIONAR decrypt_flow_request_data
)
router = APIRouter()
class SendFlowRequest(BaseModel):
to_number: str # O número para onde enviar o Flow (ex: '5582912345678')
# ... (Endpoint GET /webhook) ...
# --- Endpoint para Receber Requisições POST (Incluindo TODOS os Payloads Criptografados e Webhook Padrão) ---
@router.post("/webhook")
async def process_whatsapp_webhook(request: Request):
try:
body = await request.json()
except json.JSONDecodeError as e:
print(f"⚠️ Requisição POST recebida com corpo não-JSON ou JSON inválido: {e}")
return JSONResponse(status_code=status.HTTP_200_OK, content={"status": "corpo inválido, ignorado"})
except Exception as e:
print(f"⚠️ Erro inesperado ao ler o corpo da requisição POST: {e}")
return JSONResponse(status_code=status.HTTP_200_OK, content={"status": "erro de leitura, ignorado"})
# --- Lógica para Requisições de Dados de Flow Criptografadas (incluindo Health Check criptografado) ---
if isinstance(body, dict) and "encrypted_flow_data" in body and "encrypted_aes_key" in body and "initial_vector" in body:
print("🔒 Recebido payload de Flow criptografado.")
try:
# Descriptografa a requisição para obter os dados, a chave AES e o IV originais
decrypted_result = decrypt_flow_request_data(
body["encrypted_flow_data"],
body["encrypted_aes_key"],
body["initial_vector"]
)
decrypted_data = decrypted_result["decrypted_payload"]
aes_key_from_request = decrypted_result["aes_key"]
iv_from_request = decrypted_result["initial_vector"]
print(f"🔓 Dados do Flow descriptografados: {json.dumps(decrypted_data, indent=2)}")
flow_response_data = {
"data": {
"status": "active"
}
}
# Processa o tipo de requisição descriptografada
if decrypted_data.get("action") == "ping":
print("💚 Descriptografado: Ping de dados do Flow. Preparando resposta 'active'.")
else:
print(f"❓ Descriptografado: Outros dados de Flow. Conteúdo: {decrypted_data}")
flow_response_data = {"status": "success", "message": "Dados de Flow processados."}
# Criptografa a resposta usando a chave AES e o IV DA REQUISIÇÃO ORIGINAL
# A função encrypt_flow_response_data AGORA RETORNA A STRING BASE64 DIRETA
encrypted_final_response_string = encrypt_flow_response_data(
flow_response_data,
aes_key_from_request,
iv_from_request
)
print(f"DEBUG: Enviando resposta final criptografada (Base64): {encrypted_final_response_string[:50]}...")
return Response(content=encrypted_final_response_string, media_type="text/plain")
except ValueError as ve:
print(f"❌ ERRO de chave ou dados para descriptografia/criptografia de Flow: {ve}")
return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"status": f"Erro de chave ou criptografia: {ve}"})
except Exception as e:
print(f"❌ ERRO ao processar dados de Flow criptografados: {e}")
return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"status": f"Erro interno ao processar Flow: {e}"})
# --- Lógica para Eventos de Webhook Padrão do WhatsApp (mensagens, status) ---
# Este bloco só será acionado se não for um payload de Flow criptografado
# --- Bloco para Eventos Padrão do WhatsApp (mensagens, status, etc.) ---
# Este é o bloco que interessa para o teste de sessão
elif isinstance(body, dict) and "object" in body and "entry" in body:
try:
event = WebhookEvent(**body)
if event.object != 'whatsapp_business_account':
print("❌ Evento recebido, mas não é do tipo 'whatsapp_business_account'. Ignorando.")
return JSONResponse(status_code=status.HTTP_404_NOT_FOUND, content={"status": "ignorado"})
for entry in event.entry:
for change in entry.changes:
if change.field == 'messages':
if change.value and change.value.messages:
for message in change.value.messages:
print(f"\n💬 Mensagem recebida de {message.from_} (Tipo: {message.type}, ID: {message.id})")
await mark_message_as_read(message.id)
# CHAME handle_message_type PASSANDO O OBJETO 'message' COMPLETO
await handle_message_type(message)
else:
print("⚠️ Evento de 'messages' recebido, mas sem mensagens válidas no payload.")
elif change.field == 'statuses':
if change.value and change.value.statuses:
for status_event in change.value.statuses:
print(f"️ Status da mensagem ID {status_event.id}: {status_event.status} (para {status_event.recipient_id})")
# Futuramente: handle_status_event(status_event)
else:
print("⚠️ Evento de 'statuses' recebido, mas sem status válidos no payload.")
# REMOVA OU COMENTE TEMPORARIAMENTE o bloco 'elif change.field == 'flows':' se estiver lá
# para focar apenas em mensagens/sessão.
# elif change.field == 'flows':
# ...
else:
print(f"⚠️ Evento de campo desconhecido recebido: {change.field}. Payload completo: {change.model_dump_json(indent=2) if hasattr(change, 'model_dump_json') else json.dumps(change.dict(), indent=2)}")
return JSONResponse(status_code=status.HTTP_200_OK, content={"status": "evento processado com sucesso"})
except Exception as e:
print(f"⚠️ Payload recebido não corresponde ao modelo WebhookEvent ou erro interno: {type(e).__name__}: {e}. Payload: {json.dumps(body)}")
return JSONResponse(status_code=status.HTTP_200_OK, content={"status": "payload desconhecido, ignorado"})
# --- Fallback para payloads POST não reconhecidos ---
else:
print(f"❓ Payload POST recebido que não é Health Check, Flow criptografado, nem WebhookEvent padrão. Ignorando. Payload: {json.dumps(body)}")
return JSONResponse(status_code=status.HTTP_200_OK, content={"status": "payload não reconhecido, ignorado"})
@router.post("/send_cadastro_flow")
async def trigger_cadastro_flow(request_data: SendFlowRequest):
"""
Dispara o Flow de cadastro do WhatsApp para um número específico.
"""
target_number = request_data.to_number # <-- ESTA LINHA DEVE ESTAR AQUI E ACESSÍVEL
# --- MUITO IMPORTANTE: Substitua pelo FLOW_ID REAL que você publicou ---
FLOW_ID_DO_SEU_CADASTRO_PUBLICADO = 1094799999286205
if FLOW_ID_DO_SEU_CADASTRO_PUBLICADO == "COLOQUE_AQUI_O_FLOW_ID_DO_SEU_CADASTRO_PUBLICADO":
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Por favor, substitua 'COLOQUE_AQUI_O_FLOW_ID_DO_SEU_CADASTRO_PUBLICADO' pelo Flow ID real no código."
)
print(f"DEBUG: Disparando Flow de Cadastro (ID: {FLOW_ID_DO_SEU_CADASTRO_PUBLICADO}) para o número: {target_number}")
try:
response = await send_whatsapp_flow(target_number, FLOW_ID_DO_SEU_CADASTRO_PUBLICADO, "Abrir Formulário de Cadastro")
if response and response.get("status") == "success":
return JSONResponse(
status_code=status.HTTP_200_OK,
content={"message": f"Flow de cadastro enviado com sucesso para {target_number}", "whatsapp_api_response": response["data"]}
)
else:
print(f"DEBUG: send_whatsapp_flow retornou erro: {response.get('message', 'Erro desconhecido')}")
raise HTTPException(
status_code=response.get("code", status.HTTP_500_INTERNAL_SERVER_ERROR),
detail=f"Falha ao enviar Flow: {response.get('message', 'Erro desconhecido')}"
)
except HTTPException:
raise
except Exception as e:
print(f"❌ ERRO INESPERADO na trigger_cadastro_flow: {type(e).__name__}: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Erro interno ao disparar Flow: {e}"
)