@learningsuite/n8n-nodes-learningsuite 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.de.md +555 -0
- package/README.md +427 -0
- package/dist/credentials/LearningSuiteApi.credentials.d.ts +10 -0
- package/dist/credentials/LearningSuiteApi.credentials.js +49 -0
- package/dist/credentials/learningsuite.svg +1 -0
- package/dist/nodes/LearningSuite/LearningSuite.node.d.ts +65 -0
- package/dist/nodes/LearningSuite/LearningSuite.node.js +221 -0
- package/dist/nodes/LearningSuite/LearningSuiteTrigger.node.d.ts +66 -0
- package/dist/nodes/LearningSuite/LearningSuiteTrigger.node.js +433 -0
- package/dist/nodes/LearningSuite/descriptions/ai.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/ai.properties.js +141 -0
- package/dist/nodes/LearningSuite/descriptions/apiCall.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/apiCall.properties.js +87 -0
- package/dist/nodes/LearningSuite/descriptions/bundle.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/bundle.properties.js +32 -0
- package/dist/nodes/LearningSuite/descriptions/community.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/community.properties.js +229 -0
- package/dist/nodes/LearningSuite/descriptions/course.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/course.properties.js +248 -0
- package/dist/nodes/LearningSuite/descriptions/customFields.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/customFields.properties.js +452 -0
- package/dist/nodes/LearningSuite/descriptions/group.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/group.properties.js +165 -0
- package/dist/nodes/LearningSuite/descriptions/hub.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/hub.properties.js +167 -0
- package/dist/nodes/LearningSuite/descriptions/member.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/member.properties.js +625 -0
- package/dist/nodes/LearningSuite/descriptions/module.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/module.properties.js +84 -0
- package/dist/nodes/LearningSuite/descriptions/popup.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/popup.properties.js +73 -0
- package/dist/nodes/LearningSuite/descriptions/resource.selector.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/resource.selector.js +87 -0
- package/dist/nodes/LearningSuite/descriptions/role.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/role.properties.js +14 -0
- package/dist/nodes/LearningSuite/descriptions/teamMember.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/teamMember.properties.js +74 -0
- package/dist/nodes/LearningSuite/descriptions/trigger.instant.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/trigger.instant.properties.js +542 -0
- package/dist/nodes/LearningSuite/descriptions/user.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/user.properties.js +135 -0
- package/dist/nodes/LearningSuite/descriptions/webhook.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/webhook.properties.js +672 -0
- package/dist/nodes/LearningSuite/descriptions/webhook.sampleData.properties.d.ts +2 -0
- package/dist/nodes/LearningSuite/descriptions/webhook.sampleData.properties.js +401 -0
- package/dist/nodes/LearningSuite/exec.types.d.ts +5 -0
- package/dist/nodes/LearningSuite/exec.types.js +2 -0
- package/dist/nodes/LearningSuite/execute/ai.handlers.d.ts +4 -0
- package/dist/nodes/LearningSuite/execute/ai.handlers.js +23 -0
- package/dist/nodes/LearningSuite/execute/apiCall.handlers.d.ts +4 -0
- package/dist/nodes/LearningSuite/execute/apiCall.handlers.js +46 -0
- package/dist/nodes/LearningSuite/execute/bundle.handlers.d.ts +5 -0
- package/dist/nodes/LearningSuite/execute/bundle.handlers.js +12 -0
- package/dist/nodes/LearningSuite/execute/community.handlers.d.ts +11 -0
- package/dist/nodes/LearningSuite/execute/community.handlers.js +94 -0
- package/dist/nodes/LearningSuite/execute/course.handlers.d.ts +10 -0
- package/dist/nodes/LearningSuite/execute/course.handlers.js +87 -0
- package/dist/nodes/LearningSuite/execute/customFields.handlers.d.ts +16 -0
- package/dist/nodes/LearningSuite/execute/customFields.handlers.js +342 -0
- package/dist/nodes/LearningSuite/execute/group.handlers.d.ts +15 -0
- package/dist/nodes/LearningSuite/execute/group.handlers.js +99 -0
- package/dist/nodes/LearningSuite/execute/hub.handlers.d.ts +9 -0
- package/dist/nodes/LearningSuite/execute/hub.handlers.js +65 -0
- package/dist/nodes/LearningSuite/execute/member.handlers.d.ts +23 -0
- package/dist/nodes/LearningSuite/execute/member.handlers.js +244 -0
- package/dist/nodes/LearningSuite/execute/module.handlers.d.ts +6 -0
- package/dist/nodes/LearningSuite/execute/module.handlers.js +36 -0
- package/dist/nodes/LearningSuite/execute/popup.handlers.d.ts +7 -0
- package/dist/nodes/LearningSuite/execute/popup.handlers.js +24 -0
- package/dist/nodes/LearningSuite/execute/registry.d.ts +2 -0
- package/dist/nodes/LearningSuite/execute/registry.js +35 -0
- package/dist/nodes/LearningSuite/execute/role.handlers.d.ts +4 -0
- package/dist/nodes/LearningSuite/execute/role.handlers.js +6 -0
- package/dist/nodes/LearningSuite/execute/teamMember.handlers.d.ts +6 -0
- package/dist/nodes/LearningSuite/execute/teamMember.handlers.js +21 -0
- package/dist/nodes/LearningSuite/execute/user.handlers.d.ts +4 -0
- package/dist/nodes/LearningSuite/execute/user.handlers.js +32 -0
- package/dist/nodes/LearningSuite/execute/webhook.handlers.d.ts +9 -0
- package/dist/nodes/LearningSuite/execute/webhook.handlers.js +306 -0
- package/dist/nodes/LearningSuite/icons/learningsuite-icon-dark.svg +1 -0
- package/dist/nodes/LearningSuite/icons/learningsuite-icon-light.svg +1 -0
- package/dist/nodes/LearningSuite/index.d.ts +1 -0
- package/dist/nodes/LearningSuite/index.js +17 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/apiCall.loadOptions.d.ts +1 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/apiCall.loadOptions.js +2 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/bundle.loadOptions.d.ts +2 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/bundle.loadOptions.js +7 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/common.d.ts +7 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/common.js +22 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/community.loadOptions.d.ts +5 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/community.loadOptions.js +80 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/course.loadOptions.d.ts +5 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/course.loadOptions.js +58 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/customFields.loadOptions.d.ts +12 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/customFields.loadOptions.js +55 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/group.loadOptions.d.ts +2 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/group.loadOptions.js +7 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/hub.loadOptions.d.ts +3 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/hub.loadOptions.js +11 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/member.loadOptions.d.ts +9 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/member.loadOptions.js +27 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/module.loadOptions.d.ts +5 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/module.loadOptions.js +29 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/popup.loadOptions.d.ts +2 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/popup.loadOptions.js +7 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/role.loadOptions.d.ts +2 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/role.loadOptions.js +7 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/teamMember.loadOptions.d.ts +9 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/teamMember.loadOptions.js +35 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/webhook.loadOptions.d.ts +6 -0
- package/dist/nodes/LearningSuite/methods/loadOptions/webhook.loadOptions.js +18 -0
- package/dist/nodes/LearningSuite/methods/resourceMappers/customFields.resourceMapper.d.ts +2 -0
- package/dist/nodes/LearningSuite/methods/resourceMappers/customFields.resourceMapper.js +35 -0
- package/dist/nodes/LearningSuite/methods/resourceMappers/hub.resourceMapper.d.ts +2 -0
- package/dist/nodes/LearningSuite/methods/resourceMappers/hub.resourceMapper.js +34 -0
- package/dist/nodes/LearningSuite/shared/customFields.helpers.d.ts +4 -0
- package/dist/nodes/LearningSuite/shared/customFields.helpers.js +56 -0
- package/dist/nodes/LearningSuite/shared/customFields.shared.d.ts +42 -0
- package/dist/nodes/LearningSuite/shared/customFields.shared.js +101 -0
- package/dist/nodes/LearningSuite/shared/customFields.upload.d.ts +13 -0
- package/dist/nodes/LearningSuite/shared/customFields.upload.js +198 -0
- package/dist/nodes/LearningSuite/shared/errors.d.ts +1 -0
- package/dist/nodes/LearningSuite/shared/errors.js +16 -0
- package/dist/nodes/LearningSuite/shared/getScopedParam.d.ts +2 -0
- package/dist/nodes/LearningSuite/shared/getScopedParam.js +39 -0
- package/dist/nodes/LearningSuite/shared/index.d.ts +4 -0
- package/dist/nodes/LearningSuite/shared/index.js +20 -0
- package/dist/nodes/LearningSuite/shared/parsing.d.ts +1 -0
- package/dist/nodes/LearningSuite/shared/parsing.js +15 -0
- package/dist/nodes/LearningSuite/shared/request.d.ts +13 -0
- package/dist/nodes/LearningSuite/shared/request.js +53 -0
- package/dist/nodes/LearningSuitePollingTrigger/LearningSuitePollingTrigger.node.d.ts +11 -0
- package/dist/nodes/LearningSuitePollingTrigger/LearningSuitePollingTrigger.node.js +278 -0
- package/dist/nodes/LearningSuitePollingTrigger/descriptions/trigger.polling.properties.d.ts +2 -0
- package/dist/nodes/LearningSuitePollingTrigger/descriptions/trigger.polling.properties.js +193 -0
- package/package.json +65 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uploadFilesFromBinaryProperties = uploadFilesFromBinaryProperties;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const request_1 = require("./request");
|
|
6
|
+
function resolveFileType(fieldType) {
|
|
7
|
+
return fieldType;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates a file slot in the LearningSuite custom-field store for a given user.
|
|
11
|
+
* Returns the fileId and the uploadSpec describing how/where to upload.
|
|
12
|
+
*/
|
|
13
|
+
async function createFileSlot(ctx, userId, isVideo) {
|
|
14
|
+
const response = (await request_1.lsRequest.call(ctx, 'POST', `/custom-fields/store/${userId}/files`, {
|
|
15
|
+
body: { isVideo },
|
|
16
|
+
}));
|
|
17
|
+
const fileId = response.fileId;
|
|
18
|
+
const uploadSpec = response.uploadSpec;
|
|
19
|
+
if (!fileId || !uploadSpec) {
|
|
20
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Upload spec or fileId missing in the response from create file API');
|
|
21
|
+
}
|
|
22
|
+
return { fileId, uploadSpec };
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Uploads a file buffer via a simple HTTP PUT (for uploadSpec.type === 'storage').
|
|
26
|
+
*/
|
|
27
|
+
async function uploadViaStorage(ctx, uploadSpec, buffer, contentType) {
|
|
28
|
+
await ctx.helpers.httpRequest({
|
|
29
|
+
method: 'PUT',
|
|
30
|
+
url: uploadSpec.uploadUrl,
|
|
31
|
+
headers: {
|
|
32
|
+
...uploadSpec.requestHeaders,
|
|
33
|
+
'Content-Type': contentType,
|
|
34
|
+
'Content-Length': String(buffer.length),
|
|
35
|
+
},
|
|
36
|
+
body: buffer,
|
|
37
|
+
json: false,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const TUS_CHUNK_SIZE = 5 * 1024 * 1024;
|
|
41
|
+
const TUS_MAX_RETRIES = 4;
|
|
42
|
+
/**
|
|
43
|
+
* Uploads a file buffer via the tus resumable upload protocol (for videos).
|
|
44
|
+
* 1. POST to create the upload resource (returns Location header)
|
|
45
|
+
* 2. PATCH in chunks until all bytes are uploaded
|
|
46
|
+
*/
|
|
47
|
+
async function uploadViaTus(ctx, uploadSpec, buffer, fileName, contentType) {
|
|
48
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
49
|
+
const metadataHeader = [
|
|
50
|
+
`filename ${Buffer.from(fileName).toString('base64')}`,
|
|
51
|
+
`filetype ${Buffer.from(contentType).toString('base64')}`,
|
|
52
|
+
].join(',');
|
|
53
|
+
const createResponse = await ctx.helpers.httpRequest({
|
|
54
|
+
method: 'POST',
|
|
55
|
+
url: uploadSpec.uploadUrl,
|
|
56
|
+
headers: {
|
|
57
|
+
...uploadSpec.requestHeaders,
|
|
58
|
+
'Tus-Resumable': '1.0.0',
|
|
59
|
+
'Upload-Length': String(buffer.length),
|
|
60
|
+
'Upload-Metadata': metadataHeader,
|
|
61
|
+
'Content-Length': '0',
|
|
62
|
+
},
|
|
63
|
+
body: Buffer.alloc(0),
|
|
64
|
+
json: false,
|
|
65
|
+
returnFullResponse: true,
|
|
66
|
+
});
|
|
67
|
+
const location = (_b = (_a = createResponse.headers) === null || _a === void 0 ? void 0 : _a['location']) !== null && _b !== void 0 ? _b : (_c = createResponse.headers) === null || _c === void 0 ? void 0 : _c['Location'];
|
|
68
|
+
if (!location) {
|
|
69
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'tus creation response missing Location header');
|
|
70
|
+
}
|
|
71
|
+
const uploadUrl = location.startsWith('http')
|
|
72
|
+
? location
|
|
73
|
+
: new URL(location, uploadSpec.uploadUrl).toString();
|
|
74
|
+
let offset = 0;
|
|
75
|
+
while (offset < buffer.length) {
|
|
76
|
+
const chunk = buffer.subarray(offset, Math.min(offset + TUS_CHUNK_SIZE, buffer.length));
|
|
77
|
+
let lastError;
|
|
78
|
+
for (let attempt = 0; attempt <= TUS_MAX_RETRIES; attempt++) {
|
|
79
|
+
try {
|
|
80
|
+
const patchResponse = await ctx.helpers.httpRequest({
|
|
81
|
+
method: 'PATCH',
|
|
82
|
+
url: uploadUrl,
|
|
83
|
+
headers: {
|
|
84
|
+
...uploadSpec.requestHeaders,
|
|
85
|
+
'Tus-Resumable': '1.0.0',
|
|
86
|
+
'Upload-Offset': String(offset),
|
|
87
|
+
'Content-Type': 'application/offset+octet-stream',
|
|
88
|
+
'Content-Length': String(chunk.length),
|
|
89
|
+
},
|
|
90
|
+
body: chunk,
|
|
91
|
+
json: false,
|
|
92
|
+
returnFullResponse: true,
|
|
93
|
+
});
|
|
94
|
+
const newOffset = parseInt((_g = (_e = (_d = patchResponse.headers) === null || _d === void 0 ? void 0 : _d['upload-offset']) !== null && _e !== void 0 ? _e : (_f = patchResponse.headers) === null || _f === void 0 ? void 0 : _f['Upload-Offset']) !== null && _g !== void 0 ? _g : '', 10);
|
|
95
|
+
if (isNaN(newOffset)) {
|
|
96
|
+
throw new Error('tus PATCH response missing Upload-Offset header');
|
|
97
|
+
}
|
|
98
|
+
offset = newOffset;
|
|
99
|
+
lastError = undefined;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (lastError) {
|
|
107
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `tus upload failed after ${TUS_MAX_RETRIES + 1} attempts: ${lastError.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Builds the file value object to be stored on the custom field,
|
|
113
|
+
* matching the structure expected by the LearningSuite API.
|
|
114
|
+
*/
|
|
115
|
+
function createUploadedFileValue(fileType, fileId, file) {
|
|
116
|
+
switch (fileType) {
|
|
117
|
+
case 'files':
|
|
118
|
+
return {
|
|
119
|
+
fileId,
|
|
120
|
+
mimeType: file.mimeType,
|
|
121
|
+
fileSize: file.fileSize,
|
|
122
|
+
name: file.fileName,
|
|
123
|
+
};
|
|
124
|
+
case 'images':
|
|
125
|
+
return {
|
|
126
|
+
fileId,
|
|
127
|
+
mimeType: file.mimeType,
|
|
128
|
+
fileSize: file.fileSize,
|
|
129
|
+
previewThumb: '',
|
|
130
|
+
dimensions: { width: 0, height: 0 },
|
|
131
|
+
meanColor: '#000000',
|
|
132
|
+
dominantColor: '#000000',
|
|
133
|
+
};
|
|
134
|
+
case 'videos':
|
|
135
|
+
return {
|
|
136
|
+
fileId,
|
|
137
|
+
mimeType: file.mimeType,
|
|
138
|
+
fileSize: file.fileSize,
|
|
139
|
+
thumbnailFileId: undefined,
|
|
140
|
+
aspectRatio: undefined,
|
|
141
|
+
duration: undefined,
|
|
142
|
+
};
|
|
143
|
+
case 'audios':
|
|
144
|
+
return {
|
|
145
|
+
fileId,
|
|
146
|
+
mimeType: file.mimeType,
|
|
147
|
+
fileSize: file.fileSize,
|
|
148
|
+
duration: undefined,
|
|
149
|
+
};
|
|
150
|
+
default:
|
|
151
|
+
throw new Error(`Unsupported custom field file type: ${fileType}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Full upload flow for a single binary property:
|
|
156
|
+
* 1. Create file slot via LS API
|
|
157
|
+
* 2. Upload the binary data via HTTP PUT
|
|
158
|
+
* 3. Return the file value object to store on the custom field
|
|
159
|
+
*/
|
|
160
|
+
async function uploadSingleFile(ctx, itemIndex, userId, binaryPropertyName, fieldType, fileNameOverride) {
|
|
161
|
+
const binaryData = ctx.helpers.assertBinaryData(itemIndex, binaryPropertyName);
|
|
162
|
+
const buffer = await ctx.helpers.getBinaryDataBuffer(itemIndex, binaryPropertyName);
|
|
163
|
+
const fileType = resolveFileType(fieldType);
|
|
164
|
+
const isVideo = fileType === 'videos';
|
|
165
|
+
const mimeType = binaryData.mimeType || 'application/octet-stream';
|
|
166
|
+
const fileName = fileNameOverride || binaryData.fileName || 'upload';
|
|
167
|
+
const { fileId, uploadSpec } = await createFileSlot(ctx, userId, isVideo);
|
|
168
|
+
if (uploadSpec.type === 'storage') {
|
|
169
|
+
await uploadViaStorage(ctx, uploadSpec, buffer, mimeType);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
await uploadViaTus(ctx, uploadSpec, buffer, fileName, mimeType);
|
|
173
|
+
}
|
|
174
|
+
return createUploadedFileValue(fileType, fileId, {
|
|
175
|
+
mimeType,
|
|
176
|
+
fileName,
|
|
177
|
+
fileSize: buffer.length,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Uploads one or more binary properties and returns the array of file value objects.
|
|
182
|
+
* The binaryPropertyNames parameter can be a comma-separated list (e.g. "data,file1,file2").
|
|
183
|
+
*/
|
|
184
|
+
async function uploadFilesFromBinaryProperties(ctx, itemIndex, userId, binaryPropertyNames, fieldType, fileNameOverride) {
|
|
185
|
+
const names = binaryPropertyNames
|
|
186
|
+
.split(',')
|
|
187
|
+
.map((n) => n.trim())
|
|
188
|
+
.filter((n) => n.length > 0);
|
|
189
|
+
if (names.length === 0) {
|
|
190
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'No binary property name provided for file upload.');
|
|
191
|
+
}
|
|
192
|
+
const results = [];
|
|
193
|
+
for (const name of names) {
|
|
194
|
+
const value = await uploadSingleFile(ctx, itemIndex, userId, name, fieldType, fileNameOverride);
|
|
195
|
+
results.push(value);
|
|
196
|
+
}
|
|
197
|
+
return results;
|
|
198
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getHttpCode(error: unknown): number | null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getHttpCode = getHttpCode;
|
|
4
|
+
function getHttpCode(error) {
|
|
5
|
+
var _a, _b, _c, _d, _e;
|
|
6
|
+
if (error == null || typeof error !== 'object')
|
|
7
|
+
return null;
|
|
8
|
+
const e = error;
|
|
9
|
+
const response = typeof e.response === 'object' && e.response !== null ? e.response : undefined;
|
|
10
|
+
const errorDetails = typeof e.errorDetails === 'object' && e.errorDetails !== null
|
|
11
|
+
? e.errorDetails
|
|
12
|
+
: undefined;
|
|
13
|
+
const raw = (_e = (_d = (_c = (_b = (_a = e.httpCode) !== null && _a !== void 0 ? _a : e.statusCode) !== null && _b !== void 0 ? _b : e.status) !== null && _c !== void 0 ? _c : response === null || response === void 0 ? void 0 : response.statusCode) !== null && _d !== void 0 ? _d : response === null || response === void 0 ? void 0 : response.status) !== null && _e !== void 0 ? _e : errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.httpCode;
|
|
14
|
+
const code = Number(raw);
|
|
15
|
+
return Number.isFinite(code) ? code : null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getScopedParam = getScopedParam;
|
|
4
|
+
function getScopedParam(paramName) {
|
|
5
|
+
var _a;
|
|
6
|
+
try {
|
|
7
|
+
const local = this.getCurrentNodeParameter(paramName);
|
|
8
|
+
if (typeof local === 'string' && local)
|
|
9
|
+
return local;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
// Fall through to broader parameter lookups when the local field is unavailable.
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const rootVal = this.getNodeParameter(paramName, 0, undefined);
|
|
16
|
+
if (typeof rootVal === 'string' && rootVal)
|
|
17
|
+
return rootVal;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Some loadOptions contexts do not expose root-level parameters directly.
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const params = ((_a = this.getNode().parameters) !== null && _a !== void 0 ? _a : {});
|
|
24
|
+
for (const val of Object.values(params)) {
|
|
25
|
+
if (val && typeof val === 'object') {
|
|
26
|
+
const obj = val;
|
|
27
|
+
if (Object.prototype.hasOwnProperty.call(obj, paramName)) {
|
|
28
|
+
const v = obj[paramName];
|
|
29
|
+
if (typeof v === 'string' && v)
|
|
30
|
+
return v;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// If parameter inspection fails, return undefined and let the caller handle it.
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./request"), exports);
|
|
18
|
+
__exportStar(require("./parsing"), exports);
|
|
19
|
+
__exportStar(require("./errors"), exports);
|
|
20
|
+
__exportStar(require("./customFields.upload"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toIdArray(input: unknown): string[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toIdArray = toIdArray;
|
|
4
|
+
function toIdArray(input) {
|
|
5
|
+
if (Array.isArray(input))
|
|
6
|
+
return input.map((v) => String(v).trim()).filter(Boolean);
|
|
7
|
+
if (typeof input === 'string')
|
|
8
|
+
return input
|
|
9
|
+
.split(',')
|
|
10
|
+
.map((v) => v.trim())
|
|
11
|
+
.filter(Boolean);
|
|
12
|
+
if (input == null)
|
|
13
|
+
return [];
|
|
14
|
+
return [String(input).trim()].filter(Boolean);
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type IDataObject, type IHttpRequestOptions, type IExecuteFunctions, type IHookFunctions, type ILoadOptionsFunctions, type IWebhookFunctions, type ITriggerFunctions, type IPollFunctions } from 'n8n-workflow';
|
|
2
|
+
export type ApiThis = IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions | ITriggerFunctions | IPollFunctions;
|
|
3
|
+
export declare function normalizeEndpoint(endpoint: string): string;
|
|
4
|
+
export declare function lsRequest(this: ApiThis, method: IHttpRequestOptions['method'], endpoint: string, { qs, body }?: {
|
|
5
|
+
qs?: IDataObject;
|
|
6
|
+
body?: IDataObject;
|
|
7
|
+
}): Promise<IDataObject | IDataObject[]>;
|
|
8
|
+
export declare function apiRequest(this: ApiThis, { method, path, qs, body, }: {
|
|
9
|
+
method: IHttpRequestOptions['method'];
|
|
10
|
+
path: string;
|
|
11
|
+
qs?: IDataObject;
|
|
12
|
+
body?: IDataObject;
|
|
13
|
+
}): Promise<IDataObject | IDataObject[]>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeEndpoint = normalizeEndpoint;
|
|
4
|
+
exports.lsRequest = lsRequest;
|
|
5
|
+
exports.apiRequest = apiRequest;
|
|
6
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
7
|
+
function hasRequestWithAuthentication(value) {
|
|
8
|
+
var _a;
|
|
9
|
+
return (typeof value === 'object' && value !== null && typeof ((_a = value.helpers) === null || _a === void 0 ? void 0 : _a.httpRequestWithAuthentication) === 'function');
|
|
10
|
+
}
|
|
11
|
+
function normalizeEndpoint(endpoint) {
|
|
12
|
+
if (!endpoint)
|
|
13
|
+
throw new n8n_workflow_1.ApplicationError('Missing endpoint');
|
|
14
|
+
if (/^https?:\/\//i.test(endpoint)) {
|
|
15
|
+
throw new n8n_workflow_1.ApplicationError('Endpoint must be a relative path (e.g. "/members").');
|
|
16
|
+
}
|
|
17
|
+
return endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
|
18
|
+
}
|
|
19
|
+
async function requestCore({ method, endpoint, qs, body, }) {
|
|
20
|
+
const url = normalizeEndpoint(endpoint);
|
|
21
|
+
const creds = (await this.getCredentials('learningSuiteApi'));
|
|
22
|
+
const baseURL = String(creds.baseUrl || '').trim();
|
|
23
|
+
if (!/^https?:\/\//i.test(baseURL)) {
|
|
24
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid Base URL in credentials');
|
|
25
|
+
}
|
|
26
|
+
const options = {
|
|
27
|
+
method,
|
|
28
|
+
baseURL,
|
|
29
|
+
url,
|
|
30
|
+
json: true,
|
|
31
|
+
};
|
|
32
|
+
if (qs && Object.keys(qs).length)
|
|
33
|
+
options.qs = qs;
|
|
34
|
+
if (body && Object.keys(body).length && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(String(method).toUpperCase())) {
|
|
35
|
+
options.body = body;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
if (!hasRequestWithAuthentication(this))
|
|
39
|
+
throw new n8n_workflow_1.ApplicationError('No HTTP helper available');
|
|
40
|
+
return await this.helpers.httpRequestWithAuthentication.call(this, 'learningSuiteApi', options);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error instanceof n8n_workflow_1.NodeApiError)
|
|
44
|
+
throw error;
|
|
45
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function lsRequest(method, endpoint, { qs, body } = {}) {
|
|
49
|
+
return requestCore.call(this, { method, endpoint, qs, body });
|
|
50
|
+
}
|
|
51
|
+
async function apiRequest({ method, path, qs, body, }) {
|
|
52
|
+
return requestCore.call(this, { method, endpoint: path, qs, body });
|
|
53
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { INodeType, INodeTypeDescription, type IPollFunctions, type INodeExecutionData } from 'n8n-workflow';
|
|
2
|
+
import * as loCommunity from '../LearningSuite/methods/loadOptions/community.loadOptions';
|
|
3
|
+
export declare class LearningSuitePollingTrigger implements INodeType {
|
|
4
|
+
description: INodeTypeDescription;
|
|
5
|
+
methods: {
|
|
6
|
+
loadOptions: {
|
|
7
|
+
community_getAreas: typeof loCommunity.community_getAreas;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LearningSuitePollingTrigger = void 0;
|
|
37
|
+
// n8n-nodes-learningsuite/nodes/LearningSuitePollingTrigger/LearningSuitePollingTrigger.node.ts
|
|
38
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
39
|
+
const request_1 = require("../LearningSuite/shared/request");
|
|
40
|
+
const trigger_polling_properties_1 = require("./descriptions/trigger.polling.properties");
|
|
41
|
+
const loCommunity = __importStar(require("../LearningSuite/methods/loadOptions/community.loadOptions"));
|
|
42
|
+
const TIMELINE_EVENTS = new Set([
|
|
43
|
+
'bundle.created',
|
|
44
|
+
'customField.card.created',
|
|
45
|
+
'customPopup.created',
|
|
46
|
+
'group.created',
|
|
47
|
+
'community.area.created',
|
|
48
|
+
'community.badge.created',
|
|
49
|
+
'community.forum.created',
|
|
50
|
+
'member.created',
|
|
51
|
+
'teamMember.created',
|
|
52
|
+
'teamMember.updated',
|
|
53
|
+
]);
|
|
54
|
+
function asPollableRecord(value) {
|
|
55
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
function extractItems(res) {
|
|
61
|
+
if (Array.isArray(res))
|
|
62
|
+
return res.map(asPollableRecord).filter((item) => item !== null);
|
|
63
|
+
if (typeof res === 'object' && res !== null) {
|
|
64
|
+
const paginated = res;
|
|
65
|
+
if (Array.isArray(paginated.items))
|
|
66
|
+
return paginated.items;
|
|
67
|
+
if (Array.isArray(paginated.data))
|
|
68
|
+
return paginated.data;
|
|
69
|
+
}
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
function isDateComparable(value) {
|
|
73
|
+
return typeof value === 'string' || typeof value === 'number' || value instanceof Date;
|
|
74
|
+
}
|
|
75
|
+
async function fetchInactiveMembers(self, { days, includeNever, limit = 100, maxPages = 50, }) {
|
|
76
|
+
let offset = 0;
|
|
77
|
+
const out = [];
|
|
78
|
+
for (let page = 0; page < maxPages; page++) {
|
|
79
|
+
const qs = {
|
|
80
|
+
limit,
|
|
81
|
+
offset,
|
|
82
|
+
days_not_logged_in_gte: days,
|
|
83
|
+
include_never_logged_in: includeNever,
|
|
84
|
+
};
|
|
85
|
+
const res = await request_1.apiRequest.call(self, {
|
|
86
|
+
method: 'GET',
|
|
87
|
+
path: '/members',
|
|
88
|
+
qs,
|
|
89
|
+
});
|
|
90
|
+
const items = extractItems(res);
|
|
91
|
+
if (!items.length)
|
|
92
|
+
break;
|
|
93
|
+
out.push(...items);
|
|
94
|
+
if (items.length < limit)
|
|
95
|
+
break;
|
|
96
|
+
offset += limit;
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
async function pollFetchCreatedSince(self, path, sinceIso, { limit = 50, createdKey = 'createdAt', updatedKey = 'updatedAt', compareOn = 'createdAt', qs: extraQs = {}, maxPages = 20, } = {}) {
|
|
101
|
+
var _a, _b, _c;
|
|
102
|
+
let offset = 0;
|
|
103
|
+
const out = [];
|
|
104
|
+
const seenIds = new Set();
|
|
105
|
+
const sinceTs = new Date(sinceIso).getTime();
|
|
106
|
+
for (let page = 0; page < maxPages; page++) {
|
|
107
|
+
const qs = {
|
|
108
|
+
limit,
|
|
109
|
+
offset,
|
|
110
|
+
...extraQs,
|
|
111
|
+
};
|
|
112
|
+
const res = await request_1.apiRequest.call(self, {
|
|
113
|
+
method: 'GET',
|
|
114
|
+
path,
|
|
115
|
+
qs,
|
|
116
|
+
});
|
|
117
|
+
const rows = extractItems(res);
|
|
118
|
+
if (!rows.length)
|
|
119
|
+
break;
|
|
120
|
+
for (const row of rows) {
|
|
121
|
+
const id = String((_a = row === null || row === void 0 ? void 0 : row.id) !== null && _a !== void 0 ? _a : '');
|
|
122
|
+
if (!id || seenIds.has(id))
|
|
123
|
+
continue;
|
|
124
|
+
seenIds.add(id);
|
|
125
|
+
const ts = compareOn === 'createdAt' ? ((_b = row === null || row === void 0 ? void 0 : row[createdKey]) !== null && _b !== void 0 ? _b : row === null || row === void 0 ? void 0 : row[updatedKey]) : ((_c = row === null || row === void 0 ? void 0 : row[updatedKey]) !== null && _c !== void 0 ? _c : row === null || row === void 0 ? void 0 : row[createdKey]);
|
|
126
|
+
if (!isDateComparable(ts)) {
|
|
127
|
+
out.push(row);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (new Date(ts).getTime() > sinceTs) {
|
|
131
|
+
out.push(row);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (rows.length < limit)
|
|
135
|
+
break;
|
|
136
|
+
offset += limit;
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
class LearningSuitePollingTrigger {
|
|
141
|
+
constructor() {
|
|
142
|
+
this.description = {
|
|
143
|
+
displayName: 'LearningSuite Polling Trigger',
|
|
144
|
+
name: 'learningSuitePollingTrigger',
|
|
145
|
+
icon: {
|
|
146
|
+
light: 'file:../LearningSuite/icons/learningsuite-icon-light.svg',
|
|
147
|
+
dark: 'file:../LearningSuite/icons/learningsuite-icon-dark.svg',
|
|
148
|
+
},
|
|
149
|
+
group: ['trigger', 'schedule'],
|
|
150
|
+
version: 1,
|
|
151
|
+
polling: true,
|
|
152
|
+
description: 'Polling Trigger node for LearningSuite API (powered by agentur-systeme.de)',
|
|
153
|
+
subtitle: '={{$parameter["event"]}}',
|
|
154
|
+
defaults: {
|
|
155
|
+
name: 'LearningSuite Polling Trigger',
|
|
156
|
+
// @ts-expect-error -- description is required by n8n node linting for defaults
|
|
157
|
+
description: 'Polling Trigger node for LearningSuite API (powered by agentur-systeme.de)',
|
|
158
|
+
},
|
|
159
|
+
inputs: [],
|
|
160
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
161
|
+
usableAsTool: true,
|
|
162
|
+
credentials: [{ name: 'learningSuiteApi', required: true }],
|
|
163
|
+
properties: trigger_polling_properties_1.properties,
|
|
164
|
+
};
|
|
165
|
+
this.methods = {
|
|
166
|
+
loadOptions: {
|
|
167
|
+
community_getAreas: loCommunity.community_getAreas,
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async poll() {
|
|
172
|
+
var _a, _b;
|
|
173
|
+
const event = this.getNodeParameter('event', 0);
|
|
174
|
+
const store = this.getWorkflowStaticData('node');
|
|
175
|
+
let items = [];
|
|
176
|
+
if (TIMELINE_EVENTS.has(event)) {
|
|
177
|
+
const cursorMap = store.lastTimeCheckedMap || {};
|
|
178
|
+
const lastIso = cursorMap[event] || new Date(0).toISOString();
|
|
179
|
+
switch (event) {
|
|
180
|
+
case 'bundle.created':
|
|
181
|
+
items = await pollFetchCreatedSince(this, '/bundles', lastIso);
|
|
182
|
+
break;
|
|
183
|
+
case 'customPopup.created':
|
|
184
|
+
items = await pollFetchCreatedSince(this, '/popups', lastIso);
|
|
185
|
+
break;
|
|
186
|
+
case 'customField.card.created':
|
|
187
|
+
items = await pollFetchCreatedSince(this, '/custom-fields/cards', lastIso, {
|
|
188
|
+
limit: 100,
|
|
189
|
+
});
|
|
190
|
+
break;
|
|
191
|
+
case 'group.created':
|
|
192
|
+
items = await pollFetchCreatedSince(this, '/groups', lastIso, {
|
|
193
|
+
qs: {
|
|
194
|
+
includeUsers: false,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
break;
|
|
198
|
+
case 'community.area.created':
|
|
199
|
+
items = await pollFetchCreatedSince(this, '/community/areas', lastIso);
|
|
200
|
+
break;
|
|
201
|
+
case 'community.badge.created':
|
|
202
|
+
items = await pollFetchCreatedSince(this, '/community/badges', lastIso);
|
|
203
|
+
break;
|
|
204
|
+
case 'community.forum.created': {
|
|
205
|
+
const rawAreaId = this.getNodeParameter('additionalCommunityForum.areaId', 0);
|
|
206
|
+
const areaId = typeof rawAreaId === 'string' ? rawAreaId.trim() : '';
|
|
207
|
+
const all = await pollFetchCreatedSince(this, '/community/forums', lastIso);
|
|
208
|
+
items = areaId ? all.filter((forum) => { var _a; return String((_a = forum.areaId) !== null && _a !== void 0 ? _a : '') === areaId; }) : all;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case 'member.created':
|
|
212
|
+
items = await pollFetchCreatedSince(this, '/members', lastIso);
|
|
213
|
+
break;
|
|
214
|
+
case 'teamMember.created':
|
|
215
|
+
items = await pollFetchCreatedSince(this, '/team-members', lastIso, {
|
|
216
|
+
compareOn: 'createdAt',
|
|
217
|
+
});
|
|
218
|
+
break;
|
|
219
|
+
case 'teamMember.updated':
|
|
220
|
+
items = await pollFetchCreatedSince(this, '/team-members', lastIso, {
|
|
221
|
+
compareOn: 'updatedAt',
|
|
222
|
+
});
|
|
223
|
+
break;
|
|
224
|
+
default:
|
|
225
|
+
items = [];
|
|
226
|
+
}
|
|
227
|
+
if (items.length) {
|
|
228
|
+
cursorMap[event] = new Date().toISOString();
|
|
229
|
+
store.lastTimeCheckedMap = cursorMap;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (event === 'member.inactiveForXDays') {
|
|
233
|
+
const days = this.getNodeParameter('inactiveDays', 0);
|
|
234
|
+
const includeNever = this.getNodeParameter('includeNeverLoggedIn', 0);
|
|
235
|
+
const triggerMode = this.getNodeParameter('inactiveTriggerMode', 0);
|
|
236
|
+
if (!Number.isFinite(days) || days < 1) {
|
|
237
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Inactive days must be greater than 0');
|
|
238
|
+
}
|
|
239
|
+
const limit = this.getNodeParameter('memberLimit', 0);
|
|
240
|
+
const maxPages = this.getNodeParameter('memberMaxPages', 0);
|
|
241
|
+
const all = await fetchInactiveMembers(this, {
|
|
242
|
+
days,
|
|
243
|
+
includeNever,
|
|
244
|
+
limit,
|
|
245
|
+
maxPages,
|
|
246
|
+
});
|
|
247
|
+
if (triggerMode === 'recurring') {
|
|
248
|
+
items = all;
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
const dedupeKey = `inactive_phases_${days}_${includeNever ? '1' : '0'}`;
|
|
252
|
+
const seenPhases = new Set(store[dedupeKey] || []);
|
|
253
|
+
const fresh = [];
|
|
254
|
+
for (const row of all) {
|
|
255
|
+
const userId = String((_a = row.id) !== null && _a !== void 0 ? _a : '');
|
|
256
|
+
if (!userId)
|
|
257
|
+
continue;
|
|
258
|
+
const lastLogin = (_b = row.lastLogin) !== null && _b !== void 0 ? _b : 'never';
|
|
259
|
+
const phaseKey = `${userId}:${lastLogin}`;
|
|
260
|
+
if (this.getMode() === 'manual') {
|
|
261
|
+
fresh.push(row);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (!seenPhases.has(phaseKey)) {
|
|
265
|
+
seenPhases.add(phaseKey);
|
|
266
|
+
fresh.push(row);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
store[dedupeKey] = Array.from(seenPhases).slice(-5000);
|
|
270
|
+
items = fresh;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (!items.length)
|
|
274
|
+
return null;
|
|
275
|
+
return [this.helpers.returnJsonArray(items)];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
exports.LearningSuitePollingTrigger = LearningSuitePollingTrigger;
|