933 lines
42 KiB
JSON
933 lines
42 KiB
JSON
{
|
|
"name": "GLM Hub - Solicitudes de acceso y aprobación",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "glm-hub-solicitar-acceso",
|
|
"responseMode": "responseNode",
|
|
"options": {
|
|
"allowedOrigins": "*"
|
|
}
|
|
},
|
|
"id": "c1e25778-7556-4c87-9069-560c848cf185",
|
|
"name": "Webhook - Solicitar acceso",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
-240,
|
|
368
|
|
],
|
|
"webhookId": "ad3e98b9-baf2-400f-90e7-dcd4c5c20457"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const source = $json.body ?? $json;\nlet payload = source;\nif (typeof payload === 'string') {\n try { payload = JSON.parse(payload); } catch { payload = {}; }\n}\nconst accessToken = String(payload?.accessToken ?? '').trim();\nconst appId = String(payload?.appId ?? '').trim();\nconst jwtPattern = /^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/;\nconst uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nlet error = '';\nif (!jwtPattern.test(accessToken)) error = 'La sesión recibida no es válida.';\nelse if (!uuidPattern.test(appId)) error = 'Selecciona una aplicación válida.';\nreturn [{ json: { valid: !error, error, authorization: `Bearer ${accessToken}`, appId } }];"
|
|
},
|
|
"id": "382d40fd-c718-4ca5-be37-33fe80ad0483",
|
|
"name": "Validar solicitud de acceso",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
-16,
|
|
368
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "b5933422-7722-4c98-b34b-262a20d3ac05",
|
|
"leftValue": "={{ $json.valid }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "edbdd398-aa28-46b5-8fdd-d359e9d8dcbd",
|
|
"name": "¿Solicitud de acceso válida?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
208,
|
|
368
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "json",
|
|
"responseBody": "={{ { ok: false, error: $json.error } }}",
|
|
"options": {
|
|
"responseCode": 400,
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Cache-Control",
|
|
"value": "no-store"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"id": "81e1ad6e-ca84-4c3f-9897-bdfcab58e965",
|
|
"name": "Responder solicitud inválida",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
432,
|
|
528
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "https://dbit.digitalcompass.agency/rest/v1/rpc/glm_hub_prepare_access_request",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "apikey",
|
|
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE"
|
|
},
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Validar solicitud de acceso').first().json.authorization }}"
|
|
},
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"contentType": "raw",
|
|
"rawContentType": "application/json",
|
|
"body": "={{ JSON.stringify({ p_app_id: $json.appId }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"responseFormat": "json",
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 30000
|
|
}
|
|
},
|
|
"id": "513d8635-0e4b-49bf-beeb-1fcd76555b9d",
|
|
"name": "Crear solicitud en Supabase",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
432,
|
|
288
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const source = $input.first()?.json ?? {};\nconst parseJson = (value) => {\n if (typeof value !== 'string') return value;\n try { return JSON.parse(value); } catch { return value; }\n};\nlet payload = source.body ?? source.data ?? source.response?.body ?? source;\npayload = parseJson(payload);\nif (Array.isArray(payload)) payload = payload[0] ?? {};\nif (payload && typeof payload === 'object' && payload.body !== undefined && payload.ok === undefined) {\n payload = parseJson(payload.body);\n if (Array.isArray(payload)) payload = payload[0] ?? {};\n}\nif (payload?.ok !== true) {\n return [{ json: {\n created: false,\n publicError: 'La solicitud fue registrada, pero no se pudo enviar el correo. Intenta nuevamente en unos minutos.',\n technicalError: String(payload?.error ?? payload?.message ?? 'No se pudieron emitir los enlaces de aprobación.')\n } }];\n}\nconst escapeHtml = (value) => String(value ?? '').replace(/[&<>\"']/g, (c) => ({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));\nconst encode = encodeURIComponent;\nconst confirmBase = 'https://agenteit.digitalcompass.agency/webhook/glm-hub-confirmar-solicitud';\nconst requesterName = String(payload.requesterName ?? 'Usuario GLM');\nconst requesterEmail = String(payload.requesterEmail ?? '');\nconst appName = String(payload.appName ?? 'Aplicación GLM');\nconst appCategory = String(payload.appCategory ?? '');\nconst requestId = String(payload.requestId ?? '');\nconst approvers = Array.isArray(payload.approvers) ? payload.approvers : [];\nif (approvers.length !== 3) {\n return [{ json: {\n created: false,\n publicError: 'No se pudo completar el envío de la solicitud. Intenta nuevamente en unos minutos.',\n technicalError: `Se esperaban 3 aprobadores y se recibieron ${approvers.length}.`\n } }];\n}\nreturn approvers.map((approver) => {\n const approveUrl = `${confirmBase}?token=${encode(String(approver.token ?? ''))}&decision=approved&app=${encode(appName)}`;\n const rejectUrl = `${confirmBase}?token=${encode(String(approver.token ?? ''))}&decision=rejected&app=${encode(appName)}`;\n const html = `<!doctype html><html><body style=\"margin:0;background:#F5F5F5;font-family:Arial,sans-serif;color:#4A4A4A\"><table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"background:#F5F5F5\"><tr><td align=\"center\" style=\"padding:32px 16px\"><table role=\"presentation\" width=\"640\" cellspacing=\"0\" cellpadding=\"0\" style=\"width:100%;max-width:640px;background:#FFFFFF;border-collapse:collapse;border-top:4px solid #6CC24A\"><tr><td style=\"padding:28px 34px 16px\"><img src=\"https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png\" width=\"220\" alt=\"GomezLee Marketing\" style=\"display:block;width:220px;max-width:100%;height:auto\"></td></tr><tr><td style=\"padding:8px 34px 0\"><div style=\"font-size:11px;font-weight:700;letter-spacing:2px;color:#4F758B\">GLM HUB · SOLICITUD DE ACCESO</div><h1 style=\"margin:12px 0 8px;font-size:30px;line-height:1.12;color:#4F758B\">Una persona necesita acceso.</h1><p style=\"margin:0;font-size:15px;line-height:1.6;color:#4A4A4A\">Hola ${escapeHtml(approver.name)}, revisa la siguiente solicitud.</p></td></tr><tr><td style=\"padding:24px 34px\"><table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:collapse;border:1px solid #D0D0D0\"><tr><td style=\"width:34%;padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Solicitante</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px\">${escapeHtml(requesterName)}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Correo</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px\">${escapeHtml(requesterEmail)}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Aplicación</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px;font-weight:700;color:#4F758B\">${escapeHtml(appName)}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;font-size:13px;font-weight:700;color:#4F758B\">Área</td><td style=\"padding:12px 14px;font-size:14px\">${escapeHtml(appCategory)}</td></tr></table></td></tr><tr><td style=\"padding:0 34px 30px\"><p style=\"margin:0 0 16px;font-size:13px;line-height:1.55;color:#6B8FA3\">Por seguridad, cada botón abre una pantalla de confirmación. La primera decisión confirmada será definitiva para los tres destinatarios.</p><table role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"padding-right:10px\"><a href=\"${approveUrl}\" style=\"display:inline-block;padding:13px 22px;background:#6CC24A;color:#FFFFFF;text-decoration:none;font-size:14px;font-weight:700;border-radius:3px\">Aceptar solicitud</a></td><td><a href=\"${rejectUrl}\" style=\"display:inline-block;padding:12px 22px;background:#FFFFFF;color:#E87722;text-decoration:none;font-size:14px;font-weight:700;border:1px solid #E87722;border-radius:3px\">Rechazar solicitud</a></td></tr></table></td></tr><tr><td style=\"padding:18px 34px;border-top:1px solid #D0D0D0;font-size:11px;line-height:1.5;color:#6B8FA3\">Solicitud ${escapeHtml(requestId)} · GomezLee Marketing · Uso interno</td></tr></table></td></tr></table></body></html>`;\n return { json: { created: true, requestId, sendTo: String(approver.email ?? ''), subject: `Solicitud de acceso | ${appName} | ${requesterName}`, html } };\n});"
|
|
},
|
|
"id": "5cf9121e-d2e8-4975-a833-a426c77d9389",
|
|
"name": "Preparar correos de aprobación",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1328,
|
|
208
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "02a636e0-63a0-4a56-b108-65029e555646",
|
|
"leftValue": "={{ $json.created }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "ee5ecbd9-95ab-42f2-a013-33eff66be5ea",
|
|
"name": "¿Solicitud registrada?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
1568,
|
|
208
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"sendTo": "=iaracena@gomezleemarketing.com",
|
|
"subject": "={{ $json.subject }}",
|
|
"message": "={{ $json.html }}",
|
|
"options": {
|
|
"appendAttribution": false,
|
|
"senderName": "GLM Hub"
|
|
}
|
|
},
|
|
"id": "6fafb4fa-b7bc-46ed-b435-63cbd6c85538",
|
|
"name": "Enviar solicitud a aprobadores",
|
|
"type": "n8n-nodes-base.gmail",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
1808,
|
|
112
|
|
],
|
|
"webhookId": "7dc65e7b-4fb6-4a2f-b685-34171dd9ce1a",
|
|
"credentials": {
|
|
"gmailOAuth2": {
|
|
"id": "UDcO1FLJqA453V2D",
|
|
"name": "Gmail account 3"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "json",
|
|
"responseBody": "={{ { ok: true, message: 'La solicitud fue enviada a Isaac Aracena, José Leopoldo Gómez y Máximo Gómez.', requestId: $('Preparar correos de aprobación').first().json.requestId } }}",
|
|
"options": {
|
|
"responseCode": 200,
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Cache-Control",
|
|
"value": "no-store"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"id": "2aea248a-8970-4439-9c5b-18800257d835",
|
|
"name": "Responder solicitud enviada",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
2048,
|
|
112
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "json",
|
|
"responseBody": "={{ { ok: false, error: $json.publicError || 'No pudimos enviar la solicitud. Intenta nuevamente.' } }}",
|
|
"options": {
|
|
"responseCode": 409,
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Cache-Control",
|
|
"value": "no-store"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"id": "b2affc40-34dd-47a5-ae2c-c2f9e8bb4fe6",
|
|
"name": "Responder error al registrar",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
1808,
|
|
320
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"path": "glm-hub-confirmar-solicitud",
|
|
"responseMode": "responseNode",
|
|
"options": {}
|
|
},
|
|
"id": "d1276943-026e-414e-92eb-d9665fce1aa4",
|
|
"name": "Webhook - Confirmar decisión",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
-240,
|
|
832
|
|
],
|
|
"webhookId": "cba1c38c-37bc-4acb-bd61-48035604a5c4"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const query = $json.query ?? {};\nconst token = String(query.token ?? '').trim();\nconst decision = String(query.decision ?? '').trim().toLowerCase();\nconst appName = String(query.app ?? 'aplicación GLM').trim();\nconst valid = /^[0-9a-f]{64}$/i.test(token) && ['approved','rejected'].includes(decision);\nconst escapeHtml = (value) => String(value ?? '').replace(/[&<>\"']/g, (c) => ({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));\nconst actionUrl = 'https://agenteit.digitalcompass.agency/webhook/glm-hub-resolver-solicitud';\nconst approved = decision === 'approved';\nconst title = approved ? 'Confirmar aprobación' : 'Confirmar rechazo';\nconst actionLabel = approved ? 'Sí, aprobar solicitud' : 'Sí, rechazar solicitud';\nconst actionColor = approved ? '#6CC24A' : '#E87722';\nconst html = valid\n ? `<!doctype html><html lang=\"es\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>${title} · GLM Hub</title></head><body style=\"margin:0;background:#F5F5F5;font-family:Arial,sans-serif;color:#4A4A4A\"><main style=\"min-height:100vh;display:grid;place-items:center;padding:24px\"><section style=\"width:100%;max-width:560px;background:#FFFFFF;border-top:4px solid #6CC24A;padding:36px;box-sizing:border-box;box-shadow:0 24px 70px rgba(0,0,0,.14)\"><img src=\"https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png\" width=\"220\" alt=\"GomezLee Marketing\" style=\"display:block;width:220px;max-width:100%;height:auto\"><p style=\"margin:28px 0 8px;font-size:11px;font-weight:700;letter-spacing:2px;color:#4F758B\">GLM HUB · DECISIÓN DE ACCESO</p><h1 style=\"margin:0;color:#4F758B;font-size:34px;line-height:1.1\">${title}</h1><p style=\"margin:16px 0 24px;font-size:15px;line-height:1.6\">Vas a ${approved ? 'aprobar' : 'rechazar'} la solicitud de acceso a <strong>${escapeHtml(appName)}</strong>. La decisión será definitiva y los otros enlaces quedarán sin efecto.</p><form method=\"post\" action=\"${actionUrl}\"><input type=\"hidden\" name=\"token\" value=\"${escapeHtml(token)}\"><input type=\"hidden\" name=\"decision\" value=\"${escapeHtml(decision)}\"><button type=\"submit\" style=\"width:100%;min-height:50px;border:0;border-radius:3px;background:${actionColor};color:#FFFFFF;font-family:Arial,sans-serif;font-size:15px;font-weight:700;cursor:pointer\">${actionLabel}</button></form><p style=\"margin:18px 0 0;font-size:12px;line-height:1.5;color:#6B8FA3\">Cierra esta pestaña para cancelar sin registrar ninguna decisión.</p></section></main></body></html>`\n : `<!doctype html><html lang=\"es\"><body style=\"margin:0;background:#F5F5F5;font-family:Arial,sans-serif\"><main style=\"min-height:100vh;display:grid;place-items:center;padding:24px\"><section style=\"max-width:520px;background:#FFFFFF;border-top:4px solid #E87722;padding:36px\"><img src=\"https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png\" width=\"220\" alt=\"GomezLee Marketing\"><h1 style=\"color:#4F758B\">Enlace no válido</h1><p style=\"color:#4A4A4A;line-height:1.6\">El enlace está incompleto o no corresponde a una solicitud de GLM Hub.</p></section></main></body></html>`;\nreturn [{ json: { html } }];"
|
|
},
|
|
"id": "84f519ec-c313-42ae-ba6c-7fb612b7b510",
|
|
"name": "Construir página de confirmación",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
-16,
|
|
832
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "text",
|
|
"responseBody": "={{ $json.html }}",
|
|
"options": {
|
|
"responseCode": 200,
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "text/html; charset=utf-8"
|
|
},
|
|
{
|
|
"name": "Cache-Control",
|
|
"value": "no-store"
|
|
},
|
|
{
|
|
"name": "X-Frame-Options",
|
|
"value": "DENY"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"id": "9fab6a61-b360-4bb9-9b07-6c8244ba40db",
|
|
"name": "Mostrar confirmación",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
208,
|
|
832
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "glm-hub-resolver-solicitud",
|
|
"responseMode": "responseNode",
|
|
"options": {}
|
|
},
|
|
"id": "95a17231-e0aa-4004-9d0e-dd581488b524",
|
|
"name": "Webhook - Resolver solicitud",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
-240,
|
|
1200
|
|
],
|
|
"webhookId": "54eeee1b-b24b-46ae-84dc-70c4103e3a3a"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const source = $json.body ?? $json;\nlet payload = source;\nif (typeof payload === 'string') {\n try {\n payload = Object.fromEntries(new URLSearchParams(payload));\n } catch { payload = {}; }\n}\nconst token = String(payload?.token ?? '').trim();\nconst decision = String(payload?.decision ?? '').trim().toLowerCase();\nlet error = '';\nif (!/^[0-9a-f]{64}$/i.test(token)) error = 'El enlace de decisión no es válido.';\nelse if (!['approved','rejected'].includes(decision)) error = 'La decisión recibida no es válida.';\nreturn [{ json: { valid: !error, error, token, decision } }];"
|
|
},
|
|
"id": "87155b04-5944-43ae-beff-9310138b2863",
|
|
"name": "Validar decisión",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
-16,
|
|
1200
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "5c42c35a-903b-4a18-a7ef-aab6e6bb5c26",
|
|
"leftValue": "={{ $json.valid }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "876e85ab-fbcd-4090-a5a4-31daf40711f5",
|
|
"name": "¿Decisión válida?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
208,
|
|
1200
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const message = String($json.error ?? 'El enlace de decisión no es válido.');\nconst escapeHtml = (value) => String(value ?? '').replace(/[&<>\"']/g, (c) => ({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));\nconst html = `<!doctype html><html lang=\"es\"><body style=\"margin:0;background:#F5F5F5;font-family:Arial,sans-serif\"><main style=\"min-height:100vh;display:grid;place-items:center;padding:24px\"><section style=\"max-width:520px;background:#FFFFFF;border-top:4px solid #E87722;padding:36px\"><img src=\"https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png\" width=\"220\" alt=\"GomezLee Marketing\"><h1 style=\"color:#4F758B\">No se pudo procesar</h1><p style=\"color:#4A4A4A;line-height:1.6\">${escapeHtml(message)}</p></section></main></body></html>`;\nreturn [{ json: { html } }];"
|
|
},
|
|
"id": "c0527ef0-615e-463d-9e54-f7a942e02421",
|
|
"name": "Preparar decisión inválida",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
432,
|
|
1392
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "text",
|
|
"responseBody": "={{ $json.html }}",
|
|
"options": {
|
|
"responseCode": 400,
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "text/html; charset=utf-8"
|
|
},
|
|
{
|
|
"name": "Cache-Control",
|
|
"value": "no-store"
|
|
},
|
|
{
|
|
"name": "X-Frame-Options",
|
|
"value": "DENY"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"id": "88bb2617-4e75-4f99-9aca-7c06bb28c86e",
|
|
"name": "Responder decisión inválida",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
672,
|
|
1392
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "https://dbit.digitalcompass.agency/rest/v1/rpc/glm_hub_decide_access_request",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "apikey",
|
|
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
|
|
},
|
|
{
|
|
"name": "Authorization",
|
|
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"contentType": "raw",
|
|
"rawContentType": "application/json",
|
|
"body": "={{ JSON.stringify({ p_token: $json.token, p_decision: $json.decision }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"responseFormat": "json"
|
|
}
|
|
},
|
|
"timeout": 30000
|
|
}
|
|
},
|
|
"id": "675cfecd-8a18-4c75-8e3f-aebb79390f34",
|
|
"name": "Registrar decisión en Supabase",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
432,
|
|
1120
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const source = $input.first()?.json ?? {};\nlet payload = source.body ?? source;\nif (typeof payload === 'string') { try { payload = JSON.parse(payload); } catch { payload = {}; } }\nif (Array.isArray(payload)) payload = payload[0] ?? {};\nconst escapeHtml = (value) => String(value ?? '').replace(/[&<>\"']/g, (c) => ({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));\nconst status = String(payload.status ?? '');\nconst approved = status === 'approved';\nconst statusLabel = approved ? 'APROBADA' : status === 'rejected' ? 'RECHAZADA' : 'SIN PROCESAR';\nconst statusColor = approved ? '#6CC24A' : '#E87722';\nconst ok = payload.ok === true;\nconst alreadyDecided = payload.alreadyDecided === true;\nconst requesterName = String(payload.requesterName ?? '');\nconst requesterEmail = String(payload.requesterEmail ?? '');\nconst appName = String(payload.appName ?? 'Aplicación GLM');\nconst decidedByName = String(payload.decidedByName ?? '');\nconst decidedByEmail = String(payload.decidedByEmail ?? '');\nconst responseTitle = ok ? (approved ? 'Solicitud aprobada' : 'Solicitud rechazada') : alreadyDecided ? 'Solicitud ya atendida' : 'No se pudo procesar';\nconst responseMessage = ok\n ? `La decisión fue registrada. IT Support recibirá los datos para continuar con el acceso.`\n : alreadyDecided\n ? `Esta solicitud ya fue ${status === 'approved' ? 'aprobada' : 'rechazada'} por ${escapeHtml(decidedByName || decidedByEmail || 'otra persona')}. No se realizó ningún cambio adicional.`\n : escapeHtml(payload.error ?? 'El enlace no pudo ser validado.');\nconst responseHtml = `<!doctype html><html lang=\"es\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>${responseTitle} · GLM Hub</title></head><body style=\"margin:0;background:#F5F5F5;font-family:Arial,sans-serif;color:#4A4A4A\"><main style=\"min-height:100vh;display:grid;place-items:center;padding:24px\"><section style=\"width:100%;max-width:560px;background:#FFFFFF;border-top:4px solid ${ok ? statusColor : '#4F758B'};padding:36px;box-sizing:border-box;box-shadow:0 24px 70px rgba(0,0,0,.14)\"><img src=\"https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png\" width=\"220\" alt=\"GomezLee Marketing\" style=\"display:block;width:220px;max-width:100%;height:auto\"><p style=\"margin:28px 0 8px;font-size:11px;font-weight:700;letter-spacing:2px;color:#4F758B\">GLM HUB · SOLICITUD DE ACCESO</p><h1 style=\"margin:0;color:#4F758B;font-size:34px;line-height:1.1\">${responseTitle}</h1><p style=\"margin:16px 0 0;font-size:15px;line-height:1.65\">${responseMessage}</p><p style=\"margin:24px 0 0;font-size:12px;color:#6B8FA3\">Ya puedes cerrar esta pestaña.</p></section></main></body></html>`;\nconst itHtml = ok ? `<!doctype html><html><body style=\"margin:0;background:#F5F5F5;font-family:Arial,sans-serif;color:#4A4A4A\"><table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"background:#F5F5F5\"><tr><td align=\"center\" style=\"padding:32px 16px\"><table role=\"presentation\" width=\"680\" cellspacing=\"0\" cellpadding=\"0\" style=\"width:100%;max-width:680px;background:#FFFFFF;border-collapse:collapse;border-top:4px solid ${statusColor}\"><tr><td style=\"padding:28px 34px 16px\"><img src=\"https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM.png\" width=\"220\" alt=\"GomezLee Marketing\" style=\"display:block;width:220px;max-width:100%;height:auto\"></td></tr><tr><td style=\"padding:8px 34px 0\"><div style=\"font-size:11px;font-weight:700;letter-spacing:2px;color:#4F758B\">GLM HUB · DECISIÓN REGISTRADA</div><h1 style=\"margin:12px 0 8px;font-size:30px;line-height:1.12;color:#4F758B\">Solicitud ${statusLabel.toLowerCase()}.</h1><p style=\"margin:0;font-size:15px;line-height:1.6\">IT Support debe continuar según la decisión indicada.</p></td></tr><tr><td style=\"padding:24px 34px\"><div style=\"display:inline-block;margin-bottom:16px;padding:7px 12px;border:1px solid ${statusColor};color:${statusColor};font-size:12px;font-weight:700;letter-spacing:1px\">${statusLabel}</div><table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:collapse;border:1px solid #D0D0D0\"><tr><td style=\"width:38%;padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Persona solicitante</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px\">${escapeHtml(requesterName)}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Correo solicitante</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px\">${escapeHtml(requesterEmail)}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Aplicación</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px;font-weight:700;color:#4F758B\">${escapeHtml(appName)}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Decisión</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px;font-weight:700;color:${statusColor}\">${statusLabel}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;border-bottom:1px solid #D0D0D0;font-size:13px;font-weight:700;color:#4F758B\">Decidido por</td><td style=\"padding:12px 14px;border-bottom:1px solid #D0D0D0;font-size:14px\">${escapeHtml(decidedByName)}</td></tr><tr><td style=\"padding:12px 14px;background:#EEF6E8;font-size:13px;font-weight:700;color:#4F758B\">Correo de quien decidió</td><td style=\"padding:12px 14px;font-size:14px\">${escapeHtml(decidedByEmail)}</td></tr></table></td></tr><tr><td style=\"padding:18px 34px;border-top:1px solid #D0D0D0;font-size:11px;line-height:1.5;color:#6B8FA3\">GomezLee Marketing · GLM Hub · Uso interno</td></tr></table></td></tr></table></body></html>` : '';\nreturn [{ json: { notifyIt: ok, responseHtml, itHtml, subject: `Acceso ${approved ? 'aprobado' : 'rechazado'} | ${appName} | ${requesterName}` } }];"
|
|
},
|
|
"id": "2c8fb533-fcc0-4958-a210-9498c55d98d2",
|
|
"name": "Preparar resultado de decisión",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
672,
|
|
1120
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "2ef854a5-d270-49bf-9a6a-5bb92aeab434",
|
|
"leftValue": "={{ $json.notifyIt }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "993d5ec8-1187-4e92-adce-8c9b41c08a91",
|
|
"name": "¿Notificar a IT Support?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
912,
|
|
1120
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"sendTo": "iaracena@gomezleemarketing.com",
|
|
"subject": "={{ $json.subject }}",
|
|
"message": "={{ $json.itHtml }}",
|
|
"options": {
|
|
"appendAttribution": false,
|
|
"senderName": "GLM Hub"
|
|
}
|
|
},
|
|
"id": "c9fbf481-045c-4f2b-80bd-2ad006b0af56",
|
|
"name": "Enviar decisión a IT Support",
|
|
"type": "n8n-nodes-base.gmail",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
1152,
|
|
1024
|
|
],
|
|
"webhookId": "234c8e3b-b904-41b8-8a74-9ca835f759df",
|
|
"credentials": {
|
|
"gmailOAuth2": {
|
|
"id": "UDcO1FLJqA453V2D",
|
|
"name": "Gmail account 3"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "text",
|
|
"responseBody": "={{ $('Preparar resultado de decisión').first().json.responseHtml }}",
|
|
"options": {
|
|
"responseCode": 200,
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "text/html; charset=utf-8"
|
|
},
|
|
{
|
|
"name": "Cache-Control",
|
|
"value": "no-store"
|
|
},
|
|
{
|
|
"name": "X-Frame-Options",
|
|
"value": "DENY"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"id": "d16bcca2-1d7c-44e0-be65-658478a2623f",
|
|
"name": "Mostrar resultado final",
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
1392,
|
|
1120
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const source = $input.first()?.json ?? {};\n\nconst parseJson = (value) => {\n if (typeof value !== 'string') return value;\n try { return JSON.parse(value); } catch { return value; }\n};\n\nlet payload = source.body ?? source.data ?? source.response?.body ?? source;\npayload = parseJson(payload);\nif (Array.isArray(payload)) payload = payload[0] ?? {};\nif (payload && typeof payload === 'object' && payload.body !== undefined && payload.ok === undefined) {\n payload = parseJson(payload.body);\n if (Array.isArray(payload)) payload = payload[0] ?? {};\n}\n\nconst statusCode = Number(source.statusCode ?? source.status ?? source.response?.statusCode ?? 200);\nconst rawError = String(payload?.error ?? payload?.message ?? source?.message ?? '').trim();\nconst normalized = rawError.toLowerCase();\nconst code = String(payload?.code ?? '').toUpperCase();\n\nlet publicError = 'No pudimos registrar la solicitud. Intenta nuevamente.';\nif (code === 'PENDING_EXISTS' || normalized.includes('pendiente')) {\n publicError = 'Ya tienes una solicitud pendiente para esta aplicación.';\n} else if (normalized.includes('sesión') || statusCode === 401) {\n publicError = 'Tu sesión venció. Cierra sesión e inicia nuevamente.';\n} else if (normalized.includes('ya no está publicada') || normalized.includes('no está publicada')) {\n publicError = 'La aplicación seleccionada ya no está disponible.';\n} else if (normalized.includes('no está autorizado') || statusCode === 403) {\n publicError = 'Tu cuenta no está habilitada para enviar esta solicitud.';\n} else if (normalized.includes('administradores no necesitan')) {\n publicError = 'Tu cuenta administrativa no necesita solicitar acceso desde el Hub.';\n}\n\nreturn [{ json: {\n registered: payload?.ok === true && statusCode >= 200 && statusCode < 300,\n publicError,\n technicalError: rawError || `Respuesta HTTP ${statusCode} sin detalle`,\n statusCode,\n requestId: String(payload?.requestId ?? '')\n} }];"
|
|
},
|
|
"id": "1f46de7c-f14a-44b1-8852-cf1a9d4d6bd5",
|
|
"name": "Confirmar registro de solicitud",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
640,
|
|
288
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "aa091e1c-09f8-4cdb-b8ac-3cbc4a7a33c8",
|
|
"leftValue": "={{ $json.registered }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "0b0d9f6a-2d91-4d8f-b4f8-b20111a4d136",
|
|
"name": "¿Solicitud registrada en Supabase?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
864,
|
|
288
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "https://dbit.digitalcompass.agency/rest/v1/rpc/glm_hub_issue_access_request_tokens",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "apikey",
|
|
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
|
|
},
|
|
{
|
|
"name": "Authorization",
|
|
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"contentType": "raw",
|
|
"rawContentType": "application/json",
|
|
"body": "={{ JSON.stringify({ p_request_id: $json.requestId }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"responseFormat": "json",
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 30000
|
|
}
|
|
},
|
|
"id": "9203157e-c9e7-4ad3-bb35-ae683c594f6b",
|
|
"name": "Emitir enlaces de aprobación",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1088,
|
|
208
|
|
]
|
|
}
|
|
],
|
|
"connections": {
|
|
"Webhook - Solicitar acceso": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Validar solicitud de acceso",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Validar solicitud de acceso": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "¿Solicitud de acceso válida?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"¿Solicitud de acceso válida?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Crear solicitud en Supabase",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Responder solicitud inválida",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Crear solicitud en Supabase": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Confirmar registro de solicitud",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Preparar correos de aprobación": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "¿Solicitud registrada?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"¿Solicitud registrada?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Enviar solicitud a aprobadores",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Responder error al registrar",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Enviar solicitud a aprobadores": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Responder solicitud enviada",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Webhook - Confirmar decisión": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Construir página de confirmación",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Construir página de confirmación": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Mostrar confirmación",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Webhook - Resolver solicitud": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Validar decisión",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Validar decisión": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "¿Decisión válida?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"¿Decisión válida?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Registrar decisión en Supabase",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Preparar decisión inválida",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Preparar decisión inválida": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Responder decisión inválida",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Registrar decisión en Supabase": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Preparar resultado de decisión",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Preparar resultado de decisión": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "¿Notificar a IT Support?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"¿Notificar a IT Support?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Enviar decisión a IT Support",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Mostrar resultado final",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Enviar decisión a IT Support": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Mostrar resultado final",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Confirmar registro de solicitud": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "¿Solicitud registrada en Supabase?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"¿Solicitud registrada en Supabase?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Emitir enlaces de aprobación",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Responder error al registrar",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Emitir enlaces de aprobación": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Preparar correos de aprobación",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"active": true,
|
|
"settings": {
|
|
"executionOrder": "v1",
|
|
"binaryMode": "separate"
|
|
},
|
|
"tags": []
|
|
} |