@tiledesk/tiledesk-whatsapp-connector 1.0.31 → 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 +1 -1
- package/index.js +97 -17
- package/package.json +1 -1
- package/tiledesk/BotTestSubscriptions.js +164 -0
- package/tiledesk/TiledeskBotTester.js +30 -6
- package/tiledesk/TiledeskChannel.js +60 -9
package/.env
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# CUSTOM ENV
|
|
2
|
-
NPM_PUBLISH_TOKEN=
|
|
2
|
+
NPM_PUBLISH_TOKEN=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
|
package/index.js
CHANGED
|
@@ -31,6 +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, getActiveTest, isProjectId } = require("./tiledesk/BotTestSubscriptions");
|
|
34
35
|
|
|
35
36
|
// mongo
|
|
36
37
|
const { KVBaseMongo } = require("./tiledesk/KVBaseMongo");
|
|
@@ -560,22 +561,22 @@ router.post("/disconnect", async (req, res) => {
|
|
|
560
561
|
// ***************************************
|
|
561
562
|
// ****** MESSAGING SECTION - START ******
|
|
562
563
|
// ***************************************
|
|
563
|
-
|
|
564
|
+
function phoneNumberIdFromTiledeskRecipient(recipient, attributes) {
|
|
565
|
+
if (attributes && attributes.whatsapp_phone_number_id) {
|
|
566
|
+
return attributes.whatsapp_phone_number_id;
|
|
567
|
+
}
|
|
568
|
+
if (!recipient || recipient.indexOf("wab-") === -1) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
return recipient.substring(recipient.lastIndexOf("wab-") + 4, recipient.lastIndexOf("-"));
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
async function handleTiledeskOutbound(req, res, settings) {
|
|
564
575
|
winston.verbose("(wab) Message received from Tiledesk");
|
|
565
576
|
|
|
566
577
|
let tiledeskChannelMessage = req.body.payload;
|
|
567
578
|
winston.debug("(wab) tiledeskChannelMessage: ", tiledeskChannelMessage);
|
|
568
579
|
|
|
569
|
-
let project_id = req.body.payload.id_project;
|
|
570
|
-
let recipient = req.body.payload.recipient;
|
|
571
|
-
let waba_id = recipient.split('-')[5];
|
|
572
|
-
|
|
573
|
-
let settings = await utils.getSettingsByProjectId(project_id);
|
|
574
|
-
|
|
575
|
-
if (!settings) {
|
|
576
|
-
settings = await utils.getSettings(project_id, waba_id);
|
|
577
|
-
}
|
|
578
|
-
|
|
579
580
|
let wab_token = settings.wab_token;
|
|
580
581
|
|
|
581
582
|
var text = req.body.payload.text;
|
|
@@ -758,6 +759,55 @@ router.post("/tiledesk", async (req, res) => {
|
|
|
758
759
|
winston.debug("(wab) no command, no text --> skip");
|
|
759
760
|
return res.status(400).send({ success: false, error: "No command or text specified. Skip message." });
|
|
760
761
|
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
router.post("/tiledesk", async (req, res) => {
|
|
765
|
+
const payload = req.body && req.body.payload;
|
|
766
|
+
if (!payload || !payload.recipient) {
|
|
767
|
+
return res.status(400).send({ success: false, error: "Invalid Tiledesk payload" });
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
const project_id = payload.id_project;
|
|
771
|
+
const waba_id = payload.recipient.split("-")[5];
|
|
772
|
+
let settings = await utils.getSettingsByProjectId(project_id);
|
|
773
|
+
if (!settings) {
|
|
774
|
+
settings = await utils.getSettings(project_id, waba_id);
|
|
775
|
+
}
|
|
776
|
+
if (!settings) {
|
|
777
|
+
winston.warn("(wab) settings not found for project " + project_id);
|
|
778
|
+
return res.sendStatus(200);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const phoneNumberId = phoneNumberIdFromTiledeskRecipient(payload.recipient, payload.attributes);
|
|
782
|
+
if (phoneNumberId) {
|
|
783
|
+
const official = await db.get("whatsapp-phone-" + phoneNumberId);
|
|
784
|
+
if (official && official.project_id && String(official.project_id) !== String(project_id)) {
|
|
785
|
+
winston.verbose("(wab) Skip Try on WhatsApp reply on the project subscription");
|
|
786
|
+
return res.sendStatus(200);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
return handleTiledeskOutbound(req, res, settings);
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
router.post("/tiledesk/test", async (req, res) => {
|
|
794
|
+
const payload = req.body && req.body.payload;
|
|
795
|
+
if (!payload || !payload.recipient) {
|
|
796
|
+
return res.sendStatus(200);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const phoneNumberId = phoneNumberIdFromTiledeskRecipient(payload.recipient, payload.attributes);
|
|
800
|
+
if (!phoneNumberId) {
|
|
801
|
+
return res.sendStatus(200);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const settings = await db.get("whatsapp-phone-" + phoneNumberId);
|
|
805
|
+
if (!settings || !settings.wab_token) {
|
|
806
|
+
winston.verbose("(wab) No official WhatsApp settings for test reply " + phoneNumberId);
|
|
807
|
+
return res.sendStatus(200);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
return handleTiledeskOutbound(req, res, settings);
|
|
761
811
|
});
|
|
762
812
|
|
|
763
813
|
// Endpoint for Whatsapp Business connected via OAuth
|
|
@@ -817,6 +867,7 @@ router.post('/webhook', async (req, res) => {
|
|
|
817
867
|
db: db,
|
|
818
868
|
tdChannel: tdChannel,
|
|
819
869
|
tlr: tlr,
|
|
870
|
+
baseUrl: BASE_URL,
|
|
820
871
|
});
|
|
821
872
|
bottester.startBotConversation(req.body, code).then((result) => {
|
|
822
873
|
winston.verbose("(wab) test conversation started");
|
|
@@ -880,7 +931,7 @@ router.post('/webhook', async (req, res) => {
|
|
|
880
931
|
winston.verbose("(wab) tiledeskJsonMessage: ", tiledeskJsonMessage);
|
|
881
932
|
|
|
882
933
|
try {
|
|
883
|
-
const response = await tdChannel
|
|
934
|
+
const response = await deliverInboundMessage(tdChannel, tiledeskJsonMessage, message_info, settings);
|
|
884
935
|
winston.verbose("(wab) Message sent to Tiledesk!");
|
|
885
936
|
winston.debug("(wab) response: ", response);
|
|
886
937
|
} catch (err) {
|
|
@@ -998,6 +1049,7 @@ router.post("/webhook/:project_id", async (req, res) => {
|
|
|
998
1049
|
db: db,
|
|
999
1050
|
tdChannel: tdChannel,
|
|
1000
1051
|
tlr: tlr,
|
|
1052
|
+
baseUrl: BASE_URL,
|
|
1001
1053
|
});
|
|
1002
1054
|
bottester.startBotConversation(req.body, code).then((result) => {
|
|
1003
1055
|
winston.verbose("(wab) test conversation started");
|
|
@@ -1114,7 +1166,7 @@ router.post("/webhook/:project_id", async (req, res) => {
|
|
|
1114
1166
|
|
|
1115
1167
|
if (tiledeskJsonMessage) {
|
|
1116
1168
|
winston.verbose("(wab) tiledeskJsonMessage: ", tiledeskJsonMessage);
|
|
1117
|
-
const response = await tdChannel
|
|
1169
|
+
const response = await deliverInboundMessage(tdChannel, tiledeskJsonMessage, message_info, settings);
|
|
1118
1170
|
winston.verbose("(wab) Message sent to Tiledesk!");
|
|
1119
1171
|
winston.debug("(wab) response: ", response);
|
|
1120
1172
|
} else {
|
|
@@ -1268,6 +1320,22 @@ router.post("/newtest", async (req, res) => {
|
|
|
1268
1320
|
let project_id = req.body.project_id;
|
|
1269
1321
|
let bot_id = req.body.bot_id;
|
|
1270
1322
|
|
|
1323
|
+
if (!project_id || !bot_id) {
|
|
1324
|
+
return res.status(400).send({ success: false, message: "project_id and bot_id are required" });
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
if (!redis_client) {
|
|
1328
|
+
return res.status(500).send({ message: "Test it out on Whatsapp not available. Redis not ready." });
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
try {
|
|
1332
|
+
await ensureGlobalSigninSubscription(db, BASE_URL);
|
|
1333
|
+
await ensureProjectTestSubscription(db, project_id, BASE_URL, redis_client);
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
winston.error("(wab) unable to prepare Try on WhatsApp: " + err);
|
|
1336
|
+
return res.status(500).send({ success: false, message: "Try on WhatsApp is not available" });
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1271
1339
|
let info = {
|
|
1272
1340
|
project_id: project_id,
|
|
1273
1341
|
bot_id: bot_id,
|
|
@@ -1276,10 +1344,6 @@ router.post("/newtest", async (req, res) => {
|
|
|
1276
1344
|
let short_uid = uuidv4().substring(0, 8);
|
|
1277
1345
|
let key = "bottest:" + short_uid;
|
|
1278
1346
|
|
|
1279
|
-
if (!redis_client) {
|
|
1280
|
-
return res.status(500).send({ message: "Test it out on Whatsapp not available. Redis not ready." });
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
1347
|
await redis_client.set(key, JSON.stringify(info), "EX", 604800);
|
|
1284
1348
|
redis_client.get(key, (err, value) => {
|
|
1285
1349
|
if (err) {
|
|
@@ -1811,6 +1875,22 @@ async function getDepartments(project_id, token) {
|
|
|
1811
1875
|
}
|
|
1812
1876
|
}
|
|
1813
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
|
+
|
|
1814
1894
|
/**
|
|
1815
1895
|
* Helper function to get or create user token with Redis caching
|
|
1816
1896
|
* @param {Object} tdChannel - TiledeskChannel instance
|
package/package.json
CHANGED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const { v4: uuidv4 } = require("uuid");
|
|
2
|
+
const winston = require("../winston");
|
|
3
|
+
|
|
4
|
+
const BOTTEST_SIGNIN_EVENT = "whatsapp.bottest.signin";
|
|
5
|
+
const WHATSAPP_MESSAGE_EVENT = "message.create.request.channel.whatsapp";
|
|
6
|
+
const BOTTEST_CREATED_BY = "whatsapp-bottest";
|
|
7
|
+
|
|
8
|
+
function isProjectId(value) {
|
|
9
|
+
return typeof value === "string" && /^[a-fA-F0-9]{24}$/.test(value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function subscriptions(kv) {
|
|
13
|
+
if (!kv || !kv.db || typeof kv.db.collection !== "function") {
|
|
14
|
+
throw new Error("WhatsApp storage is not connected");
|
|
15
|
+
}
|
|
16
|
+
return kv.db.collection("subscriptions");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function ensureGlobalSigninSubscription(kv, baseUrl) {
|
|
20
|
+
if (!baseUrl) {
|
|
21
|
+
throw new Error("BASE_URL is required to prepare Try on WhatsApp");
|
|
22
|
+
}
|
|
23
|
+
const collection = subscriptions(kv);
|
|
24
|
+
const query = { event: BOTTEST_SIGNIN_EVENT, id_project: "*", global: true };
|
|
25
|
+
let existing = await collection.findOne(query);
|
|
26
|
+
if (existing) {
|
|
27
|
+
return existing;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const now = new Date();
|
|
31
|
+
const doc = {
|
|
32
|
+
event: BOTTEST_SIGNIN_EVENT,
|
|
33
|
+
target: baseUrl + "/tiledesk/test",
|
|
34
|
+
secret: uuidv4(),
|
|
35
|
+
id_project: "*",
|
|
36
|
+
global: true,
|
|
37
|
+
createdBy: BOTTEST_CREATED_BY,
|
|
38
|
+
createdAt: now,
|
|
39
|
+
updatedAt: now
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const result = await collection.insertOne(doc);
|
|
44
|
+
doc._id = result.insertedId;
|
|
45
|
+
return doc;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
if (err && err.code === 11000) {
|
|
48
|
+
existing = await collection.findOne(query);
|
|
49
|
+
if (existing) {
|
|
50
|
+
return existing;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function ensureProjectTestSubscription(kv, projectId, baseUrl, redisClient) {
|
|
58
|
+
if (!isProjectId(projectId)) {
|
|
59
|
+
throw new Error("Try on WhatsApp project_id is invalid");
|
|
60
|
+
}
|
|
61
|
+
if (!baseUrl) {
|
|
62
|
+
throw new Error("BASE_URL is required to prepare Try on WhatsApp");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const collection = subscriptions(kv);
|
|
66
|
+
const target = baseUrl + "/tiledesk/test";
|
|
67
|
+
const query = { id_project: projectId, event: WHATSAPP_MESSAGE_EVENT, target: target };
|
|
68
|
+
let existing = await collection.findOne(query);
|
|
69
|
+
if (!existing) {
|
|
70
|
+
const now = new Date();
|
|
71
|
+
const doc = {
|
|
72
|
+
event: WHATSAPP_MESSAGE_EVENT,
|
|
73
|
+
target: target,
|
|
74
|
+
secret: uuidv4(),
|
|
75
|
+
id_project: projectId,
|
|
76
|
+
global: false,
|
|
77
|
+
createdBy: BOTTEST_CREATED_BY,
|
|
78
|
+
createdAt: now,
|
|
79
|
+
updatedAt: now
|
|
80
|
+
};
|
|
81
|
+
try {
|
|
82
|
+
const result = await collection.insertOne(doc);
|
|
83
|
+
doc._id = result.insertedId;
|
|
84
|
+
existing = doc;
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (err && err.code === 11000) {
|
|
87
|
+
existing = await collection.findOne(query);
|
|
88
|
+
} else {
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await invalidateSubscriptionCache(redisClient, projectId, WHATSAPP_MESSAGE_EVENT);
|
|
95
|
+
return existing;
|
|
96
|
+
}
|
|
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
|
+
|
|
136
|
+
function invalidateSubscriptionCache(redisClient, projectId, event) {
|
|
137
|
+
if (!redisClient || !projectId || !event) {
|
|
138
|
+
return Promise.resolve();
|
|
139
|
+
}
|
|
140
|
+
const key = "cacheman:cachegoose-cache:" + projectId + ":subscriptions:event:" + event;
|
|
141
|
+
return new Promise((resolve) => {
|
|
142
|
+
try {
|
|
143
|
+
redisClient.del(key, function (err) {
|
|
144
|
+
if (err) {
|
|
145
|
+
winston.warn("(wab) unable to refresh subscription cache for " + projectId);
|
|
146
|
+
}
|
|
147
|
+
resolve();
|
|
148
|
+
});
|
|
149
|
+
} catch (err) {
|
|
150
|
+
winston.warn("(wab) unable to refresh subscription cache for " + projectId);
|
|
151
|
+
resolve();
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = {
|
|
157
|
+
BOTTEST_SIGNIN_EVENT,
|
|
158
|
+
WHATSAPP_MESSAGE_EVENT,
|
|
159
|
+
isProjectId,
|
|
160
|
+
ensureGlobalSigninSubscription,
|
|
161
|
+
ensureProjectTestSubscription,
|
|
162
|
+
saveActiveTest,
|
|
163
|
+
getActiveTest
|
|
164
|
+
};
|
|
@@ -7,6 +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, saveActiveTest } = require("./BotTestSubscriptions");
|
|
10
11
|
|
|
11
12
|
class TiledeskBotTester {
|
|
12
13
|
|
|
@@ -46,6 +47,7 @@ class TiledeskBotTester {
|
|
|
46
47
|
this.db = config.db;
|
|
47
48
|
this.tdChannel = config.tdChannel;
|
|
48
49
|
this.tlr = config.tlr;
|
|
50
|
+
this.baseUrl = config.baseUrl;
|
|
49
51
|
|
|
50
52
|
this.utils = new Utils({ db: this.db })
|
|
51
53
|
|
|
@@ -79,7 +81,7 @@ class TiledeskBotTester {
|
|
|
79
81
|
test_info = JSON.parse(value)
|
|
80
82
|
} catch(err) {
|
|
81
83
|
winston.error("(wab) Error parsing value: " + value);
|
|
82
|
-
reject(err);
|
|
84
|
+
return reject(err);
|
|
83
85
|
}
|
|
84
86
|
let message_info = {
|
|
85
87
|
channel: "whatsapp",
|
|
@@ -103,14 +105,36 @@ class TiledeskBotTester {
|
|
|
103
105
|
|
|
104
106
|
whatsappChannelMessage.text.body = "/start";
|
|
105
107
|
let tiledeskJsonMessage = await this.tlr.toTiledesk(whatsappChannelMessage, whatsappContact.profile.name);
|
|
106
|
-
|
|
107
|
-
if (test_info) {
|
|
108
|
-
const response = await this.tdChannel.sendAndAddBot(tiledeskJsonMessage, message_info, test_info.bot_id)
|
|
109
|
-
return resolve(response)
|
|
110
|
-
} else {
|
|
108
|
+
|
|
109
|
+
if (!test_info || !test_info.bot_id || !isProjectId(test_info.project_id)) {
|
|
111
110
|
winston.verbose("(wab) No bot selected for test. Exit..")
|
|
112
111
|
return reject("Test skipped")
|
|
113
112
|
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const phoneNumberId = message_info.whatsapp.phone_number_id;
|
|
116
|
+
if (phoneNumberId && this.tdChannel && this.tdChannel.settings) {
|
|
117
|
+
await this.db.set("whatsapp-phone-" + phoneNumberId, this.tdChannel.settings);
|
|
118
|
+
}
|
|
119
|
+
const signinSubscription = await ensureGlobalSigninSubscription(this.db, this.baseUrl);
|
|
120
|
+
await ensureProjectTestSubscription(this.db, test_info.project_id, this.baseUrl, this.redis_client);
|
|
121
|
+
const response = await this.tdChannel.sendAndAddBot(tiledeskJsonMessage, message_info, test_info.bot_id, {
|
|
122
|
+
project_id: test_info.project_id,
|
|
123
|
+
subscriptionId: String(signinSubscription._id),
|
|
124
|
+
secret: signinSubscription.secret
|
|
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
|
+
}
|
|
133
|
+
return resolve(response);
|
|
134
|
+
} catch (prepareErr) {
|
|
135
|
+
winston.error("(wab) [TiledeskBotTester] unable to open test conversation: " + prepareErr);
|
|
136
|
+
return reject(prepareErr);
|
|
137
|
+
}
|
|
114
138
|
|
|
115
139
|
}
|
|
116
140
|
}
|
|
@@ -181,18 +181,23 @@ class TiledeskChannel {
|
|
|
181
181
|
* @param {string} bot_id - The bot ID
|
|
182
182
|
* @returns {Promise<Object>} - The response from the Tiledesk API
|
|
183
183
|
*/
|
|
184
|
-
async sendAndAddBot(tiledeskMessage, messageInfo, bot_id) {
|
|
185
|
-
|
|
184
|
+
async sendAndAddBot(tiledeskMessage, messageInfo, bot_id, targetProject) {
|
|
185
|
+
|
|
186
|
+
const projectId = targetProject && targetProject.project_id ? targetProject.project_id : this.settings.project_id;
|
|
187
|
+
const subscriptionId = targetProject && targetProject.subscriptionId ? targetProject.subscriptionId : this.settings.subscriptionId;
|
|
188
|
+
const secret = targetProject && targetProject.secret ? targetProject.secret : this.settings.secret;
|
|
189
|
+
|
|
186
190
|
let channel;
|
|
187
191
|
let new_request_id;
|
|
188
192
|
tiledeskMessage.participants = ["bot_" + bot_id];
|
|
189
193
|
tiledeskMessage.attributes = {
|
|
190
|
-
sourcePage: "whatsapp://&td_draft=true"
|
|
194
|
+
sourcePage: "whatsapp://&td_draft=true",
|
|
195
|
+
whatsapp_bottest: true
|
|
191
196
|
}
|
|
192
197
|
|
|
193
198
|
if (messageInfo.channel == "whatsapp") {
|
|
194
199
|
channel = messageInfo.whatsapp;
|
|
195
|
-
new_request_id = "support-group-" +
|
|
200
|
+
new_request_id = "support-group-" + projectId + "-" + uuidv4().substring(0, 8) + "-wab-" + channel.phone_number_id + "-" + channel.from;
|
|
196
201
|
} else {
|
|
197
202
|
winston.verbose("(wab) [TiledeskChannel] Channel not supported")
|
|
198
203
|
return null;
|
|
@@ -203,10 +208,11 @@ class TiledeskChannel {
|
|
|
203
208
|
first_name: channel.firstname,
|
|
204
209
|
last_name: channel.lastname,
|
|
205
210
|
sub: 'userexternal',
|
|
206
|
-
aud: 'https://tiledesk.com/subscriptions/' +
|
|
211
|
+
aud: 'https://tiledesk.com/subscriptions/' + subscriptionId
|
|
207
212
|
}
|
|
208
213
|
|
|
209
|
-
var customToken = jwt.sign(payload,
|
|
214
|
+
var customToken = jwt.sign(payload, secret);
|
|
215
|
+
const signinBody = targetProject && targetProject.project_id ? { id_project: projectId } : {};
|
|
210
216
|
|
|
211
217
|
return await axios({
|
|
212
218
|
url: this.API_URL + "/auth/signinWithCustomToken",
|
|
@@ -214,7 +220,7 @@ class TiledeskChannel {
|
|
|
214
220
|
'Content-Type': 'application/json',
|
|
215
221
|
'Authorization': 'JWT ' + customToken
|
|
216
222
|
},
|
|
217
|
-
data:
|
|
223
|
+
data: signinBody,
|
|
218
224
|
method: 'POST'
|
|
219
225
|
}).then((response) => {
|
|
220
226
|
|
|
@@ -222,7 +228,7 @@ class TiledeskChannel {
|
|
|
222
228
|
token = this.fixToken(token);
|
|
223
229
|
|
|
224
230
|
return axios({
|
|
225
|
-
url: this.API_URL + `/${
|
|
231
|
+
url: this.API_URL + `/${projectId}/requests/${new_request_id}/messages`,
|
|
226
232
|
headers: {
|
|
227
233
|
'Content-Type': 'application/json',
|
|
228
234
|
'Authorization': token
|
|
@@ -230,7 +236,9 @@ class TiledeskChannel {
|
|
|
230
236
|
data: tiledeskMessage,
|
|
231
237
|
method: 'POST'
|
|
232
238
|
}).then((response) => {
|
|
233
|
-
|
|
239
|
+
const data = response.data || {};
|
|
240
|
+
data.request_id = new_request_id;
|
|
241
|
+
return data;
|
|
234
242
|
}).catch((err) => {
|
|
235
243
|
const errorMessage = utils._extractErrorMessage(err);
|
|
236
244
|
winston.error("(wab) [TiledeskChannel] send message (open conversation) error: " + errorMessage);
|
|
@@ -241,6 +249,49 @@ class TiledeskChannel {
|
|
|
241
249
|
})
|
|
242
250
|
}
|
|
243
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
|
+
|
|
244
295
|
/**
|
|
245
296
|
* Get the project detail from Tiledesk
|
|
246
297
|
* @returns {Promise<Object>} - The response from the Tiledesk API
|