@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 +43 -3
- package/models/WhatsappLog.js +36 -0
- package/package.json +2 -1
- package/routes/api.js +28 -45
- package/template/detail.html +10 -9
- package/tiledesk/Scheduler.js +42 -0
- package/tiledesk/WhatsappLogger.js +48 -0
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.
|
|
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.
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
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
|
-
|
|
164
|
-
|
|
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
|
-
|
|
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
|
|
package/template/detail.html
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
|
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.
|
|
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">
|
|
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.
|
|
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 };
|