@tiledesk/tiledesk-whatsapp-connector 0.1.53 → 0.1.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -11,6 +11,7 @@ const { v4: uuidv4 } = require('uuid');
11
11
  const cors = require('cors');
12
12
  var winston = require('./winston');
13
13
  const url = require('url');
14
+ const mongoose = require('mongoose');
14
15
 
15
16
  //const ext = require('./routes/ext')
16
17
  //const extRoute = ext.router;
@@ -27,6 +28,7 @@ const { TiledeskAppsClient } = require('./tiledesk/TiledeskAppsClient');
27
28
  const { MessageHandler } = require('./tiledesk/MessageHandler');
28
29
  const { TiledeskBotTester } = require('./tiledesk/TiledeskBotTester');
29
30
  const { TemplateManager } = require('./tiledesk/TemplateManager');
31
+ const { WhatsappLogger } = require('./tiledesk/WhatsappLogger');
30
32
 
31
33
  // mongo
32
34
  const { KVBaseMongo } = require('./tiledesk/KVBaseMongo');
@@ -58,6 +60,8 @@ let REDIS_HOST = null;
58
60
  let REDIS_PORT = null;
59
61
  let REDIS_PASSWORD = null;
60
62
  let BASE_FILE_URL = null;
63
+ let AMQP_MANAGER_URL = null;
64
+
61
65
 
62
66
  // Handlebars register helpers
63
67
  handlebars.registerHelper('isEqual', (a, b) => {
@@ -779,13 +783,13 @@ router.post('/tiledesk', async (req, res) => {
779
783
  twClient.sendMessage(phone_number_id, whatsappJsonMessage).then((response) => {
780
784
  winston.verbose("(wab) Message sent to WhatsApp! " + response.status + " " + response.statusText);
781
785
  }).catch((err) => {
782
- res.status(400).send({ success: false, error: "il template non esiste" });
783
786
  winston.error("(wab) error send message: ", err);
787
+ res.status(400).send({ success: false, error: "Template not existing" });
784
788
  })
785
789
 
786
790
  } else {
787
- res.status(400).send({ success: false, error: "il template non esiste" });
788
791
  winston.error("(wab) Whatsapp Json Message is undefined!")
792
+ res.status(400).send({ success: false, error: "An error occurred during message translation" });
789
793
  }
790
794
 
791
795
  } else {
@@ -1038,6 +1042,29 @@ router.post("/webhook/:project_id", async (req, res) => {
1038
1042
 
1039
1043
  }
1040
1044
  }
1045
+
1046
+ if (req.body.entry &&
1047
+ req.body.entry[0].changes &&
1048
+ req.body.entry[0].changes[0] &&
1049
+ req.body.entry[0].changes[0].value.statuses &&
1050
+ req.body.entry[0].changes[0].value.statuses[0]
1051
+ ) {
1052
+ let whatsappStatusMessage = req.body.entry[0].changes[0].value.statuses[0];
1053
+ winston.verbose("(wab) whatsappStatusMessage: ", whatsappStatusMessage);
1054
+
1055
+ let message_id = whatsappStatusMessage.id;
1056
+ let status = whatsappStatusMessage.status;
1057
+ let error = null;
1058
+ if (whatsappStatusMessage.errors) {
1059
+ error = whatsappStatusMessage.errors[0].title;
1060
+ }
1061
+ winston.verbose("(wab) update status in " + status+ " for message_id " + message_id);
1062
+
1063
+ const wl = new WhatsappLogger();
1064
+ wl.updateMessageStatus(message_id, status, error);
1065
+
1066
+ }
1067
+
1041
1068
  res.sendStatus(200);
1042
1069
 
1043
1070
  } else {
@@ -1324,6 +1351,18 @@ async function startApp(settings, callback) {
1324
1351
  winston.info("(wab) Missing redis parameters --> Test it out on WhatsApp disabled");
1325
1352
  }
1326
1353
 
1354
+ if (!settings.AMQP_MANAGER_URL) {
1355
+ winston.error("(wab api) AMQP_MANAGER_URL is mandatory (?). Exit...");
1356
+ } else {
1357
+ AMQP_MANAGER_URL = settings.AMQP_MANAGER_URL;
1358
+ winston.info("(wab api) AMQP_MANAGER_URL is present");
1359
+ }
1360
+
1361
+ mongoose.connect(process.env.MONGODB_URL)
1362
+ .then(() => { winston.info("Mongoose DB Connected") })
1363
+ .catch((err) => { winston.error("(Mongoose) Unable to connect with MongoDB ", err)
1364
+ })
1365
+
1327
1366
  db.connect(settings.MONGODB_URL, () => {
1328
1367
  winston.info("(wab) KVBaseMongo successfully connected.");
1329
1368
 
@@ -1336,7 +1375,8 @@ async function startApp(settings, callback) {
1336
1375
  DB: db,
1337
1376
  API_URL: API_URL,
1338
1377
  GRAPH_URL: GRAPH_URL,
1339
- BASE_FILE_URL: BASE_FILE_URL
1378
+ BASE_FILE_URL: BASE_FILE_URL,
1379
+ AMQP_MANAGER_URL: AMQP_MANAGER_URL
1340
1380
  }, (err) => {
1341
1381
  if (!err) {
1342
1382
  winston.info("(wab) API route successfully started.")
@@ -0,0 +1,36 @@
1
+ const mongoose = require('mongoose');
2
+
3
+ const MessageLogSchema = mongoose.Schema({
4
+ json_message: {
5
+ type: Object,
6
+ required: true
7
+ },
8
+ transaction_id: {
9
+ type: String,
10
+ required: true
11
+ },
12
+ message_id: {
13
+ type: String,
14
+ required: false
15
+ },
16
+ status: {
17
+ type: String,
18
+ required: true
19
+ },
20
+ status_code: {
21
+ type: Number,
22
+ required: true
23
+ },
24
+ error: {
25
+ type: String
26
+ },
27
+ timestamp: {
28
+ type: Date,
29
+ default: Date.now
30
+ }
31
+ })
32
+
33
+
34
+ const MessageLog = mongoose.model("MessageLog", MessageLogSchema);
35
+
36
+ module.exports = { MessageLog };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-whatsapp-connector",
3
- "version": "0.1.53",
3
+ "version": "0.1.54",
4
4
  "description": "Tiledesk Whatsapp connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -19,6 +19,7 @@
19
19
  "express": "^4.18.1",
20
20
  "form-data": "^4.0.0",
21
21
  "handlebars": "^4.7.7",
22
+ "jobs-worker-queued": "^0.0.5",
22
23
  "jsonwebtoken": "^8.5.1",
23
24
  "mongoose": "^6.5.0",
24
25
  "mongodb": "^3.5.5",
package/routes/api.js CHANGED
@@ -6,11 +6,13 @@ const router = express.Router({ mergeParams: true });
6
6
  const { TemplateManager } = require('../tiledesk/TemplateManager');
7
7
  const { TiledeskWhatsappTranslator } = require('../tiledesk/TiledeskWhatsappTranslator');
8
8
  const { TiledeskWhatsapp } = require('../tiledesk/TiledeskWhatsapp');
9
+ const { Scheduler } = require('../tiledesk/Scheduler');
9
10
 
10
11
  let db = null;
11
12
  let API_URL = null;
12
13
  let GRAPH_URL = null;
13
14
  let BASE_FILE_URL = null;
15
+ let AMQP_MANAGER_URL = null;
14
16
 
15
17
  router.get('/', async (req, res) => {
16
18
  res.status(200).send({ message: "API route works"})
@@ -125,14 +127,19 @@ router.get("/templates/:project_id", async (req, res) => {
125
127
 
126
128
  router.post('/tiledesk/broadcast', async (req, res) => {
127
129
  winston.verbose("(wab) Action received from Tiledesk (Broadcast)");
128
- winston.debug("Body (broadcast): ",JSON.stringify(req.body, null, 2));
130
+ winston.debug("Body (broadcast): ", JSON.stringify(req.body, null, 2));
129
131
 
130
132
  let body = req.body;
131
133
 
132
134
  let project_id = body.id_project;
133
135
  let receiver_list = body.receiver_list;
134
- let phone_number_id = body. phone_number_id;
136
+ let phone_number_id = body.phone_number_id;
135
137
  let template = body.template;
138
+ let transaction_id = body.transaction_id;
139
+
140
+ if (!transaction_id) {
141
+ transaction_id = "tiledesk-broadcast-" + Date.now();
142
+ }
136
143
 
137
144
  let CONTENT_KEY = "whatsapp-" + project_id;
138
145
  let settings = await db.get(CONTENT_KEY);
@@ -145,51 +152,22 @@ router.post('/tiledesk/broadcast', async (req, res) => {
145
152
  return res.status(400).send({ success: false, error: "Missing parameter 'WhatsApp Business Account ID'. Please update your app."})
146
153
  }
147
154
 
148
- const tm = new TemplateManager({ token: settings.wab_token, business_account_id: settings.business_account_id, GRAPH_URL: GRAPH_URL })
149
- const tlr = new TiledeskWhatsappTranslator();
150
- const twClient = new TiledeskWhatsapp({ token: settings.wab_token, GRAPH_URL: GRAPH_URL, API_URL: API_URL, BASE_FILE_URL: BASE_FILE_URL });
151
-
152
- let response = await tm.getTemplates();
153
- let templates = response.data;
154
-
155
- let selected_template = templates.find(t => t.name === template.name);
156
- let params_object = await tm.generateParamsObject(selected_template);
155
+ let scheduler = new Scheduler({ AMQP_MANAGER_URL: AMQP_MANAGER_URL });
156
+ let data_To_scheduler = {
157
+ project_id: project_id,
158
+ receiver_list: receiver_list,
159
+ phone_number_id: phone_number_id,
160
+ transaction_id: transaction_id,
161
+ template: template,
162
+ settings: settings
163
+ };
157
164
 
158
- // Send messages
159
- let messages_sent = 0;
160
- let errors = [];
161
- let error_count = 0;
165
+ winston.debug('(wab) data_To_scheduler: ', data_To_scheduler);
162
166
 
163
- if (receiver_list) {
164
- let i = 0;
165
- async function execute(receiver) {
166
- let whatsappJsonMessage = await tlr.createTemplateMessage(selected_template, receiver, params_object);
167
- winston.debug("(wab) whatsappJsonMessage: ", JSON.stringify(whatsappJsonMessage, null, 2));
167
+ let schedulerResult = await scheduler.goSchedule(data_To_scheduler);
168
+ winston.verbose('(wab) schedulerResult: ', schedulerResult);
168
169
 
169
- await twClient.sendMessage(phone_number_id, whatsappJsonMessage).then((response) => {
170
- winston.verbose("(wab) Message sent to WhatsApp! " + response.status + " " + response.statusText);
171
- messages_sent += 1;
172
- i += 1;
173
- if (i < receiver_list.length) {
174
- execute(receiver_list[i])
175
- } else {
176
- winston.debug("(wab) End of list")
177
- return res.status(200).send({ success: true, message: "Broadcast terminated", messages_sent: messages_sent, errors: errors });
178
- }
179
- }).catch((err) => {
180
- winston.error("(wab) error send message: " + err.response.data.error.message);
181
- errors.push({ receiver: receiver.phone_number, error: err.response.data.error.message });
182
- i += 1;
183
- if (i < receiver_list.length) {
184
- execute(receiver_list[i])
185
- } else {
186
- winston.debug("(wab) End of list")
187
- return res.status(200).send({ success: true, message: "Broadcast terminated", messages_sent: messages_sent, errors: errors });
188
- }
189
- })
190
- }
191
- execute(receiver_list[0]);
192
- }
170
+ res.status(200).send({ success: true, message: "Job started. Send messages in queue." })
193
171
 
194
172
  })
195
173
 
@@ -230,7 +208,12 @@ async function startRoute(settings, callback) {
230
208
  winston.info("(wab api) BASE_FILE_URL: " + BASE_FILE_URL);
231
209
  }
232
210
 
233
-
211
+ if (!settings.AMQP_MANAGER_URL) {
212
+ winston.error("(wab api) AMQP_MANAGER_URL is mandatory (?). Exit...");
213
+ } else {
214
+ AMQP_MANAGER_URL = settings.AMQP_MANAGER_URL;
215
+ winston.info("(wab api) AMQP_MANAGER_URL is present");
216
+ }
234
217
 
235
218
  }
236
219
 
@@ -216,35 +216,36 @@
216
216
 
217
217
  <div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 15px;">
218
218
  <div>
219
+ <p>Added Messages Logs for WhatsApp broadcast</p>
220
+ <p>Added Queue Manager for Whatsapp broadcast</p>
219
221
  <p>Bug fixes and performance improvements</p>
220
222
  </div>
221
- <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.53</b></p>
223
+ <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.54</b></p>
222
224
  </div>
223
-
225
+
224
226
  <div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 15px;">
225
227
  <div>
226
228
  <p>Bug fixes and performance improvements</p>
227
229
  </div>
228
- <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.52</b></p>
230
+ <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.53</b></p>
229
231
  </div>
230
232
 
231
233
  <div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 15px;">
232
234
  <div>
233
- <p style="margin-bottom: 0px">Bug fixes</p>
234
- <!--<p>Bug fixes and performance improvements</p>-->
235
+ <p>Bug fixes and performance improvements</p>
235
236
  </div>
236
- <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.50</b></p>
237
+ <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.52</b></p>
237
238
  </div>
238
239
 
239
240
  <div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 15px;">
240
241
  <div>
241
- <p style="margin-bottom: 0px">Added support for WhatsApp voice messages</p>
242
- <p style="margin-bottom: 0px">Bug fixes and minor improvements</p>
242
+ <p style="margin-bottom: 0px">Bug fixes</p>
243
243
  <!--<p>Bug fixes and performance improvements</p>-->
244
244
  </div>
245
- <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.49</b></p>
245
+ <p style="font-size: 12px; color: #676767; margin-bottom: 0px;">Version <b>0.1.50</b></p>
246
246
  </div>
247
247
 
248
+
248
249
  <hr style="margin-top: 50px; margin-bottom: 20px">
249
250
 
250
251
  <script>
@@ -0,0 +1,42 @@
1
+ var JobManager = require("jobs-worker-queued");
2
+ var winston = require('../winston');
3
+ var jobManager;
4
+
5
+ class Scheduler {
6
+
7
+ constructor(config) {
8
+ if (!config) {
9
+ throw new Error('config is mandatory');
10
+ }
11
+
12
+ if (!config.AMQP_MANAGER_URL) {
13
+ throw new Error('config.AMQP_MANAGER_URL is mandatory');
14
+ }
15
+
16
+ this.AMQP_MANAGER_URL = config.AMQP_MANAGER_URL;
17
+ this.log = false;
18
+ if (config.log) {
19
+ this.log = config.log;
20
+ }
21
+
22
+ jobManager = new JobManager(this.AMQP_MANAGER_URL, {
23
+ debug: false,
24
+ topic: "tiledesk-whatsapp_test",
25
+ exchange: "tiledesk-whatsapp_test"
26
+ });
27
+ }
28
+
29
+ async goSchedule(mydata) {
30
+ mydata.date = new Date();
31
+ try {
32
+ winston.debug("(wab) Data arrived to scheduler: ", mydata);
33
+ jobManager.publish(mydata);
34
+ return { success: true, msg: 'scheduling success!' };
35
+ } catch (err) {
36
+ winston.error('(wab) scheduling error ', err);
37
+ return { success: false, msg: 'Error in scheduling' };
38
+ }
39
+ }
40
+ }
41
+
42
+ module.exports = { Scheduler };
@@ -0,0 +1,48 @@
1
+ const winston = require("../winston");
2
+ const { MessageLog } = require("../models/WhatsappLog");
3
+
4
+ class WhatsappLogger {
5
+
6
+ constructor() {}
7
+
8
+ async updateMessageStatus(message_id, status, error) {
9
+ let status_code = this.getCodeFromStatus(status);
10
+ winston.debug("(wab) getCodeFromStatus result " + status_code);
11
+
12
+ MessageLog.findOneAndUpdate({ message_id: message_id }, { $set: {status: status, status_code: status_code, error: error }}, { new: true }).then((messageLog) => {
13
+ winston.verbose("(wab) status of message_id " + message_id + " updated to " + status);
14
+ winston.debug("(wab) messageLog updated ", messageLog);
15
+ }).catch((err) => {
16
+ winston.error("(wab) findOneAndUpdate error: ", err);
17
+ })
18
+
19
+ }
20
+
21
+ getCodeFromStatus(status) {
22
+ let code = null;
23
+ switch (status) {
24
+ case "rejected":
25
+ code = -1;
26
+ break;
27
+ case "accepted":
28
+ code = 0;
29
+ break;
30
+ case "sent":
31
+ code = 1;
32
+ break;
33
+ case "delivered":
34
+ code = 2;
35
+ break;
36
+ case "read":
37
+ code = 3;
38
+ break;
39
+ default:
40
+ code = -2;
41
+ break;
42
+ }
43
+ return code;
44
+ }
45
+
46
+ }
47
+
48
+ module.exports = { WhatsappLogger };