@tiledesk/tiledesk-whatsapp-connector 0.1.0

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.
@@ -0,0 +1,147 @@
1
+ const axios = require("axios").default;
2
+ const jwt = require('jsonwebtoken');
3
+ const { v4: uuidv4 } = require('uuid');
4
+
5
+ class TiledeskChannel {
6
+
7
+ /**
8
+ * Constructor for TiledeskChannel
9
+ *
10
+ * @example
11
+ * const { TiledeskChannel } = require('tiledesk-channel');
12
+ * const tdChannel = new TiledeskChannel({tiledeskJsonMessage: replyFromWhatsapp, settings: appSettings, whatsappJsonMessage: originalWhatsappMessage, API_URL: tiledeskApiUrl });
13
+ *
14
+ * @param {Object} config JSON configuration.
15
+ * @param {string} config.tiledeskJsonMessage Mandatory. Message translated from Whatsapp to Tiledesk
16
+ * @param {string} config.whatsappJsonMessage Mandatory. Original whatsapp message.
17
+ * @param {string} config.settings Mandatory. Installation settings.
18
+ * @param {string} config.API_URL Mandatory. Tiledesk api url.
19
+ * @param {boolean} options.log Optional. If true HTTP requests are logged.
20
+ */
21
+
22
+ constructor(config) {
23
+ if (!config) {
24
+ throw new Error('config is mandatory');
25
+ }
26
+
27
+ if (!config.settings) {
28
+ throw new Error('config.settings is mandatory');
29
+ }
30
+
31
+ if (!config.API_URL) {
32
+ throw new Error('config.API_URL is mandatory');
33
+ }
34
+
35
+ this.log = false;
36
+ if (config.log) {
37
+ this.log = config.log;
38
+ }
39
+
40
+ this.settings = config.settings;
41
+ this.API_URL = config.API_URL;
42
+
43
+ }
44
+
45
+ async send(tiledeskMessage, messageInfo) {
46
+
47
+ let channel;
48
+ let new_request_id;
49
+
50
+ if (messageInfo.channel == "whatsapp") {
51
+ channel = messageInfo.whatsapp;
52
+ new_request_id = "support-group-" + this.settings.project_id + "-" + uuidv4().substring(0, 8) + "-wab-" + channel.phone_number_id + "-" + channel.from;
53
+
54
+ } else if (messageInfo.channel == "telegram") {
55
+ channel = messageInfo.telegram;
56
+ // Check it
57
+ //new_request_id = "support-group-" + projectId + "-" + uuidv4() + "-telegram-" + from;
58
+
59
+ } else if (messageInfo.channel == "messenger") {
60
+ channel = messageInfo.messenger;
61
+ // Check it
62
+ //new_request_id = hased_request_id = "support-group-" + projectId + "-" + uuidv4() + "-" + sender_id + "-" + webhook_event.recipient.id;
63
+
64
+ } else {
65
+ console.log("[Tiledesk Channel] Channel not supported")
66
+ }
67
+
68
+ var payload = {
69
+ _id: 'wab-' + channel.from,
70
+ first_name: channel.firstname,
71
+ last_name: channel.lastname,
72
+ email: 'na@whatsapp.com',
73
+ sub: 'userexternal',
74
+ aud: 'https://tiledesk.com/subscriptions/' + this.settings.subscriptionId
75
+ }
76
+
77
+ var customToken = jwt.sign(payload, this.settings.secret);
78
+
79
+ return await axios({
80
+ url: this.API_URL + "/auth/signinWithCustomToken",
81
+ headers: {
82
+ 'Content-Type': 'application/json',
83
+ 'Authorization': "JWT " + customToken
84
+ },
85
+ data: {},
86
+ method: 'POST'
87
+ }).then((response) => {
88
+
89
+ let token = response.data.token;
90
+
91
+ return axios({
92
+ url: this.API_URL + `/${this.settings.project_id}/requests/me?channel=${messageInfo.channel}`,
93
+ headers: {
94
+ 'Content-Type': 'application/json',
95
+ 'Authorization': token
96
+ },
97
+ method: 'GET'
98
+ }).then((response) => {
99
+
100
+ if (log) {
101
+ console.log("[Tiledesk Channel] get request response: ", response.data);
102
+ }
103
+
104
+ let request_id;
105
+ if (response.data.requests[0]) {
106
+ request_id = response.data.requests[0].request_id;
107
+ } else {
108
+ request_id = new_request_id;
109
+ }
110
+
111
+ if (log) {
112
+ console.log("[Tiledesk Channel] tiledeskMessage:", tiledeskMessage);
113
+ }
114
+
115
+ return axios({
116
+ url: this.API_URL + `/${this.settings.project_id}/requests/${request_id}/messages`,
117
+ headers: {
118
+ 'Content-Type': 'application/json',
119
+ 'Authorization': token
120
+ },
121
+ data: tiledeskMessage,
122
+ method: 'POST'
123
+ }).then((response) => {
124
+
125
+ if (log) {
126
+ console.log("[Tiledesk Channel] send message response: ", response.data);
127
+ }
128
+
129
+ return response.data;
130
+
131
+ }).catch((err) => {
132
+ console.error("[Tiledesk Channel ERROR] send message: " + err);
133
+ })
134
+ }).catch((err) => {
135
+ console.error("[Tiledesk Channel ERROR] get requests: " + err);
136
+ })
137
+
138
+
139
+ }).catch((err) => {
140
+ console.error("[Tiledesk Channel ERROR] sign in error: " + err);
141
+ })
142
+ }
143
+
144
+ }
145
+
146
+ module.exports = { TiledeskChannel }
147
+
@@ -0,0 +1,140 @@
1
+ const axios = require("axios").default;
2
+
3
+ class TiledeskSubscriptionClient {
4
+
5
+ /**
6
+ * Constructor for TiledeskSubscriptionClient
7
+ *
8
+ * @example
9
+ * const { TiledeskSubscriptionClient } = require('tiledesk-subscription-client');
10
+ * const tdClient = new TiledeskSubscriptionClient({API_URL: tiledeskApiUrl, token: jwt_token, log: log});
11
+ *
12
+ * @param {Object} config JSON configuration.
13
+ * @param {string} config.API_URL Mandatory. The Tiledesk api url.
14
+ * @param {string} config.token Optional. Token required for authentication.
15
+ * @param {boolean} config.log Optional. If true HTTP requests are logged.
16
+ */
17
+ constructor(config) {
18
+ if (!config) {
19
+ throw new Error('config is mandatory');
20
+ }
21
+
22
+ if (!config.API_URL) {
23
+ throw new Error('config.API_URL is mandatory');
24
+ }
25
+
26
+ this.project_id = config.project_id
27
+ this.API_URL = config.API_URL;
28
+ this.token = config.token;
29
+ this.config = config;
30
+ this.log = false;
31
+ if (config.log) {
32
+ this.log = config.log;
33
+ }
34
+ }
35
+
36
+ async subscribe(subscription_info, callback) {
37
+
38
+ const URL = this.API_URL + `/${this.project_id}/subscriptions`;
39
+ const HTTPREQUEST = {
40
+ url: URL,
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ 'Authorization': this.token
44
+ },
45
+ json: subscription_info,
46
+ method: 'POST'
47
+ };
48
+ let promise = new Promise((resolve, reject) => {
49
+ TiledeskSubscriptionClient.myrequest(
50
+ HTTPREQUEST,
51
+ function(err, resbody) {
52
+ if (err) {
53
+ if (callback) {
54
+ callback(err);
55
+ }
56
+ reject(err);
57
+ }
58
+ else {
59
+ if (callback) {
60
+ callback(null, resbody);
61
+ }
62
+ console.log("[Tiledesk Subscription Client] Subscribed");
63
+ resolve(resbody);
64
+ }
65
+ }, true);
66
+
67
+ })
68
+ return promise;
69
+ }
70
+
71
+ unsubscribe(subscriptionId, callback) {
72
+ const URL = this.API_URL + `/${this.project_id}/subscriptions/${subscriptionId}`;
73
+ const HTTPREQUEST = {
74
+ url: URL,
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ 'Authorization': this.token
78
+ },
79
+ method: 'DELETE'
80
+ };
81
+ let promise = new Promise((resolve, reject) => {
82
+ TiledeskSubscriptionClient.myrequest(
83
+ HTTPREQUEST,
84
+ function(err, resbody) {
85
+ if (err) {
86
+ if (callback) {
87
+ callback(err);
88
+ }
89
+ reject(err);
90
+ }
91
+ else {
92
+ if (callback) {
93
+ callback(null, resbody);
94
+ }
95
+ console.log("[Tiledesk Subscription Client] Unsubscribed");
96
+ resolve(resbody);
97
+ }
98
+ }, true);
99
+ })
100
+ return promise;
101
+ }
102
+
103
+
104
+ // HTTP REQUEST
105
+
106
+ static async myrequest(options, callback, log) {
107
+ if (this.log) {
108
+ console.log("[Tiledesk Subscription Client] Options: ", options);
109
+ }
110
+ return await axios({
111
+ url: options.url,
112
+ method: options.method,
113
+ data: options.json,
114
+ params: options.params,
115
+ headers: options.headers
116
+ }).then((res) => {
117
+ if (this.log) {
118
+ console.log("[Tiledesk Subscription Client] Response headers:\n", res.headers);
119
+ }
120
+ if (res && res.status == 200 && res.data) {
121
+ if (callback) {
122
+ callback(null, res.data);
123
+ }
124
+ }
125
+ else {
126
+ if (callback) {
127
+ callback(TiledeskClient.getErr({ message: "Response status not 200" }, options, res), null, null);
128
+ }
129
+ }
130
+ }).catch((err) => {
131
+ console.error("An error occured: ", err);
132
+ if (callback) {
133
+ callback(err, null, null);
134
+ }
135
+ })
136
+ }
137
+
138
+ }
139
+
140
+ module.exports = { TiledeskSubscriptionClient }
@@ -0,0 +1,192 @@
1
+ const axios = require("axios").default;
2
+ const fs = require('fs');
3
+ const FormData = require('form-data');
4
+
5
+ class TiledeskWhatsapp {
6
+
7
+ /**
8
+ * Constructor for TiledeskWhatsapp
9
+ *
10
+ * @example
11
+ * const { TiledeskWhatsapp } = require('tiledesk-whatsapp');
12
+ * const twclient = new TiledeskWhatsappClient({ token: whatsappBusinessToken });
13
+ *
14
+ * @param {Object} config JSON configuration.
15
+ * @param {string} config.token Mandatory. Token required for authentication.
16
+ * @param {string} config.GRAPH_URL Mandatory. Url for facebook whatsapp api.
17
+ * @param {boolean} options.log Optional. If true HTTP requests are logged.
18
+ */
19
+
20
+ constructor(config) {
21
+ if (!config) {
22
+ throw new Error('config is mandatory');
23
+ }
24
+
25
+ if (!config.token) {
26
+ throw new Error('config.token is mandatory');
27
+ }
28
+
29
+ if (!config.GRAPH_URL) {
30
+ throw new Error('config.GRAPH_URL is mandatory');
31
+ }
32
+ // this.media = config.channelMedia;
33
+ this.token = config.token;
34
+ this.GRAPH_URL = config.GRAPH_URL
35
+ }
36
+
37
+ async sendMessage(phone_number_id, message) {
38
+ if (log) {
39
+ console.log("[Tiledesk Whatsapp] Sending message...", message);
40
+ } else {
41
+ console.log("[Tiledesk Whatsapp] Sending message...");
42
+ }
43
+
44
+ return await axios({
45
+ url: this.GRAPH_URL + phone_number_id + "/messages?access_token=" + this.token,
46
+ headers: {
47
+ "Content-Type": "application/json",
48
+ },
49
+ data: message,
50
+ method: "POST"
51
+ }).then((response) => {
52
+ console.log("[Tiledesk Whatsapp] Message sent!");
53
+ return response
54
+ }).catch((err) => {
55
+ console.error("[Tiledesk Whatsapp ERROR] Send message: ", err);
56
+ throw err;
57
+ })
58
+ }
59
+
60
+ async downloadMedia(mediaId) {
61
+ if (log) {
62
+ console.log("[Tiledesk Whatsapp] Download media with id: ", mediaId);
63
+ }
64
+
65
+ return await axios({
66
+ url: this.GRAPH_URL + mediaId,
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ 'Authorization': "Bearer " + this.token
70
+ }
71
+ }).then(async (response) => {
72
+ console.log("response: ", response.data);
73
+
74
+ let download_url = response.data.url;
75
+ let mime_type = response.data.mime_type;
76
+ let extension = mime_type.substring(mime_type.lastIndexOf("/") + 1);
77
+ let tid = this.getId();
78
+ let type = "media-" + tid + "." + extension;
79
+
80
+ const writeStream = fs.createWriteStream('tmp/' + type);
81
+ console.log("[Tiledesk Whatsapp] Downloading file...");
82
+
83
+ return await axios({
84
+ url: download_url,
85
+ method: 'GET',
86
+ headers: {
87
+ 'Authorization': "Bearer " + this.token
88
+ },
89
+ responseType: 'stream'
90
+ }).then((response) => {
91
+
92
+ return new Promise((resolve, reject) => {
93
+ response.data.pipe(writeStream);
94
+ let error = null;
95
+ writeStream.on('error', err => {
96
+ error = err;
97
+ writeStream.close();
98
+ console.log("[Tiledesk Whatsapp] Download failed!")
99
+ reject(err);
100
+ });
101
+ writeStream.on('close', () => {
102
+ if (!error) {
103
+ console.log("[Tiledesk Whatsapp] Download completed")
104
+ resolve('tmp/' + type);
105
+ }
106
+ })
107
+ })
108
+ }).catch((err) => {
109
+ console.log("axios err: ", err);
110
+ })
111
+ }).catch((err) => {
112
+ console.log("axios err: ", err);
113
+ })
114
+ }
115
+
116
+ async uploadMedia(path, type) {
117
+ let url = "https://tiledesk-server-pre.herokuapp.com/" + type + "/public";
118
+ console.log("[Tiledesk Whatsapp] Uploading file...");
119
+
120
+ const form = new FormData();
121
+ form.append('file', fs.createReadStream(path));
122
+ const request_config = {
123
+ maxContentLength: Infinity,
124
+ maxBodyLength: Infinity,
125
+ header: {
126
+ ...form.getHeaders()
127
+ }
128
+ }
129
+
130
+ return await axios.post(url, form, request_config).then((response) => {
131
+ if (log) {
132
+ console.log("[Tiledesk Whatsapp] upload response: ", response.data);
133
+ }
134
+
135
+ if (type == "images") {
136
+ let image_url = "https://tiledesk-server-pre.herokuapp.com/images/?path=" + response.data.filename;
137
+ return image_url;
138
+ } else {
139
+ let file_url = "https://tiledesk-server-pre.herokuapp.com/files/download?path=" + response.data.filename;
140
+ return file_url;
141
+ }
142
+
143
+ })
144
+ }
145
+
146
+
147
+ // HTTP REQUEST
148
+ static async myrequest(options, callback, log) {
149
+ if (log) {
150
+ console.log("API URL: ", options.url);
151
+ console.log("** Options: ", options);
152
+ }
153
+ return await axios({
154
+ url: options.url,
155
+ method: options.method,
156
+ data: options.json,
157
+ params: options.params,
158
+ headers: options.headers
159
+ }).then((res) => {
160
+ if (log) {
161
+ console.log("Response for url:", options.url);
162
+ console.log("Response headers:\n", res.headers);
163
+ }
164
+ if (res && res.status == 200 && res.data) {
165
+ if (callback) {
166
+ callback(null, res.data);
167
+ }
168
+ }
169
+ else {
170
+ if (callback) {
171
+ callback(TiledeskClient.getErr({message: "Response status not 200"}, options, res), null, null);
172
+ }
173
+ }
174
+ }).catch((err) => {
175
+ console.error("An error occured: ", err);
176
+ if (callback) {
177
+ callback(err, null, null);
178
+ }
179
+ })
180
+ }
181
+
182
+
183
+ // FUNCTIONS
184
+
185
+ getId() {
186
+ var newTime = Math.floor((new Date()).getTime() / 1000) - 1546300800;//seconds since 01/01/2019
187
+ return newTime.toString(36);
188
+ }
189
+
190
+ }
191
+
192
+ module.exports = { TiledeskWhatsapp };