@tiledesk/tiledesk-tybot-connector 0.2.26 → 0.2.28

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,15 @@
5
5
  available on:
6
6
  ▶️ https://www.npmjs.com/package/@tiledesk/tiledesk-tybot-connector
7
7
 
8
+ ### v0.2.28
9
+ - DirSetAttribute, added support for attribute-filling in constants
10
+ - DirSetAttribute, added function JSONparse
11
+ - Added support for Globals (aka Secrets)
12
+
13
+ ### v0.2.27
14
+ - Added support for removing empty text from replies: TiledeskChatbotUtil.removeEmptyReplyCommands()
15
+ - Removed non-user-defined attributes from /ext/parameters method
16
+
8
17
  ### v0.2.26
9
18
  - Updated Qapla Action (tracking number from filler)
10
19
 
@@ -209,6 +209,10 @@ class TiledeskExpression {
209
209
  "roundAsNumber": {
210
210
  name: "roundAsNumber",
211
211
  applyPattern: "TiledeskMath.round(Number(#1))"
212
+ },
213
+ "JSONparse": {
214
+ name: "JSONparse",
215
+ applyPattern: "JSON.parse(String(#1))"
212
216
  }
213
217
  }
214
218
 
@@ -230,8 +234,8 @@ class TiledeskExpression {
230
234
  }
231
235
 
232
236
  evaluateJavascriptExpression(expression, context) {
233
- // console.log("(evaluateJavascriptExpression) evaluating:", expression)
234
- // console.log("context:", context)
237
+ console.log("(evaluateJavascriptExpression) evaluating:", expression)
238
+ console.log("context:", context)
235
239
  let res = null;
236
240
  try {
237
241
  const vm = new VM({
package/index.js CHANGED
@@ -221,6 +221,11 @@ router.post('/ext/:botid', async (req, res) => {
221
221
 
222
222
  });
223
223
 
224
+ router.post('/hooks/:hookid', async (req, res) => {
225
+ // chatbot_id + intend_id
226
+
227
+ });
228
+
224
229
  router.post('/ext/:projectId/requests/:requestId/messages', async (req, res) => {
225
230
  res.json({success:true});
226
231
  const projectId = req.params.projectId;
@@ -359,7 +364,18 @@ router.get('/ext/parameters/requests/:requestid', async (req, res) => {
359
364
  TiledeskChatbotConst.REQ_REQUEST_ID_KEY,
360
365
  TiledeskChatbotConst.REQ_USER_AGENT_KEY,
361
366
  TiledeskChatbotConst.REQ_USER_LANGUAGE_KEY,
362
- TiledeskChatbotConst.REQ_USER_SOURCE_PAGE_KEY
367
+ TiledeskChatbotConst.REQ_USER_SOURCE_PAGE_KEY,
368
+ TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_TYPE_KEY,
369
+ TiledeskChatbotConst.REQ_TRANSCRIPT_KEY,
370
+ TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_KEY,
371
+ "lastUserImageURL", // image
372
+ "lastUserImageName", // image
373
+ "lastUserImageWidth", // image
374
+ "lastUserImageHeight", // image
375
+ "lastUserImageType", // image
376
+ "lastUserDocumentURL", // file
377
+ "lastUserDocumentName", // file
378
+ "lastUserDocumentType" // file
363
379
  ]
364
380
  let userParams = {};
365
381
  if (parameters) {
@@ -626,9 +626,9 @@ class TiledeskChatbot {
626
626
  attributes_native_values[key] = JSON.parse(value);
627
627
  }
628
628
  }
629
- else {
630
- console.error("An error occurred. 'attributes__as_string_map' is null!");
631
- }
629
+ // else {
630
+ // console.error("Warning: 'attributes__as_string_map' is null!");
631
+ // }
632
632
  return attributes_native_values;
633
633
  }
634
634
 
@@ -5,6 +5,7 @@ class TiledeskChatbotConst {
5
5
  static REQ_REQUEST_ID_KEY = "conversation_id";
6
6
  static REQ_CHATBOT_NAME_KEY = "chatbot_name";
7
7
  static REQ_LAST_USER_TEXT_KEY = "last_user_text";
8
+ static REQ_LAST_USER_TEXT_v2_KEY = "lastUserText";
8
9
  static REQ_LAST_MESSAGE_ID_KEY = "last_message_id";
9
10
  static REQ_COUNTRY_KEY = "user_country";
10
11
  static REQ_CITY_KEY = "user_city";
@@ -15,6 +16,10 @@ class TiledeskChatbotConst {
15
16
  static REQ_END_USER_ID_KEY = "user_id";
16
17
  static REQ_END_USER_IP_ADDRESS_KEY = "user_ip_address";
17
18
  static REQ_CHAT_URL = "chat_url";
19
+ static REQ_LAST_USER_MESSAGE_TYPE_KEY = "lastUserMessageType";
20
+ static REQ_TRANSCRIPT_KEY = "transcript";
21
+ static REQ_LAST_USER_MESSAGE_KEY = "lastUserMessage";
22
+ static REQ_CHAT_CHANNEL = "chatChannel";
18
23
 
19
24
  // static REQ_DEPARTMENT_ID_KEY = "tdDepartmentId";
20
25
  // static REQ_PROJECT_ID_KEY = "projectId";
@@ -237,6 +237,57 @@ class TiledeskChatbotUtil {
237
237
  }
238
238
  }
239
239
 
240
+ static removeEmptyReplyCommands(message) {
241
+ try {
242
+ if (message && message.attributes && message.attributes.commands && message.attributes.commands.length > 0) {
243
+ let commands = message.attributes.commands;
244
+
245
+ for (let i = commands.length - 1; i >= 0; i--) {
246
+ // console.log("...commands[" + i + "]");
247
+ if (commands[i].type === "message") { // is a message, not a "wait"
248
+ // console.log("commands[i]:", commands[i].message.text);
249
+ // let textEmpty = false;
250
+ if (commands[i].message) {
251
+ if (commands[i].message.type === "text") { // check text commands
252
+ if (( commands[i].message.text && commands[i].message.text.trim() === "") || !commands[i].message.text) {
253
+ console.log("deleting command:", commands[i]);
254
+ commands.splice(i, 1);
255
+ if (commands[i-1]) {
256
+ if (commands[i-1].type === "wait") {
257
+ commands.splice(i-1, 1);
258
+ i--;
259
+ console.log("deleted wait");
260
+ }
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+ // for (let i = 0; i < commands.length; i++) {
268
+ // if (commands[i].type === 'message' && commands[i].message && commands[i].message.text) {
269
+ // if (this.log) {console.log("[" + commands[i].message.lang + "]commands[i].message.text:", commands[i].message.text);}
270
+ // }
271
+ // }
272
+ }
273
+ }
274
+ catch(error) {
275
+ log.error("error while checking", error)
276
+ }
277
+ return message;
278
+ }
279
+
280
+ /*
281
+ returns true if a valid message for a reply (i.e. at least one valid - non empty - message command)
282
+ */
283
+ static isValidReply(message) {
284
+ if (message && message.attributes && message.attributes.commands && message.attributes.commands.length > 0) {
285
+ return true;
286
+ } else {
287
+ return false;
288
+ }
289
+ }
290
+
240
291
  static totalMessageWait(message) {
241
292
  if (!message) {
242
293
  return;
@@ -337,17 +388,17 @@ class TiledeskChatbotUtil {
337
388
 
338
389
  if (message.text && message.sender !== "_tdinternal") {
339
390
  await chatbot.addParameter(TiledeskChatbotConst.REQ_LAST_USER_TEXT_KEY, message.text); // DEPRECATED
340
- await chatbot.addParameter("lastUserText", message.text);
391
+ await chatbot.addParameter(TiledeskChatbotConst.REQ_LAST_USER_TEXT_v2_KEY, message.text);
341
392
  if (message.channel) {
342
393
  if (message.channel.name === "chat21") {
343
- await chatbot.addParameter("chatChannel", "web"); // renames the channel in chat21
394
+ await chatbot.addParameter(TiledeskChatbotConst.REQ_CHAT_CHANNEL, "web"); // renames the channel in chat21
344
395
  }
345
396
  else {
346
- await chatbot.addParameter("chatChannel", message.channel.name);
397
+ await chatbot.addParameter(TiledeskChatbotConst.REQ_CHAT_CHANNEL, message.channel.name);
347
398
  }
348
399
  }
349
- await chatbot.addParameter("lastUserMessageType", message.type);
350
- await chatbot.addParameter("lastUserMessage", TiledeskChatbotUtil.lastUserMessageFrom(message)); // JSON TYPE *NEW
400
+ await chatbot.addParameter(TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_TYPE_KEY, message.type);
401
+ await chatbot.addParameter(TiledeskChatbotConst.REQ_LAST_USER_MESSAGE_KEY, TiledeskChatbotUtil.lastUserMessageFrom(message)); // JSON TYPE *NEW
351
402
  // get image
352
403
  if (message.type && message.type === "image" && message.metadata) {
353
404
  // "text": "\nimage text",
@@ -467,20 +518,39 @@ class TiledeskChatbotUtil {
467
518
  }
468
519
  }
469
520
 
470
-
521
+ const _bot = chatbot.bot; // aka FaqKB
522
+ if (chatbot.log) {
523
+ console.log("Adding Globals to context..., chatbot.attributes?", JSON.stringify(_bot));
524
+ }
525
+
526
+ if (_bot.attributes && _bot.attributes.globals) {
527
+ if (chatbot.log) {console.log("Got Globals:", JSON.stringify(_bot.attributes.globals));}
528
+ _bot.attributes.globals.forEach(async (global_var) => {
529
+ if (chatbot.log) {console.log("Adding global:", global_var.key, "value:", global_var.value);}
530
+ await chatbot.addParameter(global_var.key, global_var.value);
531
+ });
532
+ }
533
+ // await chatbot.addParameter("testVar",
534
+ // {
535
+ // name: "Andrea",
536
+ // coords: {
537
+ // x: 2, y: 1
538
+ // }
539
+ // }
540
+ // );
471
541
 
472
542
  if (chatbot.log) {
473
543
  // console.log("tdcache:", chatbot.tdcache);
474
544
  console.log("requestId:", requestId);
475
545
  console.log("KEY:", TiledeskChatbotConst.REQ_PROJECT_ID_KEY);
476
- console.log("TiledeskChatbot:", TiledeskChatbot);
546
+ // console.log("TiledeskChatbot:", TiledeskChatbot);
477
547
  let proj_ = await chatbot.getParameter(TiledeskChatbotConst.REQ_PROJECT_ID_KEY);
478
548
  console.log("request parameter proj_:", proj_);
479
549
  const all_parameters = await chatbot.allParameters();
480
550
  for (const [key, value] of Object.entries(all_parameters)) {
481
551
  // const value = all_parameters[key];
482
552
  const value_type = typeof value;
483
- if (chatbot.log) {console.log("request parameter:", key, "value:", value, "type:", value_type)}
553
+ if (chatbot.log) {console.log("REQUEST ATTRIBUTE:", key, "VALUE:", value, "TYPE:", value_type)}
484
554
  }
485
555
  }
486
556
  } catch(error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -25,6 +25,7 @@ const { DirCondition } = require('./directives/DirCondition');
25
25
  const { DirJSONCondition } = require('./directives/DirJSONCondition');
26
26
  const { DirAssign } = require('./directives/DirAssign');
27
27
  const { DirSetAttribute } = require('./directives/DirSetAttribute');
28
+ const { DirSetAttributeV2 } = require('./directives/DirSetAttributeV2');
28
29
  const { DirWebRequest } = require('./directives/DirWebRequest');
29
30
  const { DirWebRequestV2 } = require('./directives/DirWebRequestV2');
30
31
  const { DirCode } = require('./directives/DirCode');
@@ -370,6 +371,13 @@ class DirectivesChatbotPlug {
370
371
  this.process(next_dir);
371
372
  });
372
373
  }
374
+ else if (directive_name === Directives.SET_ATTRIBUTE_V2) {
375
+ // console.log("...DirSetAttribute");
376
+ new DirSetAttributeV2(context).execute(directive, async () => {
377
+ let next_dir = await this.nextDirective(this.directives);
378
+ this.process(next_dir);
379
+ });
380
+ }
373
381
  // else if (directive_name === Directives.WHEN_OPEN) {
374
382
  // // DEPRECATED
375
383
  // const whenOpenDir = new DirWhenOpen(
@@ -97,18 +97,24 @@ class DirReply {
97
97
  }
98
98
  }
99
99
  // send!
100
- message.senderFullname = this.context.chatbot.bot.name;
101
- if (this.log) {console.log("Reply:", JSON.stringify(message))};
102
- await TiledeskChatbotUtil.updateConversationTranscript(this.context.chatbot, message);
100
+ const cleanMessage = TiledeskChatbotUtil.removeEmptyReplyCommands(message);
101
+ if (!TiledeskChatbotUtil.isValidReply(cleanMessage)) {
102
+ console.log("invalid message", cleanMessage);
103
+ callback(); // cancel reply operation
104
+ }
105
+ // console.log("valid message!", cleanMessage);
106
+ cleanMessage.senderFullname = this.context.chatbot.bot.name;
107
+ if (this.log) {console.log("Reply:", JSON.stringify(cleanMessage))};
108
+ await TiledeskChatbotUtil.updateConversationTranscript(this.context.chatbot, cleanMessage);
103
109
  this.context.tdclient.sendSupportMessage(
104
110
  this.requestId,
105
- message,
111
+ cleanMessage,
106
112
  (err) => {
107
113
  if (err) {
108
114
  console.error("Error sending reply:", err);
109
115
  }
110
116
  if (this.log) {console.log("Reply message sent");}
111
- const delay = TiledeskChatbotUtil.totalMessageWait(message);
117
+ const delay = TiledeskChatbotUtil.totalMessageWait(cleanMessage);
112
118
  // console.log("got total delay:", delay)
113
119
  if (delay > 0 && delay <= 30000) { // prevent long delays
114
120
  setTimeout(() => {
@@ -0,0 +1,190 @@
1
+ const { TiledeskChatbot } = require('../../models/TiledeskChatbot');
2
+ const { TiledeskExpression } = require('../../TiledeskExpression');
3
+ const { TiledeskMath } = require('../../TiledeskMath');
4
+ const { TiledeskString } = require('../../TiledeskString');
5
+ const { Filler } = require('../Filler');
6
+ const validate = require('jsonschema').validate;
7
+
8
+ const schema = {
9
+ "type": "object",
10
+ "properties": {
11
+ "_tdActionType": {
12
+ "type": "string",
13
+ "enum": ["setattribute"]
14
+ },
15
+ "_tdActionId": {
16
+ "type": ["string", "null"]
17
+ },
18
+ "_tdActionTitle": {
19
+ "type": ["string", "null"]
20
+ },
21
+ "destination": {
22
+ "type": "string",
23
+ },
24
+ "operation": {
25
+ "type": "object",
26
+ "properties": {
27
+ "operators": {
28
+ "type": "array",
29
+ "items": {
30
+ "type": "string",
31
+ "enum": ["addAsNumber", "addAsString", "subtractAsNumber", "multiplyAsNumber", "divideAsNumber"]
32
+ }
33
+ },
34
+
35
+ "operands": {
36
+ "type": "array",
37
+ "minItems": 1,
38
+ "items": {
39
+ "type": "object",
40
+ "properties": {
41
+ "value": {
42
+ "type": "string"
43
+ },
44
+ "isVariable": {
45
+ "type": "boolean"
46
+ },
47
+ "function": {
48
+ "type": "string",
49
+ "enum": ["capitalizeAsString", "upperCaseAsString", "lowerCaseAsString", "absAsNumber", "ceilAsNumber", "floorAsNumber", "roundAsNumber"]
50
+ }
51
+ },
52
+ "required": ["value", "isVariable"],
53
+ "additionalProperties": false,
54
+ "if": {
55
+ "properties": { "isVariable": { "const": true } },
56
+ },
57
+ "then": {
58
+ "properties": { "value": { "pattern": "^[a-zA-Z_]*[.]*[a-zA-Z_]+[a-zA-Z0-9_]*$" } }
59
+ }
60
+ }
61
+ }
62
+ },
63
+ "required": ["operands"],
64
+ "additionalProperties": false
65
+ }
66
+ },
67
+ "required": ["_tdActionType", "destination", "operation"],
68
+ "additionalProperties": false
69
+ };
70
+
71
+
72
+ class DirSetAttributeV2 {
73
+
74
+ constructor(context) {
75
+ if (!context) {
76
+ throw new Error('context object is mandatory.');
77
+ }
78
+ this.context = context;
79
+ this.tdcache = context.tdcache;
80
+ this.log = context.log;
81
+ }
82
+
83
+ execute(directive, callback) {
84
+ let action;
85
+ if (directive.action) {
86
+ action = directive.action
87
+ }
88
+ else {
89
+ callback();
90
+ return;
91
+ }
92
+ // console.log("go DirAssign with action:", action);
93
+ this.go(action, () => {
94
+ callback();
95
+ });
96
+ }
97
+
98
+ async go(action, callback) {
99
+ console.log("(DirSetAttribute) action before filling:", JSON.stringify(action));
100
+ if (action && action.operation && action.operation.operands) {
101
+ console.log("filling in setattribute...");
102
+ await this.fillValues(action.operation.operands);
103
+ }
104
+ console.log("filled in setattribute:", action.operation);
105
+ // let res = validate(action, schema);
106
+ // if (res.errors) {
107
+ // console.log("(DirSetAttribute) failed validation action:", JSON.stringify(action));
108
+ // console.log("DirSetAttribute validation errors:", res.errors);
109
+ // }
110
+ // if (!res.valid) {
111
+ // if (this.log) {console.error("(DirSetAttribute) Invalid action:", res.errors)};
112
+ // callback();
113
+ // return;
114
+ // }
115
+ if (action.operation.operators === undefined && action.operation.operands.length !== 1) {
116
+ if (this.log) {console.error("(DirSetAttribute) Invalid action: operators === undefined && operands.length !== 1")};
117
+ callback();
118
+ return;
119
+ }
120
+ if (action.operation.operators !== undefined && action.operation.operators.length !== action.operation.operands.length - 1) {
121
+ if (this.log) {console.error("(DirSetAttribute) Invalid action: operators.length !== operands.length - 1")};
122
+ callback();
123
+ return;
124
+ }
125
+ // if (action && action.operation && action.operation.operands) {
126
+ // console.log("filling in setattribute...");
127
+ // await this.fillValues(action.operation.operands);
128
+ // }
129
+ console.log("dirsetattribute, action.operation.operands:", action.operation.operands);
130
+ const expression = TiledeskExpression.JSONOperationToExpression(action.operation.operators, action.operation.operands);
131
+ const attributes = await TiledeskChatbot.allParametersStatic(this.context.tdcache, this.context.requestId);
132
+ console.log("dirsetattribute, attributes:", attributes);
133
+ attributes.TiledeskMath = TiledeskMath;
134
+ attributes.TiledeskString = TiledeskString;
135
+ const result = new TiledeskExpression().evaluateJavascriptExpression(expression, attributes);
136
+ console.log("filling in setattribute, result:", result);
137
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, action.destination, result);
138
+ callback();
139
+ }
140
+
141
+ async fillValues(operands) {
142
+ // operation: {
143
+ // operators: ["addAsNumber", "subtractAsNumber", "divideAsNumber", "multiplyAsNumber"],
144
+ // operands: [
145
+ // {
146
+ // value: "previous",
147
+ // isVariable: true
148
+ // },
149
+ // {
150
+ // value: "temp",
151
+ // isVariable: true,
152
+ // function: "floorAsNumber"
153
+ // },
154
+ // {
155
+ // value: "real",
156
+ // isVariable: true,
157
+ // function: "absAsNumber"
158
+ // },
159
+ // {
160
+ // value: "input",
161
+ // isVariable: true
162
+ // },
163
+ // {
164
+ // value: "2",
165
+ // isVariable: false
166
+ // }
167
+ // ]
168
+ try {
169
+ if (this.tdcache) {
170
+ // console.log("tdcache in setattribute...", this.tdcache);
171
+ const requestAttributes =
172
+ await TiledeskChatbot.allParametersStatic(this.tdcache, this.context.requestId);
173
+ // console.log("requestAttributes in setattribute...", requestAttributes);
174
+ const filler = new Filler();
175
+ operands.forEach(operand => {
176
+ if (!operand.isVariable) {
177
+ console.log("setattribute, liquid operand:", operand);
178
+ operand.value = filler.fill(operand.value, requestAttributes);
179
+ console.log("setattribute, final operand:", operand);
180
+ }
181
+ });
182
+ }
183
+ }
184
+ catch(error) {
185
+ console.error("Error while filling operands:", error);
186
+ }
187
+ }
188
+ }
189
+
190
+ module.exports = { DirSetAttributeV2 };
@@ -22,6 +22,7 @@ class Directives {
22
22
  static FUNCTION_VALUE = "functionvalue";
23
23
  static JSON_CONDITION = "jsoncondition";
24
24
  static SET_ATTRIBUTE = "setattribute";
25
+ static SET_ATTRIBUTE_V2 = "setattribute-v2";
25
26
  static REPLY = 'reply';
26
27
  static RANDOM_REPLY = 'randomreply';
27
28
  static CODE = 'code';