n8n-nodes-zalo-custom 1.0.0

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.
@@ -0,0 +1,420 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZaloCommunication = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const ZaloNodeProperties_1 = require("../shared/ZaloNodeProperties"); // eslint-disable-line n8n-nodes-base/node-class-description-icon-not-svg
6
+ const zalo_helper_1 = require("../utils/zalo.helper");
7
+ const ZaloCommunicationDescription_1 = require("./ZaloCommunicationDescription");
8
+ const zca_js_1 = require("zca-js");
9
+
10
+ let api;
11
+
12
+ class ZaloCommunication {
13
+ constructor() {
14
+ this.description = {
15
+ displayName: 'Zalo Communication',
16
+ name: 'zaloCommunication',
17
+ icon: 'file:../shared/zalo.svg',
18
+ group: ['Zalo'],
19
+ version: 1,
20
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
21
+ description: 'Quản lý Sticker, Bình chọn và Thẻ trên Zalo',
22
+ defaults: {
23
+ name: 'Zalo Communication',
24
+ },
25
+ inputs: ['main'],
26
+ outputs: ['main'],
27
+ credentials: [...ZaloNodeProperties_1.zaloApiCredential],
28
+ properties: [
29
+ ...ZaloNodeProperties_1.zaloSessionProperties,
30
+ ...ZaloCommunicationDescription_1.zaloCommunicationOperations,
31
+ ...ZaloCommunicationDescription_1.zaloCommunicationFields,
32
+ ],
33
+ };
34
+ }
35
+
36
+ async execute() {
37
+ const items = this.getInputData();
38
+ const returnData = [];
39
+ const resource = this.getNodeParameter('resource', 0);
40
+ const operation = this.getNodeParameter('operation', 0);
41
+
42
+ try {
43
+ api = await (0, zalo_helper_1.getZaloApiClient)(this);
44
+ }
45
+ catch (error) {
46
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Zalo login error: ${error.message}`);
47
+ }
48
+ if (!api) {
49
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No API instance found. Please make sure to provide valid credentials.');
50
+ }
51
+
52
+ for (let i = 0; i < items.length; i++) {
53
+ try {
54
+ switch (resource) {
55
+ // --- Logic cho Sticker ---
56
+ case 'sticker':
57
+ switch (operation) {
58
+ case 'getStickers': {
59
+ const name = this.getNodeParameter('name', i);
60
+ const response = await api.getStickers(name);
61
+ returnData.push({
62
+ json: {
63
+ success: true,
64
+ response: response,
65
+ count: Array.isArray(response) ? response.length : 0,
66
+ },
67
+ pairedItem: { item: i },
68
+ });
69
+ break;
70
+ }
71
+ case 'getStickerDetail': {
72
+ const stickerId = this.getNodeParameter('stickerId', i);
73
+ const response = await api.getStickersDetail(parseInt(stickerId));
74
+ returnData.push({
75
+ json: {
76
+ success: true,
77
+ response: response,
78
+ },
79
+ pairedItem: { item: i },
80
+ });
81
+ break;
82
+ }
83
+ case 'searchStickers': {
84
+ const query = this.getNodeParameter('query', i);
85
+ const response = await api.getStickers(query);
86
+ returnData.push({
87
+ json: {
88
+ success: true,
89
+ response: response,
90
+ count: Array.isArray(response) ? response.length : 0,
91
+ query: query,
92
+ },
93
+ pairedItem: { item: i },
94
+ });
95
+ break;
96
+ }
97
+ case 'sendSticker': {
98
+ const stickerId = this.getNodeParameter('stickerId', i);
99
+ const threadId = this.getNodeParameter('threadId', i);
100
+ const threadTypeParam = this.getNodeParameter('threadType', i);
101
+ const stickersDetail = await api.getStickersDetail(parseInt(stickerId));
102
+ if (!stickersDetail || stickersDetail.length === 0) {
103
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Không tìm thấy chi tiết cho sticker ID: ${stickerId}`);
104
+ }
105
+ const stickerToSend = stickersDetail[0];
106
+ const threadType = threadTypeParam === 'Group' ? zca_js_1.ThreadType.Group : zca_js_1.ThreadType.User;
107
+ const response = await api.sendSticker(stickerToSend, threadId, threadType);
108
+ returnData.push({
109
+ json: {
110
+ success: true,
111
+ response: {
112
+ msgId: response.msgId,
113
+ stickerId: stickerToSend.id,
114
+ threadId: threadId,
115
+ threadType: threadTypeParam,
116
+ },
117
+ },
118
+ pairedItem: { item: i },
119
+ });
120
+ break;
121
+ }
122
+ }
123
+ break;
124
+
125
+ // --- Logic cho Poll ---
126
+ case 'poll':
127
+ switch (operation) {
128
+ case 'createPoll': {
129
+ const groupId = this.getNodeParameter('groupId', i);
130
+ const question = this.getNodeParameter('question', i);
131
+ const optionInputType = this.getNodeParameter('optionInputType', i, 'list');
132
+ let options = [];
133
+ if (optionInputType === 'list') {
134
+ try {
135
+ const pollOptionsCollection = this.getNodeParameter('pollOptionsCollection', i, { options: [] });
136
+ if ((pollOptionsCollection === null || pollOptionsCollection === void 0 ? void 0 : pollOptionsCollection.options) && Array.isArray(pollOptionsCollection.options)) {
137
+ options = pollOptionsCollection.options
138
+ .map(item => ((item === null || item === void 0 ? void 0 : item.option) || '').trim())
139
+ .filter(option => option !== '');
140
+ }
141
+ }
142
+ catch (error) {
143
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Lỗi xử lý các lựa chọn: ' + (error.message || 'Lỗi không xác định'));
144
+ }
145
+ }
146
+ else if (optionInputType === 'text') {
147
+ const optionsString = this.getNodeParameter('optionsString', i, '');
148
+ if (optionsString && optionsString.trim() !== '') {
149
+ options = optionsString.split(',')
150
+ .map(option => option.trim())
151
+ .filter(option => option !== '');
152
+ }
153
+ }
154
+ if (!options || options.length === 0) {
155
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Vui lòng nhập ít nhất một lựa chọn cho bình chọn', { itemIndex: i });
156
+ }
157
+ const expiredTime = this.getNodeParameter('expiredTime', i, null) !== null ? new Date(this.getNodeParameter('expiredTime', i)).getTime() || 0 : 0;
158
+ const pinAct = this.getNodeParameter('pinAct', i, false);
159
+ const allowMultiChoices = this.getNodeParameter('allowMultiChoices', i, true);
160
+ const allowAddNewOption = this.getNodeParameter('allowAddNewOption', i, true);
161
+ const hideVotePreview = this.getNodeParameter('hideVotePreview', i, false);
162
+ const isAnonymous = this.getNodeParameter('isAnonymous', i, false);
163
+ const createPollData = {
164
+ question: question,
165
+ options: options,
166
+ expiredTime: expiredTime,
167
+ pinAct: pinAct,
168
+ allowMultiChoices: allowMultiChoices,
169
+ allowAddNewOption: allowAddNewOption,
170
+ hideVotePreview: hideVotePreview,
171
+ isAnonymous: isAnonymous
172
+ };
173
+ this.logger.info(`Create poll with parameters: ${JSON.stringify(createPollData)}`);
174
+ if (!api) {
175
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Zalo API not initialized', { itemIndex: i });
176
+ }
177
+ const response = await api.createPoll(createPollData, groupId);
178
+ this.logger.info('Create poll successfully', { groupId, question });
179
+ returnData.push({
180
+ json: {
181
+ success: true,
182
+ response,
183
+ groupId,
184
+ createPollData,
185
+ },
186
+ });
187
+ break;
188
+ }
189
+ case 'getPoll': {
190
+ const poll_id = this.getNodeParameter('poll_id', i);
191
+ this.logger.info(`Get poll with parameters: ${JSON.stringify(poll_id)}`);
192
+ if (!api) {
193
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Zalo API not initialized', { itemIndex: i });
194
+ }
195
+ const response = await api.getPollDetail(poll_id);
196
+ this.logger.info('Get poll successfully', { response });
197
+ returnData.push({
198
+ json: {
199
+ success: true,
200
+ response,
201
+ poll_id,
202
+ },
203
+ });
204
+ break;
205
+ }
206
+ case 'lockPoll': {
207
+ const poll_id = this.getNodeParameter('poll_id', i);
208
+ this.logger.info(`Lock poll with parameters: ${JSON.stringify(poll_id)}`);
209
+ if (!api) {
210
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Zalo API not initialized', { itemIndex: i });
211
+ }
212
+ const response = await api.lockPoll(poll_id);
213
+ this.logger.info('Lock poll successfully', { response });
214
+ returnData.push({
215
+ json: {
216
+ success: true,
217
+ response,
218
+ poll_id,
219
+ },
220
+ });
221
+ break;
222
+ }
223
+ }
224
+ break;
225
+
226
+ // --- Logic cho Tag ---
227
+ case 'tag':
228
+ switch (operation) {
229
+ case 'list': {
230
+ const response = await api.getLabels();
231
+ returnData.push({
232
+ json: {
233
+ success: true,
234
+ response: response,
235
+ },
236
+ pairedItem: { item: i },
237
+ });
238
+ break;
239
+ }
240
+ case 'create': {
241
+ const labelName = this.getNodeParameter('labelName', i);
242
+ const labelColor = this.getNodeParameter('labelColor', i);
243
+ const labelEmoji = this.getNodeParameter('labelEmoji', i);
244
+ const currentLabels = await api.getLabels();
245
+ const newLabelId = Math.max(...currentLabels.labelData.map(l => l.id), 0) + 1;
246
+ const newLabel = {
247
+ id: newLabelId,
248
+ text: labelName,
249
+ textKey: labelName.toLowerCase().replace(/\s+/g, '_'),
250
+ conversations: [],
251
+ color: labelColor,
252
+ offset: 0,
253
+ emoji: labelEmoji,
254
+ createTime: Date.now()
255
+ };
256
+ const updatedLabels = [...currentLabels.labelData, newLabel];
257
+ const response = await api.updateLabels({
258
+ labelData: updatedLabels,
259
+ version: currentLabels.version
260
+ });
261
+ returnData.push({
262
+ json: {
263
+ success: true,
264
+ newLabel: newLabel,
265
+ response: response
266
+ },
267
+ pairedItem: { item: i },
268
+ });
269
+ break;
270
+ }
271
+ case 'update': {
272
+ const labelId = this.getNodeParameter('labelId', i);
273
+ const labelColor = this.getNodeParameter('labelColor', i);
274
+ const labelEmoji = this.getNodeParameter('labelEmoji', i);
275
+ const currentLabels = await api.getLabels();
276
+ const labelIndex = currentLabels.labelData.findIndex(l => l.id === labelId);
277
+ if (labelIndex === -1) {
278
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Không tìm thấy thẻ với ID: ${labelId}`);
279
+ }
280
+ currentLabels.labelData[labelIndex].color = labelColor;
281
+ currentLabels.labelData[labelIndex].emoji = labelEmoji;
282
+ const response = await api.updateLabels({
283
+ labelData: currentLabels.labelData,
284
+ version: currentLabels.version
285
+ });
286
+ returnData.push({
287
+ json: {
288
+ success: true,
289
+ updatedLabel: currentLabels.labelData[labelIndex],
290
+ response: response
291
+ },
292
+ pairedItem: { item: i },
293
+ });
294
+ break;
295
+ }
296
+ case 'tagUser': {
297
+ const labelId = this.getNodeParameter('labelId', i);
298
+ const userId = this.getNodeParameter('userId', i);
299
+ const currentLabels = await api.getLabels();
300
+ const labelIndex = currentLabels.labelData.findIndex(l => l.id === labelId);
301
+ if (labelIndex === -1) {
302
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Không tìm thấy thẻ với ID: ${labelId}`);
303
+ }
304
+ const userConversationId = `u${userId}`;
305
+ if (!currentLabels.labelData[labelIndex].conversations.includes(userConversationId)) {
306
+ currentLabels.labelData[labelIndex].conversations.push(userConversationId);
307
+ }
308
+ const response = await api.updateLabels({
309
+ labelData: currentLabels.labelData,
310
+ version: currentLabels.version
311
+ });
312
+ returnData.push({
313
+ json: {
314
+ success: true,
315
+ updatedLabel: currentLabels.labelData[labelIndex],
316
+ response: response
317
+ },
318
+ pairedItem: { item: i },
319
+ });
320
+ break;
321
+ }
322
+ case 'tagGroup': {
323
+ const labelId = this.getNodeParameter('labelId', i);
324
+ const groupId = this.getNodeParameter('groupId', i);
325
+ const currentLabels = await api.getLabels();
326
+ const labelIndex = currentLabels.labelData.findIndex(l => l.id === labelId);
327
+ if (labelIndex === -1) {
328
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Không tìm thấy thẻ với ID: ${labelId}`);
329
+ }
330
+ const groupConversationId = `g${groupId}`;
331
+ if (!currentLabels.labelData[labelIndex].conversations.includes(groupConversationId)) {
332
+ currentLabels.labelData[labelIndex].conversations.push(groupConversationId);
333
+ }
334
+ const response = await api.updateLabels({
335
+ labelData: currentLabels.labelData,
336
+ version: currentLabels.version
337
+ });
338
+ returnData.push({
339
+ json: {
340
+ success: true,
341
+ updatedLabel: currentLabels.labelData[labelIndex],
342
+ response: response
343
+ },
344
+ pairedItem: { item: i },
345
+ });
346
+ break;
347
+ }
348
+ case 'untagUser': {
349
+ const labelId = this.getNodeParameter('labelId', i);
350
+ const userId = this.getNodeParameter('userId', i);
351
+ const currentLabels = await api.getLabels();
352
+ const labelIndex = currentLabels.labelData.findIndex(l => l.id === labelId);
353
+ if (labelIndex === -1) {
354
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Không tìm thấy thẻ với ID: ${labelId}`);
355
+ }
356
+ const userConversationId = `u${userId}`;
357
+ currentLabels.labelData[labelIndex].conversations =
358
+ currentLabels.labelData[labelIndex].conversations.filter(id => id !== userConversationId);
359
+ const response = await api.updateLabels({
360
+ labelData: currentLabels.labelData,
361
+ version: currentLabels.version
362
+ });
363
+ returnData.push({
364
+ json: {
365
+ success: true,
366
+ updatedLabel: currentLabels.labelData[labelIndex],
367
+ response: response
368
+ },
369
+ pairedItem: { item: i },
370
+ });
371
+ break;
372
+ }
373
+ case 'untagGroup': {
374
+ const labelId = this.getNodeParameter('labelId', i);
375
+ const groupId = this.getNodeParameter('groupId', i);
376
+ const currentLabels = await api.getLabels();
377
+ const labelIndex = currentLabels.labelData.findIndex(l => l.id === labelId);
378
+ if (labelIndex === -1) {
379
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Không tìm thấy thẻ với ID: ${labelId}`);
380
+ }
381
+ const groupConversationId = `g${groupId}`;
382
+ currentLabels.labelData[labelIndex].conversations =
383
+ currentLabels.labelData[labelIndex].conversations.filter(id => id !== groupConversationId);
384
+ const response = await api.updateLabels({
385
+ labelData: currentLabels.labelData,
386
+ version: currentLabels.version
387
+ });
388
+ returnData.push({
389
+ json: {
390
+ success: true,
391
+ updatedLabel: currentLabels.labelData[labelIndex],
392
+ response: response
393
+ },
394
+ pairedItem: { item: i },
395
+ });
396
+ break;
397
+ }
398
+ }
399
+ break;
400
+ }
401
+ } catch (error) {
402
+ if (this.continueOnFail()) {
403
+ returnData.push({
404
+ json: {
405
+ success: false,
406
+ error: error.message,
407
+ pairedItem: {
408
+ item: i,
409
+ },
410
+ },
411
+ });
412
+ continue;
413
+ }
414
+ throw error;
415
+ }
416
+ }
417
+ return [returnData];
418
+ }
419
+ }
420
+ exports.ZaloCommunication = ZaloCommunication;