From 49691710b9b94a25a8127c0cd8ac947dbafb59ea Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Sat, 14 Aug 2021 19:29:27 -0300 Subject: [PATCH] fix(basic.gblib): TOLIST fixed for empty values. --- package-lock.json | 7 +- package.json | 1 + .../basic.gblib/services/DialogKeywords.ts | 287 +++++++++++------- packages/basic.gblib/services/GBVMService.ts | 8 +- .../basic.gblib/services/SystemKeywords.ts | 10 +- 5 files changed, 186 insertions(+), 127 deletions(-) diff --git a/package-lock.json b/package-lock.json index 13efed0af..b4ccc64a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "botserver", - "version": "2.0.127", + "version": "2.0.129", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -7559,6 +7559,11 @@ "integrity": "sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A==", "dev": true }, + "date-diff": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/date-diff/-/date-diff-0.2.2.tgz", + "integrity": "sha512-D1Mq5j938ANAf4foPgAoh5Q45vkz5e5yEsi6TUeVvCcLs4KZMhy79hXHMc8zGh48bSb7iyiim2Vrpppi34/Rjw==" + }, "date-fns": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", diff --git a/package.json b/package.json index ba58d732d..054109bd6 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "botlib": "1.9.3", "cli-spinner": "0.2.10", "core-js": "3.14.0", + "date-diff": "^0.2.2", "dotenv-extended": "2.9.0", "exceljs": "4.2.1", "express": "4.17.1", diff --git a/packages/basic.gblib/services/DialogKeywords.ts b/packages/basic.gblib/services/DialogKeywords.ts index 9e970b5bb..68935ba30 100644 --- a/packages/basic.gblib/services/DialogKeywords.ts +++ b/packages/basic.gblib/services/DialogKeywords.ts @@ -39,6 +39,8 @@ import { GBServer } from '../../../src/app'; import { GBDeployer } from '../../core.gbapp/services/GBDeployer'; import { SecService } from '../../security.gbapp/services/SecService'; import { SystemKeywords } from './SystemKeywords'; +var DateDiff = require('date-diff'); + /** * Base services of conversation to be called by BASIC which @@ -155,26 +157,75 @@ export class DialogKeywords { } /** - * Returns specified list member separated by comma. + * Returns an object ready to get information about difference in several ways + * like years, months or days. * - * @example TALK TOLIST (array, member) + * @example days = DATEDIFF date1, date2 * */ - public getToLst(array, member) { - if (!array) { - return "" + public dateDiff(date1, date2) { + let dt1 = date1; + let dt2 = date2; + if (!(dt1 instanceof Date)) { + dt1 = new Date(dt1); } - if (array[0] && array[0]['gbarray']) { - array = array.slice(1); + if (!(dt2 instanceof Date)) { + dt2 = new Date(dt2); } - array = array.filter((v, i, a) => a.findIndex(t => (t[member] === v[member])) === i); - array = array.filter(function (item, pos) { return item != undefined; }); - array = array.map((item) => { return item[member]; }) - array = array.join(", "); + return new DateDiff(date1, date2); + } - return array; + /** + * Returns specified date week day in format 'Mon'. + * + * @example DATEADD date1, date2, mode, value + * + * https://stackoverflow.com/a/1214753/18511 + */ + public dateAdd(date, units, mode) { + let dateCopy = date; + if (!(dateCopy instanceof Date)) { + dateCopy = new Date(dateCopy); + } + var ret = new Date(dateCopy); //don't change original date + var checkRollover = function () { if (ret.getDate() != date.getDate()) ret.setDate(0); }; + switch (String(mode).toLowerCase()) { + case 'year': ret.setFullYear(ret.getFullYear() + units); checkRollover(); break; + case 'quarter': ret.setMonth(ret.getMonth() + 3 * units); checkRollover(); break; + case 'month': ret.setMonth(ret.getMonth() + units); checkRollover(); break; + case 'week': ret.setDate(ret.getDate() + 7 * units); break; + case 'day': ret.setDate(ret.getDate() + units); break; + case 'hour': ret.setTime(ret.getTime() + units * 3600000); break; + case 'minute': ret.setTime(ret.getTime() + units * 60000); break; + case 'second': ret.setTime(ret.getTime() + units * 1000); break; + default: ret = undefined; break; + } + return ret; } + + + /** + * Returns specified list member separated by comma. + * + * @example TALK TOLIST (array, member) + * + */ + public getToLst(array, member) { + if (!array) { + return "" + } + if (array[0] && array[0]['gbarray']) { + array = array.slice(1); + } + array = array.filter((v, i, a) => a.findIndex(t => (t[member] === v[member])) === i); + array = array.filter(function (item, pos) { return item != undefined; }); + array = array.map((item) => { return item[member]; }) + array = array.join(", "); + + return array; +} + /** * Returns the specified time in format hh:dd. * @@ -182,17 +233,17 @@ export class DialogKeywords { * */ public getHourFromDate(date) { - if (!(date instanceof Date)) { - date = new Date(date); - } - function addZero(i) { - if (i < 10) { - i = "0" + i; - } - return i; + if (!(date instanceof Date)) { + date = new Date(date); + } + function addZero(i) { + if (i < 10) { + i = "0" + i; } - return addZero(date.getHours()) + ':' + addZero(date.getMinutes()); + return i; } + return addZero(date.getHours()) + ':' + addZero(date.getMinutes()); +} /** * Returns current time in format hh:dd. @@ -201,20 +252,20 @@ export class DialogKeywords { * */ public async getNow() { - const contentLocale = this.min.core.getParam( - this.min.instance, - 'Default Content Language', - GBConfigService.get('DEFAULT_CONTENT_LANGUAGE') - ); - - const nowUTC = new Date(); - const now = new Date((typeof nowUTC === 'string' ? - new Date(nowUTC) : - nowUTC).toLocaleString(this.getContentLocaleWithCulture(contentLocale), - { timeZone: process.env.DEFAULT_TIMEZONE })); - - return now.getHours() + ':' + now.getMinutes(); - } + const contentLocale = this.min.core.getParam( + this.min.instance, + 'Default Content Language', + GBConfigService.get('DEFAULT_CONTENT_LANGUAGE') + ); + + const nowUTC = new Date(); + const now = new Date((typeof nowUTC === 'string' ? + new Date(nowUTC) : + nowUTC).toLocaleString(this.getContentLocaleWithCulture(contentLocale), + { timeZone: process.env.DEFAULT_TIMEZONE })); + + return now.getHours() + ':' + now.getMinutes(); +} /** * Sends a file to a given mobile. @@ -223,9 +274,9 @@ export class DialogKeywords { * */ public async sendFileTo(step, mobile, filename, caption) { - GBLog.info(`BASIC: SEND FILE TO '${mobile}', filename '${filename}'.`); - return await this.internalSendFile(null, mobile, filename, caption); - } + GBLog.info(`BASIC: SEND FILE TO '${mobile}', filename '${filename}'.`); + return await this.internalSendFile(null, mobile, filename, caption); +} /** * Sends a file to the current user. @@ -234,8 +285,8 @@ export class DialogKeywords { * */ public async sendFile(step, filename, caption) { - return await this.internalSendFile(step, null, filename, caption); - } + return await this.internalSendFile(step, null, filename, caption); +} /** * Defines the current language of the bot conversation. @@ -244,14 +295,14 @@ export class DialogKeywords { * */ public async setLanguage(step, language) { - const user = await this.min.userProfile.get(step.context, {}); + const user = await this.min.userProfile.get(step.context, {}); - const sec = new SecService(); - user.systemUser = await sec.updateUserLocale(user.systemUser.userId, language); + const sec = new SecService(); + user.systemUser = await sec.updateUserLocale(user.systemUser.userId, language); - await this.min.userProfile.set(step.context, user); - this.user = user; - } + await this.min.userProfile.set(step.context, user); + this.user = user; +} /** * Defines the maximum lines to scan in spreedsheets. @@ -260,11 +311,11 @@ export class DialogKeywords { * */ public async setMaxLines(step, count) { - const user = await this.min.userProfile.get(step.context, {}); - user.basicOptions.maxLines = count; - await this.min.userProfile.set(step.context, user); - this.user = user; - } + const user = await this.min.userProfile.get(step.context, {}); + user.basicOptions.maxLines = count; + await this.min.userProfile.set(step.context, user); + this.user = user; +} /** * Defines translator behaviour. @@ -273,25 +324,25 @@ export class DialogKeywords { * */ public async setTranslatorOn(step, on) { - const user = await this.min.userProfile.get(step.context, {}); - user.basicOptions.translatorOn = (on.trim() === "on"); - await this.min.userProfile.set(step.context, user); - this.user = user; - } + const user = await this.min.userProfile.get(step.context, {}); + user.basicOptions.translatorOn = (on.trim() === "on"); + await this.min.userProfile.set(step.context, user); + this.user = user; +} /** * Returns the name of the user acquired by WhatsApp API. */ public async userName(step) { - return step ? step.context.activity.from.name : 'N/A'; - } + return step ? step.context.activity.from.name : 'N/A'; +} /** * OBSOLETE. */ public async getFrom(step) { - return step ? await this.userMobile(step) : 'N/A'; - } + return step ? await this.userMobile(step) : 'N/A'; +} /** @@ -301,18 +352,18 @@ export class DialogKeywords { * */ public async userMobile(step) { - if (!step) { - return 'N/A'; - } - if (isNaN(step.context.activity['mobile'])) { - if (step.context.activity.from && !isNaN(step.context.activity.from.id)) { - return step.context.activity.from.id; - } - return 'No mobile available.'; - } else { - return step.context.activity['mobile']; + if (!step) { + return 'N/A'; + } + if (isNaN(step.context.activity['mobile'])) { + if (step.context.activity.from && !isNaN(step.context.activity.from.id)) { + return step.context.activity.from.id; } + return 'No mobile available.'; + } else { + return step.context.activity['mobile']; } +} /** * Shows the subject menu to the user @@ -321,8 +372,8 @@ export class DialogKeywords { * */ public async showMenu(step) { - return await step.beginDialog('/menu'); - } + return await step.beginDialog('/menu'); +} /** * Performs the transfer of the conversation to a human agent. @@ -331,8 +382,8 @@ export class DialogKeywords { * */ public async transfer(step) { - return await step.beginDialog('/t'); - } + return await step.beginDialog('/t'); +} /** * Hears something from user and put it in a variable @@ -341,66 +392,66 @@ export class DialogKeywords { * */ public async hear(step, promise, previousResolve, kind, ...args) { - function random(low, high) { - return Math.random() * (high - low) + low; - } - const idPromise = random(0, 120000000); - this.min.cbMap[idPromise] = {}; - this.min.cbMap[idPromise].promise = promise; - - const opts = { id: idPromise, previousResolve: previousResolve, kind: kind, args }; - if (previousResolve !== undefined) { - previousResolve(opts); - } else { - await step.beginDialog('/hear', opts); - } + function random(low, high) { + return Math.random() * (high - low) + low; } + const idPromise = random(0, 120000000); + this.min.cbMap[idPromise] = {}; + this.min.cbMap[idPromise].promise = promise; + + const opts = { id: idPromise, previousResolve: previousResolve, kind: kind, args }; + if (previousResolve !== undefined) { + previousResolve(opts); + } else { + await step.beginDialog('/hear', opts); + } +} /** * Talks to the user by using the specified text. */ public async talk(step, text: string) { - await this.min.conversationalService['sendTextWithOptions'](this.min, step, text, - this.user.basicOptions.translatorOn, null); - } + await this.min.conversationalService['sendTextWithOptions'](this.min, step, text, + this.user.basicOptions.translatorOn, null); +} private static getChannel(step): string { - if (!isNaN(step.context.activity['mobile'])) { - return 'webchat'; - } else { - if (step.context.activity.from && !isNaN(step.context.activity.from.id)) { - return 'whatsapp'; - } - return 'webchat'; + if (!isNaN(step.context.activity['mobile'])) { + return 'webchat'; + } else { + if (step.context.activity.from && !isNaN(step.context.activity.from.id)) { + return 'whatsapp'; } + return 'webchat'; } +} /** * Processes the sending of the file. */ private async internalSendFile(step, mobile, filename, caption) { - if (filename.indexOf('.md') > -1) { - GBLog.info(`BASIC: Sending the contents of ${filename} markdown to mobile ${mobile}.`); - const md = await this.min.kbService.getAnswerTextByMediaName(this.min.instance.instanceId, filename); - if (!md) { - GBLog.info(`BASIC: Markdown file ${filename} not found on database for ${this.min.instance.botId}.`); - } - - await this.min.conversationalService['playMarkdown'](this.min, md, - DialogKeywords.getChannel(step), step); - } else { - GBLog.info(`BASIC: Sending the file ${filename} to mobile ${mobile}.`); - const url = urlJoin( - GBServer.globals.publicAddress, - 'kb', - `${this.min.botId}.gbai`, - `${this.min.botId}.gbkb`, - 'assets', - filename - ); - - await this.min.conversationalService.sendFile(this.min, step, mobile, url, caption); + if (filename.indexOf('.md') > -1) { + GBLog.info(`BASIC: Sending the contents of ${filename} markdown to mobile ${mobile}.`); + const md = await this.min.kbService.getAnswerTextByMediaName(this.min.instance.instanceId, filename); + if (!md) { + GBLog.info(`BASIC: Markdown file ${filename} not found on database for ${this.min.instance.botId}.`); } + + await this.min.conversationalService['playMarkdown'](this.min, md, + DialogKeywords.getChannel(step), step); + } else { + GBLog.info(`BASIC: Sending the file ${filename} to mobile ${mobile}.`); + const url = urlJoin( + GBServer.globals.publicAddress, + 'kb', + `${this.min.botId}.gbai`, + `${this.min.botId}.gbkb`, + 'assets', + filename + ); + + await this.min.conversationalService.sendFile(this.min, step, mobile, url, caption); } } +} diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 608e3e0ae..49eb12a97 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -81,7 +81,7 @@ export class GBVMService extends GBService { const vbsFile = filename.substr(0, filename.indexOf('docx')) + 'vbs'; const fullVbsFile = urlJoin(folder, vbsFile); const docxStat = fs.statSync(urlJoin(folder, wordFile)); - const interval = 1000; // If compiled is older 30 seconds, then recompile. + const interval = 30000; // If compiled is older 30 seconds, then recompile. let writeVBS = true; if (fs.existsSync(fullVbsFile)) { const vbsStat = fs.statSync(fullVbsFile); @@ -96,7 +96,6 @@ export class GBVMService extends GBService { if (writeVBS) { let text = await this.getTextFromWord(folder, wordFile); - const schedule = GBVMService.getSetScheduleKeywordArgs(text); const s = new ScheduleServices(); if (schedule) { @@ -105,7 +104,6 @@ export class GBVMService extends GBService { else { await s.deleteScheduleIfAny(min, mainName); } - text = text.replace(/SET SCHEDULE (.*)/gi, ''); fs.writeFileSync(urlJoin(folder, vbsFile), text); } @@ -184,8 +182,8 @@ export class GBVMService extends GBService { from = mobile; ubound = function(array){return array.length}; isarray = function(array){return Array.isArray(array) }; - weekday = this.getWeekFromDate; - hour = this.getHourFromDate; + weekday = this.getWeekFromDate.bind(this); + hour = this.getHourFromDate.bind(this); tolist = this.getToLst; headers = {}; diff --git a/packages/basic.gblib/services/SystemKeywords.ts b/packages/basic.gblib/services/SystemKeywords.ts index 9f1f99f88..d6bb52abd 100644 --- a/packages/basic.gblib/services/SystemKeywords.ts +++ b/packages/basic.gblib/services/SystemKeywords.ts @@ -80,9 +80,8 @@ export class SystemKeywords { } public async sortBy(array, memberName) { - return array ? array.sort(p => - { if (p) { return p[memberName]; } }) : - null; + return array ? array.sort(p => { if (p) { return p[memberName]; } }) : + null; } /** @@ -351,6 +350,7 @@ export class SystemKeywords { } function isValidNumber(number) { + if (number === '') { return false } return !isNaN(number); } @@ -456,6 +456,10 @@ export class SystemKeywords { case 'date': const resultDate = new Date(result); switch (filter.operator) { + case '=': + if (resultDate.getTime() == filter.value.getTime()) + filterAcceptCount++; + break; case '<': if (resultDate.getTime() < filter.value.getTime()) filterAcceptCount++;