@tiledesk/tiledesk-whatsapp-connector 0.1.84 → 0.1.86
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 +827 -542
- package/logs/app.log +4075 -0
- package/meta_errors.js +9 -0
- package/package.json +2 -1
- package/routes/api.js +25 -11
- package/template/configure.html +383 -14
- package/template/css/configure.css +101 -0
- package/tiledesk/KVBaseMongo.js +22 -10
- package/tiledesk/TiledeskChannel.js +2 -7
- package/tiledesk/Utils.js +57 -0
- package/tiledesk/WhatsappLogger.js +6 -8
- package/tiledesk/WhatsappService.js +150 -0
package/index.js
CHANGED
|
@@ -12,20 +12,16 @@ const cors = require("cors");
|
|
|
12
12
|
var winston = require("./winston");
|
|
13
13
|
const url = require("url");
|
|
14
14
|
const mongoose = require("mongoose");
|
|
15
|
-
|
|
16
|
-
//const ext = require('./routes/ext')
|
|
17
|
-
//const extRoute = ext.router;
|
|
18
15
|
const api = require("./routes/api");
|
|
19
16
|
const apiRoute = api.router;
|
|
17
|
+
const axios = require('axios').default;
|
|
18
|
+
const { parsePhoneNumberFromString } = require('libphonenumber-js');
|
|
19
|
+
|
|
20
20
|
|
|
21
21
|
// tiledesk clients
|
|
22
22
|
const { TiledeskClient } = require("@tiledesk/tiledesk-client");
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
} = require("./tiledesk/TiledeskWhatsappTranslator");
|
|
26
|
-
const {
|
|
27
|
-
TiledeskSubscriptionClient,
|
|
28
|
-
} = require("./tiledesk/TiledeskSubscriptionClient");
|
|
23
|
+
const { TiledeskWhatsappTranslator } = require("./tiledesk/TiledeskWhatsappTranslator");
|
|
24
|
+
const { TiledeskSubscriptionClient } = require("./tiledesk/TiledeskSubscriptionClient");
|
|
29
25
|
const { TiledeskWhatsapp } = require("./tiledesk/TiledeskWhatsapp");
|
|
30
26
|
const { TiledeskChannel } = require("./tiledesk/TiledeskChannel");
|
|
31
27
|
const { TiledeskAppsClient } = require("./tiledesk/TiledeskAppsClient");
|
|
@@ -33,15 +29,18 @@ const { MessageHandler } = require("./tiledesk/MessageHandler");
|
|
|
33
29
|
const { TiledeskBotTester } = require("./tiledesk/TiledeskBotTester");
|
|
34
30
|
const { TemplateManager } = require("./tiledesk/TemplateManager");
|
|
35
31
|
const { WhatsappLogger } = require("./tiledesk/WhatsappLogger");
|
|
36
|
-
const
|
|
32
|
+
const Utils = require("./tiledesk/Utils");
|
|
33
|
+
const whatsappService = require("./tiledesk/WhatsappService");
|
|
37
34
|
|
|
38
35
|
// mongo
|
|
39
36
|
const { KVBaseMongo } = require("./tiledesk/KVBaseMongo");
|
|
40
37
|
const kvbase_collection = "kvstore";
|
|
41
38
|
const db = new KVBaseMongo(kvbase_collection);
|
|
39
|
+
const utils = new Utils({db: db});
|
|
42
40
|
|
|
43
41
|
// redis
|
|
44
42
|
var redis = require("redis");
|
|
43
|
+
const { MFA_MISMATCH } = require("./meta_errors");
|
|
45
44
|
var redis_client;
|
|
46
45
|
|
|
47
46
|
router.use(bodyParser.json());
|
|
@@ -62,6 +61,8 @@ let BASE_FILE_URL = null;
|
|
|
62
61
|
let AMQP_MANAGER_URL = null;
|
|
63
62
|
let JOB_TOPIC_EXCHANGE = null;
|
|
64
63
|
let BRAND_NAME = null;
|
|
64
|
+
let FB_APP_ID = null;
|
|
65
|
+
let CONFIGURATION_ID = null;
|
|
65
66
|
|
|
66
67
|
// Handlebars register helpers
|
|
67
68
|
handlebars.registerHelper("isEqual", (a, b) => {
|
|
@@ -76,200 +77,239 @@ handlebars.registerHelper("json", (a) => {
|
|
|
76
77
|
return JSON.stringify(a);
|
|
77
78
|
});
|
|
78
79
|
|
|
80
|
+
handlebars.registerHelper('formatPhone', function (rawNumber) {
|
|
81
|
+
try {
|
|
82
|
+
const phone = parsePhoneNumberFromString("+" + rawNumber);
|
|
83
|
+
return phone.formatInternational(); // oppure .formatNational()
|
|
84
|
+
} catch(err) {
|
|
85
|
+
return rawNumber;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
79
89
|
router.get("/", async (req, res) => {
|
|
80
90
|
res.send("Welcome to Tiledesk-WhatsApp Business connector!");
|
|
81
91
|
});
|
|
82
92
|
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
|
|
94
|
+
// ***************************************
|
|
95
|
+
// ***** MANAGEMENT SECTION - START ******
|
|
96
|
+
// ***************************************
|
|
97
|
+
router.get("/configure", async (req, res) => {
|
|
98
|
+
winston.verbose("(wab) /configure");
|
|
85
99
|
|
|
86
100
|
let project_id = req.query.project_id;
|
|
87
101
|
let token = req.query.token;
|
|
88
|
-
let app_id = req.query.app_id;
|
|
89
102
|
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
let
|
|
95
|
-
|
|
96
|
-
if (!project_id || !token
|
|
97
|
-
|
|
103
|
+
const popup = req.query.view;
|
|
104
|
+
const popup_view = popup === "popup"
|
|
105
|
+
|
|
106
|
+
const type = req.query.type || 'oauth';
|
|
107
|
+
let isOAuth = type === 'oauth';
|
|
108
|
+
|
|
109
|
+
if (!project_id || !token) {
|
|
110
|
+
let error_message = "Query params project_id and token are required.";
|
|
111
|
+
return readHTMLFile("/error.html", (err, html) => {
|
|
112
|
+
var template = handlebars.compile(html);
|
|
113
|
+
|
|
114
|
+
var replacements = {
|
|
115
|
+
app_version: pjson.version,
|
|
116
|
+
error_message: error_message,
|
|
117
|
+
};
|
|
118
|
+
var html = template(replacements);
|
|
119
|
+
res.send(html);
|
|
120
|
+
});
|
|
98
121
|
}
|
|
99
122
|
|
|
100
|
-
|
|
101
|
-
|
|
123
|
+
let settings = await utils.getSettingsByProjectId(project_id);
|
|
124
|
+
if (!settings) {
|
|
125
|
+
settings = await utils.getSettings(project_id, null);
|
|
126
|
+
}
|
|
102
127
|
|
|
103
|
-
let
|
|
104
|
-
|
|
105
|
-
|
|
128
|
+
let departments = await getDepartments(project_id, token);
|
|
129
|
+
|
|
130
|
+
let proxy_url = BASE_URL + "/webhook/" + project_id;
|
|
131
|
+
|
|
132
|
+
if (settings) {
|
|
133
|
+
|
|
134
|
+
if (settings.source !== 'oauth') {
|
|
135
|
+
isOAuth = false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
readHTMLFile("/configure.html", (err, html) => {
|
|
139
|
+
let template = handlebars.compile(html);
|
|
140
|
+
let replacements = {
|
|
141
|
+
app_version: pjson.version,
|
|
142
|
+
project_id: project_id,
|
|
143
|
+
token: token,
|
|
144
|
+
proxy_url: proxy_url,
|
|
145
|
+
wab_token: settings.wab_token,
|
|
146
|
+
verify_token: settings.verify_token,
|
|
147
|
+
business_account_id: settings.business_account_id,
|
|
148
|
+
phone_number: settings.phone_number,
|
|
149
|
+
phone_number_id: settings.phone_number_id,
|
|
150
|
+
waba_id: settings.waba_id,
|
|
151
|
+
verified_name: settings.verified_name,
|
|
152
|
+
subscription_id: settings.subscriptionId,
|
|
153
|
+
department_id: settings.department_id,
|
|
154
|
+
departments: departments,
|
|
155
|
+
brand_name: BRAND_NAME,
|
|
156
|
+
isOAuth: isOAuth,
|
|
157
|
+
fb_app_id: FB_APP_ID,
|
|
158
|
+
configuration_id: CONFIGURATION_ID
|
|
159
|
+
}
|
|
160
|
+
let renderedHtml = template(replacements);
|
|
161
|
+
res.send(renderedHtml);
|
|
162
|
+
})
|
|
163
|
+
return;
|
|
106
164
|
}
|
|
107
165
|
|
|
108
|
-
readHTMLFile("/
|
|
109
|
-
|
|
110
|
-
|
|
166
|
+
readHTMLFile("/configure.html", (err, html) => {
|
|
167
|
+
let template = handlebars.compile(html);
|
|
168
|
+
let replacements = {
|
|
111
169
|
app_version: pjson.version,
|
|
112
170
|
project_id: project_id,
|
|
113
171
|
token: token,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
172
|
+
proxy_url: proxy_url,
|
|
173
|
+
departments: departments,
|
|
174
|
+
popup_view: popup_view,
|
|
175
|
+
brand_name: BRAND_NAME,
|
|
176
|
+
isOAuth: isOAuth,
|
|
177
|
+
fb_app_id: FB_APP_ID,
|
|
178
|
+
configuration_id: CONFIGURATION_ID
|
|
117
179
|
};
|
|
118
|
-
|
|
119
|
-
res.send(
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
router.post("/install", async (req, res) => {
|
|
124
|
-
winston.verbose("(wab) /install");
|
|
125
|
-
|
|
126
|
-
let project_id = req.body.project_id;
|
|
127
|
-
let app_id = req.body.app_id;
|
|
128
|
-
let token = req.body.token;
|
|
180
|
+
let renderedHtml = template(replacements);
|
|
181
|
+
res.send(renderedHtml);
|
|
182
|
+
})
|
|
183
|
+
return;
|
|
184
|
+
})
|
|
129
185
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
};
|
|
186
|
+
router.get('/onboarding/callback', async (req, res) => {
|
|
187
|
+
const { code, waba_id, phone_number_id, business_id } = req.query;
|
|
188
|
+
const state = JSON.parse(req.query.state)
|
|
189
|
+
const project_id = state.project_id;
|
|
190
|
+
const token = state.token;
|
|
136
191
|
|
|
137
|
-
|
|
138
|
-
appClient
|
|
139
|
-
.install(installation_info)
|
|
140
|
-
.then((installation) => {
|
|
141
|
-
winston.debug("(wab) installation response: ", installation);
|
|
192
|
+
try {
|
|
142
193
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
project_id: project_id,
|
|
148
|
-
app_id: app_id,
|
|
149
|
-
token: token,
|
|
150
|
-
},
|
|
151
|
-
})
|
|
152
|
-
);
|
|
194
|
+
const tdClient = new TiledeskSubscriptionClient({
|
|
195
|
+
API_URL: API_URL,
|
|
196
|
+
project_id: project_id,
|
|
197
|
+
token: token
|
|
153
198
|
})
|
|
154
|
-
.catch((err) => {
|
|
155
|
-
winston.error("(wab) installation error: " + err.data);
|
|
156
|
-
res.send("An error occurred during the installation");
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
199
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
200
|
+
const subscription_info = {
|
|
201
|
+
target: BASE_URL + "/tiledesk",
|
|
202
|
+
event: "message.create.request.channel.whatsapp",
|
|
203
|
+
}
|
|
204
|
+
const subscription = await tdClient.subscribe(subscription_info);
|
|
165
205
|
|
|
166
|
-
|
|
167
|
-
appClient.uninstall(project_id, app_id).then((response) => {
|
|
168
|
-
winston.debug("(wab) uninstallation response: ", response);
|
|
169
|
-
res.redirect(
|
|
170
|
-
url.format({
|
|
171
|
-
pathname: BASE_URL + "/detail",
|
|
172
|
-
query: {
|
|
173
|
-
project_id: project_id,
|
|
174
|
-
app_id: app_id,
|
|
175
|
-
token: token,
|
|
176
|
-
},
|
|
177
|
-
})
|
|
178
|
-
);
|
|
179
|
-
}).catch((err) => {
|
|
180
|
-
winston.error("(wab) uninstallation error: " + err.data);
|
|
181
|
-
res.send("An error occurred during the uninstallation");
|
|
182
|
-
});
|
|
183
|
-
});
|
|
206
|
+
const data = await whatsappService.handleOnboarding(code, business_id, waba_id, phone_number_id)
|
|
184
207
|
|
|
185
|
-
|
|
186
|
-
|
|
208
|
+
let settings = {
|
|
209
|
+
source: 'oauth',
|
|
210
|
+
project_id: project_id,
|
|
211
|
+
token: token,
|
|
212
|
+
subscriptionId: subscription._id,
|
|
213
|
+
secret: subscription.secret,
|
|
214
|
+
wab_token: data.access_token,
|
|
215
|
+
business_account_id: data.business_account_id,
|
|
216
|
+
waba_id: data.waba_id,
|
|
217
|
+
phone_number_id: data.phone_number_id,
|
|
218
|
+
phone_number: data.phone_number,
|
|
219
|
+
verified_name: data.verified_name
|
|
220
|
+
}
|
|
187
221
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
let popup_view = false;
|
|
222
|
+
let CONTENT_KEY = "whatsapp-" + waba_id;
|
|
223
|
+
await db.set(CONTENT_KEY, settings);
|
|
191
224
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
225
|
+
try {
|
|
226
|
+
let register_result = await whatsappService.registerNumber(data.access_token, data.phone_number_id)
|
|
227
|
+
winston.verbose("(wab) /onboarding/callback register_result: ", register_result)
|
|
228
|
+
|
|
229
|
+
let connection_result = await whatsappService.connectNumber(data.access_token, data.waba_id)
|
|
230
|
+
winston.verbose("(wab) /onboarding/callback connection_result: ", connection_result)
|
|
231
|
+
} catch (err) {
|
|
232
|
+
if (err.code === MFA_MISMATCH.CODE) {
|
|
233
|
+
res.status(202).send({
|
|
234
|
+
success: false,
|
|
235
|
+
code: MFA_MISMATCH.CODE,
|
|
236
|
+
message: "PIN Mismatch",
|
|
237
|
+
settings: settings,
|
|
238
|
+
})
|
|
239
|
+
return;
|
|
240
|
+
} else {
|
|
241
|
+
winston.error("(wab) onboarding finalizing error: ", err.response?.data || err.message);
|
|
242
|
+
res.status(500).send({ success: false, message: "Error during onboarding", settings: settings })
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
195
246
|
|
|
196
|
-
|
|
197
|
-
let error_message = "Query params project_id and token are required.";
|
|
198
|
-
readHTMLFile("/error.html", (err, html) => {
|
|
199
|
-
var template = handlebars.compile(html);
|
|
247
|
+
res.status(200).send(settings)
|
|
200
248
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
});
|
|
208
|
-
} else {
|
|
209
|
-
let proxy_url = BASE_URL + "/webhook/" + project_id;
|
|
249
|
+
} catch (err) {
|
|
250
|
+
winston.error("(wab) onboarding error: ", err.response?.data || err.message);
|
|
251
|
+
res.status(500).json({ error: "Onboarding callback error: " + err });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
})
|
|
210
255
|
|
|
211
|
-
|
|
256
|
+
router.get('/onboarding/register', async (req, res) => {
|
|
257
|
+
const { pin, waba_id, wab_token, phone_number_id } = req.query;
|
|
212
258
|
|
|
213
|
-
|
|
214
|
-
winston.debug("(wab) settings: ", settings);
|
|
215
|
-
|
|
216
|
-
// get departments
|
|
217
|
-
const tdChannel = new TiledeskChannel({
|
|
218
|
-
settings: { project_id: project_id, token: token },
|
|
219
|
-
API_URL: API_URL,
|
|
220
|
-
});
|
|
259
|
+
winston.verbose("(wab) pin: ", pin, "wab_token: ", wab_token, "phone_number_id: ", phone_number_id);
|
|
221
260
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
261
|
+
if (!wab_token || !phone_number_id || !pin) {
|
|
262
|
+
res.status(400).send({
|
|
263
|
+
success: false,
|
|
264
|
+
message: "Missing required parameters"
|
|
225
265
|
})
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
226
268
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
await db.set(CONTENT_KEY, settings);
|
|
269
|
+
try {
|
|
270
|
+
let register_result = await whatsappService.registerNumber(wab_token, phone_number_id, pin);
|
|
271
|
+
winston.verbose("(wab) /onboarding/register register_result: ", register_result)
|
|
231
272
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
var replacements = {
|
|
235
|
-
app_version: pjson.version,
|
|
236
|
-
project_id: project_id,
|
|
237
|
-
token: token,
|
|
238
|
-
proxy_url: proxy_url,
|
|
239
|
-
wab_token: settings.wab_token,
|
|
240
|
-
verify_token: settings.verify_token,
|
|
241
|
-
business_account_id: settings.business_account_id,
|
|
242
|
-
phone_number: settings.phone_number,
|
|
243
|
-
phone_number_id: settings.phone_number_id,
|
|
244
|
-
verified_name: settings.verified_name,
|
|
245
|
-
subscription_id: settings.subscriptionId,
|
|
246
|
-
department_id: settings.department_id,
|
|
247
|
-
departments: departments,
|
|
248
|
-
brand_name: BRAND_NAME
|
|
249
|
-
};
|
|
250
|
-
var html = template(replacements);
|
|
251
|
-
res.send(html);
|
|
252
|
-
});
|
|
253
|
-
} else {
|
|
254
|
-
readHTMLFile("/configure.html", (err, html) => {
|
|
255
|
-
if (err) { winston.error("(wab) error read html file: " + err); }
|
|
273
|
+
let connection_result = await whatsappService.connectNumber(data.access_token, data.waba_id)
|
|
274
|
+
winston.verbose("(wab) /onboarding/callback connection_result: ", connection_result)
|
|
256
275
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
276
|
+
} catch (err) {
|
|
277
|
+
winston.error("(wab) register error: ", err.response?.data || err.message);
|
|
278
|
+
if (err.response?.data?.code === MFA_MISMATCH.CODE) {
|
|
279
|
+
res.status(202).send({
|
|
280
|
+
success: false,
|
|
281
|
+
code: MFA_MISMATCH.CODE,
|
|
282
|
+
message: "PIN Mismatch"
|
|
283
|
+
})
|
|
284
|
+
return;
|
|
285
|
+
} else {
|
|
286
|
+
res.status(400).send({
|
|
287
|
+
success: false,
|
|
288
|
+
message: "Error registering phone number"
|
|
289
|
+
})
|
|
290
|
+
return;
|
|
270
291
|
}
|
|
271
292
|
}
|
|
272
|
-
|
|
293
|
+
|
|
294
|
+
res.status(200).send("Phone number registered");
|
|
295
|
+
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
router.put("/update/department", async (req, res) => {
|
|
299
|
+
let project_id = req.query.project_id;
|
|
300
|
+
let token = req.query.token;
|
|
301
|
+
|
|
302
|
+
let department_id = req.body.department_id;
|
|
303
|
+
winston.verbose("(wab) changing department with: ", department_id);
|
|
304
|
+
|
|
305
|
+
let settings = await utils.getSettingsByProjectId(project_id);
|
|
306
|
+
settings.department_id = department_id;
|
|
307
|
+
|
|
308
|
+
let CONTENT_KEY = "whatsapp-" + settings.waba_id;
|
|
309
|
+
await db.set(CONTENT_KEY, settings);
|
|
310
|
+
|
|
311
|
+
res.status(200).send("Department Id updated")
|
|
312
|
+
})
|
|
273
313
|
|
|
274
314
|
router.post("/update", async (req, res) => {
|
|
275
315
|
winston.verbose("(wab) /update");
|
|
@@ -291,30 +331,27 @@ router.post("/update", async (req, res) => {
|
|
|
291
331
|
settings: { project_id: project_id, token: token },
|
|
292
332
|
API_URL: API_URL,
|
|
293
333
|
});
|
|
294
|
-
let departments = await tdChannel.getDepartments()
|
|
295
|
-
winston.error("(wab) Error getting deparments");
|
|
296
|
-
return []
|
|
297
|
-
})
|
|
334
|
+
let departments = await tdChannel.getDepartments();
|
|
298
335
|
|
|
299
336
|
if (settings) {
|
|
300
337
|
settings.wab_token = wab_token;
|
|
301
338
|
settings.verify_token = verify_token;
|
|
302
339
|
settings.department_id = department_id;
|
|
303
340
|
settings.business_account_id = business_account_id;
|
|
304
|
-
|
|
341
|
+
|
|
305
342
|
const twClient = new TiledeskWhatsapp({
|
|
306
343
|
token: settings.wab_token,
|
|
307
344
|
GRAPH_URL: GRAPH_URL,
|
|
308
345
|
API_URL: API_URL,
|
|
309
346
|
BASE_FILE_URL: BASE_FILE_URL,
|
|
310
347
|
});
|
|
311
|
-
|
|
348
|
+
|
|
312
349
|
await twClient.getBusinessAccountInfo(business_account_id).then((info) => {
|
|
313
350
|
settings.phone_number_id = info.data[0].id;
|
|
314
351
|
settings.phone_number = info.data[0].display_phone_number;
|
|
315
352
|
settings.verified_name = info.data[0].verified_name;
|
|
316
353
|
}).catch((err) => {
|
|
317
|
-
winston.error("Error getting WAB Account Info");
|
|
354
|
+
winston.error("(wab) Error getting WAB Account Info");
|
|
318
355
|
})
|
|
319
356
|
|
|
320
357
|
await db.set(CONTENT_KEY, settings);
|
|
@@ -359,6 +396,7 @@ router.post("/update", async (req, res) => {
|
|
|
359
396
|
winston.debug("\n(wab) Subscription: ", subscription);
|
|
360
397
|
|
|
361
398
|
let settings = {
|
|
399
|
+
source: 'manual',
|
|
362
400
|
project_id: project_id,
|
|
363
401
|
token: token,
|
|
364
402
|
proxy_url: proxy_url,
|
|
@@ -409,207 +447,27 @@ router.post("/update", async (req, res) => {
|
|
|
409
447
|
};
|
|
410
448
|
var html = template(replacements);
|
|
411
449
|
res.send(html);
|
|
412
|
-
});
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
router.post("/getinfo", async (req, res) => {
|
|
418
|
-
|
|
419
|
-
winston.verbose("/getinfo");
|
|
420
|
-
let project_id = req.body.project_id;
|
|
421
|
-
let token = req.body.token;
|
|
422
|
-
let proxy_url = BASE_URL + "/webhook/" + project_id;
|
|
423
|
-
|
|
424
|
-
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
425
|
-
let settings = await db.get(CONTENT_KEY);
|
|
426
|
-
|
|
427
|
-
const tdChannel = new TiledeskChannel({
|
|
428
|
-
settings: { project_id: project_id, token: token },
|
|
429
|
-
API_URL: API_URL,
|
|
430
|
-
});
|
|
431
|
-
let departments = await tdChannel.getDepartments().catch((err) => {
|
|
432
|
-
winston.error("(wab) Error getting deparments");
|
|
433
|
-
return []
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
const twClient = new TiledeskWhatsapp({
|
|
437
|
-
token: settings.wab_token,
|
|
438
|
-
GRAPH_URL: GRAPH_URL,
|
|
439
|
-
API_URL: API_URL,
|
|
440
|
-
BASE_FILE_URL: BASE_FILE_URL,
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
await twClient.getBusinessAccountInfo(settings.business_account_id).then((info) => {
|
|
444
|
-
settings.phone_number_id = info.data[0].id;
|
|
445
|
-
settings.phone_number = info.data[0].display_phone_number;
|
|
446
|
-
settings.verified_name = info.data[0].verified_name;
|
|
447
|
-
winston.debug("(wab) Business account info: ", info);
|
|
448
|
-
}).catch((err) => {
|
|
449
|
-
winston.error("Error getting WAB Account Info");
|
|
450
|
-
})
|
|
451
|
-
|
|
452
|
-
await db.set(CONTENT_KEY, settings);
|
|
453
|
-
|
|
454
|
-
readHTMLFile("/configure.html", (err, html) => {
|
|
455
|
-
var template = handlebars.compile(html);
|
|
456
|
-
var replacements = {
|
|
457
|
-
app_version: pjson.version,
|
|
458
|
-
project_id: project_id,
|
|
459
|
-
token: token,
|
|
460
|
-
proxy_url: proxy_url,
|
|
461
|
-
wab_token: settings.wab_token,
|
|
462
|
-
show_success_modal: true,
|
|
463
|
-
verify_token: settings.verify_token,
|
|
464
|
-
business_account_id: settings.business_account_id,
|
|
465
|
-
phone_number: settings.phone_number,
|
|
466
|
-
phone_number_id: settings.phone_number_id,
|
|
467
|
-
verified_name: settings.verified_name,
|
|
468
|
-
subscription_id: settings.subscriptionId,
|
|
469
|
-
department_id: settings.department_id,
|
|
470
|
-
departments: departments,
|
|
471
|
-
brand_name: BRAND_NAME
|
|
472
|
-
};
|
|
473
|
-
var html = template(replacements);
|
|
474
|
-
res.send(html);
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
})
|
|
478
|
-
|
|
479
|
-
router.post("/disconnect", async (req, res) => {
|
|
480
|
-
winston.verbose("(wab) /disconnect");
|
|
481
|
-
|
|
482
|
-
let project_id = req.body.project_id;
|
|
483
|
-
let token = req.body.token;
|
|
484
|
-
let subscriptionId = req.body.subscription_id;
|
|
485
|
-
|
|
486
|
-
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
487
|
-
await db.remove(CONTENT_KEY);
|
|
488
|
-
winston.verbose("(wab) Content deleted.");
|
|
489
|
-
|
|
490
|
-
let proxy_url = BASE_URL + "/webhook/" + project_id;
|
|
491
|
-
|
|
492
|
-
const tdClient = new TiledeskSubscriptionClient({
|
|
493
|
-
API_URL: API_URL,
|
|
494
|
-
project_id: project_id,
|
|
495
|
-
token: token,
|
|
496
|
-
});
|
|
497
|
-
// get departments
|
|
498
|
-
const tdChannel = new TiledeskChannel({
|
|
499
|
-
settings: { project_id: project_id, token: token },
|
|
500
|
-
API_URL: API_URL,
|
|
501
|
-
});
|
|
502
|
-
let departments = await tdChannel.getDepartments().catch((err) => {
|
|
503
|
-
winston.error("(wab) Error getting deparments");
|
|
504
|
-
return []
|
|
505
|
-
})
|
|
506
|
-
|
|
507
|
-
/*
|
|
508
|
-
// callback
|
|
509
|
-
tdClient.unsubsribe(project_id, subscriptionId, (err, data) => {
|
|
510
|
-
// code here
|
|
511
|
-
})
|
|
512
|
-
*/
|
|
513
|
-
|
|
514
|
-
tdClient.unsubscribe(subscriptionId).then((data) => {
|
|
515
|
-
readHTMLFile("/configure.html", (err, html) => {
|
|
516
|
-
var template = handlebars.compile(html);
|
|
517
|
-
var replacements = {
|
|
518
|
-
app_version: pjson.version,
|
|
519
|
-
project_id: project_id,
|
|
520
|
-
token: token,
|
|
521
|
-
proxy_url: proxy_url,
|
|
522
|
-
departments: departments,
|
|
523
|
-
brand_name: BRAND_NAME
|
|
524
|
-
};
|
|
525
|
-
var html = template(replacements);
|
|
526
|
-
res.send(html);
|
|
527
|
-
});
|
|
528
|
-
}).catch((err) => {
|
|
529
|
-
winston.error("(wab) unsubscribe error: " + err);
|
|
530
|
-
});
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
router.get("/direct/tiledesk", async (req, res) => {
|
|
534
|
-
winston.verbose("/direct/tiledesk");
|
|
535
|
-
|
|
536
|
-
let project_id = req.query.project_id;
|
|
537
|
-
let whatsapp_receiver = req.query.whatsapp_receiver;
|
|
538
|
-
let phone_number_id = req.query.phone_number_id;
|
|
539
|
-
|
|
540
|
-
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
541
|
-
let settings = await db.get(CONTENT_KEY);
|
|
542
|
-
|
|
543
|
-
let tiledeskChannelMessage = {
|
|
544
|
-
text: "Sample text",
|
|
545
|
-
attributes: {
|
|
546
|
-
attachment: {
|
|
547
|
-
type: "wa_template",
|
|
548
|
-
template: {
|
|
549
|
-
language: "en_US",
|
|
550
|
-
name: "hello_world",
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
const tlr = new TiledeskWhatsappTranslator();
|
|
556
|
-
const twClient = new TiledeskWhatsapp({
|
|
557
|
-
token: settings.wab_token,
|
|
558
|
-
GRAPH_URL: GRAPH_URL,
|
|
559
|
-
API_URL: API_URL,
|
|
560
|
-
BASE_FILE_URL: BASE_FILE_URL,
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
let whatsappJsonMessage = await tlr.toWhatsapp(
|
|
564
|
-
tiledeskChannelMessage,
|
|
565
|
-
whatsapp_receiver
|
|
566
|
-
);
|
|
567
|
-
winston.verbose("(wab) whatsappJsonMessage", whatsappJsonMessage);
|
|
568
|
-
|
|
569
|
-
twClient.sendMessage(phone_number_id, whatsappJsonMessage).then((response) => {
|
|
570
|
-
winston.verbose(
|
|
571
|
-
"(wab) Message sent to WhatsApp! " +
|
|
572
|
-
response.status +
|
|
573
|
-
" " +
|
|
574
|
-
response.statusText
|
|
575
|
-
);
|
|
576
|
-
}).catch((err) => {
|
|
577
|
-
//winston.error("(wab) error send message: ", err);
|
|
578
|
-
return res.status(400).send({ success: false, error: err });
|
|
579
|
-
});
|
|
580
|
-
|
|
581
|
-
res.status(200).send("Message sent");
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
// Can be deleted?
|
|
586
|
-
router.post("/tiledesk/broadcast", async (req, res) => {
|
|
587
|
-
winston.verbose("(wab) Message received from Tiledesk (Broadcast)");
|
|
588
|
-
|
|
589
|
-
let tiledeskChannelMessage = req.body.payload;
|
|
590
|
-
winston.verbose("(wab) tiledeskChannelMessage: ", tiledeskChannelMessage);
|
|
591
|
-
let project_id = req.body.payload.id_project;
|
|
592
|
-
|
|
593
|
-
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
594
|
-
let settings = await db.get(CONTENT_KEY);
|
|
595
|
-
|
|
596
|
-
if (!settings) {
|
|
597
|
-
return res.status(400).send({ success: false, error: "WhatsApp is not installed for the project_id: " + project_id });
|
|
450
|
+
});
|
|
451
|
+
});
|
|
598
452
|
}
|
|
453
|
+
});
|
|
599
454
|
|
|
600
|
-
|
|
601
|
-
return res.status(400).send({ success: false, error: "Missing parameter 'WhatsApp Business Account ID'. Please update your app." });
|
|
602
|
-
}
|
|
455
|
+
router.post("/getinfo", async (req, res) => {
|
|
603
456
|
|
|
604
|
-
|
|
605
|
-
let
|
|
457
|
+
winston.verbose("(wab) /getinfo");
|
|
458
|
+
let project_id = req.body.project_id;
|
|
459
|
+
let token = req.body.token;
|
|
460
|
+
let proxy_url = BASE_URL + "/webhook/" + project_id;
|
|
606
461
|
|
|
607
|
-
let
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
462
|
+
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
463
|
+
let settings = await db.get(CONTENT_KEY);
|
|
464
|
+
|
|
465
|
+
const tdChannel = new TiledeskChannel({
|
|
466
|
+
settings: { project_id: project_id, token: token },
|
|
467
|
+
API_URL: API_URL,
|
|
611
468
|
});
|
|
612
|
-
|
|
469
|
+
let departments = await tdChannel.getDepartments();
|
|
470
|
+
|
|
613
471
|
const twClient = new TiledeskWhatsapp({
|
|
614
472
|
token: settings.wab_token,
|
|
615
473
|
GRAPH_URL: GRAPH_URL,
|
|
@@ -617,68 +475,104 @@ router.post("/tiledesk/broadcast", async (req, res) => {
|
|
|
617
475
|
BASE_FILE_URL: BASE_FILE_URL,
|
|
618
476
|
});
|
|
619
477
|
|
|
620
|
-
|
|
621
|
-
|
|
478
|
+
await twClient.getBusinessAccountInfo(settings.business_account_id).then((info) => {
|
|
479
|
+
settings.phone_number_id = info.data[0].id;
|
|
480
|
+
settings.phone_number = info.data[0].display_phone_number;
|
|
481
|
+
settings.verified_name = info.data[0].verified_name;
|
|
482
|
+
winston.debug("(wab) Business account info: ", info);
|
|
483
|
+
}).catch((err) => {
|
|
484
|
+
winston.error("(wab) Error getting WAB Account Info");
|
|
485
|
+
})
|
|
622
486
|
|
|
623
|
-
|
|
624
|
-
(t) => t.name === tiledeskChannelMessage.attributes.attachment.template.name
|
|
625
|
-
);
|
|
487
|
+
await db.set(CONTENT_KEY, settings);
|
|
626
488
|
|
|
627
|
-
|
|
489
|
+
readHTMLFile("/configure.html", (err, html) => {
|
|
490
|
+
var template = handlebars.compile(html);
|
|
491
|
+
var replacements = {
|
|
492
|
+
app_version: pjson.version,
|
|
493
|
+
project_id: project_id,
|
|
494
|
+
token: token,
|
|
495
|
+
proxy_url: proxy_url,
|
|
496
|
+
wab_token: settings.wab_token,
|
|
497
|
+
show_success_modal: true,
|
|
498
|
+
verify_token: settings.verify_token,
|
|
499
|
+
business_account_id: settings.business_account_id,
|
|
500
|
+
phone_number: settings.phone_number,
|
|
501
|
+
phone_number_id: settings.phone_number_id,
|
|
502
|
+
verified_name: settings.verified_name,
|
|
503
|
+
subscription_id: settings.subscriptionId,
|
|
504
|
+
department_id: settings.department_id,
|
|
505
|
+
departments: departments,
|
|
506
|
+
brand_name: BRAND_NAME
|
|
507
|
+
};
|
|
508
|
+
var html = template(replacements);
|
|
509
|
+
res.send(html);
|
|
510
|
+
});
|
|
628
511
|
|
|
629
|
-
|
|
630
|
-
winston.verbose("(wab) --> tiledeskChannelMessage: ", tiledeskChannelMessage);
|
|
512
|
+
})
|
|
631
513
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
let error_count = 0;
|
|
514
|
+
router.post("/disconnect", async (req, res) => {
|
|
515
|
+
winston.verbose("(wab) /disconnect");
|
|
635
516
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
let customTiledeskJsonMessage = await tlr.sanitizeTiledeskMessage(tiledeskChannelMessage, whatsapp_receiver);
|
|
640
|
-
winston.verbose("customTiledeskJsonMessage: ", customTiledeskJsonMessage);
|
|
517
|
+
let project_id = req.body.project_id;
|
|
518
|
+
let token = req.body.token;
|
|
519
|
+
let subscriptionId = req.body.subscription_id;
|
|
641
520
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
521
|
+
let deleted = await deleteSettingsByProjectId(project_id);
|
|
522
|
+
if (!deleted) {
|
|
523
|
+
deleted = deleteSettings(project_id, null)
|
|
524
|
+
}
|
|
645
525
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
winston.error("(wab) error send message: " + err.response.data.error.message);
|
|
658
|
-
errors.push({ receiver: whatsapp_receiver.phone_number, error: err.response.data.error.message });
|
|
659
|
-
i += 1;
|
|
660
|
-
if (i < receiver_list.length) {
|
|
661
|
-
execute(receiver_list[i]);
|
|
662
|
-
} else {
|
|
663
|
-
winston.debug("(wab) End of list");
|
|
664
|
-
return res.status(200).send({ success: true, message: "Broadcast terminated", messages_sent: messages_sent, errors: errors });
|
|
665
|
-
}
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
execute(receiver_list[0]);
|
|
526
|
+
if (!deleted) {
|
|
527
|
+
let error_message = "Unable to disconnect WhatsApp";
|
|
528
|
+
return readHTMLFile("/error.html", (err, html) => {
|
|
529
|
+
let template = handlebars.compile(html);
|
|
530
|
+
let replacements = {
|
|
531
|
+
app_version: pjson.version,
|
|
532
|
+
error_message: error_message,
|
|
533
|
+
};
|
|
534
|
+
let renderedHtml = template(replacements);
|
|
535
|
+
res.send(renderedHtml);
|
|
536
|
+
});
|
|
669
537
|
}
|
|
538
|
+
|
|
539
|
+
const tdClient = new TiledeskSubscriptionClient({
|
|
540
|
+
API_URL: API_URL,
|
|
541
|
+
project_id: project_id,
|
|
542
|
+
token: token,
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
tdClient.unsubscribe(subscriptionId).then((data) => {
|
|
546
|
+
res.redirect(`/configure?project_id=${project_id}&token=${token}`);
|
|
547
|
+
}).catch((err) => {
|
|
548
|
+
winston.error("(wab) unsubscribe error: " + err);
|
|
549
|
+
});
|
|
670
550
|
});
|
|
551
|
+
// ***************************************
|
|
552
|
+
// ****** MANAGEMENT SECTION - END *******
|
|
553
|
+
// ***************************************
|
|
671
554
|
|
|
555
|
+
// ---------------------------------------
|
|
556
|
+
|
|
557
|
+
// ***************************************
|
|
558
|
+
// ****** MESSAGING SECTION - START ******
|
|
559
|
+
// ***************************************
|
|
672
560
|
router.post("/tiledesk", async (req, res) => {
|
|
673
561
|
winston.verbose("(wab) Message received from Tiledesk");
|
|
674
562
|
|
|
675
|
-
|
|
563
|
+
let tiledeskChannelMessage = req.body.payload;
|
|
676
564
|
winston.debug("(wab) tiledeskChannelMessage: ", tiledeskChannelMessage);
|
|
677
|
-
var project_id = req.body.payload.id_project;
|
|
678
565
|
|
|
679
|
-
|
|
680
|
-
let
|
|
681
|
-
let
|
|
566
|
+
let project_id = req.body.payload.id_project;
|
|
567
|
+
let recipient = req.body.payload.recipient;
|
|
568
|
+
let waba_id = recipient.split('-')[5];
|
|
569
|
+
|
|
570
|
+
let settings = await utils.getSettingsByProjectId(project_id);
|
|
571
|
+
|
|
572
|
+
if (!settings) {
|
|
573
|
+
settings = await utils.getSettings(project_id, waba_id);
|
|
574
|
+
}
|
|
575
|
+
|
|
682
576
|
let wab_token = settings.wab_token;
|
|
683
577
|
|
|
684
578
|
var text = req.body.payload.text;
|
|
@@ -725,17 +619,9 @@ router.post("/tiledesk", async (req, res) => {
|
|
|
725
619
|
return res.status(400).send({ success: false, message: "Phone number id undefined" });
|
|
726
620
|
}
|
|
727
621
|
|
|
728
|
-
/*
|
|
729
|
-
if (settings.expired &&
|
|
730
|
-
settings.expired === true) {
|
|
731
|
-
winston.info("settings expired: " + settings.expired);
|
|
732
|
-
return res.status(200).send({ success: 'false', message: "plan expired"})
|
|
733
|
-
|
|
734
|
-
*/
|
|
735
|
-
|
|
736
622
|
// Return an info message option
|
|
737
623
|
if (settings.expired && settings.expired === true) {
|
|
738
|
-
winston.verbose("settings expired: " + settings.expired);
|
|
624
|
+
winston.verbose("(wab) settings expired: " + settings.expired);
|
|
739
625
|
let tiledeskJsonMessage = {
|
|
740
626
|
text: "Expired. Upgrade Plan.",
|
|
741
627
|
sender: "system",
|
|
@@ -843,7 +729,7 @@ router.post("/tiledesk", async (req, res) => {
|
|
|
843
729
|
|
|
844
730
|
if (whatsappJsonMessage) {
|
|
845
731
|
const twClient = new TiledeskWhatsapp({
|
|
846
|
-
token:
|
|
732
|
+
token: wab_token,
|
|
847
733
|
GRAPH_URL: GRAPH_URL,
|
|
848
734
|
API_URL: API_URL,
|
|
849
735
|
BASE_FILE_URL: BASE_FILE_URL,
|
|
@@ -871,8 +757,157 @@ router.post("/tiledesk", async (req, res) => {
|
|
|
871
757
|
}
|
|
872
758
|
});
|
|
873
759
|
|
|
760
|
+
// Endpoint for Whatsapp Business connected via OAuth
|
|
761
|
+
router.post('/webhook', async (req, res) => {
|
|
762
|
+
|
|
763
|
+
if (req.body.object !== "whatsapp_business_account") {
|
|
764
|
+
winston.verbose("(wab) Event not from whatsapp");
|
|
765
|
+
return res.status(400).send({ error: "Invalid request" });
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
if (!req.body.entry?.[0]?.id) {
|
|
769
|
+
winston.warn("(wab) Invalid entry for body: ", req.body)
|
|
770
|
+
return res.status(400).send({ error: "Invalid request object" })
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
const waba_id = req.body.entry[0].id;
|
|
774
|
+
|
|
775
|
+
const CONTENT_KEY = "whatsapp-" + waba_id;
|
|
776
|
+
const settings = await db.get(CONTENT_KEY);
|
|
777
|
+
winston.debug("(wab) settings: ", settings);
|
|
778
|
+
|
|
779
|
+
if (!settings) {
|
|
780
|
+
winston.warn("(wab) settings not found for waba: " + waba_id);
|
|
781
|
+
winston.warn("(wab) settings not found for request: ", req.body);
|
|
782
|
+
return res.sendStatus(200);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const tdClient = new TiledeskClient({
|
|
786
|
+
projectId: settings.project_id,
|
|
787
|
+
token: settings.token,
|
|
788
|
+
APIURL: API_URL,
|
|
789
|
+
APIKEY: "___",
|
|
790
|
+
log: false,
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
const wl = new WhatsappLogger({ tdClient: tdClient });
|
|
794
|
+
wl.forwardMessage(req.body);
|
|
795
|
+
|
|
796
|
+
// Message incoming
|
|
797
|
+
if (req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]) {
|
|
798
|
+
|
|
799
|
+
let whatsappChannelMessage = req.body.entry[0].changes[0].value.messages[0];
|
|
800
|
+
if (whatsappChannelMessage.type == "system") {
|
|
801
|
+
winston.verbose("(wab) Skip system message");
|
|
802
|
+
return res.sendStatus(200);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const tlr = new TiledeskWhatsappTranslator();
|
|
806
|
+
const tdChannel = new TiledeskChannel({ settings: settings, API_URL: API_URL });
|
|
807
|
+
|
|
808
|
+
// Try on Whatsapp - Initialize conversation with chatbot
|
|
809
|
+
if (whatsappChannelMessage.text && whatsappChannelMessage.text.body.startsWith("#td")) {
|
|
810
|
+
let code = whatsappChannelMessage.text.body.split(" ")[0];
|
|
811
|
+
const bottester = new TiledeskBotTester({
|
|
812
|
+
project_id: project_id,
|
|
813
|
+
redis_client: redis_client,
|
|
814
|
+
db: db,
|
|
815
|
+
tdChannel: tdChannel,
|
|
816
|
+
tlr: tlr,
|
|
817
|
+
});
|
|
818
|
+
bottester.startBotConversation(req.body, code).then((result) => {
|
|
819
|
+
winston.verbose("(wab) test conversation started");
|
|
820
|
+
winston.debug("(wab) startBotConversation result: ", result);
|
|
821
|
+
}).catch((err) => {
|
|
822
|
+
winston.error("(wab) start test onversation error: ", err);
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
// Standard message
|
|
826
|
+
else {
|
|
827
|
+
let firstname = req.body.entry[0].changes[0].value.contacts[0].profile.name;
|
|
828
|
+
let message_info = {
|
|
829
|
+
channel: "whatsapp",
|
|
830
|
+
whatsapp: {
|
|
831
|
+
phone_number_id: req.body.entry[0].changes[0].value.metadata.phone_number_id,
|
|
832
|
+
from: req.body.entry[0].changes[0].value.messages[0].from,
|
|
833
|
+
firstname: req.body.entry[0].changes[0].value.contacts[0].profile.name,
|
|
834
|
+
lastname: " "
|
|
835
|
+
},
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
let tiledeskJsonMessage;
|
|
839
|
+
|
|
840
|
+
let metadata_type = ["image", "video", "document", "audio"];
|
|
841
|
+
if (metadata_type.includes(whatsappChannelMessage.type)) {
|
|
842
|
+
|
|
843
|
+
const util = new TiledeskWhatsapp({
|
|
844
|
+
token: settings.wab_token,
|
|
845
|
+
GRAPH_URL: GRAPH_URL,
|
|
846
|
+
API_URL: API_URL,
|
|
847
|
+
BASE_FILE_URL: BASE_FILE_URL,
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
const media = whatsappChannelMessage[whatsappChannelMessage.type];
|
|
851
|
+
const filename = await util.downloadMedia(media.id);
|
|
852
|
+
|
|
853
|
+
if (!filename) {
|
|
854
|
+
winston.debug(`(wab) Unable to download media with id ${media.id}. Message not sent.`);
|
|
855
|
+
return res.status(500).send({ success: false, error: "unable to download media" });
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
const file_path = path.join(__dirname, "tmp", filename);
|
|
859
|
+
const uploadFolder = whatsappChannelMessage.type === "image" ? "images" : "files";
|
|
860
|
+
const media_url = await util.uploadMedia(file_path, uploadFolder);
|
|
861
|
+
winston.debug(`(wab) media_url: ${media_url}`);
|
|
862
|
+
|
|
863
|
+
tiledeskJsonMessage = await tlr.toTiledesk(whatsappChannelMessage, firstname, media_url);
|
|
864
|
+
} else {
|
|
865
|
+
winston.debug("(wab) message type: ", whatsappChannelMessage.type);
|
|
866
|
+
tiledeskJsonMessage = await tlr.toTiledesk(whatsappChannelMessage, firstname);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (tiledeskJsonMessage) {
|
|
870
|
+
winston.verbose("(wab) tiledeskJsonMessage: ", tiledeskJsonMessage);
|
|
871
|
+
const response = await tdChannel.send(tiledeskJsonMessage, message_info, settings.department_id);
|
|
872
|
+
winston.verbose("(wab) Message sent to Tiledesk!");
|
|
873
|
+
winston.debug("(wab) response: ", response);
|
|
874
|
+
} else {
|
|
875
|
+
winston.verbose("(wab) tiledeskJsonMessage is undefined");
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
// Message status update incoming
|
|
882
|
+
if (req.body.entry?.[0]?.changes?.[0]?.value?.statuses?.[0]) {
|
|
883
|
+
let whatsappStatusMessage = req.body.entry[0].changes[0].value.statuses[0];
|
|
884
|
+
winston.verbose("(wab) whatsappStatusMessage: ", whatsappStatusMessage);
|
|
885
|
+
|
|
886
|
+
let message_id = whatsappStatusMessage.id;
|
|
887
|
+
let status = whatsappStatusMessage.status;
|
|
888
|
+
let error = null;
|
|
889
|
+
if (whatsappStatusMessage.errors) {
|
|
890
|
+
error = whatsappStatusMessage.errors[0].title;
|
|
891
|
+
}
|
|
892
|
+
winston.verbose("(wab) update status in " + status + " for message_id " + message_id);
|
|
893
|
+
|
|
894
|
+
const tdClient = new TiledeskClient({
|
|
895
|
+
projectId: settings.project_id,
|
|
896
|
+
token: settings.token,
|
|
897
|
+
APIURL: API_URL,
|
|
898
|
+
APIKEY: "___",
|
|
899
|
+
log: false,
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
const wl = new WhatsappLogger({ tdClient: tdClient });
|
|
903
|
+
wl.updateMessageStatus(message_id, status, error);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
res.sendStatus(200);
|
|
907
|
+
|
|
908
|
+
})
|
|
909
|
+
|
|
874
910
|
// Endpoint for Whatsapp Business
|
|
875
|
-
// Accepts POST requests at /webhook endpoint
|
|
876
911
|
router.post("/webhook/:project_id", async (req, res) => {
|
|
877
912
|
// Parse the request body from the POST
|
|
878
913
|
let project_id = req.params.project_id;
|
|
@@ -1196,7 +1231,7 @@ router.post("/webhook/:project_id", async (req, res) => {
|
|
|
1196
1231
|
|
|
1197
1232
|
// Accepts GET requests at the /webhook endpoint. You need this URL to setup webhook initially.
|
|
1198
1233
|
// info on verification request payload: https://developers.facebook.com/docs/graph-api/webhooks/getting-started#verification-requests
|
|
1199
|
-
router.get("/webhook
|
|
1234
|
+
router.get("/webhook", async (req, res) => {
|
|
1200
1235
|
/**
|
|
1201
1236
|
* UPDATE YOUR VERIFY TOKEN
|
|
1202
1237
|
*This will be the Verify Token value when you set up webhook
|
|
@@ -1209,71 +1244,241 @@ router.get("/webhook/:project_id", async (req, res) => {
|
|
|
1209
1244
|
let token = req.query["hub.verify_token"];
|
|
1210
1245
|
let challenge = req.query["hub.challenge"];
|
|
1211
1246
|
|
|
1212
|
-
let CONTENT_KEY = "whatsapp-" + req.params.project_id;
|
|
1247
|
+
//let CONTENT_KEY = "whatsapp-" + req.params.project_id;
|
|
1248
|
+
|
|
1249
|
+
//let settings = await db.get(CONTENT_KEY);
|
|
1250
|
+
|
|
1251
|
+
// if (!settings || !settings.verify_token) {
|
|
1252
|
+
// winston.error("(wab) No settings found! Unable to verify token.");
|
|
1253
|
+
// res.sendStatus(403);
|
|
1254
|
+
// } else {
|
|
1255
|
+
//let VERIFY_TOKEN = settings.verify_token;
|
|
1256
|
+
let VERIFY_TOKEN = process.env.VERIFY_TOKEN || "tiledesk-verify-token";
|
|
1257
|
+
// Check if a token and mode were sent
|
|
1258
|
+
if (mode && token) {
|
|
1259
|
+
// Check the mode and token sent are correct
|
|
1260
|
+
if (mode === "subscribe" && token === VERIFY_TOKEN) {
|
|
1261
|
+
// Respond with 200 OK and challenge token from the request
|
|
1262
|
+
winston.verbose("(wab) Webhook verified");
|
|
1263
|
+
res.status(200).send(challenge);
|
|
1264
|
+
} else {
|
|
1265
|
+
// Responds with '403 Forbidden' if verify tokens do not match
|
|
1266
|
+
winston.error("(wab) mode is not 'subscribe' or token do not match");
|
|
1267
|
+
res.sendStatus(403);
|
|
1268
|
+
}
|
|
1269
|
+
} else {
|
|
1270
|
+
winston.error("(wab) mode or token undefined");
|
|
1271
|
+
res.status(400).send("impossible to verify the webhook: mode or token undefined.");
|
|
1272
|
+
}
|
|
1273
|
+
//}
|
|
1274
|
+
});
|
|
1213
1275
|
|
|
1214
|
-
|
|
1276
|
+
// Accepts GET requests at the /webhook endpoint. You need this URL to setup webhook initially.
|
|
1277
|
+
// info on verification request payload: https://developers.facebook.com/docs/graph-api/webhooks/getting-started#verification-requests
|
|
1278
|
+
router.get("/webhook/:project_id", async (req, res) => {
|
|
1279
|
+
/**
|
|
1280
|
+
* UPDATE YOUR VERIFY TOKEN
|
|
1281
|
+
*This will be the Verify Token value when you set up webhook
|
|
1282
|
+
*/
|
|
1283
|
+
winston.verbose("(wab) Verify the webhook... ");
|
|
1284
|
+
winston.debug("(wab) req.query: " + req.query);
|
|
1285
|
+
|
|
1286
|
+
// Parse params from the webhook verification request
|
|
1287
|
+
let mode = req.query["hub.mode"];
|
|
1288
|
+
let token = req.query["hub.verify_token"];
|
|
1289
|
+
let challenge = req.query["hub.challenge"];
|
|
1215
1290
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1291
|
+
//let CONTENT_KEY = "whatsapp-" + req.params.project_id;
|
|
1292
|
+
|
|
1293
|
+
//let settings = await db.get(CONTENT_KEY);
|
|
1294
|
+
|
|
1295
|
+
// if (!settings || !settings.verify_token) {
|
|
1296
|
+
// winston.error("(wab) No settings found! Unable to verify token.");
|
|
1297
|
+
// res.sendStatus(403);
|
|
1298
|
+
// } else {
|
|
1299
|
+
//let VERIFY_TOKEN = settings.verify_token;
|
|
1300
|
+
let VERIFY_TOKEN = "tiledesk-verify-token"
|
|
1301
|
+
// Check if a token and mode were sent
|
|
1302
|
+
if (mode && token) {
|
|
1303
|
+
// Check the mode and token sent are correct
|
|
1304
|
+
if (mode === "subscribe" && token === VERIFY_TOKEN) {
|
|
1305
|
+
// Respond with 200 OK and challenge token from the request
|
|
1306
|
+
winston.verbose("(wab) Webhook verified");
|
|
1307
|
+
res.status(200).send(challenge);
|
|
1308
|
+
} else {
|
|
1309
|
+
// Responds with '403 Forbidden' if verify tokens do not match
|
|
1310
|
+
winston.error("(wab) mode is not 'subscribe' or token do not match");
|
|
1311
|
+
res.sendStatus(403);
|
|
1312
|
+
}
|
|
1219
1313
|
} else {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1314
|
+
winston.error("(wab) mode or token undefined");
|
|
1315
|
+
res.status(400).send("impossible to verify the webhook: mode or token undefined.");
|
|
1316
|
+
}
|
|
1317
|
+
//}
|
|
1318
|
+
});
|
|
1319
|
+
// ***************************************
|
|
1320
|
+
// ******* MESSAGING SECTION - END *******
|
|
1321
|
+
// ***************************************
|
|
1322
|
+
|
|
1323
|
+
// ---------------------------------------
|
|
1324
|
+
|
|
1325
|
+
// ***************************************
|
|
1326
|
+
// ****** TRY ON WA SECTION - START ******
|
|
1327
|
+
// ***************************************
|
|
1328
|
+
router.post("/newtest", async (req, res) => {
|
|
1329
|
+
winston.verbose("(wab) initializing new test..");
|
|
1330
|
+
|
|
1331
|
+
let project_id = req.body.project_id;
|
|
1332
|
+
let bot_id = req.body.bot_id;
|
|
1333
|
+
|
|
1334
|
+
let info = {
|
|
1335
|
+
project_id: project_id,
|
|
1336
|
+
bot_id: bot_id,
|
|
1337
|
+
};
|
|
1338
|
+
|
|
1339
|
+
let short_uid = uuidv4().substring(0, 8);
|
|
1340
|
+
let key = "bottest:" + short_uid;
|
|
1341
|
+
|
|
1342
|
+
if (!redis_client) {
|
|
1343
|
+
return res.status(500).send({ message: "Test it out on Whatsapp not available. Redis not ready." });
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
await redis_client.set(key, JSON.stringify(info), "EX", 604800);
|
|
1347
|
+
redis_client.get(key, (err, value) => {
|
|
1348
|
+
if (err) {
|
|
1349
|
+
winston.error("(wab) redis get err: ", err);
|
|
1350
|
+
return res.status(500).send({ success: "false", message: "Testing info could not be saved" });
|
|
1234
1351
|
} else {
|
|
1235
|
-
winston.
|
|
1236
|
-
res.status(
|
|
1352
|
+
winston.debug("(wab) new test initialized with id: " + short_uid);
|
|
1353
|
+
return res.status(200).send({ short_uid: short_uid });
|
|
1237
1354
|
}
|
|
1355
|
+
});
|
|
1356
|
+
});
|
|
1357
|
+
// ***************************************
|
|
1358
|
+
// ******* TRY ON WA SECTION - END *******
|
|
1359
|
+
// ***************************************
|
|
1360
|
+
|
|
1361
|
+
// ---------------------------------------
|
|
1362
|
+
|
|
1363
|
+
// ***************************************
|
|
1364
|
+
// ******* APP STORE SECTION - END *******
|
|
1365
|
+
// ***************************************
|
|
1366
|
+
router.get("/detail", async (req, res) => {
|
|
1367
|
+
winston.verbose("(wab) /detail");
|
|
1368
|
+
|
|
1369
|
+
let project_id = req.query.project_id;
|
|
1370
|
+
let token = req.query.token;
|
|
1371
|
+
let app_id = req.query.app_id;
|
|
1372
|
+
|
|
1373
|
+
const tdChannel = new TiledeskChannel({
|
|
1374
|
+
settings: { project_id: project_id, token: token },
|
|
1375
|
+
API_URL: API_URL,
|
|
1376
|
+
});
|
|
1377
|
+
let isAvailable = await tdChannel.getProjectDetail();
|
|
1378
|
+
winston.debug("(wab) app is available: ", isAvailable);
|
|
1379
|
+
if (!project_id || !token || !app_id) {
|
|
1380
|
+
return res.status(500).send("<p>Ops! An error occured.</p><p>Missing query params! project_id, token and app_id are required.</p>");
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
const appClient = new TiledeskAppsClient({ APPS_API_URL: APPS_API_URL });
|
|
1384
|
+
let installation = await appClient.getInstallations(project_id, app_id);
|
|
1385
|
+
|
|
1386
|
+
let installed = false;
|
|
1387
|
+
if (installation) {
|
|
1388
|
+
installed = true;
|
|
1238
1389
|
}
|
|
1390
|
+
|
|
1391
|
+
readHTMLFile("/detail.html", (err, html) => {
|
|
1392
|
+
var template = handlebars.compile(html);
|
|
1393
|
+
var replacements = {
|
|
1394
|
+
app_version: pjson.version,
|
|
1395
|
+
project_id: project_id,
|
|
1396
|
+
token: token,
|
|
1397
|
+
app_id: app_id,
|
|
1398
|
+
installed: installed,
|
|
1399
|
+
isAvailable: isAvailable,
|
|
1400
|
+
};
|
|
1401
|
+
var html = template(replacements);
|
|
1402
|
+
res.send(html);
|
|
1403
|
+
});
|
|
1239
1404
|
});
|
|
1240
1405
|
|
|
1241
|
-
router.post("/
|
|
1242
|
-
winston.verbose("(wab)
|
|
1406
|
+
router.post("/install", async (req, res) => {
|
|
1407
|
+
winston.verbose("(wab) /install");
|
|
1243
1408
|
|
|
1244
1409
|
let project_id = req.body.project_id;
|
|
1245
|
-
let
|
|
1410
|
+
let app_id = req.body.app_id;
|
|
1411
|
+
let token = req.body.token;
|
|
1246
1412
|
|
|
1247
|
-
|
|
1413
|
+
winston.debug("(wab) Install app " + app_id + " for project id " + project_id);
|
|
1414
|
+
let installation_info = {
|
|
1248
1415
|
project_id: project_id,
|
|
1249
|
-
|
|
1416
|
+
app_id: app_id,
|
|
1417
|
+
createdAt: Date.now(),
|
|
1250
1418
|
};
|
|
1251
1419
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1420
|
+
const appClient = new TiledeskAppsClient({ APPS_API_URL: APPS_API_URL });
|
|
1421
|
+
appClient
|
|
1422
|
+
.install(installation_info)
|
|
1423
|
+
.then((installation) => {
|
|
1424
|
+
winston.debug("(wab) installation response: ", installation);
|
|
1254
1425
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1426
|
+
res.redirect(
|
|
1427
|
+
url.format({
|
|
1428
|
+
pathname: BASE_URL + "/detail",
|
|
1429
|
+
query: {
|
|
1430
|
+
project_id: project_id,
|
|
1431
|
+
app_id: app_id,
|
|
1432
|
+
token: token,
|
|
1433
|
+
},
|
|
1434
|
+
})
|
|
1435
|
+
);
|
|
1436
|
+
})
|
|
1437
|
+
.catch((err) => {
|
|
1438
|
+
winston.error("(wab) installation error: " + err.data);
|
|
1439
|
+
res.send("An error occurred during the installation");
|
|
1440
|
+
});
|
|
1441
|
+
});
|
|
1258
1442
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1443
|
+
router.post("/uninstall", async (req, res) => {
|
|
1444
|
+
winston.verbose("(wab) /uninstall");
|
|
1445
|
+
let project_id = req.body.project_id;
|
|
1446
|
+
let app_id = req.body.app_id;
|
|
1447
|
+
let token = req.body.token;
|
|
1448
|
+
|
|
1449
|
+
const appClient = new TiledeskAppsClient({ APPS_API_URL: APPS_API_URL });
|
|
1450
|
+
appClient.uninstall(project_id, app_id).then((response) => {
|
|
1451
|
+
winston.debug("(wab) uninstallation response: ", response);
|
|
1452
|
+
res.redirect(
|
|
1453
|
+
url.format({
|
|
1454
|
+
pathname: BASE_URL + "/detail",
|
|
1455
|
+
query: {
|
|
1456
|
+
project_id: project_id,
|
|
1457
|
+
app_id: app_id,
|
|
1458
|
+
token: token,
|
|
1459
|
+
},
|
|
1460
|
+
})
|
|
1461
|
+
);
|
|
1462
|
+
}).catch((err) => {
|
|
1463
|
+
winston.error("(wab) uninstallation error: " + err.data);
|
|
1464
|
+
res.send("An error occurred during the uninstallation");
|
|
1268
1465
|
});
|
|
1269
1466
|
});
|
|
1467
|
+
// ***************************************
|
|
1468
|
+
// ****** APP STORE SECTION - START ******
|
|
1469
|
+
// ***************************************
|
|
1470
|
+
|
|
1471
|
+
// ---------------------------------------
|
|
1270
1472
|
|
|
1473
|
+
// ***************************************
|
|
1474
|
+
// ******* IN DEPRECATION - START ********
|
|
1475
|
+
// ***************************************
|
|
1271
1476
|
router.get("/templates/detail", async (req, res) => {
|
|
1272
1477
|
let project_id = req.query.project_id;
|
|
1273
1478
|
let token = req.query.token;
|
|
1274
1479
|
let app_id = req.query.app_id;
|
|
1275
1480
|
let template_id = req.query.id_template;
|
|
1276
|
-
winston.debug("get template_id: " + template_id);
|
|
1481
|
+
winston.debug("(wab) get template_id: " + template_id);
|
|
1277
1482
|
|
|
1278
1483
|
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
1279
1484
|
let settings = await db.get(CONTENT_KEY);
|
|
@@ -1323,97 +1528,148 @@ router.get("/templates/detail", async (req, res) => {
|
|
|
1323
1528
|
}
|
|
1324
1529
|
});
|
|
1325
1530
|
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
winston.verbose("(wab) /templates");
|
|
1531
|
+
router.get("/direct/tiledesk", async (req, res) => {
|
|
1532
|
+
winston.verbose("(wab) /direct/tiledesk");
|
|
1329
1533
|
|
|
1330
|
-
let project_id = req.
|
|
1331
|
-
let
|
|
1332
|
-
let
|
|
1534
|
+
let project_id = req.query.project_id;
|
|
1535
|
+
let whatsapp_receiver = req.query.whatsapp_receiver;
|
|
1536
|
+
let phone_number_id = req.query.phone_number_id;
|
|
1333
1537
|
|
|
1334
1538
|
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
1335
1539
|
let settings = await db.get(CONTENT_KEY);
|
|
1336
|
-
winston.debug("(wab) settings: ", settings);
|
|
1337
1540
|
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1541
|
+
let tiledeskChannelMessage = {
|
|
1542
|
+
text: "Sample text",
|
|
1543
|
+
attributes: {
|
|
1544
|
+
attachment: {
|
|
1545
|
+
type: "wa_template",
|
|
1546
|
+
template: {
|
|
1547
|
+
language: "en_US",
|
|
1548
|
+
name: "hello_world",
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
const tlr = new TiledeskWhatsappTranslator();
|
|
1554
|
+
const twClient = new TiledeskWhatsapp({
|
|
1555
|
+
token: settings.wab_token,
|
|
1556
|
+
GRAPH_URL: GRAPH_URL,
|
|
1557
|
+
API_URL: API_URL,
|
|
1558
|
+
BASE_FILE_URL: BASE_FILE_URL,
|
|
1559
|
+
});
|
|
1345
1560
|
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
});
|
|
1366
|
-
}
|
|
1561
|
+
let whatsappJsonMessage = await tlr.toWhatsapp(
|
|
1562
|
+
tiledeskChannelMessage,
|
|
1563
|
+
whatsapp_receiver
|
|
1564
|
+
);
|
|
1565
|
+
winston.verbose("(wab) whatsappJsonMessage", whatsappJsonMessage);
|
|
1566
|
+
|
|
1567
|
+
twClient.sendMessage(phone_number_id, whatsappJsonMessage).then((response) => {
|
|
1568
|
+
winston.verbose(
|
|
1569
|
+
"(wab) Message sent to WhatsApp! " +
|
|
1570
|
+
response.status +
|
|
1571
|
+
" " +
|
|
1572
|
+
response.statusText
|
|
1573
|
+
);
|
|
1574
|
+
}).catch((err) => {
|
|
1575
|
+
//winston.error("(wab) error send message: ", err);
|
|
1576
|
+
return res.status(400).send({ success: false, error: err });
|
|
1577
|
+
});
|
|
1578
|
+
|
|
1579
|
+
res.status(200).send("Message sent");
|
|
1367
1580
|
});
|
|
1368
|
-
*/
|
|
1369
1581
|
|
|
1370
|
-
|
|
1371
|
-
router.
|
|
1372
|
-
winston.verbose("(wab)
|
|
1582
|
+
// Can be deleted?
|
|
1583
|
+
router.post("/tiledesk/broadcast", async (req, res) => {
|
|
1584
|
+
winston.verbose("(wab) Message received from Tiledesk (Broadcast)");
|
|
1373
1585
|
|
|
1374
|
-
let
|
|
1586
|
+
let tiledeskChannelMessage = req.body.payload;
|
|
1587
|
+
winston.verbose("(wab) tiledeskChannelMessage: ", tiledeskChannelMessage);
|
|
1588
|
+
let project_id = req.body.payload.id_project;
|
|
1375
1589
|
|
|
1376
1590
|
let CONTENT_KEY = "whatsapp-" + project_id;
|
|
1377
1591
|
let settings = await db.get(CONTENT_KEY);
|
|
1378
1592
|
|
|
1379
|
-
if (settings) {
|
|
1593
|
+
if (!settings) {
|
|
1594
|
+
return res.status(400).send({ success: false, error: "WhatsApp is not installed for the project_id: " + project_id });
|
|
1595
|
+
}
|
|
1380
1596
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
if (templates) {
|
|
1385
|
-
res.status(200).send(templates.data);
|
|
1386
|
-
} else {
|
|
1387
|
-
res.status(500).send({ success: false, code: '02', message: "A problem occurred while getting templates from WhatsApp" })
|
|
1388
|
-
}
|
|
1597
|
+
if (!settings.business_account_id) {
|
|
1598
|
+
return res.status(400).send({ success: false, error: "Missing parameter 'WhatsApp Business Account ID'. Please update your app." });
|
|
1599
|
+
}
|
|
1389
1600
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
}
|
|
1601
|
+
let receiver_list = req.body.receiver_list;
|
|
1602
|
+
let phone_number_id = req.body.phone_number_id;
|
|
1393
1603
|
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1604
|
+
let tm = new TemplateManager({
|
|
1605
|
+
token: settings.wab_token,
|
|
1606
|
+
business_account_id: settings.business_account_id,
|
|
1607
|
+
GRAPH_URL: GRAPH_URL,
|
|
1608
|
+
});
|
|
1609
|
+
const tlr = new TiledeskWhatsappTranslator();
|
|
1610
|
+
const twClient = new TiledeskWhatsapp({
|
|
1611
|
+
token: settings.wab_token,
|
|
1612
|
+
GRAPH_URL: GRAPH_URL,
|
|
1613
|
+
API_URL: API_URL,
|
|
1614
|
+
BASE_FILE_URL: BASE_FILE_URL,
|
|
1615
|
+
});
|
|
1397
1616
|
|
|
1398
|
-
|
|
1399
|
-
|
|
1617
|
+
let response = await tm.getTemplates();
|
|
1618
|
+
let templates = response.data;
|
|
1400
1619
|
|
|
1401
|
-
|
|
1620
|
+
let selected_template = templates.find(
|
|
1621
|
+
(t) => t.name === tiledeskChannelMessage.attributes.attachment.template.name
|
|
1622
|
+
);
|
|
1402
1623
|
|
|
1403
|
-
|
|
1404
|
-
router.get("/ext/:project_id", async (req, res) => {
|
|
1405
|
-
winston.verbose("(wab) /ext/");
|
|
1624
|
+
let params_object = await tm.generateParamsObject(selected_template);
|
|
1406
1625
|
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
let settings = await db.get(CONTENT_KEY);
|
|
1626
|
+
tiledeskChannelMessage.attributes.attachment.template.params = params_object;
|
|
1627
|
+
winston.verbose("(wab) --> tiledeskChannelMessage: ", tiledeskChannelMessage);
|
|
1410
1628
|
|
|
1411
|
-
|
|
1412
|
-
|
|
1629
|
+
let messages_sent = 0;
|
|
1630
|
+
let errors = [];
|
|
1631
|
+
let error_count = 0;
|
|
1632
|
+
|
|
1633
|
+
if (receiver_list) {
|
|
1634
|
+
let i = 0;
|
|
1635
|
+
async function execute(whatsapp_receiver) {
|
|
1636
|
+
let customTiledeskJsonMessage = await tlr.sanitizeTiledeskMessage(tiledeskChannelMessage, whatsapp_receiver);
|
|
1637
|
+
winston.verbose("(wab) customTiledeskJsonMessage: ", customTiledeskJsonMessage);
|
|
1638
|
+
|
|
1639
|
+
let whatsappJsonMessage = await tlr.toWhatsapp(customTiledeskJsonMessage, whatsapp_receiver.phone_number);
|
|
1640
|
+
winston.verbose("(wab) message created for receiver: " + whatsapp_receiver.phone_number);
|
|
1641
|
+
winston.verbose("(wab) whatsappJsonMessage", whatsappJsonMessage);
|
|
1642
|
+
|
|
1643
|
+
await twClient.sendMessage(phone_number_id, whatsappJsonMessage).then((response) => {
|
|
1644
|
+
winston.verbose("(wab) Message sent to WhatsApp! " + response.status + " " + response.statusText);
|
|
1645
|
+
messages_sent += 1;
|
|
1646
|
+
i += 1;
|
|
1647
|
+
if (i < receiver_list.length) {
|
|
1648
|
+
execute(receiver_list[i]);
|
|
1649
|
+
} else {
|
|
1650
|
+
winston.debug("(wab) End of list");
|
|
1651
|
+
return res.status(200).send({ success: true, message: "Broadcast terminated", messages_sent: messages_sent, errors: errors });
|
|
1652
|
+
}
|
|
1653
|
+
}).catch((err) => {
|
|
1654
|
+
winston.error("(wab) error send message: " + err.response.data.error.message);
|
|
1655
|
+
errors.push({ receiver: whatsapp_receiver.phone_number, error: err.response.data.error.message });
|
|
1656
|
+
i += 1;
|
|
1657
|
+
if (i < receiver_list.length) {
|
|
1658
|
+
execute(receiver_list[i]);
|
|
1659
|
+
} else {
|
|
1660
|
+
winston.debug("(wab) End of list");
|
|
1661
|
+
return res.status(200).send({ success: true, message: "Broadcast terminated", messages_sent: messages_sent, errors: errors });
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
execute(receiver_list[0]);
|
|
1413
1666
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1667
|
+
});
|
|
1668
|
+
// ***************************************
|
|
1669
|
+
// ******** IN DEPRECATION - END *********
|
|
1670
|
+
// ***************************************
|
|
1671
|
+
|
|
1672
|
+
// ---------------------------------------
|
|
1417
1673
|
|
|
1418
1674
|
// *****************************
|
|
1419
1675
|
// ********* FUNCTIONS *********
|
|
@@ -1421,7 +1677,7 @@ router.get("/ext/:project_id", async (req, res) => {
|
|
|
1421
1677
|
|
|
1422
1678
|
async function startApp(settings, callback) {
|
|
1423
1679
|
winston.info("(wab) Starting Whatsapp App");
|
|
1424
|
-
|
|
1680
|
+
|
|
1425
1681
|
if (!settings.MONGODB_URL) {
|
|
1426
1682
|
winston.error("(wab) MONGODB_URL is mandatory. Exit...");
|
|
1427
1683
|
return callback("Missing parameter: MONGODB_URL");
|
|
@@ -1495,6 +1751,20 @@ async function startApp(settings, callback) {
|
|
|
1495
1751
|
BRAND_NAME = settings.BRAND_NAME;
|
|
1496
1752
|
}
|
|
1497
1753
|
|
|
1754
|
+
if (!settings.FB_APP_ID) {
|
|
1755
|
+
winston.info("(wab) Missing FB_APP_ID parameter");
|
|
1756
|
+
} else {
|
|
1757
|
+
FB_APP_ID = process.env.FB_APP_ID;
|
|
1758
|
+
winston.info("(wab) FB_APP_ID is present");
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
if (!settings.CONFIGURATION_ID) {
|
|
1762
|
+
winston.info("(wab) Missing CONFIGURATION_ID parameter");
|
|
1763
|
+
} else {
|
|
1764
|
+
CONFIGURATION_ID = process.env.CONFIGURATION_ID;
|
|
1765
|
+
winston.info("(wab) CONFIGURATION_ID is present");
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1498
1768
|
// // For test only
|
|
1499
1769
|
// if (settings.LOG_MONGODB_URL) {
|
|
1500
1770
|
// /**
|
|
@@ -1518,9 +1788,9 @@ async function startApp(settings, callback) {
|
|
|
1518
1788
|
}
|
|
1519
1789
|
|
|
1520
1790
|
mongoose.connect(LOG_MONGODB_URL).then(() => {
|
|
1521
|
-
winston.info("Mongoose DB Connected");
|
|
1791
|
+
winston.info("(wab) Mongoose DB Connected");
|
|
1522
1792
|
}).catch((err) => {
|
|
1523
|
-
winston.error("(Mongoose) Unable to connect with MongoDB ", err);
|
|
1793
|
+
winston.error("(wab) (Mongoose) Unable to connect with MongoDB ", err);
|
|
1524
1794
|
});
|
|
1525
1795
|
|
|
1526
1796
|
if (settings.dbconnection) {
|
|
@@ -1595,4 +1865,19 @@ function readHTMLFile(templateName, callback) {
|
|
|
1595
1865
|
);
|
|
1596
1866
|
}
|
|
1597
1867
|
|
|
1868
|
+
async function getDepartments(project_id, token) {
|
|
1869
|
+
try {
|
|
1870
|
+
const tdChannel = new TiledeskChannel({
|
|
1871
|
+
settings: { project_id, token },
|
|
1872
|
+
API_URL,
|
|
1873
|
+
});
|
|
1874
|
+
|
|
1875
|
+
const departments = await tdChannel.getDepartments();
|
|
1876
|
+
return departments;
|
|
1877
|
+
} catch (err) {
|
|
1878
|
+
winston.error("(wab) Error getting departments:", err?.response?.data || err.message || err);
|
|
1879
|
+
return [];
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1598
1883
|
module.exports = { router: router, startApp: startApp };
|