@tiledesk/tiledesk-whatsapp-connector 0.1.33 → 0.1.34

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/index.js CHANGED
@@ -11,7 +11,7 @@ const { v4: uuidv4 } = require('uuid');
11
11
  const cors = require('cors');
12
12
 
13
13
  // tiledesk clients
14
- const { TiledeskClient } = require('@tiledesk/tiledesk-client');
14
+ //const { TiledeskClient } = require('@tiledesk/tiledesk-client');
15
15
  const { TiledeskWhatsappTranslator } = require('./tiledesk/TiledeskWhatsappTranslator');
16
16
  const { TiledeskSubscriptionClient } = require('./tiledesk/TiledeskSubscriptionClient');
17
17
  const { TiledeskWhatsapp } = require('./tiledesk/TiledeskWhatsapp');
@@ -21,9 +21,9 @@ const { MessageHandler } = require('./tiledesk/MessageHandler');
21
21
  const { TiledeskBotTester } = require('./tiledesk/TiledeskBotTester');
22
22
 
23
23
  // mongo
24
- const { KVBaseMongo } = require('@tiledesk/tiledesk-kvbasemongo');
24
+ const { KVBaseMongo } = require('./tiledesk/KVBaseMongo');
25
25
  const kvbase_collection = 'kvstore';
26
- const db = new KVBaseMongo(kvbase_collection);
26
+ const db = new KVBaseMongo({KVBASE_COLLECTION: kvbase_collection, log: false});
27
27
 
28
28
  // redis
29
29
  var redis = require('redis')
@@ -43,6 +43,15 @@ let REDIS_PORT = null;
43
43
  let REDIS_PASSWORD = null;
44
44
  let log = false;
45
45
 
46
+ // Handlebars register helpers
47
+ handlebars.registerHelper('isEqual', (a, b) => {
48
+ if (a == b) {
49
+ return true
50
+ } else {
51
+ return false
52
+ }
53
+ })
54
+
46
55
  router.get('/', async (req, res) => {
47
56
  res.send('Welcome to Tiledesk-WhatsApp Business connector!')
48
57
  })
@@ -183,6 +192,13 @@ router.get('/configure', async (req, res) => {
183
192
  console.log("(whatsapp) kvdb settings: ", settings);
184
193
  }
185
194
 
195
+ // get departments
196
+ const tdChannel = new TiledeskChannel({ settings: { project_id: projectId, token: token }, API_URL: API_URL })
197
+ let departments = await tdChannel.getDepartments(token);
198
+ if (log) {
199
+ console.log("departments: ", JSON.stringify(departments))
200
+ }
201
+
186
202
  if (settings) {
187
203
 
188
204
  readHTMLFile('/configure.html', (err, html) => {
@@ -199,6 +215,8 @@ router.get('/configure', async (req, res) => {
199
215
  wab_token: settings.wab_token,
200
216
  verify_token: settings.verify_token,
201
217
  subscription_id: settings.subscriptionId,
218
+ department_id: settings.department_id,
219
+ departments: departments
202
220
  }
203
221
  var html = template(replacements);
204
222
  res.send(html);
@@ -219,6 +237,7 @@ router.get('/configure', async (req, res) => {
219
237
  project_id: projectId,
220
238
  token: token,
221
239
  proxy_url: proxy_url,
240
+ departments: departments
222
241
  }
223
242
  var html = template(replacements);
224
243
  res.send(html);
@@ -229,24 +248,33 @@ router.get('/configure', async (req, res) => {
229
248
 
230
249
  router.post('/update', async (req, res) => {
231
250
  console.log("\n(whatsapp) /update");
232
- if (log) {
233
251
  console.log("(whatsapp) /update body: ", req.body);
252
+ if (log) {
234
253
  }
235
254
 
236
255
  let projectId = req.body.project_id;
237
256
  let token = req.body.token;
238
257
  let wab_token = req.body.wab_token;
239
258
  let verify_token = req.body.verify_token;
259
+ let department_id = req.body.department;
240
260
 
241
261
  let CONTENT_KEY = "whatsapp-" + projectId;
242
262
  let settings = await db.get(CONTENT_KEY);
243
263
 
244
264
  let proxy_url = BASE_URL + "/webhook/" + projectId;
245
265
 
266
+ // get departments
267
+ const tdChannel = new TiledeskChannel({ settings: { project_id: projectId, token: token }, API_URL: API_URL })
268
+ let departments = await tdChannel.getDepartments(token);
269
+ if (log) {
270
+ console.log("departments: ", JSON.stringify(departments))
271
+ }
272
+
246
273
  if (settings) {
247
274
 
248
275
  settings.wab_token = wab_token;
249
276
  settings.verify_token = verify_token;
277
+ settings.department_id = department_id;
250
278
 
251
279
  await db.set(CONTENT_KEY, settings);
252
280
 
@@ -265,6 +293,8 @@ router.post('/update', async (req, res) => {
265
293
  show_success_modal: true,
266
294
  verify_token: settings.verify_token,
267
295
  subscription_id: settings.subscriptionId,
296
+ department_id: settings.department_id,
297
+ departments: departments
268
298
  }
269
299
  var html = template(replacements);
270
300
  res.send(html);
@@ -301,6 +331,7 @@ router.post('/update', async (req, res) => {
301
331
  secret: subscription.secret,
302
332
  wab_token: wab_token,
303
333
  verify_token: verify_token,
334
+ department_id: department_id
304
335
  }
305
336
 
306
337
  db.set(CONTENT_KEY, settings)
@@ -321,6 +352,8 @@ router.post('/update', async (req, res) => {
321
352
  wab_token: settings.wab_token,
322
353
  verify_token: settings.verify_token,
323
354
  subscription_id: settings.subscriptionId,
355
+ department_id: settings.department_id,
356
+ departments: departments
324
357
  }
325
358
  var html = template(replacements);
326
359
  res.send(html);
@@ -339,6 +372,7 @@ router.post('/update', async (req, res) => {
339
372
  project_id: projectId,
340
373
  token: token,
341
374
  proxy_url: proxy_url,
375
+ departments: departments,
342
376
  show_error_modal: true
343
377
  }
344
378
  var html = template(replacements);
@@ -367,6 +401,12 @@ router.post('/disconnect', async (req, res) => {
367
401
  let proxy_url = BASE_URL + "/webhook/" + projectId;
368
402
 
369
403
  const tdClient = new TiledeskSubscriptionClient({ API_URL: API_URL, project_id: projectId, token: token, log: false })
404
+ // get departments
405
+ const tdChannel = new TiledeskChannel({ settings: { project_id: projectId, token: token }, API_URL: API_URL })
406
+ let departments = await tdChannel.getDepartments(token);
407
+ if (log) {
408
+ console.log("departments: ", JSON.stringify(departments))
409
+ }
370
410
 
371
411
  /*
372
412
  // callback
@@ -389,6 +429,7 @@ router.post('/disconnect', async (req, res) => {
389
429
  project_id: projectId,
390
430
  token: token,
391
431
  proxy_url: proxy_url,
432
+ departments: departments
392
433
  }
393
434
  var html = template(replacements);
394
435
  res.send(html);
@@ -402,8 +443,8 @@ router.post('/disconnect', async (req, res) => {
402
443
 
403
444
  router.post('/tiledesk', async (req, res) => {
404
445
  console.log("\n(whatsapp) /tiledesk")
446
+ console.log("(whatsapp) /tiledesk ---> tiledeskChannelMessage: " + JSON.stringify(req.body.payload));
405
447
  if (log) {
406
- console.log("(whatsapp) /tiledesk ---> tiledeskChannelMessage: " + JSON.stringify(req.body.payload));
407
448
  }
408
449
 
409
450
  var tiledeskChannelMessage = req.body.payload;
@@ -680,7 +721,7 @@ router.post("/webhook/:project_id", async (req, res) => {
680
721
  }
681
722
 
682
723
  console.log("🟠 tiledeskJsonMessage: ", JSON.stringify(tiledeskJsonMessage));
683
- const response = await tdChannel.send(tiledeskJsonMessage, message_info);
724
+ const response = await tdChannel.send(tiledeskJsonMessage, message_info, settings.department_id);
684
725
  if (log) {
685
726
  console.log("(whatsapp) /whatsapp Send response: ", response)
686
727
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-whatsapp-connector",
3
- "version": "0.1.33",
3
+ "version": "0.1.34",
4
4
  "description": "Tiledesk Whatsapp connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,7 +12,6 @@
12
12
  "license": "MIT",
13
13
  "dependencies": {
14
14
  "@tiledesk/tiledesk-client": "^0.8.29",
15
- "@tiledesk/tiledesk-kvbasemongo": "^1.0.0",
16
15
  "app-root-path": "^3.0.0",
17
16
  "axios": "^0.27.2",
18
17
  "body-parser": "^1.20.0",
@@ -201,9 +201,54 @@
201
201
  </div>
202
202
  </div>
203
203
 
204
+ <!-- Departments -->
205
+ <div class="form-group" style="width: 522px;">
206
+ <label class="input-label" for="department">Department <span style="font-weight: normal;">(Optional)</span></label>
207
+
208
+
209
+
210
+
211
+
212
+ <!--
213
+ <div class="dep-container">
214
+ {{#each departments}}
215
+
216
+ {{#if (isEqual _id department_id)}}
217
+ <div class="selected-department-div" onclick="submitInputSelected.click()">
218
+ <img class="tick-image" src="https://static.vecteezy.com/system/resources/previews/010/152/436/original/tick-check-mark-icon-sign-symbol-design-free-png.png" width="18" height="auto">
219
+ {{ name }}
220
+ </div>
221
+ {{else}}
222
+ <div class="department-div">
223
+ {{ name }}
224
+ </div>
225
+ {{/if}}
226
+ {{/each}}
227
+ </div>
228
+ -->
229
+
230
+ <div style="display: flex; flex-direction: row; align-items: center;">
231
+ <select class="custom-select" name="department" class="form-control">
232
+ {{#each departments}}
233
+ {{#if (isEqual _id ../department_id)}}
234
+ <option value="{{ _id }}" selected>{{ name }}</option>
235
+ {{else}}
236
+ <option value="{{ _id }}">{{ name }}</option>
237
+ {{/if}}
238
+ {{/each}}
239
+ </select>
240
+ <span style="margin-left: 10px;">
241
+ <i class="fa fa-question-circle custom-tooltip">
242
+ <span class="custom-tooltiptext">Select the department where you want to open conversations coming from WhatsApp. Conversations are sent on the Default Department by default.</span>
243
+ </i>
244
+ </span>
245
+ </div>
246
+
247
+ </div>
248
+
204
249
  <input type="hidden" name="project_id" value="{{ project_id }}" />
205
250
  <input type="hidden" name="token" value="{{ token }}" />
206
-
251
+
207
252
  {{#if wab_token}}
208
253
  <div style="width: 500px; text-align: right;">
209
254
  <input type="submit" class="btn" style="width: 200px; background-color: #0ba2dc; color: white; font-weight: 500;" value="Update">
@@ -142,14 +142,35 @@ ul {
142
142
 
143
143
  .custom-input {
144
144
  height: 45px;
145
- border: solid 2px #d8d8d8;
145
+ box-shadow: 0px 0px 7px 0px #bdbdbd;
146
+ border: solid 2px transparent;
147
+ border-radius: 6px;
146
148
  }
147
149
 
148
150
  .custom-input:hover {
149
151
  border-color: #0ba2dc;
152
+ box-shadow: 0 0 transparent;
150
153
  }
151
154
 
152
155
  .custom-input:focus {
156
+ border: solid 2px;
157
+ border-color: #0ba2dc;
158
+ }
159
+
160
+ .custom-select{
161
+ width: 100%;
162
+ height: 45px;
163
+ box-shadow: 0px 0px 7px 0px #bdbdbd;
164
+ border: solid 2px transparent;
165
+ border-radius: 6px;
166
+ }
167
+
168
+ .custom-select:hover {
169
+ box-shadow: 0 0 transparent;
170
+ border-color: #0ba2dc;
171
+ }
172
+
173
+ .custom-select:focus {
153
174
  border-color: #0ba2dc;
154
175
  }
155
176
 
@@ -359,4 +380,42 @@ ul {
359
380
  border-color: #929292;
360
381
  background-color: #929292;
361
382
  letter-spacing: 0.5px;
362
- }
383
+ }
384
+
385
+ .dep-container {
386
+ display: flex;
387
+ flex-direction: row;
388
+ width: 700px;
389
+ }
390
+
391
+ .department-div {
392
+ cursor: pointer;
393
+ height: 40px;
394
+ background-color: #ececec;
395
+ border: solid 2px #ececec;
396
+ border-radius: 6px;
397
+ margin-right: 10px;
398
+ padding: 20px;
399
+ display: flex;
400
+ align-items: center;
401
+ }
402
+
403
+ .department-div:hover {
404
+ background-color: #fff;
405
+ border: solid 2px #0ba2dc;
406
+ }
407
+
408
+ .selected-department-div {
409
+ cursor: pointer;
410
+ height: 40px;
411
+ background-color: #fff;
412
+ border: solid 2px #0ba2dc;
413
+ border-radius: 6px;
414
+ margin-right: 10px;
415
+ padding: 20px;
416
+ display: flex;
417
+ flex-direction: row;
418
+ align-items: center;
419
+ justify-content: space-evenly;
420
+ /*justify-content: center;*/
421
+ }
@@ -190,6 +190,15 @@
190
190
 
191
191
  <p style="font-size: 18px;"><b>What's new?</b></p>
192
192
 
193
+ <div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 15px;">
194
+ <div>
195
+ <p style="margin-bottom: 0px">Added possibility to select a department for Whatsapp conversations.</p>
196
+ <p style="margin-bottom: 0px">Bug fixes and minor improvements</p>
197
+ <!--<p>Bug fixes and performance improvements</p>-->
198
+ </div>
199
+ <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.34</b></p>
200
+ </div>
201
+
193
202
  <div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 15px;">
194
203
  <div>
195
204
  <p style="margin-bottom: 0px">Bug Fixes</p>
@@ -208,15 +217,6 @@
208
217
  <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.24</b></p>
209
218
  </div>
210
219
 
211
- <div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 15px;">
212
- <div>
213
- <p style="margin-bottom: 0px">Bug Fixes</p>
214
- <!--<p>Bug fixes and performance improvements</p>-->
215
- </div>
216
- <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.23</b></p>
217
- </div>
218
-
219
-
220
220
  <hr style="margin-top: 50px; margin-bottom: 20px">
221
221
 
222
222
  </body>
@@ -0,0 +1,96 @@
1
+ const mongodb = require("mongodb");
2
+
3
+ class KVBaseMongo {
4
+
5
+ /**
6
+ * Constructor for KVBaseMongo object
7
+ *
8
+ * @example
9
+ * const { KVBaseMongo } = require('./KVBaseMongo');
10
+ * let db = new KVBaseMongo("kvstore");
11
+ *
12
+ * @param {KVBASE_COLLECTION} The name of the Mongodb collection used as key-value store. Mandatory.
13
+ */
14
+ constructor(config) {
15
+ if (!config.KVBASE_COLLECTION) {
16
+ throw new Error('KVBASE_COLLECTION (the name of the Mongodb collection used as key-value store) is mandatory.');
17
+ }
18
+ this.KV_COLLECTION = config.KVBASE_COLLECTION;
19
+
20
+ this.log = false;
21
+ if (config.log) {
22
+ this.log = config.log;
23
+ }
24
+ }
25
+
26
+ connect(MONGODB_URI, callback) {
27
+ mongodb.MongoClient.connect(MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
28
+ if (err) {
29
+ console.log(err);
30
+ process.exit(1);
31
+ } else {
32
+ this.db = client.db();
33
+ this.db.collection(this.KV_COLLECTION).createIndex(
34
+ { "key": 1 }, { unique: true }
35
+ );
36
+ callback();
37
+ }
38
+ });
39
+ }
40
+
41
+ set(k, v) {
42
+ return new Promise(resolve => {
43
+ //this.db.set(k, v).then(() => {resolve();});
44
+ this.db.collection(this.KV_COLLECTION).updateOne({key: k}, { $set: { value: v, key: k } }, { upsert: true }, function(err, doc) {
45
+ if (err) {
46
+ reject(err);
47
+ }
48
+ else {
49
+ resolve();
50
+ }
51
+ });
52
+ });
53
+ }
54
+
55
+ get(k) {
56
+ return new Promise(resolve => {
57
+ //this.db.get(k).then(value => {resolve(value)});
58
+ if (this.log) {
59
+ console.log("Searching on ", this.db)
60
+ }
61
+ console.log("Searching on Collection", this.KV_COLLECTION)
62
+
63
+ this.db.collection(this.KV_COLLECTION).findOne({ key: k }, function(err, doc) {
64
+ if (err) {
65
+ console.error("Error reading mongodb value", err);
66
+ reject(err);
67
+ }
68
+ else {
69
+ if (doc) {
70
+ console.log("Doc found with key -->", doc.key);
71
+ resolve(doc.value);
72
+ }
73
+ else {
74
+ console.log("No Doc found!");
75
+ resolve(null);
76
+ }
77
+ }
78
+ });
79
+ });
80
+ }
81
+
82
+ remove(k) {
83
+ return new Promise(resolve => {
84
+ this.db.collection(this.KV_COLLECTION).deleteOne({key: k}, function(err) {
85
+ if (err) {
86
+ reject(err);
87
+ }
88
+ else {
89
+ resolve();
90
+ }
91
+ });
92
+ });
93
+ }
94
+ }
95
+
96
+ module.exports = { KVBaseMongo };
@@ -42,11 +42,15 @@ class TiledeskChannel {
42
42
 
43
43
  }
44
44
 
45
- async send(tiledeskMessage, messageInfo) {
45
+ async send(tiledeskMessage, messageInfo, department_id) {
46
46
 
47
47
  let channel;
48
48
  let new_request_id;
49
49
 
50
+ if (department_id) {
51
+ tiledeskMessage.departmentid = department_id;
52
+ }
53
+
50
54
  if (messageInfo.channel == "whatsapp") {
51
55
  channel = messageInfo.whatsapp;
52
56
  new_request_id = "support-group-" + this.settings.project_id + "-" + uuidv4().substring(0, 8) + "-wab-" + channel.phone_number_id + "-" + channel.from;
@@ -143,6 +147,28 @@ class TiledeskChannel {
143
147
  })
144
148
  }
145
149
 
150
+
151
+ async getDepartments() {
152
+
153
+ console.log("[Tiledesk Channel] getDepartments");
154
+
155
+ return await axios({
156
+ url: this.API_URL + "/" + this.settings.project_id + "/departments/allstatus",
157
+ headers: {
158
+ 'Content-Type': 'application/json',
159
+ 'Authorization': this.settings.token
160
+ },
161
+ method: 'GET'
162
+ }).then((response) => {
163
+ if (this.log) {
164
+ console.log("\nget departments response.data: ", response.data)
165
+ }
166
+ return response.data;
167
+ }).catch((err) => {
168
+ console.error("\nget departments error: ", err);
169
+ })
170
+ }
171
+
146
172
  async sendAndAddBot(tiledeskMessage, messageInfo, bot_id) {
147
173
 
148
174
  let channel;
@@ -181,7 +207,6 @@ class TiledeskChannel {
181
207
 
182
208
  return axios({
183
209
  url: this.API_URL + `/${this.settings.project_id}/requests/${new_request_id}/messages`,
184
- //url: this.API_URL + `/${this.settings.project_id}/requests/${new_request_id}/participants`,
185
210
  headers: {
186
211
  'Content-Type': 'application/json',
187
212
  'Authorization': token
@@ -190,23 +215,6 @@ class TiledeskChannel {
190
215
  method: 'POST'
191
216
  }).then((response) => {
192
217
  return response.data
193
-
194
- /*
195
- return axios({
196
- url: this.API_URL + `/${this.settings.project_id}/requests/${new_request_id}/participants`,
197
- headers: {
198
- 'Content-Type': 'application/json',
199
- 'Authorization': token
200
- },
201
- data: { member: bot_id },
202
- method: 'POST'
203
- }).then((response) => {
204
- console.log("response: ", response.data)
205
- return response.data
206
- }).catch((err) => {
207
- console.error("[Tiledesk Channel ERROR] add participant: ", err);
208
- })
209
- */
210
218
  }).catch((err) => {
211
219
  console.error("[Tiledesk Channel ERROR] send message (open conversation): " + err);
212
220
  })
@@ -127,7 +127,7 @@ class TiledeskSubscriptionClient {
127
127
  }
128
128
  }
129
129
  }).catch((err) => {
130
- console.error("An error occured: ", err);
130
+ //console.error("An error occured: ", err);
131
131
  if (callback) {
132
132
  callback(err, null, null);
133
133
  }