110 lines
4.6 KiB
Python
110 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Fix del bug de token en la cascada del workflow Marca->Sucursal V2.
|
|
|
|
El nodo `Buscar Contacto Objetivo - SUCURSAL(mail)` (workflow 4UMRwxJdHFfOGHBp)
|
|
usa una expression IMPLICITA para el header Authorization:
|
|
=Bearer {{ $json['Token/API'] }}
|
|
|
|
Esto resuelve al token de MARCA (heredado del set node 'Datos API Cuenta Origen'),
|
|
no al de sucursal, por lo que el endpoint POST /contacts/search responde 401.
|
|
El nodo siguiente (`Obtener Contacto Cuenta objetivo - SUCURSAL`) recibe
|
|
{error: ...} en lugar de {contacts: [...]} y termina rebotando con 403 porque
|
|
$json.contacts[0].id es undefined.
|
|
|
|
Fix: cambiar la expression a la explicita usada por los otros 9 HTTP nodes:
|
|
=Bearer {{ $('Datos API Cuenta objetivo - SUCURSAL').item.json['Token/API'] }}
|
|
|
|
Cambio neto: 1 expression. Total nodos sin cambios (42).
|
|
Modo dry-run por defecto; --apply para PUT real + reactivar.
|
|
"""
|
|
import argparse
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from scripts.n8n_workflow_lib import load_credentials, N8NClient
|
|
|
|
WID = "4UMRwxJdHFfOGHBp"
|
|
TARGET_NODE = "Buscar Contacto Objetivo - SUCURSAL(mail)"
|
|
BUGGY_VALUE = "=Bearer {{ $json['Token/API'] }}"
|
|
FIXED_VALUE = "=Bearer {{ $('Datos API Cuenta objetivo - SUCURSAL').item.json['Token/API'] }}"
|
|
|
|
|
|
def parse_args():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--apply", action="store_true",
|
|
help="Aplicar PUT real (default: dry-run a n8n/dryrun_*.json)")
|
|
return ap.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
api_key, base_url = load_credentials()
|
|
client = N8NClient(api_key, base_url)
|
|
|
|
print(f"[1/6] GET workflow {WID}")
|
|
wf = client.get_workflow(WID)
|
|
prev_version = wf.get("versionId")
|
|
print(f" versionId previo: {prev_version}")
|
|
print(f" active : {wf.get('active')}")
|
|
print(f" total nodos : {len(wf.get('nodes') or [])}")
|
|
|
|
# Localizar nodo y validar expression actual (defensa contra cambios concurrentes)
|
|
target = next((n for n in wf["nodes"] if n.get("name") == TARGET_NODE), None)
|
|
if not target:
|
|
print(f"\nERROR: nodo {TARGET_NODE!r} no existe. Abortando.")
|
|
sys.exit(2)
|
|
headers = ((target.get("parameters") or {}).get("headerParameters") or {}).get("parameters") or []
|
|
auth_header = next((h for h in headers if h.get("name") == "Authorization"), None)
|
|
if not auth_header:
|
|
print(f"\nERROR: nodo {TARGET_NODE!r} no tiene header Authorization. Abortando.")
|
|
sys.exit(2)
|
|
current = auth_header.get("value", "")
|
|
print(f"\n[2/6] Verificar expression actual")
|
|
print(f" actual : {current}")
|
|
print(f" esperada : {BUGGY_VALUE}")
|
|
if current == FIXED_VALUE:
|
|
print(f"\n [SKIP] La expression ya esta arreglada. Nada que hacer.")
|
|
return
|
|
if current != BUGGY_VALUE:
|
|
print(f"\nERROR: expression actual difiere de la esperada y tampoco esta arreglada.")
|
|
print(f" Abortando para no sobrescribir cambios manuales.")
|
|
sys.exit(2)
|
|
|
|
print(f"\n[3/6] Backup fresco")
|
|
_, bpath = client.backup_workflow(WID, label="pre_fix_cascada_token_mail")
|
|
print(f" backup -> {bpath}")
|
|
|
|
print(f"\n[4/6] Aplicar cambio en memoria")
|
|
auth_header["value"] = FIXED_VALUE
|
|
print(f" nuevo: {FIXED_VALUE}")
|
|
|
|
print(f"\n[5/6] {'APPLY' if args.apply else 'DRY-RUN'} put_workflow")
|
|
result = client.put_workflow(WID, wf, dry_run=not args.apply)
|
|
if not args.apply:
|
|
print(f" dry-run dump -> {result}")
|
|
print("\nLISTO. Revisa el JSON. Si todo bien, corre con --apply.")
|
|
return
|
|
|
|
print(f"\n[6/6] Verificar y reactivar")
|
|
new_wf = client.verify_post(WID, prev_version_id=prev_version)
|
|
# Re-verificar la expression
|
|
target_post = next((n for n in new_wf["nodes"] if n.get("name") == TARGET_NODE), None)
|
|
headers_post = ((target_post.get("parameters") or {}).get("headerParameters") or {}).get("parameters") or []
|
|
auth_post = next((h for h in headers_post if h.get("name") == "Authorization"), None)
|
|
print(f" versionId nuevo : {new_wf.get('versionId')}")
|
|
print(f" total nodos : {len(new_wf.get('nodes') or [])} (esperado: 42)")
|
|
print(f" expression post : {auth_post.get('value') if auth_post else '?'}")
|
|
print(f" coincide con fix : {auth_post.get('value') == FIXED_VALUE if auth_post else False}")
|
|
if not new_wf.get("active"):
|
|
print(" workflow inactivo tras PUT; reactivando...")
|
|
client.activate(WID)
|
|
new_wf = client.get_workflow(WID)
|
|
print(f" active final : {new_wf.get('active')}")
|
|
print("\nOK.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|