@tiledesk/tiledesk-whatsapp-connector 1.0.32 → 1.0.33

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/.env CHANGED
@@ -1,2 +1,2 @@
1
1
  # CUSTOM ENV
2
- NPM_PUBLISH_TOKEN=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
2
+ NPM_PUBLISH_TOKEN=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
package/index.js CHANGED
@@ -31,7 +31,7 @@ const { TemplateManager } = require("./tiledesk/TemplateManager");
31
31
  const { WhatsappLogger } = require("./tiledesk/WhatsappLogger");
32
32
  const Utils = require("./tiledesk/Utils");
33
33
  const whatsappService = require("./tiledesk/WhatsappService");
34
- const { ensureGlobalSigninSubscription, ensureProjectTestSubscription } = require("./tiledesk/BotTestSubscriptions");
34
+ const { ensureGlobalSigninSubscription, ensureProjectTestSubscription, getActiveTest, isProjectId } = require("./tiledesk/BotTestSubscriptions");
35
35
 
36
36
  // mongo
37
37
  const { KVBaseMongo } = require("./tiledesk/KVBaseMongo");
@@ -931,7 +931,7 @@ router.post('/webhook', async (req, res) => {
931
931
  winston.verbose("(wab) tiledeskJsonMessage: ", tiledeskJsonMessage);
932
932
 
933
933
  try {
934
- const response = await tdChannel.send(tiledeskJsonMessage, message_info, settings.department_id);
934
+ const response = await deliverInboundMessage(tdChannel, tiledeskJsonMessage, message_info, settings);
935
935
  winston.verbose("(wab) Message sent to Tiledesk!");
936
936
  winston.debug("(wab) response: ", response);
937
937
  } catch (err) {
@@ -1166,7 +1166,7 @@ router.post("/webhook/:project_id", async (req, res) => {
1166
1166
 
1167
1167
  if (tiledeskJsonMessage) {
1168
1168
  winston.verbose("(wab) tiledeskJsonMessage: ", tiledeskJsonMessage);
1169
- const response = await tdChannel.send(tiledeskJsonMessage, message_info, settings.department_id);
1169
+ const response = await deliverInboundMessage(tdChannel, tiledeskJsonMessage, message_info, settings);
1170
1170
  winston.verbose("(wab) Message sent to Tiledesk!");
1171
1171
  winston.debug("(wab) response: ", response);
1172
1172
  } else {
@@ -1875,6 +1875,22 @@ async function getDepartments(project_id, token) {
1875
1875
  }
1876
1876
  }
1877
1877
 
1878
+ async function deliverInboundMessage(tdChannel, tiledeskJsonMessage, messageInfo, settings) {
1879
+ const whatsapp = messageInfo && messageInfo.whatsapp;
1880
+ const session = await getActiveTest(redis_client, whatsapp && whatsapp.phone_number_id, whatsapp && whatsapp.from);
1881
+ if (session && session.request_id && isProjectId(session.project_id)) {
1882
+ winston.verbose("(wab) Continue Try on WhatsApp in project " + session.project_id);
1883
+ const signinSubscription = await ensureGlobalSigninSubscription(db, BASE_URL);
1884
+ return tdChannel.sendToExistingRequest(tiledeskJsonMessage, messageInfo, {
1885
+ project_id: session.project_id,
1886
+ request_id: session.request_id,
1887
+ subscriptionId: String(signinSubscription._id),
1888
+ secret: signinSubscription.secret
1889
+ });
1890
+ }
1891
+ return tdChannel.send(tiledeskJsonMessage, messageInfo, settings.department_id);
1892
+ }
1893
+
1878
1894
  /**
1879
1895
  * Helper function to get or create user token with Redis caching
1880
1896
  * @param {Object} tdChannel - TiledeskChannel instance
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-whatsapp-connector",
3
- "version": "1.0.32",
3
+ "version": "1.0.33",
4
4
  "description": "Tiledesk Whatsapp connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -95,6 +95,44 @@ async function ensureProjectTestSubscription(kv, projectId, baseUrl, redisClient
95
95
  return existing;
96
96
  }
97
97
 
98
+ function activeTestKey(phoneNumberId, from) {
99
+ return "bottest:active:" + phoneNumberId + ":" + from;
100
+ }
101
+
102
+ function saveActiveTest(redisClient, phoneNumberId, from, session) {
103
+ if (!redisClient || !phoneNumberId || !from || !session) {
104
+ return Promise.resolve();
105
+ }
106
+ const key = activeTestKey(phoneNumberId, from);
107
+ return new Promise((resolve, reject) => {
108
+ redisClient.set(key, JSON.stringify(session), "EX", 604800, function (err) {
109
+ if (err) {
110
+ return reject(err);
111
+ }
112
+ resolve();
113
+ });
114
+ });
115
+ }
116
+
117
+ function getActiveTest(redisClient, phoneNumberId, from) {
118
+ if (!redisClient || !phoneNumberId || !from) {
119
+ return Promise.resolve(null);
120
+ }
121
+ const key = activeTestKey(phoneNumberId, from);
122
+ return new Promise((resolve) => {
123
+ redisClient.get(key, function (err, value) {
124
+ if (err || !value) {
125
+ return resolve(null);
126
+ }
127
+ try {
128
+ resolve(JSON.parse(value));
129
+ } catch (parseErr) {
130
+ resolve(null);
131
+ }
132
+ });
133
+ });
134
+ }
135
+
98
136
  function invalidateSubscriptionCache(redisClient, projectId, event) {
99
137
  if (!redisClient || !projectId || !event) {
100
138
  return Promise.resolve();
@@ -120,5 +158,7 @@ module.exports = {
120
158
  WHATSAPP_MESSAGE_EVENT,
121
159
  isProjectId,
122
160
  ensureGlobalSigninSubscription,
123
- ensureProjectTestSubscription
161
+ ensureProjectTestSubscription,
162
+ saveActiveTest,
163
+ getActiveTest
124
164
  };
@@ -7,7 +7,7 @@ const { TiledeskClient } = require('@tiledesk/tiledesk-client');
7
7
  const { TiledeskWhatsappTranslator } = require('./TiledeskWhatsappTranslator');
8
8
  const { TiledeskChannel } = require('./TiledeskChannel');
9
9
  const Utils = require("./Utils");
10
- const { ensureGlobalSigninSubscription, ensureProjectTestSubscription, isProjectId } = require("./BotTestSubscriptions");
10
+ const { ensureGlobalSigninSubscription, ensureProjectTestSubscription, isProjectId, saveActiveTest } = require("./BotTestSubscriptions");
11
11
 
12
12
  class TiledeskBotTester {
13
13
 
@@ -123,6 +123,13 @@ class TiledeskBotTester {
123
123
  subscriptionId: String(signinSubscription._id),
124
124
  secret: signinSubscription.secret
125
125
  });
126
+ if (response && response.request_id) {
127
+ await saveActiveTest(this.redis_client, phoneNumberId, message_info.whatsapp.from, {
128
+ project_id: test_info.project_id,
129
+ bot_id: test_info.bot_id,
130
+ request_id: response.request_id
131
+ });
132
+ }
126
133
  return resolve(response);
127
134
  } catch (prepareErr) {
128
135
  winston.error("(wab) [TiledeskBotTester] unable to open test conversation: " + prepareErr);
@@ -236,7 +236,9 @@ class TiledeskChannel {
236
236
  data: tiledeskMessage,
237
237
  method: 'POST'
238
238
  }).then((response) => {
239
- return response.data
239
+ const data = response.data || {};
240
+ data.request_id = new_request_id;
241
+ return data;
240
242
  }).catch((err) => {
241
243
  const errorMessage = utils._extractErrorMessage(err);
242
244
  winston.error("(wab) [TiledeskChannel] send message (open conversation) error: " + errorMessage);
@@ -247,6 +249,49 @@ class TiledeskChannel {
247
249
  })
248
250
  }
249
251
 
252
+ /**
253
+ * Append a message to a Try on WhatsApp request that already lives in the bot's project.
254
+ */
255
+ async sendToExistingRequest(tiledeskMessage, messageInfo, target) {
256
+ if (!target || !target.project_id || !target.request_id || !target.subscriptionId || !target.secret) {
257
+ throw new Error("Try on WhatsApp session is incomplete");
258
+ }
259
+
260
+ const channel = messageInfo.whatsapp || {};
261
+ const payload = {
262
+ _id: 'wab-' + channel.from,
263
+ first_name: channel.firstname,
264
+ last_name: channel.lastname,
265
+ sub: 'userexternal',
266
+ aud: 'https://tiledesk.com/subscriptions/' + target.subscriptionId
267
+ };
268
+ const customToken = jwt.sign(payload, target.secret);
269
+
270
+ const signinResponse = await axios({
271
+ url: this.API_URL + "/auth/signinWithCustomToken",
272
+ headers: {
273
+ 'Content-Type': 'application/json',
274
+ 'Authorization': 'JWT ' + customToken
275
+ },
276
+ data: { id_project: target.project_id },
277
+ method: 'POST'
278
+ });
279
+
280
+ const token = this.fixToken(signinResponse.data.token);
281
+ delete tiledeskMessage.participants;
282
+
283
+ const sendResponse = await axios({
284
+ url: this.API_URL + `/${target.project_id}/requests/${target.request_id}/messages`,
285
+ headers: {
286
+ 'Content-Type': 'application/json',
287
+ 'Authorization': token
288
+ },
289
+ data: tiledeskMessage,
290
+ method: 'POST'
291
+ });
292
+ return sendResponse.data;
293
+ }
294
+
250
295
  /**
251
296
  * Get the project detail from Tiledesk
252
297
  * @returns {Promise<Object>} - The response from the Tiledesk API