diff --git a/packages/analytics.gblib/services/AnalyticsService.ts b/packages/analytics.gblib/services/AnalyticsService.ts index b904eccd8..3be6af745 100644 --- a/packages/analytics.gblib/services/AnalyticsService.ts +++ b/packages/analytics.gblib/services/AnalyticsService.ts @@ -83,15 +83,16 @@ export class AnalyticsService { public async createMessage ( instanceId: number, - conversation: GuaribasConversation, + conversationId: number, userId: number, content: string ): Promise { + const message = GuaribasConversationMessage.build(); message.content = typeof content === 'object' ? JSON.stringify(content) : content; message.instanceId = instanceId; message.userId = userId; - message.conversationId = conversation.conversationId; + message.conversationId = conversationId; return await message.save(); } diff --git a/packages/basic.gblib/services/DialogKeywords.ts b/packages/basic.gblib/services/DialogKeywords.ts index 321a478cf..738a11c1c 100644 --- a/packages/basic.gblib/services/DialogKeywords.ts +++ b/packages/basic.gblib/services/DialogKeywords.ts @@ -588,8 +588,29 @@ export class DialogKeywords { this['id'] = this.sys().getRandomId(); } + private isUserSystemParam(name: string): Boolean { + const names = [ + 'welcomed', + 'loaded', + 'subjects', + 'cb', + 'welcomed', + 'maxLines', + 'translatorOn', + 'wholeWord', + 'theme', + 'maxColumns' + ]; + + return names.indexOf(name) > -1; + } + + private async setOption({pid, name, value}) { + if (this.isUserSystemParam(name)){ + throw new Error(`Not possible to define ${name} as it is a reserved system param name.`); + } const process = GBServer.globals.processes[pid]; let { min, user, params } = await DialogKeywords.getProcessInfo(pid); const sec = new SecService(); @@ -598,6 +619,17 @@ export class DialogKeywords { return { min, user, params }; } + private async getOption({pid, name}) + { + if (this.isUserSystemParam(name)){ + throw new Error(`Not possible to retrieve ${name} system param.`); + } + const process = GBServer.globals.processes[pid]; + let { min, user, params } = await DialogKeywords.getProcessInfo(pid); + const sec = new SecService(); + return await sec.getParam(user, name); + } + /** * Defines the maximum lines to scan in spreedsheets. * @@ -608,6 +640,27 @@ export class DialogKeywords { await this.setOption({pid, name: "maxLines", value: count}); } + /** + * Defines a custom user param to be persisted to storage. + * + * @example SET PARAM name AS value + * + */ + public async setUserParam({ pid, name, value }) { + await this.setOption({pid, name, value}); + } + + /** + * Returns a custom user param persisted on storage. + * + * @example GET PARAM name + * + */ + public async getUserParam({ pid, name }) { + await this.getOption({pid, name}); + } + + /** * Defines the maximum lines to scan in spreedsheets. * @@ -772,12 +825,14 @@ export class DialogKeywords { await sleep(DEFAULT_HEAR_POLL_INTERVAL); } - const text = min.cbMap[userId].promise; + const answer = min.cbMap[userId].promise; if (kind === 'file') { + GBLog.info('BASIC: HEAR (Asking for input).'); + // TODO: answer.filename, answer.data. } else if (kind === 'boolean') { - if (isIntentYes('pt-BR', text)) { + if (isIntentYes('pt-BR', answer)) { result = true; } else { result = false; @@ -787,7 +842,7 @@ export class DialogKeywords { return text.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)/gi); }; - const value = extractEntity(text); + const value = extractEntity(answer); if (value === null) { await this.talk({ pid, text: 'Por favor, digite um e-mail válido.' }); @@ -800,7 +855,7 @@ export class DialogKeywords { return text.match(/[_a-zA-Z][_a-zA-Z0-9]{0,16}/gi); }; - const value = extractEntity(text); + const value = extractEntity(answer); if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um nome válido.' }); @@ -813,7 +868,7 @@ export class DialogKeywords { return text.match(/\d+/gi); }; - const value = extractEntity(text); + const value = extractEntity(answer); if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um número válido.' }); @@ -828,7 +883,7 @@ export class DialogKeywords { ); }; - const value = extractEntity(text); + const value = extractEntity(answer); if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite uma data no formato 12/12/2020.' }); @@ -841,7 +896,7 @@ export class DialogKeywords { return text.match(/^([0-1]?[0-9]|2[0-4]):([0-5][0-9])(:[0-5][0-9])?$/gi); }; - const value = extractEntity(text); + const value = extractEntity(answer); if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um horário no formato hh:ss.' }); @@ -860,7 +915,7 @@ export class DialogKeywords { return []; }; - const value = extractEntity(text); + const value = extractEntity(answer); if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um valor monetário.' }); @@ -872,7 +927,7 @@ export class DialogKeywords { let phoneNumber; try { // https://github.com/GeneralBots/BotServer/issues/307 - phoneNumber = phone(text, { country: 'BRA' })[0]; + phoneNumber = phone(answer, { country: 'BRA' })[0]; phoneNumber = phoneUtil.parse(phoneNumber); } catch (error) { await this.talk({ pid, text: Messages[locale].validation_enter_valid_mobile }); @@ -897,7 +952,7 @@ export class DialogKeywords { } }; - const value = extractEntity(text); + const value = extractEntity(answer); if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um CEP válido.' }); @@ -909,7 +964,7 @@ export class DialogKeywords { const list = args; result = null; await CollectionUtil.asyncForEach(list, async item => { - if (GBConversationalService.kmpSearch(text, item) != -1) { + if (GBConversationalService.kmpSearch(answer, item) != -1) { result = item; } }); @@ -939,8 +994,8 @@ export class DialogKeywords { await CollectionUtil.asyncForEach(list, async item => { if ( - GBConversationalService.kmpSearch(text.toLowerCase(), item.name.toLowerCase()) != -1 || - GBConversationalService.kmpSearch(text.toLowerCase(), item.code.toLowerCase()) != -1 + GBConversationalService.kmpSearch(answer.toLowerCase(), item.name.toLowerCase()) != -1 || + GBConversationalService.kmpSearch(answer.toLowerCase(), item.code.toLowerCase()) != -1 ) { result = item.code; } diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 7bb2f324e..9b4887d11 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -659,6 +659,20 @@ export class GBVMService extends GBService { } ]; + keywords[i++] = [ + /^\s*set param \s*(.*)\s*as\s*(.*)/gim, + ($0, $1, $2) => { + return `await dk.setUserParam ({pid: pid, ${$1}}, ${$2})`; + } + ]; + + keywords[i++] = [ + /^\s*get param \s*(.*)/gim, + ($0, $1, $2) => { + return `await dk.getUserParam ({pid: pid, ${$1}})`; + } + ]; + keywords[i++] = [ /^\s*set header\s*(.*)\s*as\s*(.*)/gim, ($0, $1, $2) => { diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index d65165e80..474136372 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -826,11 +826,11 @@ export class GBMinService { // Get loaded user state - const member = context.activity.from; const step = await min.dialogs.createContext(context); step.context.activity.locale = 'pt-BR'; let firstTime = false; + const member = context.activity.from; const sec = new SecService(); const user = await sec.ensureUser(instance.instanceId, member.id, member.name, '', 'web', member.name, null); const userId = user.userId; @@ -1061,9 +1061,9 @@ export class GBMinService { private static async downloadAttachmentAndWrite(attachment) { const url = attachment.contentUrl; - // https://github.com/GeneralBots/BotServer/issues/195 - '${botId}','uploads'); + // TODO: https://github.com/GeneralBots/BotServer/issues/195 - '${botId}','uploads'); const localFolder = Path.join('work'); - const localFileName = Path.join(localFolder, this['botId'],'uploads', attachment.name); + const localFileName = Path.join(localFolder, this['botId'], 'uploads', attachment.name); try { let response; @@ -1133,21 +1133,29 @@ export class GBMinService { context.activity.text = context.activity.text.trim(); - const user = await min.userProfile.get(context, {}); + const member = context.activity.from; + + let user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name, null); + const userId = user.userId; + const params = user.params ? JSON.parse(user.params) : {}; + let message: GuaribasConversationMessage; if (process.env.PRIVACY_STORE_MESSAGES === 'true') { // Adds message to the analytics layer. const analytics = new AnalyticsService(); + if (user) { - if (!user.conversation) { - user.conversation = await analytics.createConversation(user.systemUser); + let conversation; + if (!user.conversationId) { + conversation = await analytics.createConversation(user); + user.conversationId = conversation.Id; } message = await analytics.createMessage( min.instance.instanceId, - user.conversation, - user.systemUser.userId, + user.conversationId, + userId, context.activity.text ); } @@ -1156,7 +1164,9 @@ export class GBMinService { if (process.env.ENABLE_DOWNLOAD) { // Prepare Promises to download each attachment and then execute each Promise. - const promises = step.context.activity.attachments.map(GBMinService.downloadAttachmentAndWrite.bind(min)); + const promises = step.context.activity.attachments.map( + GBMinService.downloadAttachmentAndWrite.bind({ min, user, params }) + ); const successfulSaves = await Promise.all(promises); async function replyForReceivedAttachments(localAttachmentData) { if (localAttachmentData) { @@ -1171,10 +1181,17 @@ export class GBMinService { // The current TurnContext is bound so `replyForReceivedAttachments` can also send replies. const replyPromises = successfulSaves.map(replyForReceivedAttachments.bind(step.context)); await Promise.all(replyPromises); - const result = { - data: Fs.readFileSync(successfulSaves[0]['localPath']), - filename: successfulSaves[0]['fileName'] - }; + if (successfulSaves.length) { + const result = { + data: Fs.readFileSync(successfulSaves[0]['localPath']), + filename: successfulSaves[0]['fileName'] + }; + + if (min.cbMap[userId] && min.cbMap[userId].promise == '!GBHEAR') { + min.cbMap[userId].promise = result; + } + + } } // Files in .gbdialog can be called directly by typing its name normalized into JS . @@ -1298,13 +1315,11 @@ export class GBMinService { 'Language Detector', GBConfigService.getBoolean('LANGUAGE_DETECTOR') ) === 'true'; - const systemUser = user.systemUser; - locale = systemUser.locale; + locale = user.locale; if (text != '' && detectLanguage && !locale) { locale = await min.conversationalService.getLanguage(min, text); - if (systemUser.locale != locale) { - user.systemUser = await sec.updateUserLocale(systemUser.userId, locale); - await min.userProfile.set(step.context, user); + if (user.locale != locale) { + user = await sec.updateUserLocale(user.userId, locale); } } @@ -1340,10 +1355,10 @@ export class GBMinService { GBLog.info(`Text>: ${text}.`); - if (user.systemUser.agentMode === 'self') { - const manualUser = await sec.getUserFromAgentSystemId(user.systemUser.userSystemId); + if (user.agentMode === 'self') { + const manualUser = await sec.getUserFromAgentSystemId(user.userSystemId); - GBLog.info(`HUMAN AGENT (${user.systemUser.userSystemId}) TO USER ${manualUser.userSystemId}: ${text}`); + GBLog.info(`HUMAN AGENT (${user.userId}) TO USER ${manualUser.userSystemId}: ${text}`); const cmd = 'SEND FILE '; if (text.startsWith(cmd)) { @@ -1366,8 +1381,8 @@ export class GBMinService { ); } } else { - if (min.cbMap[user.systemUser.userId] && min.cbMap[user.systemUser.userId].promise == '!GBHEAR') { - min.cbMap[user.systemUser.userId].promise = text; + if (min.cbMap[userId] && min.cbMap[userId].promise == '!GBHEAR') { + min.cbMap[userId].promise = text; } // If there is a dialog in course, continue to the next step. diff --git a/packages/security.gbapp/models/index.ts b/packages/security.gbapp/models/index.ts index 03ec59f79..1c92a9f35 100644 --- a/packages/security.gbapp/models/index.ts +++ b/packages/security.gbapp/models/index.ts @@ -36,6 +36,7 @@ 'use strict'; +import { GuaribasConversation } from '../../analytics.gblib/models/index.js'; import { AutoIncrement, BelongsTo, @@ -97,11 +98,14 @@ export class GuaribasUser extends Model { @Column(DataType.TEXT) declare conversationReference: string; + @Column(DataType.INTEGER) + declare conversationId: number; + @Column(DataType.STRING(64)) declare hearOnDialog: string; @Column(DataType.STRING(4000)) - declare params: string; + declare params: string; } /**