@tiledesk/tiledesk-tybot-connector 0.1.37 → 0.1.38

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,9 @@
5
5
  available on:
6
6
  ▶️ https://www.npmjs.com/package/@tiledesk/tiledesk-tybot-connector
7
7
 
8
+ ### 0.1.38 - online
9
+ - tiledesk-client => 0.9.3
10
+
8
11
  ### 0.1.37 - online
9
12
  - log clean
10
13
 
package/index.js CHANGED
@@ -52,7 +52,7 @@ router.post('/ext/:botid', async (req, res) => {
52
52
  TiledeskClient.version09();
53
53
  }
54
54
  res.status(200).send({"success":true});
55
-
55
+
56
56
  const botId = req.params.botid;
57
57
  if (log) {console.log("query botId:", botId);}
58
58
  const message = req.body.payload;
@@ -62,7 +62,16 @@ router.post('/ext/:botid', async (req, res) => {
62
62
  const requestId = message.request.request_id;
63
63
  const projectId = message.id_project;
64
64
 
65
+ let requestSourcePage = null;
66
+ let requestLanguage = null;
67
+ let requestUserAgent = null;
65
68
 
69
+ if (message.payload) {
70
+ requestSourcePage = message.payload.sourcePage;
71
+ requestLanguage = message.payload.language;
72
+ requestUserAgent = message.payload.userAgent;
73
+ }
74
+
66
75
  // NEXTTTTTTT
67
76
  const message_context = {
68
77
  projectId: projectId,
@@ -117,9 +126,20 @@ router.post('/ext/:botid', async (req, res) => {
117
126
  projectId: projectId,
118
127
  log: log
119
128
  });
120
-
129
+
130
+ // initial request context
121
131
  await chatbot.addParameter("_tdLastMessageId", messageId);
122
132
  await chatbot.addParameter("_tdProjectId", projectId);
133
+ if (requestSourcePage) {
134
+ await chatbot.addParameter("requestSourcePage", sourcePage);
135
+ }
136
+ if (requestLanguage) {
137
+ await chatbot.addParameter("requestLanguage", language);
138
+ }
139
+ if (requestUserAgent) {
140
+ await chatbot.addParameter("requestUserAgent", userAgent);
141
+ }
142
+
123
143
  let reply = await chatbot.replyToMessage(message);
124
144
  if (!reply) {
125
145
  reply = {
@@ -135,7 +155,7 @@ router.post('/ext/:botid', async (req, res) => {
135
155
  ENDPOINT: extEndpoint,
136
156
  log: log
137
157
  });
138
-
158
+
139
159
  apiext.sendSupportMessageExt(reply, projectId, requestId, token, () => {
140
160
  if (log) {
141
161
  console.log("SupportMessageExt() reply sent:", reply);
@@ -264,8 +284,8 @@ router.get('/message/context/:messageid', async (req, res) => {
264
284
  router.get('/ext/parameters/requests/:requestid', async (req, res) => {
265
285
  const requestId = req.params.requestid;
266
286
  const parameters = await TiledeskChatbot.allParametersStatic(tdcache, requestId);
267
- console.log("parameters:", parameters);
268
- console.log("req.query.all:", req.query.all);
287
+ // console.log("parameters:", parameters);
288
+ // console.log("req.query.all:", req.query.all);
269
289
  if (req.query.all != null) {
270
290
  res.send(parameters);
271
291
  }
@@ -273,7 +293,7 @@ router.get('/ext/parameters/requests/:requestid', async (req, res) => {
273
293
  let userParams = {};
274
294
  if (parameters) {
275
295
  for (const [key, value] of Object.entries(parameters)) {
276
- console.log(key, value);
296
+ // console.log(key, value);
277
297
  if (!key.startsWith("_td")) {
278
298
  userParams[key] = value;
279
299
  }
@@ -0,0 +1,213 @@
1
+ //const CURRENT_FIELD_K = "tilebot:requests:forms:currentField"; // form field index
2
+ const CURRENT_FORM_K = "CURRENT_FORM"; // form json
3
+
4
+ class IntentForm {
5
+
6
+ constructor(options) {
7
+ this.db = options.chatbot.tdcache;
8
+ this.chatbot = options.chatbot;
9
+ this.requestId = options.requestId;
10
+ this.form = options.form;
11
+ this.CURRENT_FIELD_INDEX_KEY = "tilebot:requests:" + this.requestId + ":currentFieldIndex"
12
+ this.CURRENT_FORM_KEY = "tilebot:requests:" + this.requestId + ":currentForm"
13
+ this.log = options.log;
14
+ }
15
+
16
+ async setValue(key, value) {
17
+ await this.db.set(key, value);
18
+ }
19
+
20
+ async getValue(key) {
21
+ const value = await this.db.get(key);
22
+ return value;
23
+ }
24
+
25
+ async delValue(key) {
26
+ await this.db.del(key);
27
+ }
28
+
29
+ /**
30
+ intent_text: Used to send final text when the form is completed.
31
+ example form schema
32
+ the_form = {
33
+ "name": "form_name",
34
+ "id": "form_id",
35
+ "fields": [
36
+ {
37
+ "name": "userFullname",
38
+ "type": "text",
39
+ "label": "Your name"
40
+ },
41
+ {
42
+ "name": "userEmail",
43
+ "type": "text",
44
+ "regex": "/^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$/",
45
+ "label": "Your email",
46
+ "errorLabel": "Invalid email address"
47
+ }
48
+ ]
49
+ }
50
+ */
51
+ async getMessage(user_text) {
52
+ //console.log("get message:", user_text)
53
+ if (
54
+ this.form &&
55
+ this.form.cancelCommands &&
56
+ this.form.cancelCommands.includes(user_text.toLowerCase())) {
57
+ const cancelReply = this.form.cancelReply ? this.form.cancelReply : "Canceled"
58
+ await this.delValue(this.CURRENT_FIELD_INDEX_KEY)
59
+ await this.delValue(this.CURRENT_FORM_KEY)
60
+ return {
61
+ canceled: true,
62
+ message: {
63
+ text: cancelReply
64
+ }
65
+ };
66
+ }
67
+ let current_field = null;
68
+ const _current_field = await this.getValue(this.CURRENT_FIELD_INDEX_KEY);
69
+ if (_current_field) {
70
+ current_field = Number(_current_field);
71
+ }
72
+ let current_form = null;
73
+ const _current_form = await this.getValue(this.CURRENT_FORM_KEY);
74
+ if (_current_form) {
75
+ current_form = JSON.parse(_current_form);
76
+ }
77
+ //console.log("CURRENT FORM IS", current_form);
78
+ if (current_field == null) {
79
+ if (this.log) {console.log("current_field is undefined")}
80
+ current_field = 0;
81
+
82
+ await this.setValue(this.CURRENT_FORM_KEY, JSON.stringify(this.form));
83
+ // if (getParam(this.form.fields[current_field].name)) {
84
+ // //current_field++;
85
+ // await this.setValue(this.CURRENT_FIELD_INDEX_KEY, current_field); //=0
86
+ // return this.getMessage(current_value)
87
+ // }
88
+
89
+ await this.setValue(this.CURRENT_FIELD_INDEX_KEY, current_field);
90
+ const is_current_value = getParam(this.form.fields[current_field].name);
91
+ if (is_current_value) {
92
+ return await this.getMessage(is_current_value);
93
+ }
94
+ if (this.log) {console.log("INTENT_FORM:", this.form);}
95
+ if (this.log) {console.log("CURRENT FIELD:", current_field);}
96
+ let message = {
97
+ text: this.form.fields[current_field].label
98
+ }
99
+ if (this.log) {console.log("form reply message:", message);}
100
+ return {
101
+ message: message
102
+ }
103
+ }
104
+ else {
105
+ // = 0
106
+ // current++ (1) y? =>
107
+ //
108
+ //inc(current_field)=1 getMessage(null)
109
+ // == 1?
110
+ // n => continue =>
111
+ // param[1] n? => continue
112
+ // == 2? => set fields[2].name => user_text
113
+ //console.log("current_form:", current_form);
114
+ if (this.log) {console.log("current_field:", current_field);}
115
+
116
+
117
+ if (current_form.fields[current_field].regex) {
118
+ if (!this.validate(user_text, current_form.fields[current_field].regex)) {
119
+ if (this.log) {console.log("text is invalid");}
120
+ // send error message
121
+ let error_reply_text = this.form.fields[current_field].label;
122
+ if (this.log) {console.log("text is invalid label", error_reply_text);}
123
+ if (current_form.fields[current_field].errorLabel) {
124
+ if (this.log) {console.log("text is invalid errorLabel", current_form.fields[current_field].errorLabel);}
125
+ error_reply_text = current_form.fields[current_field].errorLabel;
126
+ }
127
+ let message = {
128
+ text: error_reply_text // Error
129
+ }
130
+ if (this.log) {console.log("IntentForm error message:", message);}
131
+ return {
132
+ message: message
133
+ };
134
+ }
135
+ }
136
+ else {
137
+ if (this.log) {console.log("no regex validation requested. next field...")}
138
+ }
139
+
140
+ // text ok?
141
+ // y: set value for current_field = text
142
+ //. inc current_field, send message[current_field]
143
+ //. n: send error message => error[current_field]
144
+ //. no inc, no changes in status
145
+ //await this.setValue(FIELD_VALUE_K, user_text);
146
+
147
+ // persist parameter
148
+ const parameter_name = current_form.fields[current_field].name;
149
+ const parameter_value = user_text;
150
+ if (this.log) {console.log("adding parameters, name:", parameter_name, "value:", parameter_value)}
151
+ await this.chatbot.addParameter(parameter_name, parameter_value);
152
+ if (current_form.fields[current_field].type) { // adding type
153
+ await this.chatbot.addParameter("_tdTypeOf:" + parameter_name, current_form.fields[current_field].type);
154
+ }
155
+ if (this.log) {console.log("next field...");}
156
+
157
+ current_field += 1;
158
+ if (current_field === current_form.fields.length) {
159
+ // Form completed!
160
+ await this.delValue(this.CURRENT_FIELD_INDEX_KEY)
161
+ await this.delValue(this.CURRENT_FORM_KEY)
162
+ return {
163
+ end: true
164
+ };
165
+ }
166
+ else {
167
+ if (this.log) {console.log("Processing next field:", current_field)}
168
+ await this.setValue(this.CURRENT_FIELD_INDEX_KEY, current_field);
169
+ const is_current_value = getParam(this.form.fields[current_field].name);
170
+ if (is_current_value) {
171
+ return await this.getMessage(is_current_value);
172
+ }
173
+ else {
174
+ let message = {
175
+ text: current_form.fields[current_field].label
176
+ }
177
+ return {
178
+ message: message
179
+ };
180
+ }
181
+
182
+ }
183
+ }
184
+ }
185
+
186
+ validate(text, regex) {
187
+ let _regex = regex;
188
+ if (regex.startsWith("/")) {
189
+ // removing leading and trailing / if regex is sorrounded by (legacy support, to be removed)
190
+ _regex = regex.substring(1, regex.length-1);
191
+ }
192
+ if (this.log) {console.log("Validating using regex:", _regex);}
193
+ const rg = new RegExp(_regex, "g");
194
+ return rg.test(text);
195
+ }
196
+
197
+ static isValidForm(form) {
198
+ let is_valid = true;
199
+ if (!form) {
200
+ is_valid = false;
201
+ }
202
+ else if (form && !form.fields) {
203
+ is_valid = false;
204
+ }
205
+ else if (form && form.fields.length === 0) {
206
+ is_valid = false;
207
+ }
208
+ return is_valid;
209
+ }
210
+
211
+ }
212
+
213
+ module.exports = { IntentForm };
@@ -316,6 +316,7 @@ class TiledeskChatbot {
316
316
  }
317
317
  form_reply.message.attributes.fillParams = true;
318
318
  form_reply.message.attributes.splits = true;
319
+ form_reply.message.attributes.directives = true;
319
320
  return form_reply.message
320
321
  }
321
322
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -14,7 +14,7 @@
14
14
  "@tiledesk/helpcenter-query-client": "^0.1.8",
15
15
  "@tiledesk/tiledesk-chatbot-client": "^0.5.30",
16
16
  "@tiledesk/tiledesk-chatbot-util": "^0.8.38",
17
- "@tiledesk/tiledesk-client": "^0.9.2",
17
+ "@tiledesk/tiledesk-client": "^0.9.3",
18
18
  "axios": "^0.27.2",
19
19
  "body-parser": "^1.19.0",
20
20
  "cors": "^2.8.5",
@@ -49,7 +49,7 @@ before( () => {
49
49
 
50
50
  after(function(done) {
51
51
  app_listener.close( () => {
52
- console.log('app_listener closed.');
52
+ // console.log('app_listener closed.');
53
53
  done();
54
54
  });
55
55
  });
@@ -63,7 +63,7 @@ describe('Conversation1', async() => {
63
63
  let endpointServer = express();
64
64
  endpointServer.use(bodyParser.json());
65
65
  endpointServer.post('/:projectId/requests/:requestId/messages', function (req, res) {
66
- // console.log("req.body:", JSON.stringify(req.body));
66
+ //console.log("req.body:", JSON.stringify(req.body));
67
67
  res.send({success: true});
68
68
  const message = req.body;
69
69
  assert(message.text === "Hello");
@@ -87,7 +87,7 @@ describe('Conversation1', async() => {
87
87
  assert.ok(false);
88
88
  }
89
89
  else {
90
- console.log("params /start:", params);
90
+ // console.log("params /start:", params);
91
91
  assert(params);
92
92
  assert(params["_tdLastMessageId"] === message_id);
93
93
  assert(params["_tdProjectId"] === PROJECT_ID);
@@ -100,7 +100,7 @@ describe('Conversation1', async() => {
100
100
  });
101
101
 
102
102
  listener = endpointServer.listen(10002, '0.0.0.0', function () {
103
- // console.log('endpointServer started', listener.address());
103
+ //console.log('endpointServer started', listener.address());
104
104
  });
105
105
  let request = {
106
106
  "payload": {
@@ -119,7 +119,7 @@ describe('Conversation1', async() => {
119
119
  "token": CHATBOT_TOKEN
120
120
  }
121
121
  sendMessageToBot(request, BOT_ID, CHATBOT_TOKEN, () => {
122
- // console.log("Message sent.");
122
+ //console.log("Message sent.");
123
123
  });
124
124
  });
125
125
 
@@ -213,7 +213,7 @@ describe('Conversation1', async() => {
213
213
  assert.ok(false);
214
214
  }
215
215
  else {
216
- console.log("params:", params);
216
+ // console.log("params:", params);
217
217
  assert(params);
218
218
  assert(params["_tdLastMessageId"] === message_id);
219
219
  assert(params["_tdProjectId"] === PROJECT_ID);
@@ -258,6 +258,87 @@ describe('Conversation1', async() => {
258
258
  });
259
259
  });
260
260
 
261
+ it('/splitted', (done) => {
262
+ // console.log("/splitted...");
263
+ const message_id = uuidv4();
264
+ const reply_text = "Andrea";
265
+ let listener;
266
+ let endpointServer = express();
267
+ endpointServer.use(bodyParser.json());
268
+ endpointServer.post('/:projectId/requests/:requestId/messages', function (req, res) {
269
+ // console.log("req.body:", JSON.stringify(req.body));
270
+ res.send({success: true});
271
+ const message = req.body;
272
+ // console.log("message:", JSON.stringify(message));
273
+ if (message.attributes.commands) {
274
+ assert(message.attributes.commands.length === 5);
275
+ assert(message.attributes.commands[0].type === "message");
276
+ assert(message.attributes.commands[0].message.text === "Row1");
277
+ assert(message.attributes.commands[0].message.type === "text");
278
+
279
+ assert(message.attributes.commands[1].type === "wait");
280
+ assert(message.attributes.commands[1].time === 500);
281
+
282
+ assert(message.attributes.commands[2].type === "message");
283
+ assert(message.attributes.commands[2].message.text === "Row2");
284
+ assert(message.attributes.commands[2].message.type === "image");
285
+ assert(message.attributes.commands[2].message.metadata);
286
+
287
+ assert(message.attributes.commands[3].type === "wait");
288
+ assert(message.attributes.commands[3].time === 500);
289
+
290
+ assert(message.attributes.commands[4].type === "message");
291
+ assert(message.attributes.commands[4].message.text === "Row4");
292
+ assert(message.attributes.commands[4].message.type === "text");
293
+ assert(message.attributes.commands[4].message.attributes);
294
+ assert(message.attributes.commands[4].message.attributes.attachment);
295
+ assert(message.attributes.commands[4].message.attributes.attachment.type === 'template');
296
+ assert(message.attributes.commands[4].message.attributes.attachment.buttons.length === 1);
297
+ assert(message.attributes.commands[4].message.attributes.attachment.buttons[0].type === 'text');
298
+ assert(message.attributes.commands[4].message.attributes.attachment.buttons[0].value === '/start');
299
+
300
+ const expected_raw_message = 'Row1\n' +
301
+ '\n' +
302
+ 'Row2\n' +
303
+ 'tdImage:https://nypost.com/wp-content/uploads/sites/2/2020/03/covid-tiger-01.jpg?quality=75&strip=all&w=1488\n' +
304
+ '\n' +
305
+ 'Row4\n' +
306
+ '* /start';
307
+ assert(message.attributes._raw_message === expected_raw_message);
308
+ done();
309
+ }
310
+ else {
311
+ console.error("Unexpected message.");
312
+ assert.ok(false);
313
+ }
314
+
315
+ });
316
+
317
+ listener = endpointServer.listen(10002, '0.0.0.0', function () {
318
+ // console.log('endpointServer started', listener.address());
319
+ // console.log("REQUEST_ID:", REQUEST_ID);
320
+ let request = {
321
+ "payload": {
322
+ "_id": uuidv4(),
323
+ "senderFullname": "guest#367e",
324
+ "type": "text",
325
+ "sender": "A-SENDER",
326
+ "recipient": REQUEST_ID,
327
+ "text": "/splitted",
328
+ "id_project": PROJECT_ID,
329
+ "request": {
330
+ "request_id": REQUEST_ID,
331
+ "id_project": PROJECT_ID
332
+ }
333
+ },
334
+ "token": CHATBOT_TOKEN
335
+ }
336
+ sendMessageToBot(request, BOT_ID, CHATBOT_TOKEN, () => {
337
+ // console.log("Message sent.");
338
+ });
339
+ });
340
+ });
341
+
261
342
  });
262
343
 
263
344
  // function createRequest(projectId, callback) {
@@ -337,7 +418,7 @@ function sendMessageToBot(message, botId, token, callback) {
337
418
  callback(null, resbody);
338
419
  }
339
420
  }
340
- }, true
421
+ }, false
341
422
  );
342
423
  }
343
424
 
@@ -370,12 +451,12 @@ function sendMessageToBot(message, botId, token, callback) {
370
451
  callback(null, resbody);
371
452
  }
372
453
  }
373
- }, true
454
+ }, false
374
455
  );
375
456
  }
376
457
 
377
458
  function myrequest(options, callback, log) {
378
- if (this.log) {
459
+ if (log) {
379
460
  console.log("API URL:", options.url);
380
461
  console.log("** Options:", options);
381
462
  }
@@ -388,7 +469,7 @@ function myrequest(options, callback, log) {
388
469
  headers: options.headers
389
470
  })
390
471
  .then((res) => {
391
- if (this.log) {
472
+ if (log) {
392
473
  console.log("Response for url:", options.url);
393
474
  console.log("Response headers:\n", res.headers);
394
475
  //console.log("******** Response for url:", res);
@@ -2,5 +2,5 @@
2
2
  #npx mocha ./test/mock_query_test.js
3
3
  #npx mocha ./test/disable_input_text_directive_test.js
4
4
  #npx mocha ./test/close_directive_test.js
5
- #npx mocha ./test/conversation1-test.js --exit
6
- npx mocha ./test/intent_form_test.js --exit
5
+ npx mocha ./test/conversation1-test.js --exit
6
+ #npx mocha ./test/intent_form_test.js --exit
@@ -20,14 +20,14 @@ class DirDeflectToHelpCenter {
20
20
  let default_hc_reply = "No matching reply but...\n\nI found something interesting in the Help Center 🧐\n\nTake a look 👇";
21
21
  let hc_reply = default_hc_reply;
22
22
  if (directive.parameter) {
23
- console.log("processing parameters")
23
+ // console.log("processing parameters")
24
24
  const params = this.parseParams(directive.parameter);
25
- console.log("parameters found", params);
25
+ // console.log("parameters found", params);
26
26
  workspace_id = params.workspace_id;
27
- console.log("workspaceid found", workspace_id);
27
+ // console.log("workspaceid found", workspace_id);
28
28
  if (params.hc_reply) {
29
29
  hc_reply = params.hc_reply;
30
- console.log("hc_reply found", hc_reply);
30
+ // console.log("hc_reply found", hc_reply);
31
31
  }
32
32
  }
33
33
  else {
@@ -52,10 +52,10 @@ class DirDeflectToHelpCenter {
52
52
  const workspaces = await helpcenter.allWorkspaces();
53
53
  if (workspaces.length > 0) {
54
54
  workspace_id = workspaces[0]._id;
55
- console.log("First Workspace selected", workspaces[0]);
55
+ // console.log("First Workspace selected", workspaces[0]);
56
56
  }
57
57
  else {
58
- console.log("No Workspace found");
58
+ // console.log("No Workspace found");
59
59
  completion();
60
60
  }
61
61
  }
@@ -64,12 +64,12 @@ class DirDeflectToHelpCenter {
64
64
  completion();
65
65
  }
66
66
  }
67
- console.log("searching on workspace_id:", workspace_id);
67
+ // console.log("searching on workspace_id:", workspace_id);
68
68
  try {
69
69
  const results = await helpcenter.search(workspace_id, original_text, maxresults);
70
70
  if (results && results.length > 0) {
71
- console.log("Successfully got results", results);
72
- console.log("Sending REPL", hc_reply);
71
+ // console.log("Successfully got results", results);
72
+ // console.log("Sending REPL", hc_reply);
73
73
  pipeline.message.text = hc_reply;
74
74
  results.forEach(content => {
75
75
  if (content.url.charAt(content.url.length -1) != "/") {
@@ -93,9 +93,9 @@ class DirDeflectToHelpCenter {
93
93
  parseParams(directive_parameter) {
94
94
  let workspace_id = null;
95
95
  let hc_reply = null;
96
- console.log("ms found:", ms)
96
+ // console.log("ms found:", ms)
97
97
  const params = ms(directive_parameter);
98
- console.log("ms decoded params:", params)
98
+ // console.log("ms decoded params:", params)
99
99
  if (params.w) {
100
100
  workspace_id = params.w
101
101
  }
@@ -104,16 +104,16 @@ class DirDeflectToHelpCenter {
104
104
  }
105
105
 
106
106
  if (params.m) {
107
- console.log("_params.m:", params.m)
107
+ // console.log("_params.m:", params.m)
108
108
  //hc_reply = params.m.replaceAll("\\n", "\n");
109
109
  hc_reply = params.m.replace(/\\n/g, "\n");
110
- console.log("hc_reply with replaced slash n regex|replaceAll", hc_reply)
110
+ // console.log("hc_reply with replaced slash n regex|replaceAll", hc_reply)
111
111
  }
112
112
  if (params.message) {
113
- console.log("_params.message:", params.message)
113
+ // console.log("_params.message:", params.message)
114
114
  //hc_reply = params.message.replaceAll("\\n", "\n");
115
115
  hc_reply = params.message.replace(/\\n/g, "\n");
116
- console.log("hc_reply -message with replaced slash n replace(/\\n/g", hc_reply)
116
+ // console.log("hc_reply -message with replaced slash n replace(/\\n/g", hc_reply)
117
117
  }
118
118
  return {
119
119
  workspace_id: workspace_id,