657 lines
18 KiB
JSON
657 lines
18 KiB
JSON
{
|
|
"name": "W1 - Customer Provision (AList User + Role)",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "alist-customer-provision",
|
|
"responseMode": "onReceived",
|
|
"options": {}
|
|
},
|
|
"id": "trigger-webhook",
|
|
"name": "NocoDB: Customer Webhook",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
0,
|
|
0
|
|
],
|
|
"webhookId": "customer-provision"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const body = $input.item.json.body ?? $input.item.json;\nconst data = body.data ?? {};\nconst rows = data.rows?.[0] ?? data.previous_rows?.[0] ?? data.rows_new?.[0] ?? data.rows_old?.[0] ?? {};\nconst id = rows.Id ?? data.data?.rows?.[0]?.Id;\nif (!id) throw new Error('no customer Id in webhook');\nreturn { json: { customerId: Number(id), eventType: body.type ?? '' } };\n"
|
|
},
|
|
"id": "extract-id",
|
|
"name": "Extract Customer Record Id",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
220,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "// Step 2: read ALL env via $env (works in Code node), and pass through\n// the webhook-derived fields so downstream keeps customerId.\nconst prev = $input.item.json;\nreturn { json: {\n customerId: prev.customerId,\n eventType: prev.eventType,\n NOCODB_URL: $env.NOCODB_URL,\n NOCODB_TOKEN: $env.NOCODB_TOKEN,\n T_CUSTOMERS: $env.NOCODB_TABLE_CUSTOMERS,\n ALIST_URL: $env.ALIST_URL,\n ALIST_ADMIN_USERNAME: $env.ALIST_ADMIN_USERNAME,\n ALIST_ADMIN_PASSWORD: $env.ALIST_ADMIN_PASSWORD,\n ALIST_ADMIN_OTP: $env.ALIST_ADMIN_OTP || '',\n} };\n"
|
|
},
|
|
"id": "load-env",
|
|
"name": "Load Env",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
220,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Load Env').item.json.NOCODB_URL }}/api/v2/tables/{{ $('Load Env').item.json.T_CUSTOMERS }}/records/{{ $json.customerId }}",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "xc-token",
|
|
"value": "{{ $('Load Env').item.json.NOCODB_TOKEN }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "fetch-customer",
|
|
"name": "Fetch Latest Customer Record",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
440,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const cust = $input.item.json;\nconst username = cust.username; const password = cust.password;\nif (!username) throw new Error('Customer missing username');\nconst newUserId = cust.alist_user_id ?? null;\nconst newRoleId = cust.alist_role_id ?? null;\nconst isCreate = !newUserId;\n// Break loop: only write back if semantic fields would actually change.\n// If the record already has alist_user_id + role_id + sync_status=synced,\n// this webhook was fired by our own write-back (echo) -> skip.\nconst skipWriteBack = (!isCreate) && (cust.sync_status === 'synced');\nreturn { json: {\n customerId: cust.Id ?? cust.id,\n username, password,\n displayName: cust.display_name ?? username,\n basePath: '/',\n alistUserId: newUserId,\n alistRoleId: newRoleId,\n isCreate,\n skipWriteBack,\n} };\n"
|
|
},
|
|
"id": "prepare",
|
|
"name": "Prepare Provision Payload",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
660,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Load Env').item.json.ALIST_URL }}/api/auth/login",
|
|
"authentication": "none",
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ username: $('Load Env').item.json.ALIST_ADMIN_USERNAME, password: $('Load Env').item.json.ALIST_ADMIN_PASSWORD }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "alist-login",
|
|
"name": "AList Admin Login",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
880,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const resp = $input.item.json;\nconst token = resp?.data?.token;\nif (!token) throw new Error('AList admin login failed: ' + JSON.stringify(resp));\nreturn { json: { token } };\n"
|
|
},
|
|
"id": "extract-token",
|
|
"name": "Extract Admin Token",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1100,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeName": "boolean",
|
|
"ignoreCase": true
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "cond-create",
|
|
"leftValue": "={{ $('Prepare Provision Payload').item.json.isCreate }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "equals",
|
|
"singleValue": true,
|
|
"rightType": "boolean"
|
|
}
|
|
}
|
|
],
|
|
"combinator": "or"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "branch-create-update",
|
|
"name": "Create vs Update",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1320,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Load Env').item.json.ALIST_URL }}/api/admin/role/create",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Extract Admin Token').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ name: 'customer-' + $('Prepare Provision Payload').item.json.username, description: 'Auto role for ' + $('Prepare Provision Payload').item.json.username, default: false, permission_scopes: [] }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "alist-create-role",
|
|
"name": "AList Create Role",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1540,
|
|
-240
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Load Env').item.json.ALIST_URL }}/api/admin/role/list?page=1&per_page=100",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Extract Admin Token').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "alist-list-roles",
|
|
"name": "AList List Roles (find id)",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1760,
|
|
-240
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const roles = $input.item.json?.data?.content ?? [];\nconst target = 'customer-' + $('Prepare Provision Payload').item.json.username;\nconst r = roles.find(x => x.name === target);\nif (!r) throw new Error('Role not found: ' + target);\nreturn { json: { alistRoleId: r.id, roleName: target } };\n"
|
|
},
|
|
"id": "find-role-id",
|
|
"name": "Find New Role Id",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1980,
|
|
-240
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Load Env').item.json.ALIST_URL }}/api/admin/user/create",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Extract Admin Token').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ username: $('Prepare Provision Payload').item.json.username, password: $('Prepare Provision Payload').item.json.password, base_path: $('Prepare Provision Payload').item.json.basePath, role: [$('Find New Role Id').item.json.alistRoleId], permission: 16384 }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "alist-create-user",
|
|
"name": "AList Create User",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
2200,
|
|
-240
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Load Env').item.json.ALIST_URL }}/api/admin/user/list?page=1&per_page=100",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Extract Admin Token').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "alist-list-users",
|
|
"name": "AList List Users (find id)",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
2420,
|
|
-240
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "const users = $input.item.json?.data?.content ?? [];\nconst target = $('Prepare Provision Payload').item.json.username;\nconst u = users.find(x => x.username === target);\nif (!u) throw new Error('Created user not found: ' + target);\nreturn { json: { alistUserId: u.id, username: target } };\n"
|
|
},
|
|
"id": "find-user-id",
|
|
"name": "Find New User Id",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2640,
|
|
-240
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "PATCH",
|
|
"url": "={{ $('Load Env').item.json.NOCODB_URL }}/api/v2/tables/{{ $('Load Env').item.json.T_CUSTOMERS }}/records",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "xc-token",
|
|
"value": "{{ $('Load Env').item.json.NOCODB_TOKEN }}"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify([{ Id: $('Prepare Provision Payload').item.json.customerId, alist_user_id: $('Find New User Id').item.json.alistUserId, alist_role_id: $('Find New Role Id').item.json.alistRoleId, sync_status: 'synced', last_sync_error: null }]) }}",
|
|
"options": {}
|
|
},
|
|
"id": "nocodb-writeback-create",
|
|
"name": "Write Back (Created)",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
2860,
|
|
-240
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Load Env').item.json.ALIST_URL }}/api/admin/user/update",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Extract Admin Token').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ id: $('Prepare Provision Payload').item.json.alistUserId, username: $('Prepare Provision Payload').item.json.username, password: $('Prepare Provision Payload').item.json.password, base_path: $('Prepare Provision Payload').item.json.basePath, role: $('Prepare Provision Payload').item.json.alistRoleId ? [$('Prepare Provision Payload').item.json.alistRoleId] : [], permission: 16384 }) }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"id": "alist-update-user",
|
|
"name": "AList Update User",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1540,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "PATCH",
|
|
"url": "={{ $('Load Env').item.json.NOCODB_URL }}/api/v2/tables/{{ $('Load Env').item.json.T_CUSTOMERS }}/records",
|
|
"authentication": "none",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "xc-token",
|
|
"value": "{{ $('Load Env').item.json.NOCODB_TOKEN }}"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify([{ Id: $('Prepare Provision Payload').item.json.customerId, sync_status: 'synced', last_sync_error: null }]) }}",
|
|
"options": {}
|
|
},
|
|
"id": "nocodb-writeback-update",
|
|
"name": "Write Back (Updated)",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
1760,
|
|
0
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "// Loop guard: echo webhook already synced -> stop here, no login, no write-back.\nreturn { json: { skipped: true, customerId: $('Prepare Provision Payload').item.json.customerId } };"
|
|
},
|
|
"id": "skip-echo-end",
|
|
"name": "Skip Echo (No-op)",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1540,
|
|
-520
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeName": "boolean",
|
|
"ignoreCase": true
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "cond-skip",
|
|
"leftValue": "={{ $('Prepare Provision Payload').item.json.skipWriteBack }}",
|
|
"rightValue": true,
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "equals",
|
|
"singleValue": true,
|
|
"rightType": "boolean"
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "if-skip",
|
|
"name": "Skip if already synced",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1320,
|
|
0
|
|
]
|
|
}
|
|
],
|
|
"connections": {
|
|
"NocoDB: Customer Webhook": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Extract Customer Record Id",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Extract Customer Record Id": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Load Env",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fetch Latest Customer Record": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Prepare Provision Payload",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Prepare Provision Payload": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Skip if already synced",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AList Admin Login": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Extract Admin Token",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Extract Admin Token": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Create vs Update",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Create vs Update": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AList Create Role",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "AList Update User",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AList Create Role": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AList List Roles (find id)",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AList List Roles (find id)": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Find New Role Id",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Find New Role Id": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AList Create User",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AList Create User": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AList List Users (find id)",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AList List Users (find id)": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Find New User Id",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Find New User Id": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Write Back (Created)",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Write Back (Created)": {
|
|
"main": []
|
|
},
|
|
"AList Update User": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Write Back (Updated)",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Write Back (Updated)": {
|
|
"main": []
|
|
},
|
|
"Load Env": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Fetch Latest Customer Record",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Skip if already synced": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Skip Echo (No-op)",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "AList Admin Login",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
}
|
|
} |