Files
alist-serve-resource/n8n/W1-customer-provision.json
T

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
}
]
]
}
}
}