@tiledesk/tiledesk-tybot-connector 0.2.67 → 0.2.68

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/CHANGELOG.md CHANGED
@@ -5,6 +5,10 @@
5
5
  available on:
6
6
  ▶️ https://www.npmjs.com/package/@tiledesk/tiledesk-tybot-connector
7
7
 
8
+ # v0.2.68
9
+ - added flow attributes in replyv2
10
+ - ReplyV2 now "re-forwards" the original message when the "no-match" connector is undefined (behaving exactly like the classic Reply)
11
+
8
12
  # v0.2.67
9
13
  - console.log crash fixed on noinput
10
14
 
package/index.js CHANGED
@@ -369,49 +369,52 @@ router.get('/ext/reserved/parameters/requests/:requestid', async (req, res) => {
369
369
  res.send(parameters);
370
370
  }
371
371
  else {
372
- const RESERVED = [
373
- TiledeskChatbotConst.REQ_CHATBOT_NAME_KEY,
374
- TiledeskChatbotConst.REQ_CHAT_URL,
375
- TiledeskChatbotConst.REQ_CITY_KEY,
376
- TiledeskChatbotConst.REQ_COUNTRY_KEY,
377
- TiledeskChatbotConst.REQ_DEPARTMENT_ID_KEY,
378
- TiledeskChatbotConst.REQ_DEPARTMENT_NAME_KEY,
379
- TiledeskChatbotConst.REQ_END_USER_ID_KEY,
380
- TiledeskChatbotConst.REQ_END_USER_IP_ADDRESS_KEY,
381
- TiledeskChatbotConst.REQ_LAST_MESSAGE_ID_KEY,
382
- TiledeskChatbotConst.REQ_LAST_USER_TEXT_KEY,
383
- TiledeskChatbotConst.REQ_PROJECT_ID_KEY,
384
- TiledeskChatbotConst.REQ_REQUEST_ID_KEY,
385
- TiledeskChatbotConst.REQ_USER_AGENT_KEY,
386
- TiledeskChatbotConst.REQ_USER_LANGUAGE_KEY,
387
- TiledeskChatbotConst.REQ_USER_SOURCE_PAGE_KEY,
388
- TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_TYPE_KEY,
389
- TiledeskChatbotConst.REQ_TRANSCRIPT_KEY,
390
- TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_KEY,
391
- "lastUserImageURL", // image
392
- "lastUserImageName", // image
393
- "lastUserImageWidth", // image
394
- "lastUserImageHeight", // image
395
- "lastUserImageType", // image
396
- "lastUserDocumentURL", // file
397
- "lastUserDocumentName", // file
398
- "lastUserDocumentType", // file
399
- "ticketId",
400
- TiledeskChatbotConst.REQ_CHAT_CHANNEL,
401
- "user_lead_id",
402
- "lastUserText",
403
- TiledeskChatbotConst.REQ_REQUESTER_IS_AUTHENTICATED_KEY
404
- ]
405
- let userParams = {};
406
- if (parameters) {
407
- for (const [key, value] of Object.entries(parameters)) {
408
- // console.log(key, value);
409
- // There is a bug that moves the requestId as a key in request attributes, so: && !key.startsWith("support-group-")
410
- if (!key.startsWith("_") && !RESERVED.some(e => e === key) && !key.startsWith("support-group-")) {
411
- userParams[key] = value;
412
- }
413
- }
414
- }
372
+ // const RESERVED = [
373
+ // TiledeskChatbotConst.REQ_CHATBOT_NAME_KEY,
374
+ // TiledeskChatbotConst.REQ_CHAT_URL,
375
+ // TiledeskChatbotConst.REQ_CITY_KEY,
376
+ // TiledeskChatbotConst.REQ_COUNTRY_KEY,
377
+ // TiledeskChatbotConst.REQ_DEPARTMENT_ID_KEY,
378
+ // TiledeskChatbotConst.REQ_DEPARTMENT_NAME_KEY,
379
+ // TiledeskChatbotConst.REQ_END_USER_ID_KEY,
380
+ // TiledeskChatbotConst.REQ_END_USER_IP_ADDRESS_KEY,
381
+ // TiledeskChatbotConst.REQ_LAST_MESSAGE_ID_KEY,
382
+ // TiledeskChatbotConst.REQ_LAST_USER_TEXT_KEY,
383
+ // TiledeskChatbotConst.REQ_PROJECT_ID_KEY,
384
+ // TiledeskChatbotConst.REQ_REQUEST_ID_KEY,
385
+ // TiledeskChatbotConst.REQ_USER_AGENT_KEY,
386
+ // TiledeskChatbotConst.REQ_USER_LANGUAGE_KEY,
387
+ // TiledeskChatbotConst.REQ_USER_SOURCE_PAGE_KEY,
388
+ // TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_TYPE_KEY,
389
+ // TiledeskChatbotConst.REQ_TRANSCRIPT_KEY,
390
+ // TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_KEY,
391
+ // TiledeskChatbot.REQ_DECODED_JWT_KEY,
392
+ // "lastUserImageURL", // image
393
+ // "lastUserImageName", // image
394
+ // "lastUserImageWidth", // image
395
+ // "lastUserImageHeight", // image
396
+ // "lastUserImageType", // image
397
+ // "lastUserDocumentURL", // file
398
+ // "lastUserDocumentName", // file
399
+ // "lastUserDocumentType", // file
400
+ // "ticketId",
401
+ // TiledeskChatbotConst.REQ_CHAT_CHANNEL,
402
+ // "user_lead_id",
403
+ // "lastUserText",
404
+ // TiledeskChatbotConst.REQ_REQUESTER_IS_AUTHENTICATED_KEY,
405
+ // "userInput"
406
+ // ]
407
+ // let userParams = {};
408
+ // if (parameters) {
409
+ // for (const [key, value] of Object.entries(parameters)) {
410
+ // // console.log(key, value);
411
+ // // There is a bug that moves the requestId as a key in request attributes, so: && !key.startsWith("support-group-")
412
+ // if (!key.startsWith("_") && !RESERVED.some(e => e === key) && !key.startsWith("support-group-")) {
413
+ // userParams[key] = value;
414
+ // }
415
+ // }
416
+ // }
417
+ TiledeskChatbotUtil.userFlowAttributes(parameters);
415
418
  res.send(userParams);
416
419
  }
417
420
  });
@@ -34,8 +34,12 @@ class MockBotsDataSource {
34
34
  * @returns an Array of matches
35
35
  */
36
36
  async getByExactMatch(botId, text) {
37
+ // console.log("text is:", text);
38
+ // console.log("this.data.bots[botId]:", this.data.bots[botId]);
37
39
  const intent_display_name = this.data.bots[botId].questions_intent[text];
40
+ // console.log("intent_display_name:", intent_display_name);
38
41
  if (intent_display_name) {
42
+ // console.log("intent by display name:", this.data.bots[botId].intents[intent_display_name]);
39
43
  return [this.data.bots[botId].intents[intent_display_name]];
40
44
  }
41
45
  return null;
@@ -254,6 +254,7 @@ class TiledeskChatbot {
254
254
  let faqs;
255
255
  try {
256
256
  faqs = await this.botsDataSource.getByExactMatch(this.botId, message.text);
257
+ if (this.log) {console.log("got faq by EXACT MATCH", faqs);}
257
258
  }
258
259
  catch (error) {
259
260
  console.error("An error occurred during exact match:", error);
@@ -352,7 +352,7 @@ class TiledeskChatbotUtil {
352
352
  let buttons = command.message.attributes.attachment.buttons;
353
353
 
354
354
  buttons.forEach(button => {
355
- if (button.type === "action" || button.type === "text") {
355
+ if (button.type === "action") {
356
356
  // console.log("pushing button:", button);
357
357
  all_buttons.push(button);
358
358
  }
@@ -800,6 +800,56 @@ class TiledeskChatbotUtil {
800
800
  return isValid;
801
801
  }
802
802
 
803
+ static userFlowAttributes(flowAttributes) {
804
+ const RESERVED = [
805
+ TiledeskChatbotConst.REQ_CHATBOT_NAME_KEY,
806
+ TiledeskChatbotConst.REQ_CHAT_URL,
807
+ TiledeskChatbotConst.REQ_CITY_KEY,
808
+ TiledeskChatbotConst.REQ_COUNTRY_KEY,
809
+ TiledeskChatbotConst.REQ_DEPARTMENT_ID_KEY,
810
+ TiledeskChatbotConst.REQ_DEPARTMENT_NAME_KEY,
811
+ TiledeskChatbotConst.REQ_END_USER_ID_KEY,
812
+ TiledeskChatbotConst.REQ_END_USER_IP_ADDRESS_KEY,
813
+ TiledeskChatbotConst.REQ_LAST_MESSAGE_ID_KEY,
814
+ TiledeskChatbotConst.REQ_LAST_USER_TEXT_KEY,
815
+ TiledeskChatbotConst.REQ_PROJECT_ID_KEY,
816
+ TiledeskChatbotConst.REQ_REQUEST_ID_KEY,
817
+ TiledeskChatbotConst.REQ_USER_AGENT_KEY,
818
+ TiledeskChatbotConst.REQ_USER_LANGUAGE_KEY,
819
+ TiledeskChatbotConst.REQ_USER_SOURCE_PAGE_KEY,
820
+ TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_TYPE_KEY,
821
+ TiledeskChatbotConst.REQ_TRANSCRIPT_KEY,
822
+ TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_KEY,
823
+ TiledeskChatbotConst.REQ_DECODED_JWT_KEY,
824
+ "lastUserImageURL", // image
825
+ "lastUserImageName", // image
826
+ "lastUserImageWidth", // image
827
+ "lastUserImageHeight", // image
828
+ "lastUserImageType", // image
829
+ "lastUserDocumentURL", // file
830
+ "lastUserDocumentName", // file
831
+ "lastUserDocumentType", // file
832
+ "ticketId",
833
+ TiledeskChatbotConst.REQ_CHAT_CHANNEL,
834
+ "user_lead_id",
835
+ "userLeadId",
836
+ "lastUserText",
837
+ TiledeskChatbotConst.REQ_REQUESTER_IS_AUTHENTICATED_KEY,
838
+ "userInput"
839
+ ]
840
+ let userParams = {};
841
+ if (flowAttributes) {
842
+ for (const [key, value] of Object.entries(flowAttributes)) {
843
+ // console.log(key, value);
844
+ // There is a bug that moves the requestId as a key in request attributes, so: && !key.startsWith("support-group-")
845
+ if (!key.startsWith("_") && !RESERVED.some(e => e === key) && !key.startsWith("support-group-")) {
846
+ userParams[key] = value;
847
+ }
848
+ }
849
+ }
850
+ return userParams;
851
+ }
852
+
803
853
  /**
804
854
  * A stub to get the request parameters, hosted by tilebot on:
805
855
  * /${TILEBOT_ROUTE}/ext/parameters/requests/${requestId}?all
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "0.2.67",
3
+ "version": "0.2.68",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Only prototype code for the new "Code orchestrator"
3
+ */
4
+ class Context {
5
+ constructor(env) {this.attributes = env;this.ops = {set: {},del: {} } } setAttribute(key, value) { this.ops.set[key] = value; }
6
+ deleteAttribute(key) { this.ops.del[key] = true; }
7
+ allAttributes() { return this.attributes; }
8
+ }
@@ -0,0 +1,154 @@
1
+ let axios = require('axios');
2
+ let https = require("https");
3
+ const { v4: uuidv4 } = require('uuid');
4
+
5
+ class DirMessageToBot {
6
+
7
+ constructor(context) {
8
+ if (!context) {
9
+ throw new Error('context object is mandatory.');
10
+ }
11
+ this.context = context;
12
+ this.API_ENDPOINT = context.TILEDESK_APIURL,
13
+ this.TILEBOT_ENDPOINT = context.TILEBOT_ENDPOINT;
14
+ this.supportRequest = context.supportRequest;
15
+ this.token = context.token;
16
+ this.log = context.log;
17
+ // let context = {
18
+ // projectId: projectId,
19
+ // token: token,
20
+ // supportRequest: supportRequest,
21
+ // requestId: supportRequest.request_id,
22
+ // TILEDESK_APIURL: API_URL,
23
+ // TILEBOT_ENDPOINT: TILEBOT_ENDPOINT,
24
+ // departmentId: depId,
25
+ // tdcache: tdcache,
26
+ // tdclient: tdclient,
27
+ // log: true
28
+ // }
29
+ }
30
+
31
+ execute(directive, callback) {
32
+ // console.log("exec intent:", JSON.stringify(directive));
33
+ let action;
34
+ if (directive.action) {
35
+ // console.log("got intent action:", JSON.stringify(directive.action));
36
+ action = directive.action;
37
+ }
38
+ else {
39
+ console.error("Incorrect directive:", directive);
40
+ callback();
41
+ return;
42
+ }
43
+ this.go(action, (stop) => {
44
+ callback(stop);
45
+ });
46
+ }
47
+
48
+ go(action, callback) {
49
+ // console.log("message action intent:", action);
50
+ const message = action.message;
51
+ // const projectId = this.supportRequest.id_project;
52
+ // const requestId = this.supportRequest.request_id;
53
+ const botId = this.supportRequest.bot_id;
54
+
55
+ let outgoing_message = {
56
+ "payload": message,
57
+ "token": this.token
58
+ }
59
+ if (this.log) {console.log("sending message:", JSON.stringify(outgoing_message));}
60
+ let TILEBOT_ENDPOINT;
61
+ if (this.TILEBOT_ENDPOINT) {
62
+ TILEBOT_ENDPOINT = this.TILEBOT_ENDPOINT;
63
+ }
64
+ else {
65
+ TILEBOT_ENDPOINT = `${this.API_ENDPOINT}/modules/tilebot`
66
+ }
67
+ this.sendMessageToBot(TILEBOT_ENDPOINT, outgoing_message, botId, () => {
68
+ // console.log("(DirMessageToBot) sendMessageToBot() req_body sent");
69
+ callback(true);
70
+ });
71
+ }
72
+
73
+ /**
74
+ * A stub to send message to the "ext/botId" endpoint, hosted by tilebot on:
75
+ * /${TILEBOT_ROUTE}/ext/${botId}
76
+ *
77
+ * @param {Object} message. The message to send
78
+ * @param {string} botId. Tiledesk botId
79
+ * @param {string} token. User token
80
+ */
81
+ sendMessageToBot(CHATBOT_ENDPOINT, message, botId, callback) {
82
+ // const jwt_token = this.fixToken(token);
83
+ const url = `${CHATBOT_ENDPOINT}/ext/${botId}`;
84
+ // console.log("sendMessageToBot URL", url);
85
+ const HTTPREQUEST = {
86
+ url: url,
87
+ headers: {
88
+ 'Content-Type' : 'application/json'
89
+ },
90
+ json: message,
91
+ method: 'POST'
92
+ };
93
+ this.myrequest(
94
+ HTTPREQUEST,
95
+ function(err, resbody) {
96
+ if (err) {
97
+ if (callback) {
98
+ callback(err);
99
+ }
100
+ }
101
+ else {
102
+ if (callback) {
103
+ callback(null, resbody);
104
+ }
105
+ }
106
+ }, false
107
+ );
108
+ }
109
+
110
+ myrequest(options, callback, log) {
111
+ if (this.log) {
112
+ console.log("API URL:", options.url);
113
+ console.log("** Options:", JSON.stringify(options));
114
+ }
115
+ let axios_options = {
116
+ url: options.url,
117
+ method: options.method,
118
+ data: options.json,
119
+ params: options.params,
120
+ headers: options.headers
121
+ }
122
+ if (options.url.startsWith("https:")) {
123
+ const httpsAgent = new https.Agent({
124
+ rejectUnauthorized: false,
125
+ });
126
+ axios_options.httpsAgent = httpsAgent;
127
+ }
128
+ axios(axios_options)
129
+ .then((res) => {
130
+ if (this.log) {
131
+ console.log("Response for url:", options.url);
132
+ console.log("Response headers:\n", JSON.stringify(res.headers));
133
+ }
134
+ if (res && res.status == 200 && res.data) {
135
+ if (callback) {
136
+ callback(null, res.data);
137
+ }
138
+ }
139
+ else {
140
+ if (callback) {
141
+ callback(TiledeskClient.getErr({message: "Response status not 200"}, options, res), null, null);
142
+ }
143
+ }
144
+ })
145
+ .catch( (error) => {
146
+ console.error("An error occurred:", error);
147
+ if (callback) {
148
+ callback(error, null, null);
149
+ }
150
+ });
151
+ }
152
+ }
153
+
154
+ module.exports = { DirMessageToBot };
@@ -3,6 +3,8 @@ const { TiledeskChatbot } = require('../../models/TiledeskChatbot');
3
3
  const { TiledeskChatbotConst } = require('../../models/TiledeskChatbotConst');
4
4
  const { TiledeskChatbotUtil } = require('../../models/TiledeskChatbotUtil');
5
5
  const { DirIntent } = require("./DirIntent");
6
+ const { defaultOptions } = require('liquidjs');
7
+ const { DirMessageToBot } = require('./DirMessageToBot');
6
8
 
7
9
  class DirReplyV2 {
8
10
 
@@ -19,6 +21,7 @@ class DirReplyV2 {
19
21
  this.intentDir = new DirIntent(context);
20
22
  this.chatbot = context.chatbot;
21
23
  this.reply = context.reply;
24
+ this.originalMessage = context.message;
22
25
  }
23
26
 
24
27
  execute(directive, callback) {
@@ -72,7 +75,36 @@ class DirReplyV2 {
72
75
  if (this.log) { console.log("Action Buttons:", JSON.stringify(buttons)); }
73
76
  if (buttons && buttons.length > 0) {
74
77
  const locked = await this.lockUnlock(action); // first execution returns locked, then unlocked
75
- if (!locked) {
78
+ if (locked) { // fist execution returns (just) locked
79
+ if (this.log) { console.log("first time pass!"); }
80
+ must_stop = true; // you must stop after next callbacks (in this flow) if there are buttons
81
+ // console.log("action:", action);
82
+ if (action.noInputIntent) {
83
+ if (this.log) { console.log("NoInputIntent found:", action.noInputIntent); }
84
+ const noInputIntent = action.noInputIntent;
85
+ const noInputTimeout = action.noInputTimeout;
86
+ if (this.log) { console.log("noInputTimeout found:", noInputTimeout); }
87
+ if (noInputTimeout > 0 && noInputTimeout < 300000) {
88
+ await this.chatbot.addParameter("userInput", false); // control variable. On each user input is set to true
89
+ if (this.log) { console.log("Set userInput: false, checking...", await this.chatbot.getParameter("userInput")); }
90
+ setTimeout(async () => {
91
+ if (this.log) { console.log("noinput timeout triggered!"); }
92
+ let userInput = await this.chatbot.getParameter("userInput");
93
+ if (!userInput) {
94
+ if (this.log) { console.log("no 'userInput'. Executing noinput action:", noInputIntent); }
95
+ await this.chatbot.unlockIntent(this.requestId);
96
+ await this.chatbot.unlockAction(this.requestId);
97
+ if (this.log) { console.log("unlocked (for noInput) ReplyV2"); }
98
+ let noinput_action = DirIntent.intentDirectiveFor(noInputIntent, null);
99
+ this.intentDir.execute(noinput_action, () => {
100
+ if (this.log) { console.log("noinput action invoked", noinput_action); }
101
+ });
102
+ }
103
+ }, noInputTimeout);
104
+ }
105
+ }
106
+ }
107
+ else { // second execution
76
108
  if (this.log) { console.log("second pass! unlocked!"); }
77
109
  const last_user_text = await this.chatbot.getParameter(TiledeskChatbotConst.REQ_LAST_USER_TEXT_v2_KEY);
78
110
  if (this.log) { console.log("got last user text"); }
@@ -116,39 +148,31 @@ class DirReplyV2 {
116
148
  return;
117
149
  }
118
150
  else {
119
- // there is no "no-match", go on...
120
- if (this.log) { console.log("callback(false) + return 3", current); }
121
- callback(false);
151
+ // const defaultFallbackAction = { action: { intentName: "defaultFallback" } };
152
+
153
+ // console.log("re-send original message:",JSON.stringify(this.originalMessage));
154
+ const messageDir = new DirMessageToBot(this.context);
155
+ messageDir.execute( { action: { message: this.originalMessage } }, () => {
156
+ if (this.log) { console.log("messageDir invoked"); }
157
+ });
158
+ if (this.log) { console.log("callback(true) + return no-match", current); }
159
+ callback(true); // must_stop = true
122
160
  return;
123
- }
124
- }
125
- }
126
- else {
127
- if (this.log) { console.log("first time pass!"); }
128
- must_stop = true; // you must stop after next callbacks (in this flow) if there are buttons
129
- // console.log("action:", action);
130
- if (action.noInputIntent) {
131
- if (this.log) { console.log("NoInputIntent found:", action.noInputIntent); }
132
- const noInputIntent = action.noInputIntent;
133
- const noInputTimeout = action.noInputTimeout;
134
- if (this.log) { console.log("noInputTimeout found:", noInputTimeout); }
135
- if (noInputTimeout > 0 && noInputTimeout < 300000) {
136
- await this.chatbot.addParameter("userInput", false); // control variable. On each user input is set to true
137
- if (this.log) { console.log("Set userInput: false, checking...", await this.chatbot.getParameter("userInput")); }
138
- setTimeout(async () => {
139
- if (this.log) { console.log("noinput timeout triggered!"); }
140
- let userInput = await this.chatbot.getParameter("userInput");
141
- if (!userInput) {
142
- if (this.log) { console.log("no 'userInput'. Executing noinput action:", noInputIntent); }
143
- await this.chatbot.unlockIntent(this.requestId);
144
- await this.chatbot.unlockAction(this.requestId);
145
- if (this.log) { console.log("unlocked (for noInput) ReplyV2"); }
146
- let noinput_action = DirIntent.intentDirectiveFor(noInputIntent, null);
147
- this.intentDir.execute(noinput_action, () => {
148
- if (this.log) { console.log("noinput action invoked", noinput_action); }
149
- });
150
- }
151
- }, noInputTimeout);
161
+
162
+ // const textAction = { action: { text: last_user_text } };
163
+ // console.log("textAction invoked:",textAction ); //, defaultFallbackAction);
164
+ // this.intentDir.execute( textAction, () => {
165
+ // if (this.log) { console.log("textAction invoked", textAction); }
166
+ // });
167
+ // if (this.log) { console.log("callback(true) + return no-match", current); }
168
+ // callback(true); // must_stop = true
169
+ // return;
170
+
171
+
172
+ // // there is no "no-match", go on...
173
+ // if (this.log) { console.log("callback(false) + return 3", current); }
174
+ // callback(false);
175
+ // return;
152
176
  }
153
177
  }
154
178
  }
@@ -214,6 +238,12 @@ class DirReplyV2 {
214
238
  if (this.context.reply && this.context.reply.attributes && this.context.reply.attributes.intent_info) {
215
239
  message.attributes.intentName = this.context.reply.attributes.intent_info.intent_name;
216
240
  }
241
+ // userFlowAttributes
242
+ let userFlowAttributes = TiledeskChatbotUtil.userFlowAttributes(requestAttributes);
243
+ if (this.log) { console.log("userFlowAttributes:", userFlowAttributes); }
244
+ if (userFlowAttributes) {
245
+ message.attributes["flowAttributes"] = userFlowAttributes;
246
+ }
217
247
  }
218
248
  // send!
219
249
  let cleanMessage = message;
@@ -252,6 +282,7 @@ class DirReplyV2 {
252
282
 
253
283
  }
254
284
 
285
+
255
286
  async lockUnlock(action, callback) {
256
287
  let lockedAction = await this.chatbot.currentLockedAction(this.requestId);
257
288
  // console.log("(DirReplyV2) lockedAction:", lockedAction);