1 | const AWSLambdaCaller = require('./services/AWSLambdaCaller');
|
2 | const accounting = require('accounting');
|
3 | const fallbackIntents = require('./util/fallbackIntent');
|
4 | const _ = require('lodash');
|
5 | const request = require('request');
|
6 |
|
7 | const str = [
|
8 | 'oi',
|
9 | 'oi',
|
10 | 'ola',
|
11 | 'bom dia',
|
12 | 'boa tarde',
|
13 | 'boa noite',
|
14 | 'como vai',
|
15 | 'ei',
|
16 | 'oii',
|
17 | 'oiii',
|
18 | 'oiiii',
|
19 | 'oiiiii',
|
20 | 'oiiiiii',
|
21 | 'oiiiiiii',
|
22 | 'ooi',
|
23 | 'oooi',
|
24 | 'oooii',
|
25 | 'ooooii',
|
26 | 'ooooiii',
|
27 | 'oola',
|
28 | 'olaa',
|
29 | 'olaaa',
|
30 | 'hola',
|
31 | 'holaa',
|
32 | 'heloo',
|
33 | 'hello',
|
34 | 'helooo',
|
35 | 'hellooo',
|
36 | 'booa',
|
37 | 'boaa',
|
38 | 'tudo bem',
|
39 | 'tudo bem',
|
40 | 'como vai',
|
41 | 'tudo certo',
|
42 | 'obrigado',
|
43 | 'certo',
|
44 | 'entendi',
|
45 | 'entendi mas',
|
46 | 'certo mas',
|
47 | 'olá!',
|
48 | 'ola!',
|
49 | ];
|
50 |
|
51 | class Util {
|
52 | static isPhrase(phrase) {
|
53 | return phrase.split(' ').length >= 3;
|
54 | }
|
55 |
|
56 | static wordInString(s, words, replacement) {
|
57 | s = Util.removeDotsAndComma(s);
|
58 |
|
59 | const re = new RegExp('(\\s|^)(?:' + words.join('|') + ')(?=\\s|$)');
|
60 | return s.replace(re, replacement);
|
61 | }
|
62 |
|
63 | static removeDotsAndComma(phrase) {
|
64 | const regex = /[.,]/g;
|
65 | return phrase.replace(regex, '');
|
66 | }
|
67 |
|
68 | static replaceIfIsPhrase(phrase) {
|
69 | phrase = phrase.toLowerCase();
|
70 | phrase = phrase.trim();
|
71 | return Util.isPhrase(phrase) ? Util.wordInString(phrase, str, '').trim() : phrase;
|
72 | }
|
73 |
|
74 | static capitalizeFirstLetter(string) {
|
75 | return string.charAt(0).toUpperCase() + string.slice(1);
|
76 | }
|
77 |
|
78 | static dateDiffInDays(a, b) {
|
79 | const _MS_PER_DAY = 1000 * 60 * 60 * 24;
|
80 |
|
81 | const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
|
82 | const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
|
83 |
|
84 | return Math.floor((utc2 - utc1) / _MS_PER_DAY);
|
85 | }
|
86 |
|
87 | static toReal(numero) {
|
88 | let num = numero;
|
89 |
|
90 | if (typeof numero === 'string') {
|
91 | num = Number.parseFloat(numero);
|
92 | }
|
93 |
|
94 | return accounting.formatMoney(num, 'R$ ', 2, '.', ',');
|
95 | }
|
96 |
|
97 | static letterCount(str) {
|
98 | let i = 0,
|
99 | seq = 0;
|
100 | const results = [];
|
101 |
|
102 | while (i < str.length) {
|
103 | const current = str[i],
|
104 | next = str[i + 1];
|
105 |
|
106 | if (typeof results[seq] === 'undefined') {
|
107 | results[seq] = [current, 0];
|
108 | }
|
109 |
|
110 | results[seq][1]++;
|
111 |
|
112 | if (current !== next) {
|
113 | seq++;
|
114 | }
|
115 |
|
116 | i++;
|
117 | }
|
118 |
|
119 | return results;
|
120 | }
|
121 |
|
122 | static isNumeric(n) {
|
123 | return !isNaN(parseFloat(n)) && isFinite(n);
|
124 | }
|
125 |
|
126 | static existsletterCount(str, letterMaxCount = 3) {
|
127 | let value = false;
|
128 |
|
129 | if (str != null) {
|
130 | const letterCount = Util.letterCount(str);
|
131 | if (letterCount && letterCount.length > 0) {
|
132 | const find = letterCount.find(item => {
|
133 | return item[1] >= letterMaxCount;
|
134 | });
|
135 |
|
136 | value = find != null;
|
137 | }
|
138 | }
|
139 | return value;
|
140 | }
|
141 |
|
142 | static isNaoentendi(intent) {
|
143 | const namesFallbackIntents = _.chain(fallbackIntents)
|
144 | .values()
|
145 | .map('intent')
|
146 | .value();
|
147 | if (intent && namesFallbackIntents.indexOf(intent) > -1) {
|
148 | return true;
|
149 | }
|
150 | return false;
|
151 | }
|
152 |
|
153 | static getPriceAsFloat(string) {
|
154 | try {
|
155 | const numberString = string.match(/(?:[\d\.,])+/)[0];
|
156 |
|
157 | const dot = numberString.length - numberString.lastIndexOf('.') - 1;
|
158 | const comma = numberString.length - numberString.lastIndexOf(',') - 1;
|
159 | const decimal = dot < comma ? dot : comma;
|
160 |
|
161 | let number = numberString.replace(/\D/g, '');
|
162 | number = Number(number) / Math.pow(10, decimal);
|
163 |
|
164 | return number;
|
165 | } catch (e) {
|
166 | return null;
|
167 | }
|
168 | }
|
169 |
|
170 | static getPriceExtremes(results) {
|
171 | if (!Array.isArray(results) || !results.length) {
|
172 | return { minimumPrice: null, maximumPrice: null };
|
173 | }
|
174 |
|
175 | const sortedPrices = _.chain(results)
|
176 | .map(e => Util.getPriceAsFloat(e.price))
|
177 | .sortBy()
|
178 | .value();
|
179 |
|
180 | return {
|
181 | minimumPrice: _.head(sortedPrices),
|
182 | maximumPrice: _.last(sortedPrices),
|
183 | };
|
184 | }
|
185 |
|
186 | static getDateAndTimeFromDateISO(dateISO) {
|
187 | if (dateISO && dateISO.length >= 10) {
|
188 | const [date, time] = dateISO.split('T');
|
189 | const timeOrNull = time ? time.split('.')[0] : null;
|
190 |
|
191 | return [date, timeOrNull];
|
192 | } else {
|
193 | return [null, null];
|
194 | }
|
195 | }
|
196 |
|
197 | static appendTimeISOStringToDate(
|
198 | date,
|
199 | hour = '00',
|
200 | minutes = '00',
|
201 | seconds = '00',
|
202 | milliseconds = '000',
|
203 | ) {
|
204 | return date ? `${date}T${hour}:${minutes}:${seconds}.${milliseconds}` : null;
|
205 | }
|
206 |
|
207 | |
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 | static fallbackCacheFactory(cache) {
|
221 | return f => x =>
|
222 | f(x)
|
223 | .then(
|
224 | result => new Promise(resolve => cache.set(x, _.cloneDeep(result)) && resolve(result)),
|
225 | )
|
226 | .catch(
|
227 | err =>
|
228 | new Promise(
|
229 | (resolve, reject) =>
|
230 | (cache.has(x) && resolve(_.cloneDeep(cache.get(x)))) || reject(err),
|
231 | ),
|
232 | );
|
233 | }
|
234 |
|
235 | static wrapperSaveRequestOnQueue(config) {
|
236 | const addCreatedAtAndUpdatedAtOnUrl = url => {
|
237 | url += /\?|&/.test(url) ? '&' : '?';
|
238 | const date = new Date().getTime();
|
239 | url += `createdAt=${date}&updatedAt=${date}`;
|
240 | return url;
|
241 | };
|
242 |
|
243 | const isErrorToSaveOnQueue = ({ error, response }) => {
|
244 | if (error) {
|
245 | return ['ENOTFOUND', 'ECONNREFUSED', 'ESOCKETTIMEDOUT'].includes(error.code);
|
246 | }
|
247 |
|
248 | if (response) {
|
249 | return [404].includes(response.statusCode);
|
250 | }
|
251 | };
|
252 |
|
253 | const awsLambdaCaller = new AWSLambdaCaller(config.CORE_LAMBDA_AWS);
|
254 |
|
255 | return (wrapped, requestInfo) => {
|
256 | return wrapped(requestInfo).catch(async error => {
|
257 | if (!isErrorToSaveOnQueue(error)) {
|
258 | return Promise.reject(error);
|
259 | }
|
260 |
|
261 | if (process.env.NODE_ENV === 'dev') {
|
262 | console.log('not send request to lambda');
|
263 | return Promise.reject(error);
|
264 | }
|
265 |
|
266 | console.log('sending request to lambda control-requests');
|
267 |
|
268 | const clonnedRequestInfo = _.cloneDeep(requestInfo);
|
269 |
|
270 | clonnedRequestInfo.request.url = addCreatedAtAndUpdatedAtOnUrl(
|
271 | clonnedRequestInfo.request.url,
|
272 | );
|
273 |
|
274 | await awsLambdaCaller.call(
|
275 | clonnedRequestInfo,
|
276 | 'asksuite-lambda-sqs-dev-control-requests-insert',
|
277 | );
|
278 | return Promise.reject(error);
|
279 | });
|
280 | };
|
281 | }
|
282 |
|
283 | static executeRequestAndSaveOnError(requestInfo, config) {
|
284 | return Util.wrapperSaveRequestOnQueue(config)(() => {
|
285 | return new Promise((resolve, reject) => {
|
286 | request(requestInfo.request, function(err, _resp, _body) {
|
287 | if (err || _resp.statusCode >= 400) {
|
288 | reject({ error: err, response: _resp });
|
289 | } else {
|
290 | resolve(_body);
|
291 | }
|
292 | });
|
293 | });
|
294 | }, requestInfo);
|
295 | }
|
296 | }
|
297 |
|
298 | module.exports = Util;
|