Skip to content

Commit f7ea193

Browse files
committed
update: add type param to webhook
1 parent 06d2d7e commit f7ea193

File tree

1 file changed

+100
-81
lines changed

1 file changed

+100
-81
lines changed

nodes/Lowcoder/Lowcoder.node.ts

Lines changed: 100 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
2-
31
import {
4-
INodeType,
5-
INodeTypeDescription,
2+
INodeType,
3+
INodeTypeDescription,
64
ILoadOptionsFunctions,
75
INodeListSearchResult,
86
IExecuteFunctions,
@@ -17,22 +15,22 @@ import { apiRequest } from './GenericFunctions';
1715
import isbot from 'isbot';
1816

1917
interface LowcoderAppType {
20-
applicationId: string;
21-
name: string;
18+
applicationId: string;
19+
name: string;
2220
applicationType: number
2321
}
2422

2523
const WAIT_TIME_UNLIMITED = '3000-01-01T00:00:00.000Z';
2624

2725
export class Lowcoder implements INodeType {
28-
description: INodeTypeDescription = {
26+
description: INodeTypeDescription = {
2927
displayName: 'Lowcoder',
3028
name: 'lowcoder',
3129
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
3230
icon: 'file:lowcoder.png',
3331
group: ['transform'],
3432
version: 1,
35-
subtitle: '=app:{{ $parameter["appId"]',
33+
subtitle: '=app:{{ $parameter["appId"]',
3634
description: 'Consume Lowcoder API',
3735
defaults: {
3836
name: 'Lowcoder',
@@ -50,100 +48,121 @@ export class Lowcoder implements INodeType {
5048
name: 'default',
5149
httpMethod: '={{$parameter["httpMethod"]}}',
5250
isFullPath: true,
53-
responseCode: '200',
5451
responseMode: 'onReceived',
55-
responseData: 'allEntries',
56-
responseContentType: '={{$parameter["options"]["responseContentType"]}}',
52+
responseData: '={{$parameter["options"]["responseData"] || "Workflow Resumed!"}}',
53+
responseContentType: '={{$parameter["options"]["responseContentType"] || "application/json"}}',
5754
responsePropertyName: '={{$parameter["options"]["responsePropertyName"]}}',
5855
responseHeaders: '={{$parameter["options"]["responseHeaders"]}}',
5956
path: '={{$parameter["appId"] || ""}}',
60-
restartWebhook: true,
57+
restartWebhook: true,
6158
},
62-
],
59+
],
6360
properties: [
6461
...appFields,
6562
{
66-
displayName: 'Resume the workflow by calling this Webhook: http(s)://{n8n-url}/webhook-waiting/{Workflow-Execution-ID}/{Lowcoder-App-ID}',
67-
name: 'webhookNotice',
68-
type: 'notice',
69-
default: '',
70-
},
71-
{
72-
displayName: 'The Workflow-Execution-ID is available via the n8n Rest API',
73-
name: 'webhookNotice',
74-
type: 'notice',
75-
default: '',
76-
},
63+
displayName: 'Resume the workflow by calling this Webhook: http(s)://{n8n-url}/webhook-waiting/{Workflow-Execution-ID}/{Lowcoder-App-ID}',
64+
name: 'webhookNotice',
65+
type: 'notice',
66+
default: '',
67+
},
68+
{
69+
displayName: 'The Workflow-Execution-ID is available via the n8n Rest API',
70+
name: 'webhookNotice',
71+
type: 'notice',
72+
default: '',
73+
},
7774
httpMethodsProperty,
78-
optionsProperty
75+
optionsProperty,
76+
{
77+
displayName: 'Response Code',
78+
name: 'responseCode',
79+
type: 'number',
80+
default: 200,
81+
description: 'The HTTP response code to return',
82+
},
7983
],
80-
};
84+
};
8185

8286
methods = {
83-
listSearch: {
84-
async searchApps(
85-
this: ILoadOptionsFunctions,
86-
query?: string,
87-
): Promise<INodeListSearchResult> {
88-
89-
const searchResults = await apiRequest.call(
90-
this,
91-
'GET',
92-
'applications/list',
93-
{},
94-
{
95-
query,
87+
listSearch: {
88+
async searchApps(
89+
this: ILoadOptionsFunctions,
90+
query?: string,
91+
): Promise<INodeListSearchResult> {
92+
const searchResults = await apiRequest.call(
93+
this,
94+
'GET',
95+
'applications/list',
96+
{},
97+
{
98+
query,
9699
withContainerSize: false
97-
},
98-
);
99-
console.log(searchResults);
100-
return {
101-
results: searchResults.data.map((b: LowcoderAppType) => ({
102-
name: `${b.name} (${b.applicationType == 2 ? "Module" : "App"})`,
103-
value: b.applicationId,
104-
})),
105-
};
106-
},
107-
},
108-
};
100+
},
101+
);
102+
console.log(searchResults);
103+
return {
104+
results: searchResults.data.map((b: LowcoderAppType) => ({
105+
name: `${b.name} (${b.applicationType == 2 ? "Module" : "App"})`,
106+
value: b.applicationId,
107+
})),
108+
};
109+
},
110+
},
111+
};
109112

110113
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
111-
const options = this.getNodeParameter('options', {}) as {
112-
binaryData: boolean;
113-
ignoreBots: boolean;
114-
rawBody: Buffer;
115-
responseData?: string;
116-
};
117-
const req = this.getRequestObject();
118-
const resp = this.getResponseObject();
114+
const options = this.getNodeParameter('options', {}) as {
115+
binaryData: boolean;
116+
ignoreBots: boolean;
117+
rawBody: Buffer;
118+
responseData?: string;
119+
responseCode?: number;
120+
};
121+
const req = this.getRequestObject();
122+
const resp = this.getResponseObject();
119123

120-
try {
121-
if (options.ignoreBots && isbot(req.headers['user-agent'])) {
122-
throw new NodeApiError(this.getNode(), {}, { message: 'Authorization data is wrong!' });
124+
try {
125+
if (options.ignoreBots && isbot(req.headers['user-agent'])) {
126+
throw new NodeApiError(this.getNode(), {}, { message: 'Authorization data is wrong!' });
123127
}
124-
} catch (error) {
125-
resp.writeHead(error.responseCode, { 'WWW-Authenticate': 'Basic realm="Webhook"' });
128+
} catch (error) {
129+
resp.writeHead(error.responseCode || 401, { 'WWW-Authenticate': 'Basic realm="Webhook"' });
126130
resp.end(error.message);
127131
return { noWebhookResponse: true };
128-
}
129-
const body = typeof req.body != 'undefined' ? req.body : {};
130-
const returnItem: INodeExecutionData = {
131-
binary: {},
132-
json: {
133-
headers: req.headers,
134-
params: req.params,
135-
query: req.query,
136-
body: body,
137-
},
138-
};
139-
return { workflowData: [[returnItem]] };
140-
}
132+
}
141133

142-
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
134+
const type = req.query.type;
135+
if (type === 'resume') {
136+
// Resume workflow as before
137+
const body = typeof req.body != 'undefined' ? req.body : {};
138+
const returnItem: INodeExecutionData = {
139+
binary: {},
140+
json: {
141+
headers: req.headers,
142+
params: req.params,
143+
query: req.query,
144+
body: body,
145+
},
146+
};
147+
const responseCode = options.responseCode || 200;
148+
resp.statusCode = responseCode;
149+
return { workflowData: [[returnItem]] };
150+
} else {
151+
// Return input data, and don't resume
152+
const staticData = this.getWorkflowStaticData('node');
153+
const previousData = staticData.previousNodeData || [];
154+
resp.statusCode = 200;
155+
resp.setHeader('Content-Type', 'application/json');
156+
resp.end(JSON.stringify({ message: 'Static response: workflow not resumed', type, previousData }));
157+
return { noWebhookResponse: true };
158+
}
159+
}
143160

161+
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
144162
let waitTill = new Date(WAIT_TIME_UNLIMITED);
145-
163+
const staticData = this.getWorkflowStaticData('node');
164+
staticData.previousNodeData = this.getInputData().map(item => item.json);
146165
await this.putExecutionToWait(waitTill);
147-
return [this.getInputData()];
148-
}
166+
return [this.getInputData()];
167+
}
149168
}

0 commit comments

Comments
 (0)