diff --git a/CHANGELOG.md b/CHANGELOG.md index e2fd346c..6cc4f7ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -227,7 +227,7 @@ ### Features * **core.gbapp:** Development options added (ngrok) ([223801d](https://github.com/pragmatismo-io/BotServer/commit/223801d)) -* **security.gblib:** Phone field and conversation refeerence. ([46261d7](https://github.com/pragmatismo-io/BotServer/commit/46261d7)) +* **security.gbapp:** Phone field and conversation refeerence. ([46261d7](https://github.com/pragmatismo-io/BotServer/commit/46261d7)) ## [1.3.10](https://github.com/pragmatismo-io/BotServer/compare/1.3.9...1.3.10) (2019-06-21) diff --git a/package-lock.json b/package-lock.json index 9ca07dc1..be7ade89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "botserver", - "version": "1.7.6", + "version": "2.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4349,9 +4349,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.27.tgz", - "integrity": "sha512-J0oqm9ZfAXaPdwNXMMgAhylw5fhmXkToJd06vuDUSAgEDZ/n/69/69UmyBZbc+zT34UnShuDSBqvim3SPnozJg==" + "version": "10.17.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.28.tgz", + "integrity": "sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ==" } } }, @@ -4473,9 +4473,9 @@ } }, "botlib": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/botlib/-/botlib-1.5.9.tgz", - "integrity": "sha512-pvUdntYLTMtiLnmP+skZDf7Cxf5D0NIiOzdsDwx4QIXjBmP0BwuaLWD3X4JaPcRrzqrJE0PAy+wZuoxupSMZLA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/botlib/-/botlib-1.6.2.tgz", + "integrity": "sha512-t3aDi+OK6KsKCpXt1HzzPrMqPM7TcNIB3xzOWZVv/qgPE92qCmXosbgcm1zsTEoVN39lhEEQNyQ5esk5O4c4iQ==", "requires": { "async": "3.1.0", "botbuilder": "4.7.0", @@ -4509,14 +4509,6 @@ "which": "^2.0.1" } }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, "dotenv-extended": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/dotenv-extended/-/dotenv-extended-2.7.1.tgz", @@ -4542,33 +4534,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "sequelize": { - "version": "5.21.5", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.5.tgz", - "integrity": "sha512-n9hR5K4uQGmBGK/Y/iqewCeSFmKVsd0TRnh0tfoLoAkmXbKC4tpeK96RhKs7d+TTMtrJlgt2TNLVBaAxEwC4iw==", - "requires": { - "bluebird": "^3.5.0", - "cls-bluebird": "^2.1.0", - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.24.0", - "moment-timezone": "^0.5.21", - "retry-as-promised": "^3.2.0", - "semver": "^6.3.0", - "sequelize-pool": "^2.3.0", - "toposort-class": "^1.0.1", - "uuid": "^3.3.3", - "validator": "^10.11.0", - "wkx": "^0.4.8" - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4587,11 +4552,6 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" }, - "validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index a322ece3..7aa148b6 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "botbuilder-ai": "4.7.0", "botbuilder-dialogs": "4.7.0", "botframework-connector": "4.7.0", - "botlib": "1.5.9", + "botlib": "1.6.2", "cli-spinner": "0.2.10", "core-js": "^3.6.5", "dotenv-extended": "2.8.0", diff --git a/packages/admin.gbapp/services/GBAdminService.ts b/packages/admin.gbapp/services/GBAdminService.ts index 95da7426..ecd5eedf 100644 --- a/packages/admin.gbapp/services/GBAdminService.ts +++ b/packages/admin.gbapp/services/GBAdminService.ts @@ -86,6 +86,21 @@ export class GBAdminService implements IGBAdminService { public static async getADALCredentialsFromUsername(username: string, password: string) { return await msRestAzure.loginWithUsernamePassword(username, password); } + + public static getMobileCode() { + const passwordGenerator = new PasswordGenerator(); + const options = { + upperCaseAlpha: false, + lowerCaseAlpha: false, + number: true, + specialCharacter: false, + minimumLength: 6, + maximumLength: 6 + }; + + return passwordGenerator.generatePassword(options); + } + public static getRndPassword(): string { const passwordGenerator = new PasswordGenerator(); diff --git a/packages/analytics.gblib/models/index.ts b/packages/analytics.gblib/models/index.ts index 7b9a562a..29082944 100644 --- a/packages/analytics.gblib/models/index.ts +++ b/packages/analytics.gblib/models/index.ts @@ -56,7 +56,7 @@ import { import { GuaribasChannel, GuaribasInstance } from '../../core.gbapp/models/GBModel'; import { GuaribasSubject } from '../../kb.gbapp/models'; -import { GuaribasUser } from '../../security.gblib/models'; +import { GuaribasUser } from '../../security.gbapp/models'; /** diff --git a/packages/analytics.gblib/services/AnalyticsService.ts b/packages/analytics.gblib/services/AnalyticsService.ts index e9c1fe4f..80f1eaed 100644 --- a/packages/analytics.gblib/services/AnalyticsService.ts +++ b/packages/analytics.gblib/services/AnalyticsService.ts @@ -34,7 +34,7 @@ * @fileoverview General Bots server core. */ -import { GuaribasUser } from '../../security.gblib/models'; +import { GuaribasUser } from '../../security.gbapp/models'; import { GuaribasConversation, GuaribasConversationMessage } from '../models'; /** diff --git a/packages/core.gbapp/dialogs/SwitchBot.ts b/packages/core.gbapp/dialogs/SwitchBot.ts index 620826f5..f463e63d 100644 --- a/packages/core.gbapp/dialogs/SwitchBot.ts +++ b/packages/core.gbapp/dialogs/SwitchBot.ts @@ -40,7 +40,7 @@ import { BotAdapter } from 'botbuilder'; import { WaterfallDialog } from 'botbuilder-dialogs'; import { GBMinInstance, IGBDialog } from 'botlib'; import { Messages } from '../strings'; -import { SecService } from '../../security.gblib/services/SecService'; +import { SecService } from '../../security.gbapp/services/SecService'; import { GBServer } from '../../../src/app'; import { GBConversationalService } from '../services/GBConversationalService'; /** diff --git a/packages/core.gbapp/services/GBConversationalService.ts b/packages/core.gbapp/services/GBConversationalService.ts index aa428def..b9b0c320 100644 --- a/packages/core.gbapp/services/GBConversationalService.ts +++ b/packages/core.gbapp/services/GBConversationalService.ts @@ -42,7 +42,7 @@ import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService } from 'botlib'; import { GBServer } from '../../../src/app'; import { Readable } from 'stream' import { GBAdminService } from '../../admin.gbapp/services/GBAdminService'; -import { SecService } from '../../security.gblib/services/SecService'; +import { SecService } from '../../security.gbapp/services/SecService'; import { AnalyticsService } from '../../analytics.gblib/services/AnalyticsService'; const urlJoin = require('url-join'); const PasswordGenerator = require("strict-password-generator").default; diff --git a/packages/core.gbapp/services/GBCoreService.ts b/packages/core.gbapp/services/GBCoreService.ts index 2cf74d58..6fa23b81 100644 --- a/packages/core.gbapp/services/GBCoreService.ts +++ b/packages/core.gbapp/services/GBCoreService.ts @@ -48,7 +48,7 @@ import { StartDialog } from '../../azuredeployer.gbapp/dialogs/StartDialog'; import { GBCorePackage } from '../../core.gbapp'; import { GBCustomerSatisfactionPackage } from '../../customer-satisfaction.gbapp'; import { GBKBPackage } from '../../kb.gbapp'; -import { GBSecurityPackage } from '../../security.gblib'; +import { GBSecurityPackage } from '../../security.gbapp'; import { GBWhatsappPackage } from '../../whatsapp.gblib/index'; import { GuaribasInstance } from '../models/GBModel'; import { GBConfigService } from './GBConfigService'; @@ -211,16 +211,18 @@ export class GBCoreService implements IGBCoreService { */ public async loadInstances(): Promise { if (process.env.LOAD_ONLY !== undefined) { - + const bots = process.env.LOAD_ONLY.split(`;`); const and = []; await CollectionUtil.asyncForEach(bots, async e => { - and.push({botId: e}); + and.push({ botId: e }); }); - - const options = {where: { - [Op.or]: and - }}; + + const options = { + where: { + [Op.or]: and + } + }; return GuaribasInstance.findAll(options); } else { @@ -593,7 +595,7 @@ STORAGE_SYNC=true * @param name Name of param to get from instance. * @param defaultValue Value returned when no param is defined in Config.xlsx. */ - public getParam(instance:IGBInstance, name: string, defaultValue?: T): any { + public getParam(instance: IGBInstance, name: string, defaultValue?: T): any { let value = null; if (instance.params) { const params = JSON.parse(instance.params); @@ -608,5 +610,12 @@ STORAGE_SYNC=true if (typeof (defaultValue) === "number") { return new Number(value ? defaultValue : (defaultValue ? defaultValue : 0)); } + value = instance['dataValues'][name]; + if (value === null) { + const minBoot = GBServer.globals.minBoot as any; + value = minBoot.instance.datavalues[name]; + } + + return value; } } diff --git a/packages/core.gbapp/services/GBDeployer.ts b/packages/core.gbapp/services/GBDeployer.ts index a389ce78..1aaa78dc 100644 --- a/packages/core.gbapp/services/GBDeployer.ts +++ b/packages/core.gbapp/services/GBDeployer.ts @@ -575,7 +575,7 @@ export class GBDeployer implements IGBDeployer { } private isSystemPackage(name: string): Boolean { - const names = ['analytics.gblib', 'console.gblib', 'security.gblib', 'whatsapp.gblib', 'sharepoint.gblib', 'core.gbapp', 'admin.gbapp', 'azuredeployer.gbapp', 'customer-satisfaction.gbapp', 'kb.gbapp']; + const names = ['analytics.gblib', 'console.gblib', 'security.gbapp', 'whatsapp.gblib', 'sharepoint.gblib', 'core.gbapp', 'admin.gbapp', 'azuredeployer.gbapp', 'customer-satisfaction.gbapp', 'kb.gbapp']; return names.indexOf(name) > -1; } diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index 7bfeff5e..4cf808c4 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -64,7 +64,7 @@ import { KBService } from '../../kb.gbapp/services/KBService'; import { Messages } from '../strings'; import { GBConfigService } from './GBConfigService'; import { GBDeployer } from './GBDeployer'; -import { SecService } from '../../security.gblib/services/SecService'; +import { SecService } from '../../security.gbapp/services/SecService'; import { AnalyticsService } from '../../analytics.gblib/services/AnalyticsService'; import { WhatsappDirectLine } from '../../whatsapp.gblib/services/WhatsappDirectLine'; import fs = require('fs'); @@ -469,6 +469,17 @@ export class GBMinService { min.packages = sysPackages; min.appPackages = appPackages; + // Create a hub of services available in .gbapps. + + let handled = false; + await CollectionUtil.asyncForEach(min.appPackages, async (e: IGBPackage) => { + let services: ConcatArray; + if (services = await e.onExchangeData(min, "getServices", null)) { + min.gbappServices.concat(services); + } + }); + + if (min.instance.whatsappServiceKey !== null) { min.whatsAppDirectLine = new WhatsappDirectLine( min, @@ -517,7 +528,7 @@ export class GBMinService { await p.loadBot(min); if (p.getDialogs !== undefined) { const dialogs = await p.getDialogs(min); - if (dialogs!== undefined){ + if (dialogs !== undefined) { dialogs.forEach(dialog => { min.dialogs.add(new WaterfallDialog(dialog.id, dialog.waterfall)); }); @@ -708,8 +719,8 @@ export class GBMinService { let locale = 'pt'; - if (process.env.TRANSLATOR_DISABLED !== "true" || - min.core.getParam (min.instance,'Enable Worldwide Translator') ) { + if (process.env.TRANSLATOR_DISABLED !== "true" || + min.core.getParam(min.instance, 'Enable Worldwide Translator')) { const minBoot = GBServer.globals.minBoot as any; // TODO: Switch keys automatically to master/per bot. locale = await AzureText.getLocale(minBoot.instance.textAnalyticsKey ? minBoot.instance.textAnalyticsKey : minBoot.instance.textAnalyticsKey, @@ -737,17 +748,19 @@ export class GBMinService { let handled = false; await CollectionUtil.asyncForEach(min.appPackages, async (e: IGBPackage) => { - if (await e.onExchangeData(min, "handleAnswer", { query: query, step: step, + if (await e.onExchangeData(min, "handleAnswer", { + query: query, step: step, notTranslatedQuery: notTranslatedQuery, - message: message, - user })) { + message: message['dataValues'], + user: user['dataValues'] + })) { handled = true; } }); if (!handled) { await step.beginDialog('/answer', { - query: query + query: query, message: message }); } } diff --git a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts index cd7aa57f..d17600a1 100644 --- a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts +++ b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts @@ -42,7 +42,7 @@ import { GBMinInstance, IGBDialog } from 'botlib'; import { AzureText } from 'pragmatismo-io-framework'; import { CSService } from '../services/CSService'; import { Messages } from '../strings'; -import { SecService } from '../../security.gblib/services/SecService'; +import { SecService } from '../../security.gbapp/services/SecService'; import { GBServer } from '../../../src/app'; /** diff --git a/packages/kb.gbapp/dialogs/AskDialog.ts b/packages/kb.gbapp/dialogs/AskDialog.ts index 14213e93..11af8fcb 100644 --- a/packages/kb.gbapp/dialogs/AskDialog.ts +++ b/packages/kb.gbapp/dialogs/AskDialog.ts @@ -39,13 +39,13 @@ import { GBServer } from '../../../src/app'; import { BotAdapter } from 'botbuilder'; import { WaterfallDialog } from 'botbuilder-dialogs'; -import { GBLog, GBMinInstance, IGBDialog } from 'botlib'; -import { AzureText } from 'pragmatismo-io-framework'; +import { GBLog, GBMinInstance, IGBDialog, IGBPackage } from 'botlib'; import { Messages } from '../strings'; import { KBService } from './../services/KBService'; import { GuaribasAnswer } from '../models'; import { GBMinService } from '../../../packages/core.gbapp/services/GBMinService'; -import { SecService } from '../../security.gblib/services/SecService'; +import { SecService } from '../../security.gbapp/services/SecService'; +import { CollectionUtil, AzureText } from 'pragmatismo-io-framework'; /** * Dialog arguments. @@ -103,7 +103,7 @@ export class AskDialog extends IGBDialog { const translatorEnabled = () => { if (min.instance.params) { const params = JSON.parse(min.instance.params); - return params?params['Enable Worldwide Translator'] === "TRUE": false; + return params ? params['Enable Worldwide Translator'] === "TRUE" : false; } return false; } // TODO: Encapsulate. @@ -126,14 +126,35 @@ export class AskDialog extends IGBDialog { member.name, "", "web", member.name); user.locale = locale; await user.save(); - - query = await min.conversationalService.translate(min, + const notTranslatedQuery = query; + query = await min.conversationalService.translate(min, min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey, min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint, query, 'pt'); GBLog.info(`Translated text: ${query}.`) - return await step.replaceDialog('/answer', { query: query }); + + let handled = false; + await CollectionUtil.asyncForEach(min.appPackages, async (e: IGBPackage) => { + if (await e.onExchangeData(min, "handleAnswer", { + query: query, step: step, + notTranslatedQuery: notTranslatedQuery, + message: query, + user: user['dataValues'] + })) { + handled = true; + } + }); + + if (!handled) { + return await step.beginDialog('/answer', { + query: query + }); + } else { + return await step.next(); + } + + } else { return await step.next(); } @@ -152,7 +173,7 @@ export class AskDialog extends IGBDialog { const userDb = await sec.ensureUser(min.instance.instanceId, member.id, member.name, "", "web", member.name); const minBoot = GBServer.globals.minBoot as any; - text = await min.conversationalService.translate(min, + text = await min.conversationalService.translate(min, min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey, min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint, text, @@ -209,7 +230,7 @@ export class AskDialog extends IGBDialog { user2.isAsking = false; user2.lastQuestionId = resultsB.questionId; await min.userProfile.set(step.context, user2); - + // Informs user that a broader search will be used. if (user2.subjects.length > 0) { await min.conversationalService.sendText(min, step, Messages[locale].wider_answer); diff --git a/packages/kb.gbapp/models/index.ts b/packages/kb.gbapp/models/index.ts index 952dadd2..58bf73ed 100644 --- a/packages/kb.gbapp/models/index.ts +++ b/packages/kb.gbapp/models/index.ts @@ -58,7 +58,7 @@ import { GuaribasInstance, GuaribasPackage } from '../../core.gbapp/models/GBModel'; -import { GuaribasUser } from '../../security.gblib/models'; +import { GuaribasUser } from '../../security.gbapp/models'; /** * Subjects to group the pair of questions and answers. diff --git a/packages/kb.gbapp/services/KBService.ts b/packages/kb.gbapp/services/KBService.ts index 74576541..be5f3281 100644 --- a/packages/kb.gbapp/services/KBService.ts +++ b/packages/kb.gbapp/services/KBService.ts @@ -55,7 +55,7 @@ import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from '../models'; import { Messages } from '../strings'; import { GBConfigService } from './../../core.gbapp/services/GBConfigService'; import { CSService } from '../../customer-satisfaction.gbapp/services/CSService'; -import { SecService } from '../../security.gblib/services/SecService'; +import { SecService } from '../../security.gbapp/services/SecService'; import { CollectionUtil } from 'pragmatismo-io-framework'; /** diff --git a/packages/security.gbapp/dialogs/ProfileDialog.ts b/packages/security.gbapp/dialogs/ProfileDialog.ts new file mode 100644 index 00000000..623132a0 --- /dev/null +++ b/packages/security.gbapp/dialogs/ProfileDialog.ts @@ -0,0 +1,183 @@ +/*****************************************************************************\ +| ( )_ _ | +| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | +| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | +| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) | +| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | +| | | ( )_) | | +| (_) \___/' | +| | +| General Bots Copyright (c) Pragmatismo.io. All rights reserved. | +| Licensed under the AGPL-3.0. | +| | +| According to our dual licensing model, this program can be used either | +| under the terms of the GNU Affero General Public License, version 3, | +| or under a proprietary license. | +| | +| The texts of the GNU Affero General Public License with an additional | +| permission and of our proprietary license can be found at and | +| in the LICENSE file you have received along with this program. | +| | +| This program is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY, without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | +| GNU Affero General Public License for more details. | +| | +| "General Bots" is a registered trademark of Pragmatismo.io. | +| The licensing of the program under the AGPLv3 does not imply a | +| trademark license. Therefore any rights, title and interest in | +| our trademarks remain entirely with us. | +| | +\*****************************************************************************/ + +/** + * @fileoverview Main dialog for kb.gbapp + */ + +'use strict'; + +import urlJoin = require('url-join'); + +import { BotAdapter, CardFactory, MessageFactory } from 'botbuilder'; +import { WaterfallDialog } from 'botbuilder-dialogs'; +import { GBMinInstance, IGBDialog, GBLog } from 'botlib'; +import { Messages } from '../strings'; +import { GBConversationalService } from '../../core.gbapp/services/GBConversationalService'; +import { GBAdminService } from '../../admin.gbapp/services/GBAdminService'; +const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance(); +const phone = require('phone'); + +/** + * Dialogs for handling Menu control. + */ +export class ProfileDialog extends IGBDialog { + + static getNameDialog(min: GBMinInstance) { + + return { + id: '/welcome_saas_name', waterfall: [ + async step => { + const locale = step.context.activity.locale; + await step.prompt("textPrompt", Messages[locale].whats_name); + }, + async step => { + const locale = step.context.activity.locale; + + const fullName = (text) => { + return text.match(/^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$/gi); + } + + const value = fullName(step.result); + + if (value === null) { + await step.context.sendActivity(Messages[locale].validation_enter_name); + await step.replaceDialog('/welcome_saas_name', step.activeDialog.state.options); + } + else { + step.activeDialog.state.options.name = value[0]; + + return await step.replaceDialog('/welcome_saas_mobile', step.activeDialog.state.options); + + } + }] + } + } + + + static getMobileDialog(min: GBMinInstance) { + + return { + id: '/store_mobile', waterfall: [ + async step => { + + + const locale = step.context.activity.locale; + await step.prompt("textPrompt", Messages[locale].whats_mobile); + }, + async step => { + const locale = step.context.activity.locale; + let phoneNumber; + try { + phoneNumber = phone(step.result, 'BRA')[0]; // TODO: Use accordingly to the person. + phoneNumber = phoneUtil.parse(phoneNumber); + } catch (error) { + await step.context.sendActivity(Messages[locale].validation_enter_valid_mobile); + + return await step.replaceDialog('/store_mobile', step.activeDialog.state.options); + } + if (!phoneUtil.isPossibleNumber(phoneNumber)) { + await step.context.sendActivity(Messages[locale].validation_enter_valid_mobile); + + return await step.replaceDialog('/store_mobile', step.activeDialog.state.options); + } + else { + step.activeDialog.state.options.mobile = `${phoneNumber.values_['1']}${phoneNumber.values_['2']}`; + step.activeDialog.state.options.mobileCode = GBAdminService.getMobileCode(); + + return await step.replaceDialog('/store_mobile_confirm', step.activeDialog.state.options); + } + }] + } + } + + static getMobileConfirmDialog(min: GBMinInstance) { + + return { + id: '/store_mobile_confirm', waterfall: [ + async step => { + const locale = step.context.activity.locale; + let from = step.activeDialog.state.options.mobile; + if (min.whatsAppDirectLine) { + + await min.whatsAppDirectLine.sendToDevice(from, `${step.activeDialog.state.options.mobileCode} is your General Bots creation code.`); + } else { + GBLog.info(`WhatsApp not configured. Here is the code: ${step.activeDialog.state.options.mobileCode}.`); + } + + await step.prompt("textPrompt", Messages[locale].confirm_mobile); + }, + async step => { + const locale = step.context.activity.locale; + + if (step.result !== step.activeDialog.state.options.mobileCode) { + await step.context.sendActivity(Messages[locale].confirm_mobile_again); + + return await step.replaceDialog('/store_mobile_confirm', step.activeDialog.state.options); + } + else { + await step.replaceDialog('/store_botxxxxxxxxxxxxxxxxxxxxxxxxxx', step.activeDialog.state.options); + } + }] + } + } + + + static getEmailDialog(min: GBMinInstance) { + return { + id: '/store_email', waterfall: [ + async step => { + const locale = step.context.activity.locale; + await step.prompt("textPrompt", Messages[locale].whats_email); + }, + async step => { + const locale = step.context.activity.locale; + + const extractEntity = (text) => { + return text.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)/gi); + } + + const value = extractEntity(step.result); + + if (value === null) { + await step.context.sendActivity(Messages[locale].validation_enter_valid_email); + await step.replaceDialog('/store_email', step.activeDialog.state.options); + } + else { + step.activeDialog.state.options.email = value[0]; + + + } + }] + } + } +} diff --git a/packages/security.gbapp/index.ts b/packages/security.gbapp/index.ts index 3ec44838..15609d57 100644 --- a/packages/security.gbapp/index.ts +++ b/packages/security.gbapp/index.ts @@ -39,7 +39,7 @@ import urlJoin = require('url-join'); import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib'; - +import {ProfileDialog} from './dialogs/ProfileDialog' import { Sequelize } from 'sequelize-typescript'; import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from './models'; @@ -49,6 +49,12 @@ import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from './models'; export class GBSecurityPackage implements IGBPackage { public sysPackages: IGBPackage[]; public async getDialogs(min: GBMinInstance) { + return [ + ProfileDialog.getNameDialog(min), + ProfileDialog.getEmailDialog(min), + ProfileDialog.getMobileDialog(min), + ProfileDialog.getMobileConfirmDialog(min), + ]; GBLog.verbose(`getDialogs called.`); } public async unloadPackage(core: IGBCoreService): Promise { diff --git a/packages/security.gbapp/strings.ts b/packages/security.gbapp/strings.ts new file mode 100644 index 00000000..0248d62f --- /dev/null +++ b/packages/security.gbapp/strings.ts @@ -0,0 +1,35 @@ +export const Messages = { + 'en-US': { + did_not_find: 'I\'m sorry I didn\'t find anything.', + going_answer: 'Great choice, now looking for your answer...', + wider_answer: subjectText => + `Answering to you in a broader way... Not just about ${subjectText}.`, + which_question: 'What\'s your question?', + anything_else: 'So, may I help with anything else?', + here_is_subjects: 'Here are some subjects to choose from...', + menu_select: 'Select', + lets_search: query => + `Lets search for ${query}... What do you want to know?`, + see_faq: 'Please take a look at the FAQ I\'ve prepared for you. You can click on them to get the answer.', + will_answer_projector: + 'I\'ll answer on the projector to a better experience...', + ask_first_time: 'What are you looking for?' + }, + 'pt-BR': { + did_not_find: 'Desculpe-me, não encontrei nada a respeito.', + going_answer: 'Ótima escolha, procurando resposta para sua questão...', + wider_answer: subjectText => + `Vou te responder de modo mais abrangente... Não apenas sobre ${subjectText}`, + which_question: 'Qual a pergunta?', + anything_else: 'Então, posso ajudar em algo mais?', + here_is_subjects: 'Aqui estão algumas categorias de assuntos...', + menu_select: 'Selecionar', + lets_search: query => + `Let's search about ${query}... What do you want to know?`, + see_faq: + 'Veja algumas perguntas mais frequentes logo na tela. Clique numa delas para eu responder.', + will_answer_projector: + 'Vou te responder na tela para melhor visualização...', + ask_first_time: 'Como eu posso ajudar?' + } +}; diff --git a/packages/whatsapp.gblib/services/WhatsappDirectLine.ts b/packages/whatsapp.gblib/services/WhatsappDirectLine.ts index 5a56faa9..5699605e 100644 --- a/packages/whatsapp.gblib/services/WhatsappDirectLine.ts +++ b/packages/whatsapp.gblib/services/WhatsappDirectLine.ts @@ -39,7 +39,7 @@ import { GBLog, GBService, GBMinInstance, IGBPackage } from 'botlib'; import * as request from 'request-promise-native'; import { GBServer } from '../../../src/app'; import { GBConversationalService } from '../../core.gbapp/services/GBConversationalService'; -import { SecService } from '../../security.gblib/services/SecService'; +import { SecService } from '../../security.gbapp/services/SecService'; import { Messages } from '../strings'; import { CollectionUtil } from 'pragmatismo-io-framework'; diff --git a/src/app.ts b/src/app.ts index 85d96ba4..65b030dd 100644 --- a/src/app.ts +++ b/src/app.ts @@ -134,7 +134,7 @@ export class GBServer { GBLog.info(`Defining server address at ${serverAddress}...`); GBServer.globals.publicAddress = serverAddress; } - + // Creates a boot instance or load it from storage. try { @@ -189,12 +189,12 @@ export class GBServer { } GBLog.info(`The Bot Server is in RUNNING mode...`); - + // Opens Navigator. // TODO: Config: core.openBrowserInDevelopment(); } catch (err) { - GBLog.error(`STOP: ${err} ${err.stack ? err.stack : ''}`); + GBLog.error(`STOP: ${err.message ? err.message : err} ${err.stack ? err.stack : ''}`); process.exit(1); } })();