diff --git a/.gitignore b/.gitignore index 54ca5f1d..173aee38 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ package-lock.json yarn-lock.json logo.svg screenshot.png +data.db diff --git a/.test-init.ts b/.test-init.ts new file mode 100644 index 00000000..9b280f03 --- /dev/null +++ b/.test-init.ts @@ -0,0 +1,47 @@ +import { expect, test } from 'vitest'; +import { GBServer } from './src/app'; +import { RootData } from './src/RootData'; +import { GBMinInstance } from 'botlib'; +import { Mutex } from 'async-mutex'; + +export default function init() { + + const min = { + packages: null, + appPackages: null, + botId: 'gbtest', + instance: {botId: 'gbtest'}, + core: {}, + conversationalService: {}, + kbService: {}, + adminService: {}, + deployService: {}, + textServices: {}, + bot: {}, + dialogs: {}, + userState: {}, + userProfile: {}, + whatsAppDirectLine: {}, + cbMap: {}, + scriptMap: {}, + sandBoxMap: {}, + gbappServices: {} + + } + + GBServer.globals = new RootData(); + GBServer.globals.server = null; + GBServer.globals.httpsServer = null; + GBServer.globals.webSessions = {}; + GBServer.globals.processes = [0, { pid: 1, proc: {step: {}}}]; + GBServer.globals.files = {}; + GBServer.globals.appPackages = []; + GBServer.globals.sysPackages = []; + GBServer.globals.minInstances = [min]; + GBServer.globals.minBoot = min; + GBServer.globals.wwwroot = null; + GBServer.globals.entryPointDialog = null; + GBServer.globals.debuggers = []; + GBServer.globals.indexSemaphore = new Mutex(); + GBServer.globals.users = {1: {userId: 1}}; +} diff --git a/boot.mjs b/boot.mjs index dfe9e303..3f5afe03 100644 --- a/boot.mjs +++ b/boot.mjs @@ -8,7 +8,7 @@ import pjson from './package.json' assert { type: 'json' }; // Displays version of Node JS being used at runtime and others attributes. -process.stdout.write(`General Bots. BotServer@${pjson.version}, botlib@${pjson.dependencies.botlib}, botbuilder@${pjson.dependencies.botbuilder}, node@${process.version.replace('v', '')}, ${process.platform} ${process.arch} `); +process.stdout.write(`General Bots. BotServer@${pjson.version}, botlib@${pjson.dependencies.botlib}, node@${process.version.replace('v', '')}, ${process.platform} ${process.arch} `); console.log(`\nLoading virtual machine source code files...`); var __dirname = process.env.PWD || process.cwd(); diff --git a/package.json b/package.json index 03c5d47b..a5aa46a5 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@azure/keyvault-keys": "4.8.0", "@azure/ms-rest-js": "2.7.0", "@azure/msal-node": "2.8.1", - "@azure/openai": "^2.0.0-beta.1", + "@azure/openai": "2.0.0-beta.1", "@azure/search-documents": "12.0.0", "@azure/storage-blob": "12.18.0", "@google-cloud/pubsub": "4.4.0", @@ -137,11 +137,12 @@ "google-libphonenumber": "3.2.34", "googleapis": "126.0.1", "hnswlib-node": "3.0.0", - "html-to-md": "^0.8.5", + "html-to-md": "0.8.5", "http-proxy": "1.18.1", "ibm-watson": "9.1.0", - "instagram-private-api": "^1.46.1", + "instagram-private-api": "1.46.1", "iso-639-1": "3.1.2", + "isomorphic-fetch": "3.0.0", "join-images-updated": "1.1.11", "js-md5": "0.8.3", "json-schema-to-zod": "2.1.0", @@ -210,7 +211,7 @@ "textract": "2.5.0", "twilio": "5.1.0", "twitter-api-v2": "1.17.0", - "typeorm": "^0.3.20", + "typeorm": "0.3.20", "typescript": "5.4.5", "url-join": "5.0.0", "vhost": "3.0.2", @@ -218,6 +219,7 @@ "vm2-process": "2.1.5", "walk-promise": "0.2.0", "washyourmouthoutwithsoap": "1.0.2", + "webdav-server": "2.6.2", "whatsapp-cloud-api": "0.3.1", "whatsapp-web.js": "https://github.com/Julzk/whatsapp-web.js/tarball/jkr_hotfix_7", "winston": "3.13.0", diff --git a/packages/admin.gbapp/dialogs/AdminDialog.ts b/packages/admin.gbapp/dialogs/AdminDialog.ts index c396e864..5a9acdaa 100644 --- a/packages/admin.gbapp/dialogs/AdminDialog.ts +++ b/packages/admin.gbapp/dialogs/AdminDialog.ts @@ -313,7 +313,7 @@ export class AdminDialog extends IGBDialog { } if (packageName.indexOf('.') !== -1) { - cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${process.env.STORAGE_LIBRARY}/${botId}.gbai/${packageName}`; + cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${GBConfigService.get('STORAGE_LIBRARY')}/${botId}.gbai/${packageName}`; } else { cmd1 = `deployPackage ${packageName}`; } diff --git a/packages/admin.gbapp/index.ts b/packages/admin.gbapp/index.ts index 7b093560..0abbf1c6 100644 --- a/packages/admin.gbapp/index.ts +++ b/packages/admin.gbapp/index.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/admin.gbapp/models/AdminModel.ts b/packages/admin.gbapp/models/AdminModel.ts index 34e24a22..224ebc2d 100644 --- a/packages/admin.gbapp/models/AdminModel.ts +++ b/packages/admin.gbapp/models/AdminModel.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/admin.gbapp/services/GBAdminService.ts b/packages/admin.gbapp/services/GBAdminService.ts index 0b0e7f0a..e13b5fa6 100644 --- a/packages/admin.gbapp/services/GBAdminService.ts +++ b/packages/admin.gbapp/services/GBAdminService.ts @@ -1,5 +1,3 @@ - - /*****************************************************************************\ | █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® | | ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | @@ -7,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -23,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -49,13 +47,14 @@ import { GBSharePointService } from '../../sharepoint.gblib/services/SharePointS import { GuaribasAdmin } from '../models/AdminModel.js'; import msRestAzure from 'ms-rest-azure'; import Path from 'path'; -import { caseSensitive_Numbs_SpecialCharacters_PW, lowercase_PW } from 'super-strong-password-generator' +import { caseSensitive_Numbs_SpecialCharacters_PW, lowercase_PW } from 'super-strong-password-generator'; import crypto from 'crypto'; import Fs from 'fs'; import { GBServer } from '../../../src/app.js'; import { GuaribasUser } from '../../security.gbapp/models/index.js'; import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js'; import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js'; +import { GBUtil } from '../../../src/util.js'; /** * Services for server administration. @@ -89,45 +88,40 @@ export class GBAdminService implements IGBAdminService { } public static async getADALCredentialsFromUsername(username: string, password: string) { - return await msRestAzure.loginWithUsernamePassword(username, password); } public static getMobileCode() { - return this.getNumberIdentifier(6); } public static getRndPassword(): string { - let password = caseSensitive_Numbs_SpecialCharacters_PW(15); password = password.replace(/[\@\[\=\:\;\?\"\'\#]/gi, '*'); const removeRepeatedChars = (s, r) => { - let res = '', last = null, counter = 0; + let res = '', + last = null, + counter = 0; s.split('').forEach(char => { - if (char == last) - counter++; - else { - counter = 0; - last = char; - } - if (counter < r) - res += char; - }); + if (char == last) counter++; + else { + counter = 0; + last = char; + } + if (counter < r) res += char; + }); return res; - } + }; return removeRepeatedChars(password, 1); } public static getRndReadableIdentifier(): string { - return lowercase_PW(14); } public static getNumberIdentifier(digits: number = 14): string { - if (digits <= 0) { throw new Error('Number of digits should be greater than 0.'); } @@ -155,7 +149,6 @@ export class GBAdminService implements IGBAdminService { } public static async undeployPackageCommand(text: string, min: GBMinInstance) { - const packageName = text.split(' ')[1]; const importer = new GBImporter(min.core); const deployer = new GBDeployer(min.core, importer); @@ -167,7 +160,12 @@ export class GBAdminService implements IGBAdminService { public static isSharePointPath(path: string) { return path.indexOf('sharepoint.com') !== -1; } - public static async deployPackageCommand(min: GBMinInstance, user: GuaribasUser, text: string, deployer: IGBDeployer) { + public static async deployPackageCommand( + min: GBMinInstance, + user: GuaribasUser, + text: string, + deployer: IGBDeployer + ) { const packageName = text.split(' ')[1]; if (!this.isSharePointPath(packageName)) { @@ -190,19 +188,21 @@ export class GBAdminService implements IGBAdminService { await deployer['cleanupPackage'](min.instance, packageName); } - await deployer['downloadFolder'](min, - Path.join('work', `${gbai}`), - Path.basename(localFolder)); + if (!GBConfigService.get('STORAGE_NAME')) { + const path = Path.join(GBConfigService.get('STORAGE_LIBRARY'), gbaiPath); + GBUtil.copyIfNewerRecursive(path, localFolder); + } else { + await deployer['downloadFolder'](min, Path.join('work', `${gbai}`), Path.basename(localFolder)); + } await deployer['deployPackage2'](min, user, localFolder); } } public static async rebuildIndexPackageCommand(min: GBMinInstance, deployer: GBDeployer) { const service = await AzureDeployerService.createInstance(deployer); - const searchIndex = min.instance.searchIndex ? min.instance.searchIndex : GBServer.globals.minBoot.instance.searchIndex; - await deployer.rebuildIndex( - min.instance, - service.getKBSearchSchema(searchIndex) - ); + const searchIndex = min.instance.searchIndex + ? min.instance.searchIndex + : GBServer.globals.minBoot.instance.searchIndex; + await deployer.rebuildIndex(min.instance, service.getKBSearchSchema(searchIndex)); } public static async syncBotServerCommand(min: GBMinInstance, deployer: GBDeployer) { @@ -245,15 +245,15 @@ export class GBAdminService implements IGBAdminService { return obj.value; } - public async acquireElevatedToken(instanceId: number, root: boolean = false, + public async acquireElevatedToken( + instanceId: number, + root: boolean = false, tokenName: string = '', clientId: string = null, clientSecret: string = null, host: string = null, tenant: string = null ): Promise { - - if (root) { const minBoot = GBServer.globals.minBoot; instanceId = minBoot.instance.instanceId; @@ -267,7 +267,6 @@ export class GBAdminService implements IGBAdminService { throw new Error(`/setupSecurity is required before running /publish.`); } - return new Promise(async (resolve, reject) => { const instance = await this.core.loadInstanceById(instanceId); @@ -276,14 +275,10 @@ export class GBAdminService implements IGBAdminService { const accessToken = await this.getValue(instanceId, `${tokenName}accessToken`); resolve(accessToken); } else { - if (tokenName && !root) { - const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`); - let url = urlJoin( - host, - tenant, 'oauth/token'); + let url = urlJoin(host, tenant, 'oauth/token'); let buff = new Buffer(`${clientId}:${clientSecret}`); const base64 = buff.toString('base64'); @@ -295,8 +290,8 @@ export class GBAdminService implements IGBAdminService { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ - 'grant_type': 'refresh_token', - 'refresh_token': refreshToken + grant_type: 'refresh_token', + refresh_token: refreshToken }) }; const result = await fetch(url, options); @@ -313,15 +308,15 @@ export class GBAdminService implements IGBAdminService { await this.setValue(instanceId, `${tokenName}accessToken`, token['access_token']); await this.setValue(instanceId, `${tokenName}refreshToken`, token['refresh_token']); - await this.setValue(instanceId, `${tokenName}expiresOn`, - new Date(Date.now() + (token['expires_in'] * 1000)).toString()); + await this.setValue( + instanceId, + `${tokenName}expiresOn`, + new Date(Date.now() + token['expires_in'] * 1000).toString() + ); await this.setValue(instanceId, `${tokenName}AntiCSRFAttackState`, null); resolve(token['access_token']); - - } - else { - + } else { const oauth2 = tokenName ? 'oauth' : 'oauth2'; const authorizationUrl = urlJoin( tokenName ? host : instance.authenticatorAuthorityHostUrl, @@ -359,5 +354,5 @@ export class GBAdminService implements IGBAdminService { }); } - public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise { } + public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise {} } diff --git a/packages/analytics.gblib/index.ts b/packages/analytics.gblib/index.ts index 785057fb..f6ae8074 100644 --- a/packages/analytics.gblib/index.ts +++ b/packages/analytics.gblib/index.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/analytics.gblib/models/index.ts b/packages/analytics.gblib/models/index.ts index 27b22d77..b6a6a0a3 100644 --- a/packages/analytics.gblib/models/index.ts +++ b/packages/analytics.gblib/models/index.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/analytics.gblib/services/AnalyticsService.ts b/packages/analytics.gblib/services/AnalyticsService.ts index a227cf2f..5fb52456 100644 --- a/packages/analytics.gblib/services/AnalyticsService.ts +++ b/packages/analytics.gblib/services/AnalyticsService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/azuredeployer.gbapp/dialogs/StartDialog.ts b/packages/azuredeployer.gbapp/dialogs/StartDialog.ts index af182036..b7b9e278 100644 --- a/packages/azuredeployer.gbapp/dialogs/StartDialog.ts +++ b/packages/azuredeployer.gbapp/dialogs/StartDialog.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/azuredeployer.gbapp/index.ts b/packages/azuredeployer.gbapp/index.ts index d8d9ffcd..d765958c 100644 --- a/packages/azuredeployer.gbapp/index.ts +++ b/packages/azuredeployer.gbapp/index.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/azuredeployer.gbapp/services/AzureDeployerService.ts b/packages/azuredeployer.gbapp/services/AzureDeployerService.ts index bc59da41..4aca5208 100644 --- a/packages/azuredeployer.gbapp/services/AzureDeployerService.ts +++ b/packages/azuredeployer.gbapp/services/AzureDeployerService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/basic.gblib/index.ts b/packages/basic.gblib/index.ts index 2226c8c4..ecc47c7c 100644 --- a/packages/basic.gblib/index.ts +++ b/packages/basic.gblib/index.ts @@ -6,7 +6,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -22,7 +22,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/basic.gblib/models/Model.ts b/packages/basic.gblib/models/Model.ts index fcc5db0b..3c126973 100644 --- a/packages/basic.gblib/models/Model.ts +++ b/packages/basic.gblib/models/Model.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/basic.gblib/services/ChartServices.ts b/packages/basic.gblib/services/ChartServices.ts index 8a4106cb..c3f73425 100644 --- a/packages/basic.gblib/services/ChartServices.ts +++ b/packages/basic.gblib/services/ChartServices.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/basic.gblib/services/DebuggerService.ts b/packages/basic.gblib/services/DebuggerService.ts index dfaf8c65..bc079acb 100644 --- a/packages/basic.gblib/services/DebuggerService.ts +++ b/packages/basic.gblib/services/DebuggerService.ts @@ -1,31 +1,29 @@ /*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | -| | | ( )_) | | -| (_) \___/' | +| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® | +| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ | +| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. 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, | +| 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 | +| 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | The licensing of the program under the AGPLv3 does not imply a | -| trademark license. Therefore any rights,title and interest in | +| trademark license. Therefore any rights, title and interest in | | our trademarks remain entirely with us. | | | \*****************************************************************************/ @@ -39,6 +37,7 @@ import SwaggerClient from 'swagger-client'; import { spawn } from 'child_process'; import { CodeServices } from '../../gpt.gblib/services/CodeServices.js'; import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js'; +import { GBUtil } from '../../../src/util.js'; /** * Web Automation services of conversation to be called by BASIC. @@ -156,12 +155,8 @@ export class DebuggerService { let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0]; - const client = await new SwaggerClient({ - spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')), - requestInterceptor: req => { - req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; - } - }); + const client = await GBUtil.getDirectLineClient(min); + GBServer.globals.debuggers[botId].client = client; const response = await client.apis.Conversations.Conversations_StartConversation(); const conversationId = response.obj.conversationId; diff --git a/packages/basic.gblib/services/DialogKeywords.ts b/packages/basic.gblib/services/DialogKeywords.ts index b92bd9cf..1350fca4 100644 --- a/packages/basic.gblib/services/DialogKeywords.ts +++ b/packages/basic.gblib/services/DialogKeywords.ts @@ -1,31 +1,29 @@ /*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | -| | | ( )_) | | -| (_) \___/' | +| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® | +| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ | +| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. 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, | +| 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 | +| 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | The licensing of the program under the AGPLv3 does not imply a | -| trademark license. Therefore any rights,title and interest in | +| trademark license. Therefore any rights, title and interest in | | our trademarks remain entirely with us. | | | \*****************************************************************************/ @@ -429,7 +427,7 @@ export class DialogKeywords { * @example TALK TOLIST (array,member) * */ - public async getToLst(pid, array, member) { + public async getToLst({pid, array, member}) { const { min, user } = await DialogKeywords.getProcessInfo(pid); if (!array) { @@ -1350,12 +1348,7 @@ export class DialogKeywords { const conversation = min['apiConversations'][pid]; - const client = await new SwaggerClient({ - spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')), - requestInterceptor: req => { - req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; - } - }); + const client = await GBUtil.getDirectLineClient(min); conversation.client = client; const response = await client.apis.Conversations.Conversations_StartConversation(); conversation.conversationId = response.obj.conversationId; @@ -1368,7 +1361,7 @@ export class DialogKeywords { const step = proc.step; const min = GBServer.globals.minInstances.filter(p => p.instance.instanceId == proc.instanceId)[0]; const sec = new SecService(); - const user = await sec.getUserFromId(min.instance.instanceId, proc.userId); + const user = GBServer.globals.users [proc.userId]; const params = user ? JSON.parse(user.params) : {}; return { min, diff --git a/packages/basic.gblib/services/GBVMService.test.ts b/packages/basic.gblib/services/GBVMService.test.ts deleted file mode 100644 index 7951735d..00000000 --- a/packages/basic.gblib/services/GBVMService.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { GBVMService } from './GBVMService'; -import { expect, test } from 'vitest' - -test('Default', () => { - - - const args = GBVMService.getSetScheduleKeywordArgs(` - - SET SCHEDULE "0 0 */1 * * *" - SET SCHEDULE "0 0 */3 * * *" - SET SCHEDULE "0 0 */2 * * *" - SET SCHEDULE "0 0 */2 * * *" - SET SCHEDULE "0 0 */3 * * *" - - `); - - expect(args.length).toBe(5); - -}); diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 93283ad6..638f920f 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -32,7 +32,7 @@ import { GBMinInstance, GBService, IGBCoreService, GBLog } from 'botlib'; import * as Fs from 'fs'; -import * as ji from 'just-indent' +import * as ji from 'just-indent'; import { GBServer } from '../../../src/app.js'; import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js'; import { CollectionUtil } from 'pragmatismo-io-framework'; @@ -52,8 +52,8 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js'; import { GuaribasUser } from '../../security.gbapp/models/index.js'; import { SystemKeywords } from './SystemKeywords.js'; import { Sequelize, QueryTypes } from '@sequelize/core'; -import { z } from "zod"; -import { zodToJsonSchema } from "zod-to-json-schema"; +import { z } from 'zod'; +import { zodToJsonSchema } from 'zod-to-json-schema'; /** * @fileoverview Decision was to priorize security(isolation) and debugging, @@ -68,7 +68,8 @@ export class GBVMService extends GBService { public static API_PORT = 1111; public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) { - const files = await walkPromise(folder); + const ignore = Path.join('work', DialogKeywords.getGBAIPath(min.botId, 'gbdialog'), 'node_modules'); + const files = await walkPromise(folder, { ignore: [ignore] }); await CollectionUtil.asyncForEach(files, async file => { if (!file) { @@ -77,9 +78,7 @@ export class GBVMService extends GBService { let filename: string = file.name; - if (filename.endsWith('.docx')) { - filename = await this.loadDialog(filename, folder, min); - } + filename = await this.loadDialog(filename, folder, min); }); } @@ -91,14 +90,11 @@ export class GBVMService extends GBService { //check every key for being same return Object.keys(obj1).every(function (key) { - //if object - if ((typeof obj1[key] == "object") && (typeof obj2[key] == "object")) { - + if (typeof obj1[key] == 'object' && typeof obj2[key] == 'object') { //recursively check return GBVMService.compare(obj1[key], obj2[key]); } else { - //do the normal compare return obj1[key] === obj2[key]; } @@ -106,14 +102,27 @@ export class GBVMService extends GBService { } public async loadDialog(filename: string, folder: string, min: GBMinInstance) { + const isWord = filename.endsWith('.docx'); + if ( + !( + isWord || + filename.endsWith('.vbs') || + filename.endsWith('.vb') || + filename.endsWith('.vba') || + filename.endsWith('.bas') || + filename.endsWith('.basic') + ) + ) { + return; + } + const wordFile = filename; - const vbsFile = filename.substr(0, filename.indexOf('docx')) + 'vbs'; + const vbsFile = isWord ? filename.substr(0, filename.indexOf('docx')) + 'vbs' : filename; const fullVbsFile = urlJoin(folder, vbsFile); const docxStat = Fs.statSync(urlJoin(folder, wordFile)); const interval = 3000; // If compiled is older 30 seconds, then recompile. let writeVBS = true; - // TODO: #412. // const subscription = { // changeType: 'created,updated', @@ -125,11 +134,10 @@ export class GBVMService extends GBService { // }; // let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min); - + // await client.api('/subscriptions') // .post(subscription); - if (Fs.existsSync(fullVbsFile)) { const vbsStat = Fs.statSync(fullVbsFile); if (docxStat['mtimeMs'] < vbsStat['mtimeMs'] + interval) { @@ -140,26 +148,9 @@ export class GBVMService extends GBService { let mainName = GBVMService.getMethodNameFromVBSFilename(filename); min.scriptMap[filename] = mainName; - if (writeVBS) { + if (writeVBS && GBConfigService.get('STORAGE_NAME')) { let text = await this.getTextFromWord(folder, wordFile); - // Pre process SET SCHEDULE calls. - - const schedules = GBVMService.getSetScheduleKeywordArgs(text); - - const s = new ScheduleServices(); - await s.deleteScheduleIfAny(min, mainName); - - let i = 1; - await CollectionUtil.asyncForEach(schedules, async (syntax) => { - - if (s) { - await s.createOrUpdateSchedule(min, syntax, `${mainName};${i++}`); - } - }); - - text = text.replace(/^\s*SET SCHEDULE (.*)/gim, ''); - // Write VBS file without pragma keywords. Fs.writeFileSync(urlJoin(folder, vbsFile), text); @@ -167,6 +158,41 @@ export class GBVMService extends GBService { // Process node_modules install. + this.processNodeModules(folder, min); + + // Hot swap for .vbs files. + + const fullFilename = urlJoin(folder, filename); + if (process.env.DEV_HOTSWAP) { + Fs.watchFile(fullFilename, async () => { + await this.translateBASIC(mainName, fullFilename, min); + const parsedCode: string = Fs.readFileSync(jsfile, 'utf8'); + min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode; + }); + } + + const compiledAt = Fs.statSync(fullFilename); + const jsfile = urlJoin(folder, `${filename}.js`); + + if (Fs.existsSync(jsfile)) { + const jsStat = Fs.statSync(jsfile); + const interval = 1000; // If compiled is older 1 seconds, then recompile. + if (compiledAt.isFile() && compiledAt['mtimeMs'] > jsStat['mtimeMs'] + interval) { + await this.translateBASIC(mainName, fullFilename, min); + } + } else { + await this.translateBASIC(mainName, fullFilename, min); + } + + // Syncronizes Database Objects with the ones returned from "Word". + + this.syncStorageFromTABLE(folder, filename, min, mainName); + + const parsedCode: string = Fs.readFileSync(jsfile, 'utf8'); + min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode; + return filename; + } + private processNodeModules(folder: string, min: GBMinInstance) { const node_modules = urlJoin(process.env.PWD, folder, 'node_modules'); if (!Fs.existsSync(node_modules)) { const packageJson = ` @@ -193,33 +219,9 @@ export class GBVMService extends GBService { const npmPath = urlJoin(process.env.PWD, 'node_modules', '.bin', 'npm'); child_process.execSync(`${npmPath} install`, { cwd: folder }); } + } - // Hot swap for .vbs files. - - const fullFilename = urlJoin(folder, filename); - if (process.env.DEV_HOTSWAP) { - Fs.watchFile(fullFilename, async () => { - await this.translateBASIC(mainName, fullFilename, min); - const parsedCode: string = Fs.readFileSync(jsfile, 'utf8'); - min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode; - }); - } - - const compiledAt = Fs.statSync(fullFilename); - const jsfile = urlJoin(folder, `${filename}.js`); - - if (Fs.existsSync(jsfile)) { - const jsStat = Fs.statSync(jsfile); - const interval = 30000; // If compiled is older 30 seconds, then recompile. - if (compiledAt.isFile() && compiledAt['mtimeMs'] > jsStat['mtimeMs'] + interval) { - await this.translateBASIC(mainName, fullFilename, min); - } - } else { - await this.translateBASIC(mainName, fullFilename, min); - } - - // Syncronizes Database Objects with the ones returned from "Word". - + private syncStorageFromTABLE(folder: string, filename: string, min: GBMinInstance, mainName: string) { const tablesFile = urlJoin(folder, `${filename}.tables.json`); let sync = false; @@ -229,7 +231,6 @@ export class GBVMService extends GBService { const tableDef = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')) as any; const getTypeBasedOnCondition = (t, size) => { - if (1) { switch (t) { case 'string': @@ -253,7 +254,6 @@ export class GBVMService extends GBService { default: return { type: 'TABLE', name: t }; } - } else { switch (t) { case 'string': @@ -277,43 +277,34 @@ export class GBVMService extends GBService { default: return { key: 'TABLE', name: t }; } - } }; const associations = []; // Loads storage custom connections. - const path = DialogKeywords.getGBAIPath(min.botId, null); const filePath = Path.join('work', path, 'connections.json'); let connections = null; if (Fs.existsSync(filePath)) { connections = JSON.parse(Fs.readFileSync(filePath, 'utf8')); } - const shouldSync = min.core.getParam( - min.instance, - 'Synchronize Database', - false - ); + const shouldSync = min.core.getParam(min.instance, 'Synchronize Database', false); tableDef.forEach(async t => { - const tableName = t.name.trim(); // Determines autorelationship. - Object.keys(t.fields).forEach(key => { let obj = t.fields[key]; obj.type = getTypeBasedOnCondition(obj.type, obj.size); - if (obj.type.key === "TABLE") { - obj.type.key = "BIGINT" + if (obj.type.key === 'TABLE') { + obj.type.key = 'BIGINT'; associations.push({ from: tableName, to: obj.type.name }); } }); // Cutom connection for TABLE. - const connectionName = t.connection; let con; @@ -330,8 +321,8 @@ export class GBVMService extends GBService { const logging: boolean | Function = GBConfigService.get('STORAGE_LOGGING') === 'true' ? (str: string): void => { - GBLogEx.info(min, str); - } + GBLogEx.info(min, str); + } : false; const encrypt: boolean = GBConfigService.get('STORAGE_ENCRYPT') === 'true'; @@ -367,11 +358,12 @@ export class GBVMService extends GBService { if (!min[connectionName]) { GBLogEx.info(min, `Loading custom connection ${connectionName}...`); min[connectionName] = new Sequelize(storageName, username, password, sequelizeOptions); - min[`llmconnection`] ={ + min[`llmconnection`] = { type: dialect, username, - database: storageName, password}; - + database: storageName, + password + }; } } @@ -380,27 +372,22 @@ export class GBVMService extends GBService { } // Field checking, syncs if there is any difference. - - const seq = min[connectionName] ? min[connectionName] - : minBoot.core.sequelize; + const seq = min[connectionName] ? min[connectionName] : minBoot.core.sequelize; if (seq) { - const model = seq.models[tableName]; if (model) { // Except Id, checks if has same number of fields. - let equals = 0; Object.keys(t.fields).forEach(key => { let obj1 = t.fields[key]; let obj2 = model['fieldRawAttributesMap'][key]; - if (key !== "id") { + if (key !== 'id') { if (obj1 && obj2) { equals++; } } - }); if (equals != Object.keys(t.fields).length) { @@ -410,23 +397,25 @@ export class GBVMService extends GBService { seq.define(tableName, t.fields); - // New table checking, if needs sync. + // New table checking, if needs sync. let tables; if (con.storageDriver === 'mssql') { - tables = await seq.query(`SELECT table_name, table_schema + tables = await seq.query( + `SELECT table_name, table_schema FROM information_schema.tables WHERE table_type = 'BASE TABLE' - ORDER BY table_name ASC`, { - type: QueryTypes.RAW - })[0] - } - else if (con.storageDriver === 'mariadb') { + ORDER BY table_name ASC`, + { + type: QueryTypes.RAW + } + )[0]; + } else if (con.storageDriver === 'mariadb') { tables = await seq.getQueryInterface().showAllTables(); } let found = false; - tables.forEach((storageTable) => { + tables.forEach(storageTable => { if (storageTable['table_name'] === tableName) { found = true; } @@ -441,15 +430,17 @@ export class GBVMService extends GBService { try { to.hasMany(from); } catch (error) { - throw new Error(`BASIC: Invalid relationship in ${mainName}: from ${e.from} to ${e.to} (${min.botId})... ${error.message}`); + throw new Error( + `BASIC: Invalid relationship in ${mainName}: from ${e.from} to ${e.to} (${min.botId})... ${error.message}` + ); } - }); - if (sync && shouldSync) { - - GBLogEx.info(min, `BASIC: Syncing changes for TABLE ${connectionName} ${tableName} keyword (${min.botId})...`); + GBLogEx.info( + min, + `BASIC: Syncing changes for TABLE ${connectionName} ${tableName} keyword (${min.botId})...` + ); await seq.sync({ alter: true, @@ -460,18 +451,29 @@ export class GBVMService extends GBService { } }); } - - const parsedCode: string = Fs.readFileSync(jsfile, 'utf8'); - min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode; - return filename; } public async translateBASIC(mainName, filename: any, min: GBMinInstance) { - // Converts General Bots BASIC into regular VBS let basicCode: string = Fs.readFileSync(filename, 'utf8'); + // Pre process SET SCHEDULE calls. + + const schedules = GBVMService.getSetScheduleKeywordArgs(basicCode); + + const s = new ScheduleServices(); + await s.deleteScheduleIfAny(min, mainName); + + let i = 1; + await CollectionUtil.asyncForEach(schedules, async syntax => { + if (s) { + await s.createOrUpdateSchedule(min, syntax, `${mainName};${i++}`); + } + }); + + basicCode = basicCode.replace(/^\s*SET SCHEDULE (.*)/gim, ''); + // Process INCLUDE keyword to include another // dialog inside the dialog. @@ -712,7 +714,6 @@ export class GBVMService extends GBService { Fs.writeFileSync(jsfile, code); GBLogEx.info(min, `[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${code}`); - } private async executeTasks(min, tasks) { @@ -720,12 +721,10 @@ export class GBVMService extends GBService { const task = tasks[i]; if (task.kind === 'writeTableDefinition') { - // Creates an empty object that will receive Sequelize fields. const tablesFile = `${task.file}.tables.json`; Fs.writeFileSync(tablesFile, JSON.stringify(task.tables)); - } } } @@ -744,10 +743,10 @@ export class GBVMService extends GBService { lines.forEach(line => { if (line.trim()) { console.log(line); - const keyword = /\s*SET SCHEDULE (.*)/gi; + const keyword = /^\s*SET SCHEDULE (.*)/gi; let result: any = keyword.exec(line); if (result) { - result = result[1].replace(/\`|\"|\'/, '') + result = result[1].replace(/\`|\"|\'/, ''); result = result.trim(); results.push(result); } @@ -756,6 +755,7 @@ export class GBVMService extends GBService { return results; } + private async getTextFromWord(folder: string, filename: string) { return new Promise(async (resolve, reject) => { const path = urlJoin(folder, filename); @@ -777,7 +777,6 @@ export class GBVMService extends GBService { } public static normalizeQuotes(text: any) { - text = text.replace(/\"/gm, '`'); text = text.replace(/\¨/gm, '`'); text = text.replace(/\“/gm, '`'); @@ -791,27 +790,22 @@ export class GBVMService extends GBService { public static getMetadata(mainName: string, propertiesText, description) { let properties = {}; if (!propertiesText || !description) { - - return {} + return {}; } const getType = asClause => { - asClause = asClause.trim().toUpperCase(); if (asClause.indexOf('STRING') !== -1) { return 'string'; - } - else if (asClause.indexOf('OBJECT') !== -1) { + } else if (asClause.indexOf('OBJECT') !== -1) { return 'object'; - } - else if (asClause.indexOf('INTEGER') !== -1 || asClause.indexOf('NUMBER') !== -1) { + } else if (asClause.indexOf('INTEGER') !== -1 || asClause.indexOf('NUMBER') !== -1) { return 'number'; } else { return 'enum'; } }; - for (let i = 0; i < propertiesText.length; i++) { const propertiesExp = propertiesText[i]; const t = getType(propertiesExp[2]); @@ -834,21 +828,19 @@ export class GBVMService extends GBService { properties[propertiesExp[1].trim()] = element; } - let json = { - type: "function", + type: 'function', function: { name: `${mainName}`, description: description ? description : '', parameters: zodToJsonSchema(z.object(properties)) } - } + }; return json; } public async parseField(line) { - let required = line.indexOf('*') !== -1; let unique = /\bunique\b/gi.test(line); let primaryKey = /\bkey\b/gi.test(line); @@ -870,7 +862,8 @@ export class GBVMService extends GBService { let definition = { allowNull: !required, - unique: unique, primaryKey: primaryKey, + unique: unique, + primaryKey: primaryKey, autoIncrement: autoIncrement }; definition['type'] = t; @@ -889,7 +882,6 @@ export class GBVMService extends GBService { * @param code General Bots BASIC */ public async convert(filename: string, mainName: string, code: string) { - // Start and End of VB2TS tags of processing. code = process.env.ENABLE_AUTH ? `hear GBLogExin as login\n${code}` : code; @@ -910,7 +902,6 @@ export class GBVMService extends GBService { const outputLines = []; let emmitIndex = 1; for (let i = 1; i <= lines.length; i++) { - let line = lines[i - 1]; // Remove lines before statements. @@ -961,12 +952,12 @@ export class GBVMService extends GBService { const endTableKeyword = /^\s*END TABLE\s*/gim; let endTableReg = endTableKeyword.exec(line); if (endTableReg && table) { - tables.push({ - name: table, fields: fields, connection: connection + name: table, + fields: fields, + connection: connection }); - fields = {}; table = null; connection = null; @@ -1006,14 +997,14 @@ export class GBVMService extends GBService { const talkKeyword = /^\s*BEGIN TALK\s*/gim; let talkReg = talkKeyword.exec(line); if (talkReg && !talk) { - talk = "await dk.talk ({pid: pid, text: `"; + talk = 'await dk.talk ({pid: pid, text: `'; emmit = false; } const systemPromptKeyword = /^\s*BEGIN SYSTEM PROMPT\s*/gim; let systemPromptReg = systemPromptKeyword.exec(line); if (systemPromptReg && !systemPrompt) { - systemPrompt = "await sys.setSystemPrompt ({pid: pid, text: `"; + systemPrompt = 'await sys.setSystemPrompt ({pid: pid, text: `'; emmit = false; } @@ -1031,9 +1022,10 @@ export class GBVMService extends GBService { if (tables) { tasks.push({ - kind: 'writeTableDefinition', file: filename, tables + kind: 'writeTableDefinition', + file: filename, + tables }); - } code = `${outputLines.join('\n')}\n`; @@ -1046,14 +1038,7 @@ export class GBVMService extends GBService { /** * Executes the converted JavaScript from BASIC code inside execution context. */ - public static async callVM( - text: string, - min: GBMinInstance, - step, - pid, - debug: boolean = false, - params = [] - ) { + public static async callVM(text: string, min: GBMinInstance, step, pid, debug: boolean = false, params = []) { // Creates a class DialogKeywords which is the *this* pointer // in BASIC. @@ -1069,8 +1054,7 @@ export class GBVMService extends GBService { // These variables will be automatically be available as normal BASIC variables. try { - variables['aadToken'] = await (min.adminService as any)['acquireElevatedToken'] - (min.instance.instanceId, false); + variables['aadToken'] = await (min.adminService as any)['acquireElevatedToken'](min.instance.instanceId, false); } catch (error) { variables['aadToken'] = 'ERROR: Configure /setupSecurity before using aadToken variable.'; } @@ -1111,12 +1095,10 @@ export class GBVMService extends GBService { let code = min.sandBoxMap[text]; const channel = step ? step.context.activity.channelId : 'web'; - const dk = new DialogKeywords(); const sys = new SystemKeywords(); await dk.setFilter({ pid: pid, value: null }); - // Find all tokens in .gbot Config. const strFind = ' Client ID'; @@ -1152,7 +1134,7 @@ export class GBVMService extends GBService { return await new Promise((resolve, reject) => { sandbox['resolve'] = resolve; // TODO: #411 sandbox['reject'] = reject; - sandbox['reject'] = ()=>{}; + sandbox['reject'] = () => {}; const vm1 = new NodeVM({ allowAsync: true, @@ -1169,7 +1151,6 @@ export class GBVMService extends GBService { const s = new VMScript(code, { filename: scriptPath }); result = vm1.run(s); }); - })(); } else { const runnerPath = urlJoin( @@ -1200,10 +1181,15 @@ export class GBVMService extends GBService { } catch (error) { throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`); } - } - public static createProcessInfo(user: GuaribasUser, min: GBMinInstance, channel: any, executable: string, step = null) { + public static createProcessInfo( + user: GuaribasUser, + min: GBMinInstance, + channel: any, + executable: string, + step = null + ) { const pid = GBAdminService.getNumberIdentifier(); GBServer.globals.processes[pid] = { pid: pid, diff --git a/packages/basic.gblib/services/ImageProcessingServices.ts b/packages/basic.gblib/services/ImageProcessingServices.ts index bd93218e..8ad1553c 100644 --- a/packages/basic.gblib/services/ImageProcessingServices.ts +++ b/packages/basic.gblib/services/ImageProcessingServices.ts @@ -1,31 +1,29 @@ /*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | -| | | ( )_) | | -| (_) \___/' | +| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® | +| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ | +| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. 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, | +| 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 | +| 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | The licensing of the program under the AGPLv3 does not imply a | -| trademark license. Therefore any rights,title and interest in | +| trademark license. Therefore any rights, title and interest in | | our trademarks remain entirely with us. | | | \*****************************************************************************/ @@ -35,13 +33,13 @@ import Path from 'path'; import { GBLog, GBMinInstance } from 'botlib'; import { DialogKeywords } from './DialogKeywords.js'; -import sharp from 'sharp'; import joinImages from 'join-images-updated'; import { CollectionUtil } from 'pragmatismo-io-framework'; import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js'; import urlJoin from 'url-join'; import { GBServer } from '../../../src/app.js'; import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js'; +import sharp from 'sharp'; /** * Image processing services of conversation to be called by BASIC. diff --git a/packages/basic.gblib/services/KeywordsExpressions.ts b/packages/basic.gblib/services/KeywordsExpressions.ts index 68275fbf..c0cd4e07 100644 --- a/packages/basic.gblib/services/KeywordsExpressions.ts +++ b/packages/basic.gblib/services/KeywordsExpressions.ts @@ -1,35 +1,34 @@ /*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ __ __ _ _ | ,_)(_) __ __ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(___/(_) (_)`\__/' | -| | | ( )_) | | -| (_) \__/' | +| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® | +| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ | +| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. 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, | +| 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 | +| 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | The licensing of the program under the AGPLv3 does not imply a | -| trademark license. Therefore any rights,title and interest in | +| trademark license. Therefore any rights, title and interest in | | our trademarks remain entirely with us. | | | \*****************************************************************************/ + 'use strict'; import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js'; diff --git a/packages/basic.gblib/services/ScheduleServices.ts b/packages/basic.gblib/services/ScheduleServices.ts index f6003bf0..de19c832 100644 --- a/packages/basic.gblib/services/ScheduleServices.ts +++ b/packages/basic.gblib/services/ScheduleServices.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -47,33 +47,30 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js'; * Basic services for BASIC manipulation. */ export class ScheduleServices extends GBService { - public async deleteScheduleIfAny(min: GBMinInstance, name: string) { - let i = 1; while (i <= 10) { const task = min['scheduleMap'] ? min['scheduleMap'][name + i] : null; if (task) { task.destroy(); - const id = `${name};${i}`; - - delete min['scheduleMap'][id]; - const count = await GuaribasSchedule.destroy({ - where: { - instanceId: min.instance.instanceId, - name: id - } - }); - - if (count > 0) { - GBLogEx.info(min, `BASIC: Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`); - } } + const id = `${name};${i}`; + + delete min['scheduleMap'][id]; + const count = await GuaribasSchedule.destroy({ + where: { + instanceId: min.instance.instanceId, + name: id + } + }); + + if (count > 0) { + GBLogEx.info(min, `BASIC: Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`); + } + i++; - } - } /** @@ -113,12 +110,10 @@ export class ScheduleServices extends GBService { let i = 0; let lastName = ''; - await CollectionUtil.asyncForEach(schedules, async (item) => { - + await CollectionUtil.asyncForEach(schedules, async item => { if (item.name === lastName) { item.name = item.name + ++i; - } - else { + } else { i = 0; } @@ -169,7 +164,6 @@ export class ScheduleServices extends GBService { }, options ); - } catch (error) { GBLogEx.error(min, `Running .gbdialog word ${item.name} : ${error}...`); } diff --git a/packages/basic.gblib/services/SystemKeywords.ts b/packages/basic.gblib/services/SystemKeywords.ts index 660f1251..94cdd66f 100644 --- a/packages/basic.gblib/services/SystemKeywords.ts +++ b/packages/basic.gblib/services/SystemKeywords.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -92,6 +92,7 @@ export class SystemKeywords { } public async append({ pid, args }) { + if (!args) return []; let array = [].concat(...args); return array.filter(function (item, pos) { return item; diff --git a/packages/basic.gblib/services/WebAutomationServices.ts b/packages/basic.gblib/services/WebAutomationServices.ts index d6702e06..4214ac1e 100644 --- a/packages/basic.gblib/services/WebAutomationServices.ts +++ b/packages/basic.gblib/services/WebAutomationServices.ts @@ -1,31 +1,29 @@ /*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | -| | | ( )_) | | -| (_) \___/' | +| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® | +| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ | +| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. 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, | +| 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 | +| 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | The licensing of the program under the AGPLv3 does not imply a | -| trademark license. Therefore any rights,title and interest in | +| trademark license. Therefore any rights, title and interest in | | our trademarks remain entirely with us. | | | \*****************************************************************************/ diff --git a/packages/basic.gblib/tests/DialogKeywords.test.ts b/packages/basic.gblib/tests/DialogKeywords.test.ts new file mode 100644 index 00000000..681f41b2 --- /dev/null +++ b/packages/basic.gblib/tests/DialogKeywords.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from 'vitest'; +import { DialogKeywords } from '../services/DialogKeywords'; +import init from '../../../.test-init' + +init(); + +const dk = new DialogKeywords(); +const pid = 1; + +test('TOLIST', async () => { + + const obj = [{a:1, b:2}, {a:2, b:4}]; + + expect(await dk.getToLst({ pid, array: obj, member:'a' })) + .toBe("1,2"); +}); diff --git a/packages/basic.gblib/tests/GBVMService.test.ts b/packages/basic.gblib/tests/GBVMService.test.ts new file mode 100644 index 00000000..e990016c --- /dev/null +++ b/packages/basic.gblib/tests/GBVMService.test.ts @@ -0,0 +1,43 @@ +import { GBVMService } from '../services/GBVMService'; +import { expect, test } from 'vitest' + +test('Default', () => { + + + const args = GBVMService.getSetScheduleKeywordArgs(` + + SET SCHEDULE "0 0 */1 * * *" + SET SCHEDULE "0 0 */3 * * *" + SET SCHEDULE "0 0 */2 * * *" + SET SCHEDULE "0 0 */2 * * *" + SET SCHEDULE "0 0 */3 * * *" + + `); + + expect(args.length).toBe(5); + +}); + + +test('Compare', () => { + + expect(GBVMService.compare(1,1)).toBeTruthy(); + expect(GBVMService.compare({a:1},{a:1})).toBeTruthy(); + expect(GBVMService.compare({a:1},{a:2})).toBeFalsy(); + expect(GBVMService.compare({a:1, b:2},{a:1, b:2})).toBeTruthy(); + +}); + +test('Parse Storage Field', async () => { + + const s = new GBVMService(); + + expect(await s.parseField('name STRING(30)')).toStrictEqual({name: 'name', definition: { + allowNull: true, + unique: false, primaryKey: false, + size: 30, + autoIncrement: false, + type:"STRING" + }}); + +}); diff --git a/packages/basic.gblib/tests/SystemKeywords.test.ts b/packages/basic.gblib/tests/SystemKeywords.test.ts new file mode 100644 index 00000000..73e0cd2f --- /dev/null +++ b/packages/basic.gblib/tests/SystemKeywords.test.ts @@ -0,0 +1,36 @@ +import { GBVMService } from '../services/GBVMService'; +import { expect, test } from 'vitest'; +import { SystemKeywords } from '../services/SystemKeywords'; + +const s = new SystemKeywords(); +const pid = 1; + +test('APPEND', async () => { + expect(await s.append({ pid, args: [1, 1, 1, 1] })).toStrictEqual([1, 1, 1, 1]); + expect(await s.append({ pid, args: [1] })).toStrictEqual([1]); + expect(await s.append({ pid, args: [] })).toStrictEqual([]); + expect(await s.append({ pid, args: null })).toStrictEqual([]); +}); + +test('COMPARE', () => { + expect(GBVMService.compare(1, 1)).toBeTruthy(); + expect(GBVMService.compare({ a: 1 }, { a: 1 })).toBeTruthy(); + expect(GBVMService.compare({ a: 1 }, { a: 2 })).toBeFalsy(); + expect(GBVMService.compare({ a: 1, b: 2 }, { a: 1, b: 2 })).toBeTruthy(); +}); + +test('Parse Storage Field', async () => { + const s = new GBVMService(); + + expect(await s.parseField('name STRING(30)')).toStrictEqual({ + name: 'name', + definition: { + allowNull: true, + unique: false, + primaryKey: false, + size: 30, + autoIncrement: false, + type: 'STRING' + } + }); +}); diff --git a/packages/core.gbapp/dialogs/BroadcastDialog.ts b/packages/core.gbapp/dialogs/BroadcastDialog.ts index e2026293..44b679c6 100644 --- a/packages/core.gbapp/dialogs/BroadcastDialog.ts +++ b/packages/core.gbapp/dialogs/BroadcastDialog.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/dialogs/LanguageDialog.ts b/packages/core.gbapp/dialogs/LanguageDialog.ts index 96b4d654..4a85c519 100644 --- a/packages/core.gbapp/dialogs/LanguageDialog.ts +++ b/packages/core.gbapp/dialogs/LanguageDialog.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/dialogs/SwitchBot.ts b/packages/core.gbapp/dialogs/SwitchBot.ts index 168e13fd..b3fc8087 100644 --- a/packages/core.gbapp/dialogs/SwitchBot.ts +++ b/packages/core.gbapp/dialogs/SwitchBot.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/dialogs/WelcomeDialog.ts b/packages/core.gbapp/dialogs/WelcomeDialog.ts index 23cd75e1..ca9d7192 100644 --- a/packages/core.gbapp/dialogs/WelcomeDialog.ts +++ b/packages/core.gbapp/dialogs/WelcomeDialog.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -36,11 +36,11 @@ import { BotAdapter } from 'botbuilder'; import { WaterfallDialog } from 'botbuilder-dialogs'; -import { GBLog, GBMinInstance, IGBDialog } from 'botlib'; +import { GBMinInstance, IGBDialog } from 'botlib'; import { GBServer } from '../../../src/app.js'; -import { GBConversationalService } from '../services/GBConversationalService.js'; import { Messages } from '../strings.js'; import { GBLogEx } from '../services/GBLogEx.js'; +import { GBConfigService } from '../services/GBConfigService.js'; /** * Dialog for Welcoming people. @@ -65,7 +65,7 @@ export class WelcomeDialog extends IGBDialog { async step => { if ( GBServer.globals.entryPointDialog !== null && - min.instance.botId === process.env.BOT_ID && + min.instance.botId === GBConfigService.get('BOT_ID') && step.context.activity.channelId === 'webchat' ) { return step.replaceDialog(GBServer.globals.entryPointDialog); diff --git a/packages/core.gbapp/dialogs/WhoAmIDialog.ts b/packages/core.gbapp/dialogs/WhoAmIDialog.ts index 2aad9af3..333b7ef8 100644 --- a/packages/core.gbapp/dialogs/WhoAmIDialog.ts +++ b/packages/core.gbapp/dialogs/WhoAmIDialog.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/index.ts b/packages/core.gbapp/index.ts index 57cf65f8..9b84dad3 100644 --- a/packages/core.gbapp/index.ts +++ b/packages/core.gbapp/index.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/models/GBError.ts b/packages/core.gbapp/models/GBError.ts index c92dadbb..3c6502d9 100644 --- a/packages/core.gbapp/models/GBError.ts +++ b/packages/core.gbapp/models/GBError.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/models/GBModel.ts b/packages/core.gbapp/models/GBModel.ts index e24235e6..7f99bf59 100644 --- a/packages/core.gbapp/models/GBModel.ts +++ b/packages/core.gbapp/models/GBModel.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/services/GBConfigService.ts b/packages/core.gbapp/services/GBConfigService.ts index e31f025a..16fe7c5b 100644 --- a/packages/core.gbapp/services/GBConfigService.ts +++ b/packages/core.gbapp/services/GBConfigService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -42,7 +42,7 @@ import * as en from 'dotenv-extended'; */ export class GBConfigService { public static getBoolean(value: string): boolean { - return (this.get(value) as unknown) as boolean; + return this.get(value) as unknown as boolean; } public static getServerPort(): string { if (process.env.PORT) { @@ -79,13 +79,19 @@ export class GBConfigService { public static get(key: string): string | undefined { let value = GBConfigService.tryGet(key); - if (value === undefined) { + if (!value) { switch (key) { + case 'STORAGE_NAME': + value = null; + break; case 'CLOUD_USERNAME': value = undefined; break; + case 'STORAGE_LIBRARY': + value = `${process.env.HOME}/gbpackages`; + break; case 'BOT_ID': - value = undefined; + value = 'default'; break; case 'CLOUD_PASSWORD': value = undefined; @@ -103,10 +109,10 @@ export class GBConfigService { value = undefined; break; case 'STORAGE_DIALECT': - value = undefined; + value = 'sqlite'; break; case 'STORAGE_FILE': - value = './guaribas.sqlite'; + value = './data.db'; break; case 'GBKB_AUTO_DEPLOY': value = false; @@ -160,7 +166,7 @@ export class GBConfigService { value = true; break; case 'BOT_URL': - value = undefined; + value = 'http://localhost:4242'; break; case 'STORAGE_SERVER': value = undefined; diff --git a/packages/core.gbapp/services/GBConversationalService.ts b/packages/core.gbapp/services/GBConversationalService.ts index 74c70576..53765ac6 100644 --- a/packages/core.gbapp/services/GBConversationalService.ts +++ b/packages/core.gbapp/services/GBConversationalService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -341,6 +341,7 @@ export class GBConversationalService { } public async sendEvent(min: GBMinInstance, step: GBDialogStep, name: string, value: Object): Promise { + if (step.context.activity.channelId !== 'msteams' && step.context.activity.channelId !== 'omnichannel') { GBLogEx.info( min, diff --git a/packages/core.gbapp/services/GBCoreService.ts b/packages/core.gbapp/services/GBCoreService.ts index 76cc4ff3..7374fa83 100644 --- a/packages/core.gbapp/services/GBCoreService.ts +++ b/packages/core.gbapp/services/GBCoreService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -50,6 +50,7 @@ import { GBSecurityPackage } from '../../security.gbapp/index.js'; import { GBWhatsappPackage } from '../../whatsapp.gblib/index.js'; import { GuaribasApplications, GuaribasInstance, GuaribasLog } from '../models/GBModel.js'; import { GBConfigService } from './GBConfigService.js'; +import mkdirp from 'mkdirp'; import { GBAzureDeployerPackage } from '../../azuredeployer.gbapp/index.js'; import { GBSharePointPackage } from '../../sharepoint.gblib/index.js'; import { CollectionUtil } from 'pragmatismo-io-framework'; @@ -109,7 +110,7 @@ export class GBCoreService implements IGBCoreService { constructor() { this.adminService = new GBAdminService(this); } - public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) { } + public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) {} /** * Gets database config and connect to storage. Currently two databases @@ -131,6 +132,12 @@ export class GBCoreService implements IGBCoreService { password = GBConfigService.get('STORAGE_PASSWORD'); } else if (this.dialect === 'sqlite') { storage = GBConfigService.get('STORAGE_FILE'); + + if (!Fs.existsSync(storage)){ + process.env.STORAGE_SYNC = 'true'; + } + + } else { throw new Error(`Unknown dialect: ${this.dialect}.`); } @@ -138,8 +145,8 @@ export class GBCoreService implements IGBCoreService { const logging: boolean | Function = GBConfigService.get('STORAGE_LOGGING') === 'true' ? (str: string): void => { - GBLogEx.info(0, str); - } + GBLogEx.info(0, str); + } : false; const encrypt: boolean = GBConfigService.get('STORAGE_ENCRYPT') === 'true'; @@ -231,12 +238,11 @@ export class GBCoreService implements IGBCoreService { return out; } - /** * Loads all items to start several listeners. */ public async loadInstances(): Promise { - if (process.env.LOAD_ONLY !== undefined) { + if (process.env.LOAD_ONLY) { const bots = process.env.LOAD_ONLY.split(`;`); const and = []; await CollectionUtil.asyncForEach(bots, async e => { @@ -426,12 +432,11 @@ ENDPOINT_UPDATE=true let instances: IGBInstance[]; try { instances = await core.loadInstances(); - const group = GBConfigService.get('CLOUD_GROUP')??GBConfigService.get('BOT_ID'); if (process.env.ENDPOINT_UPDATE === 'true') { + const group = GBConfigService.get('CLOUD_GROUP') ?? GBConfigService.get('BOT_ID'); await CollectionUtil.asyncForEach(instances, async instance => { GBLogEx.info(instance.instanceId, `Updating bot endpoint for ${instance.botId}...`); try { - await installationDeployer.updateBotProxy( instance.botId, group, @@ -459,7 +464,10 @@ ENDPOINT_UPDATE=true Try setting STORAGE_SYNC to true in .env file. Error: ${error.message}.` ); } else { - GBLogEx.info(0, `Storage is empty. After collecting storage structure from all .gbapps it will get synced.`); + GBLogEx.info( + 0, + `Storage is empty. After collecting storage structure from all .gbapps it will get synced.` + ); } } else { throw new Error(`Cannot connect to operating storage: ${error.message}.`); @@ -512,15 +520,8 @@ ENDPOINT_UPDATE=true * before starting the server. */ public ensureAdminIsSecured() { - const password = GBConfigService.get('ADMIN_PASS'); - if (!GBAdminService.StrongRegex.test(password)) { - throw new Error( - 'Please, define a really strong password in ADMIN_PASS environment variable before running the server.' - ); - } } - public async createBootInstance( core: GBCoreService, installationDeployer: IGBInstallationDeployer, @@ -529,9 +530,10 @@ ENDPOINT_UPDATE=true return await this.createBootInstanceEx( core, installationDeployer, - proxyAddress, null, - GBConfigService.get('FREE_TIER')); - + proxyAddress, + null, + GBConfigService.get('FREE_TIER') + ); } /** * Creates the first bot instance (boot instance) used to "boot" the server. @@ -548,8 +550,10 @@ ENDPOINT_UPDATE=true ) { GBLogEx.info(0, `Deploying cognitive infrastructure (on the cloud / on premises)...`); try { - const { instance, credentials, subscriptionId, installationDeployer } - = await StartDialog.createBaseInstance(deployer, freeTier); + const { instance, credentials, subscriptionId, installationDeployer } = await StartDialog.createBaseInstance( + deployer, + freeTier + ); installationDeployer['core'] = this; const changedInstance = await installationDeployer['deployFarm2']( proxyAddress, @@ -668,27 +672,26 @@ ENDPOINT_UPDATE=true } public async setConfig(min, name: string, value: any): Promise { - // Handles calls for BASIC persistence on sheet files. - GBLog.info( `Defining Config.xlsx variable ${name}= '${value}'...`); + GBLog.info(`Defining Config.xlsx variable ${name}= '${value}'...`); let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min); const maxLines = 512; - const file = "Config.xlsx"; - const path = DialogKeywords.getGBAIPath(min.botId, `gbot`);; + const file = 'Config.xlsx'; + const path = DialogKeywords.getGBAIPath(min.botId, `gbot`); - let document = await (new SystemKeywords()).internalGetDocument(client, baseUrl, path, file); + let document = await new SystemKeywords().internalGetDocument(client, baseUrl, path, file); - // Creates workbook session that will be discarded. + // Creates book session that will be discarded. - let sheets = await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`) - .get(); + let sheets = await client.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`).get(); let results = await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')`) + .api( + `${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')` + ) .get(); const rows = results.text; @@ -708,12 +711,12 @@ ENDPOINT_UPDATE=true body.values[0][0] = value; await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`) + .api( + `${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')` + ) .patch(body); } - - /** * Get a dynamic param from instance. Dynamic params are defined in Config.xlsx * and loaded into the work folder from comida command. @@ -729,8 +732,7 @@ ENDPOINT_UPDATE=true // Gets .gbot Params from specified bot. if (instance.params) { - - params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params); + params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params); params = GBUtil.caseInsensitive(params); value = params ? params[name] : defaultValue; } @@ -740,7 +742,6 @@ ENDPOINT_UPDATE=true params = GBUtil.caseInsensitive(instance['dataValues']); if (params && !value) { - // Retrieves the value from specified bot instance (no params collection). value = instance['dataValues'][name]; @@ -749,30 +750,26 @@ ENDPOINT_UPDATE=true const minBoot = GBServer.globals.minBoot as any; - if ( - minBoot.instance && - !value && instance.botId != minBoot.instance.botId) { - + if (minBoot.instance && !value && instance.botId != minBoot.instance.botId) { instance = minBoot.instance; - - if(instance.params){ - params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params); + + if (instance.params) { + params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params); params = GBUtil.caseInsensitive(params); value = params ? params[name] : defaultValue; } // If still did not found in boot bot params, try instance fields. - if (!value){ + if (!value) { value = instance['dataValues'][name]; } - if (!value){ + if (!value) { value = instance[name]; } - } } - + if (value === undefined) { value = null; } @@ -786,9 +783,9 @@ ENDPOINT_UPDATE=true if (value && typeof defaultValue === 'number') { return new Number(value ? value : defaultValue ? defaultValue : 0).valueOf(); } - - const ret = value ?? defaultValue; - return ret; + + const ret = value ?? defaultValue; + return ret; } /** @@ -798,7 +795,7 @@ ENDPOINT_UPDATE=true let params = null; const list = []; if (instance.params) { - params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params); + params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params); } Object.keys(params).forEach(e => { @@ -810,5 +807,79 @@ ENDPOINT_UPDATE=true return list; } + public async ensureFolders(instances, deployer: GBDeployer) { + let libraryPath = GBConfigService.get('STORAGE_LIBRARY'); + if (!Fs.existsSync(libraryPath)) { + mkdirp.sync(libraryPath); + } + + await this.syncBotStorage(instances, 'default', deployer, libraryPath); + + const files = Fs.readdirSync(libraryPath); + await CollectionUtil.asyncForEach(files, async file => { + + if (file.trim().toLowerCase() !== 'default.gbai'){ + + let botId = file.replace(/\.gbai/, ''); + + await this.syncBotStorage(instances, botId, deployer, libraryPath); + } + }); + } + + private async syncBotStorage(instances: any, botId: any, deployer: GBDeployer, libraryPath: string) { + let instance = instances.find(p => p.botId.toLowerCase().trim() === botId.toLowerCase().trim()); + + if (!instance) { + + GBLog.info(`Importing package ${botId}...`); + + // Creates a bot. + + let mobile = null, + email = null; + + instance = await deployer.deployBlankBot(botId, mobile, email); + const gbaiPath = Path.join(libraryPath, `${botId}.gbai`); + + if (!Fs.existsSync(gbaiPath)) { + + Fs.mkdirSync(gbaiPath, { recursive: true }); + + const base = Path.join(process.env.PWD, 'templates', 'default.gbai'); + + Fs.cpSync(Path.join(base, `default.gbkb`), Path.join(gbaiPath,`default.gbkb`), { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbot`), Path.join(gbaiPath, `default.gbot`), { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbtheme`), Path.join(gbaiPath, `default.gbtheme`), { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbdata`), Path.join(gbaiPath, `default.gbdata`), { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbdialog`), Path.join(gbaiPath, `default.gbdialog`), { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbdrive`), Path.join(gbaiPath, `default.gbdrive`), { + errorOnExist: false, + force: true, + recursive: true + }); + } + } + } } diff --git a/packages/core.gbapp/services/GBDeployer.ts b/packages/core.gbapp/services/GBDeployer.ts index ae63b6fd..7fec4b09 100644 --- a/packages/core.gbapp/services/GBDeployer.ts +++ b/packages/core.gbapp/services/GBDeployer.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -45,6 +45,8 @@ import { AzureSearch } from 'pragmatismo-io-framework'; import { CollectionUtil } from 'pragmatismo-io-framework'; import { GBServer } from '../../../src/app.js'; import { GBVMService } from '../../basic.gblib/services/GBVMService.js'; +import Excel from 'exceljs'; +import asyncPromise from 'async-promises'; import { GuaribasPackage } from '../models/GBModel.js'; import { GBAdminService } from './../../admin.gbapp/services/GBAdminService.js'; import { AzureDeployerService } from './../../azuredeployer.gbapp/services/AzureDeployerService.js'; @@ -118,7 +120,7 @@ export class GBDeployer implements IGBDeployer { ); const siteId = process.env.STORAGE_SITE_ID; - const libraryId = process.env.STORAGE_LIBRARY; + const libraryId = GBConfigService.get('STORAGE_LIBRARY'); const client = MicrosoftGraph.Client.init({ authProvider: done => { @@ -220,22 +222,24 @@ export class GBDeployer implements IGBDeployer { const instance = await this.importer.createBotInstance(botId); const bootInstance = GBServer.globals.bootInstance; - // Gets the access token to perform service operations. + if (GBConfigService.get('STORAGE_NAME')) { + // Gets the access token to perform service operations. - const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken']( - bootInstance.instanceId, - true - ); + const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken']( + bootInstance.instanceId, + true + ); - // Creates the MSFT application that will be associated to the bot. + // Creates the MSFT application that will be associated to the bot. - const service = await AzureDeployerService.createInstance(this); - const application = await service.createApplication(accessToken, botId); + const service = await AzureDeployerService.createInstance(this); + const application = await service.createApplication(accessToken, botId); + // Fills new instance base information and get App secret. - // Fills new instance base information and get App secret. + instance.marketplaceId = (application as any).appId; + instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id); + } - instance.marketplaceId = (application as any).appId; - instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id); instance.adminPass = GBAdminService.getRndPassword(); instance.title = botId; instance.activationCode = instance.botId.substring(0, 15); @@ -247,10 +251,17 @@ export class GBDeployer implements IGBDeployer { // Saves bot information to the store. await this.core.saveInstance(instance); + if (GBConfigService.get('STORAGE_NAME')) { + await this.deployBotOnAzure(instance, GBServer.globals.publicAddress); + } + + // Makes available bot to the channels and .gbui interfaces. + + await GBServer.globals.minService.mountBot(instance); // Creates remaining objects on the cloud and updates instance information. - return await this.deployBotFull(instance, GBServer.globals.publicAddress); + return instance; } /** @@ -265,7 +276,7 @@ export class GBDeployer implements IGBDeployer { /** * Performs all tasks of deploying a new bot on the cloud. */ - public async deployBotFull(instance: IGBInstance, publicAddress: string): Promise { + public async deployBotOnAzure(instance: IGBInstance, publicAddress: string): Promise { // Reads base configuration from environent file. const service = await AzureDeployerService.createInstance(this); @@ -286,7 +297,6 @@ export class GBDeployer implements IGBDeployer { `${publicAddress}/api/messages/${instance.botId}` ); } else { - // Internally create resources on cloud provider. instance = await service.internalDeployBot( @@ -305,11 +315,7 @@ export class GBDeployer implements IGBDeployer { subscriptionId ); - // Makes available bot to the channels and .gbui interfaces. - - await GBServer.globals.minService.mountBot(instance); - await GBServer.globals.minService.ensureAPI(); - } + } // Saves final instance object and returns it. @@ -326,7 +332,6 @@ export class GBDeployer implements IGBDeployer { let embedding; if (!azureOpenAIEmbeddingModel) { - return; } @@ -337,14 +342,13 @@ export class GBDeployer implements IGBDeployer { azureOpenAIApiVersion: azureOpenAIVersion, azureOpenAIApiInstanceName: azureOpenAIApiInstanceName }); - + try { vectorStore = await HNSWLib.load(min['vectorStorePath'], embedding); } catch { vectorStore = new HNSWLib(embedding, { space: 'cosine' }); - } return vectorStore; } @@ -412,70 +416,50 @@ export class GBDeployer implements IGBDeployer { public async deployBotFromLocalPath(localPath: string, publicAddress: string): Promise { const packageName = Path.basename(localPath); const instance = await this.importer.importIfNotExistsBotPackage(undefined, packageName, localPath); - await this.deployBotFull(instance, publicAddress); + await this.deployBotOnAzure(instance, publicAddress); } /** * Loads all para from tabular file Config.xlsx. */ - public async loadParamsFromTabular(min: GBMinInstance): Promise { - const siteId = process.env.STORAGE_SITE_ID; - const libraryId = process.env.STORAGE_LIBRARY; + public async loadParamsFromTabular(min: GBMinInstance, path): Promise { + const workbook = new Excel.Workbook(); + const data = await workbook.xlsx.readFile(Path.join(path, 'Config.xlsx')); - GBLogEx.info(min, `Connecting to Config.xslx (siteId: ${siteId}, libraryId: ${libraryId})...`); + let worksheet: any; + for (let t = 0; t < data.worksheets.length; t++) { + worksheet = data.worksheets[t]; + if (worksheet) { + break; + } + } + const rows = worksheet._rows; + GBLogEx.info(min, `Processing ${rows.length} rows from Config file ${path}...`); + let list = []; - // Connects to MSFT storage. + // Skips the header lines. - const token = await (min.adminService as any)['acquireElevatedToken'](min.instance.instanceId, true); + for (let index = 0; index < 6; index++) { + rows.shift(); + } + - const client = MicrosoftGraph.Client.init({ - authProvider: done => { - done(null, token); + let obj = {}; + await asyncPromise.eachSeries(rows, async line => { + + if (line && line._cells[0] && line._cells[1] && line._cells[0].text) { + + // Extracts values from columns in the current line. + + obj[line._cells[0].text] = line._cells[1].text; } }); - // Retrieves all files in .bot folder. - - const botId = min.instance.botId; - const path = DialogKeywords.getGBAIPath(botId, 'gbot'); - let url = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:/${path}:/children`; - - GBLogEx.info(min, `Loading .gbot from Excel: ${url}`); - const res = await client.api(url).get(); - - // Finds Config.xlsx. - - const document = res.value.filter(m => { - return m.name === 'Config.xlsx'; - }); - if (document === undefined || document.length === 0) { - GBLogEx.info(min, `Config.xlsx not found on .bot folder, check the package.`); - - return null; - } - - // Reads all rows in Config.xlsx that contains a pair of name/value - // and fills an object that is returned to be saved in params instance field. - - const results = await client - .api( - `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/items/${document[0].id}/workbook/worksheets('General')/range(address='A7:B100')` - ) - .get(); - let index = 0, - obj = {}; - for (; index < results.text.length; index++) { - if (results.text[index][0] === '') { - return obj; - } - obj[results.text[index][0]] = results.text[index][1]; - } - + GBLogEx.info(min, GBUtil.toYAML(list)); return obj; } /** - * Loads all para from tabular file Config.xlsx. */ public async downloadFolder( min: GBMinInstance, @@ -632,14 +616,7 @@ export class GBDeployer implements IGBDeployer { case '.gbot': // Extracts configuration information from .gbot files. - if (process.env.ENABLE_PARAMS_ONLINE === 'false') { - if (Fs.existsSync(localPath)) { - GBLogEx.info(min, `Loading .gbot from ${localPath}.`); - await this.deployBotFromLocalPath(localPath, GBServer.globals.publicAddress); - } - } else { - min.instance.params = await this.loadParamsFromTabular(min); - } + min.instance.params = await this.loadParamsFromTabular(min, localPath); let connections = []; diff --git a/packages/core.gbapp/services/GBImporterService.ts b/packages/core.gbapp/services/GBImporterService.ts index a29e6cda..b4376c16 100644 --- a/packages/core.gbapp/services/GBImporterService.ts +++ b/packages/core.gbapp/services/GBImporterService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/services/GBLogEx.ts b/packages/core.gbapp/services/GBLogEx.ts index 3a5b764c..0e26523f 100644 --- a/packages/core.gbapp/services/GBLogEx.ts +++ b/packages/core.gbapp/services/GBLogEx.ts @@ -1,13 +1,11 @@ /*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ _ _ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/ \ /`\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| |*| |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | -| | | ( )_) | | -| (_) \___/' | +| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® | +| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ | +| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | +| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -23,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index a926e654..f0eb1ce3 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | @@ -44,7 +44,9 @@ import Fs from 'fs'; import arrayBufferToBuffer from 'arraybuffer-to-buffer'; import { NlpManager } from 'node-nlp'; import Koa from 'koa'; +import { v2 as webdav } from 'webdav-server'; import { createRpcServer } from '@push-rpc/core'; +import { start as startRouter } from '../../../packages/core.gbapp/services/router/bridge.js'; import wash from 'washyourmouthoutwithsoap'; import { AutoSaveStateMiddleware, @@ -140,10 +142,7 @@ export class GBMinService { this.deployer = deployer; } - - public async enableAPI(min: GBMinInstance) { - - } + public async enableAPI(min: GBMinInstance) {} /** * Constructs a new minimal instance for each bot. @@ -168,25 +167,20 @@ export class GBMinService { let i = 1; - if (instances.length > 1) { - } - await CollectionUtil.asyncForEach( instances, (async instance => { + try { - GBLog.info(`Mounting ${instance.botId}...`) + GBLog.info(`Mounting ${instance.botId}...`); await this['mountBot'](instance); } catch (error) { GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`); } }).bind(this) + ); - // Loads API. - - await this.ensureAPI(); - // Loads schedules. GBLogEx.info(0, `Loading SET SCHEDULE entries...`); @@ -196,6 +190,37 @@ export class GBMinService { GBLogEx.info(0, `All Bot instances loaded.`); } + public async startSimpleTest(min) { + if (process.env.TEST_MESSAGE && min['isDefault']) { + GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`); + + const client = await GBUtil.getDirectLineClient(min); + + const response = await client.apis.Conversations.Conversations_StartConversation(); + const conversationId = response.obj.conversationId; + GBServer.globals.debugConversationId = conversationId; + + const steps = process.env.TEST_MESSAGE.split(';'); + + await CollectionUtil.asyncForEach(steps, async (step) => { + client.apis.Conversations.Conversations_PostActivity({ + conversationId: conversationId, + activity: { + textFormat: 'plain', + text: step, + type: 'message', + from: { + id: 'test', + name: 'test' + } + } + }); + + await GBUtil.sleep(3000); + }); + } + } + /** * Removes bot endpoint from web listeners and remove bot instance * from list of global server bot instances. @@ -234,7 +259,7 @@ export class GBMinService { /** * Unmounts the bot web site (default.gbui) secure domain, if any. */ - public async unloadDomain(instance: IGBInstance) { } + public async unloadDomain(instance: IGBInstance) {} /** * Mount the instance by creating an BOT Framework bot object, @@ -243,6 +268,7 @@ export class GBMinService { */ public async mountBot(instance: IGBInstance) { + // Build bot adapter. const { min, adapter, conversationState } = await this.buildBotAdapter( @@ -254,10 +280,14 @@ export class GBMinService { // https://github.com/GeneralBots/BotServer/issues/286 // min['groupCache'] = await KBService.getGroupReplies(instance.instanceId); + min['isDefault'] = GBServer.globals.minInstances.length === 0; + GBServer.globals.minInstances.push(min); const user = null; // No user context. - await this.deployer['deployPackage2'](min, user, 'packages/default.gbtheme'); + // Serves individual URL for each bot conversational interface. + + await this.deployer['deployPackage2'](min, user, 'templates/default.gbai/default.gbtheme'); // Install per bot deployed packages. @@ -318,21 +348,23 @@ export class GBMinService { mkdirp.sync(dir); } - // Loads Named Entity data for this bot. + if (!GBConfigService.get('STORAGE_NAME')) { + dir = Path.join(GBConfigService.get('STORAGE_LIBRARY'), 'work', gbai); - // TODO: await KBService.RefreshNER(min); + const server = GBServer.globals.webDavServer; + server.setFileSystem(`/${botId}`, new webdav.PhysicalFileSystem(dir), success => { + GBLogEx.info(1, `WebDav for ${botId} loaded.`); + }); + } // Calls the loadBot context.activity for all packages. await this.invokeLoadBot(min.appPackages, GBServer.globals.sysPackages, min); - - // Serves individual URL for each bot conversational interface. - const receiver = async (req, res) => { await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages); }; - const url = `/api/messages/${instance.botId}`; - GBServer.globals.server.post(url, receiver); + let url = `/api/messages/${instance.botId}`; + GBServer.globals.server.get(url, (req, res) => { if (req.query['hub.mode'] === 'subscribe') { if (req.query['hub.verify_token'] === process.env.FACEBOOK_VERIFY_TOKEN) { @@ -347,39 +379,6 @@ export class GBMinService { }); GBLog.verbose(`GeneralBots(${instance.engineName}) listening on: ${url}.`); - // Test code. - if (process.env.TEST_MESSAGE) { - GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`); - - const client = await new SwaggerClient({ - spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')), - requestInterceptor: req => { - req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; - } - }); - - const response = await client.apis.Conversations.Conversations_StartConversation(); - const conversationId = response.obj.conversationId; - GBServer.globals.debugConversationId = conversationId; - - const steps = process.env.TEST_MESSAGE.split(';'); - - await CollectionUtil.asyncForEach(steps, async step => { - client.apis.Conversations.Conversations_PostActivity({ - conversationId: conversationId, - activity: { - textFormat: 'plain', - text: step, - type: 'message', - from: { - id: 'test', - name: 'test' - } - } - }); - - await GBUtil.sleep(3000); - }); // Generates MS Teams manifest. @@ -390,7 +389,6 @@ export class GBMinService { const data = await this.deployer.getBotManifest(instance); Fs.writeFileSync(packageTeams, data); } - } // Serves individual URL for each bot user interface. @@ -426,37 +424,44 @@ export class GBMinService { // Setups official handler for WhatsApp. - GBServer.globals.server.all(`/${min.instance.botId}/whatsapp`, async (req, res) => { + GBServer.globals.server + .all(`/${min.instance.botId}/whatsapp`, async (req, res) => { + if (req.query['hub.mode'] === 'subscribe') { + const val = req.query['hub.verify_token']; + if (val === process.env.META_CHALLENGE) { + res.send(req.query['hub.challenge']); + res.status(200); + GBLogEx.info(min, `Meta callback OK. ${JSON.stringify(req.query)}`); + } else { + res.status(401); + } + res.end(); - if (req.query['hub.mode'] === 'subscribe') { - const val = req.query['hub.verify_token']; - - if (val === process.env.META_CHALLENGE) { - res.send(req.query['hub.challenge']); - res.status(200); - GBLogEx.info(min, `Meta callback OK. ${JSON.stringify(req.query)}`); - } else { - res.status(401); + return; } - res.end(); - return; - } + let whatsAppDirectLine = min.whatsAppDirectLine; - let whatsAppDirectLine = min.whatsAppDirectLine; + // Not meta, multiples bots on root bot. - // Not meta, multiples bots on root bot. + if (!req.body.object) { + const to = req.body.To.replace(/whatsapp\:\+/gi, ''); + whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to]; + } - if (!req.body.object) { - const to = req.body.To.replace(/whatsapp\:\+/gi, ''); - whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to]; - } - - await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId); - }).bind(min); + if (whatsAppDirectLine) { + await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId); + } + }) + .bind(min); GBDeployer.mountGBKBAssets(`${botId}.gbkb`, botId, `${botId}.gbkb`); + + // Loads API. + + await this.ensureAPI(); + } public static getProviderName(req: any, res: any) { @@ -510,9 +515,7 @@ export class GBMinService { * on https:////token URL. */ private handleOAuthTokenRequests(server: any, min: GBMinInstance, instance: IGBInstance) { - server.get(`/${min.instance.botId}/token`, async (req, res) => { - let tokenName = req.query['value']; if (!tokenName) { tokenName = ''; @@ -535,9 +538,7 @@ export class GBMinService { if (tokenName) { const code = req?.query?.code; - let url = urlJoin( - host, - tenant, 'oauth/token'); + let url = urlJoin(host, tenant, 'oauth/token'); let buff = new Buffer(`${clientId}:${clientSecret}`); const base64 = buff.toString('base64'); @@ -549,14 +550,14 @@ export class GBMinService { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ - 'grant_type': 'authorization_code', - 'code': code + grant_type: 'authorization_code', + code: code }) }; const result = await fetch(url, options); if (result.status != 200) { - throw new Error(`handleOAuthTokenRequests error: ${result.status}: ${result.statusText}.`) + throw new Error(`handleOAuthTokenRequests error: ${result.status}: ${result.statusText}.`); } const text = await result.text(); @@ -564,24 +565,31 @@ export class GBMinService { // Saves token to the database. - await this.adminService.setValue(instance.instanceId, - `${tokenName}accessToken`, token['accessToken'] ? token['accessToken'] : token['access_token']); - await this.adminService.setValue(instance.instanceId, - `${tokenName}refreshToken`, token['refreshToken'] ? token['refreshToken'] : token['refresh_token']); + await this.adminService.setValue( + instance.instanceId, + `${tokenName}accessToken`, + token['accessToken'] ? token['accessToken'] : token['access_token'] + ); + await this.adminService.setValue( + instance.instanceId, + `${tokenName}refreshToken`, + token['refreshToken'] ? token['refreshToken'] : token['refresh_token'] + ); - await this.adminService.setValue(instance.instanceId, - `${tokenName}expiresOn`, token['expiresOn'] ? - token['expiresOn'].toString() : - new Date(Date.now() + (token['expires_in'] * 1000)).toString()); + await this.adminService.setValue( + instance.instanceId, + `${tokenName}expiresOn`, + token['expiresOn'] + ? token['expiresOn'].toString() + : new Date(Date.now() + token['expires_in'] * 1000).toString() + ); await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null); - - - } - else { + } else { const authenticationContext = new AuthenticationContext.AuthenticationContext( urlJoin( tokenName ? host : min.instance.authenticatorAuthorityHostUrl, - tokenName ? tenant : min.instance.authenticatorTenant) + tokenName ? tenant : min.instance.authenticatorTenant + ) ); const resource = 'https://graph.microsoft.com'; @@ -595,26 +603,24 @@ export class GBMinService { tokenName ? clientSecret : instance.marketplacePassword, async (err, token) => { if (err) { - const msg = `handleOAuthTokenRequests: Error acquiring token: ${err}`; GBLog.error(msg); res.send(msg); - } else { - // Saves token to the database. await this.adminService.setValue(instance.instanceId, `${tokenName}accessToken`, token['accessToken']); await this.adminService.setValue(instance.instanceId, `${tokenName}refreshToken`, token['refreshToken']); - await this.adminService.setValue(instance.instanceId, `${tokenName}expiresOn`, token['expiresOn'].toString()); + await this.adminService.setValue( + instance.instanceId, + `${tokenName}expiresOn`, + token['expiresOn'].toString() + ); await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null); - } } ); - - } // Inform the home for default .gbui after finishing token retrival. @@ -633,8 +639,9 @@ export class GBMinService { min.instance.authenticatorTenant, '/oauth2/authorize' ); - authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${min.instance.marketplaceId - }&redirect_uri=${urlJoin(process.env.BOT_URL, min.instance.botId, 'token')}`; + authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${ + min.instance.marketplaceId + }&redirect_uri=${urlJoin(process.env.BOT_URL, min.instance.botId, 'token')}`; GBLogEx.info(min, `HandleOAuthRequests: ${authorizationUrl}.`); res.redirect(authorizationUrl); }); @@ -651,7 +658,6 @@ export class GBMinService { botId = GBConfigService.get('BOT_ID'); } - // Loads by the botId itself or by the activationCode field. let instance = await this.core.loadInstanceByBotId(botId); @@ -663,7 +669,6 @@ export class GBMinService { if (instance !== null) { // Gets the webchat token, speech token and theme. - const webchatTokenContainer = await this.getWebchatToken(instance); const speechToken = instance.speechKey != undefined ? await this.getSTSToken(instance) : null; let theme = instance.theme; @@ -673,29 +678,36 @@ export class GBMinService { theme = `default.gbtheme`; } - res.send( - JSON.stringify({ - instanceId: instance.instanceId, - botId: botId, - theme: theme, - webchatToken: webchatTokenContainer.token, - speechToken: speechToken, - conversationId: webchatTokenContainer.conversationId, - authenticatorTenant: instance.authenticatorTenant, - authenticatorClientId: instance.marketplaceId, - paramLogoImageUrl: this.core.getParam(instance, 'Logo Image Url', null), - paramLogoImageAlt: this.core.getParam(instance, 'Logo Image Alt', null), - paramLogoImageWidth: this.core.getParam(instance, 'Logo Image Width', null), - paramLogoImageHeight: this.core.getParam(instance, 'Logo Image Height', null), - paramLogoImageType: this.core.getParam(instance, 'Logo Image Type', null), - logo: this.core.getParam(instance, 'Logo', null), - color1: this.core.getParam(instance, 'Color1', null), - color2: this.core.getParam(instance, 'Color2', null), - - + let logo = this.core.getParam(instance, 'Logo', null); - }) - ); + logo = logo ? urlJoin(instance.botId, 'cache', logo) : 'images/logo-gb.png'; + + let config = { + instanceId: instance.instanceId, + botId: botId, + theme: theme, + speechToken: speechToken, + authenticatorTenant: instance.authenticatorTenant, + authenticatorClientId: instance.marketplaceId, + paramLogoImageUrl: this.core.getParam(instance, 'Logo Image Url', null), + paramLogoImageAlt: this.core.getParam(instance, 'Logo Image Alt', null), + paramLogoImageWidth: this.core.getParam(instance, 'Logo Image Width', null), + paramLogoImageHeight: this.core.getParam(instance, 'Logo Image Height', null), + paramLogoImageType: this.core.getParam(instance, 'Logo Image Type', null), + logo: logo, + color1: this.core.getParam(instance, 'Color1', null), + color2: this.core.getParam(instance, 'Color2', null) + }; + + if (!GBConfigService.get('STORAGE_NAME')) { + config['domain'] = `http://localhost:${process.env.PORT}/directline/${botId}`; + } else { + const webchatTokenContainer = await this.getWebchatToken(instance); + (config['conversationId'] = webchatTokenContainer.conversationId), + (config['webchatToken'] = webchatTokenContainer.token); + } + + res.send(JSON.stringify(config)); } else { const error = `Instance not found while retrieving from .gbui web client: ${botId}.`; res.sendStatus(error); @@ -753,12 +765,18 @@ export class GBMinService { private async buildBotAdapter(instance: any, sysPackages: IGBPackage[], appPackages: IGBPackage[]) { // MSFT stuff. - const adapter = new BotFrameworkAdapter({ + let config = { appId: instance.marketplaceId ? instance.marketplaceId : GBConfigService.get('MARKETPLACE_ID'), appPassword: instance.marketplacePassword ? instance.marketplacePassword : GBConfigService.get('MARKETPLACE_SECRET') - }); + }; + if (!GBConfigService.get('STORAGE_NAME')) { + startRouter(GBServer.globals.server, instance.botId); + config['clientOptions'] = { baseUri: `http://localhost:${process.env.PORT}` }; + } + + const adapter = new BotFrameworkAdapter(config); const storage = new MemoryStorage(); const conversationState = new ConversationState(storage); const userState = new UserState(storage); @@ -771,6 +789,28 @@ export class GBMinService { // The minimal bot is built here. const min = new GBMinInstance(); + + // Setups default BOT Framework dialogs. + + min.userProfile = conversationState.createProperty('userProfile'); + const dialogState = conversationState.createProperty('dialogState'); + + min.dialogs = new DialogSet(dialogState); + min.dialogs.add(new TextPrompt('textPrompt')); + min.dialogs.add(new AttachmentPrompt('attachmentPrompt')); + + min.dialogs.add(new ConfirmPrompt('confirmPrompt')); + if (process.env.ENABLE_AUTH) { + min.dialogs.add( + new OAuthPrompt('oAuthPrompt', { + connectionName: 'OAuth2', + text: 'Please sign in to General Bots.', + title: 'Sign in', + timeout: 300000 + }) + ); + } + min.botId = instance.botId; min.bot = adapter; min.userState = userState; @@ -793,6 +833,15 @@ export class GBMinService { min['apiConversations'] = {}; min.packages = sysPackages; + const receiver = async (req, res) => { + await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages); + }; + + let url = `/api/messages/${instance.botId}`; + GBServer.globals.server.post(url, receiver); + url = `/api/messages`; + GBServer.globals.server.post(url, receiver); + // NLP Manager. const manager = new NlpManager({ languages: ['pt'], forceNER: true }); @@ -802,7 +851,6 @@ export class GBMinService { GBServer.globals.minBoot = min; GBServer.globals.minBoot.instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID'); GBServer.globals.minBoot.instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET'); - } if (min.instance.facebookWorkplaceVerifyToken) { @@ -860,8 +908,7 @@ export class GBMinService { await min.whatsAppDirectLine.setup(true); } else { - if (min !== minBoot && minBoot.instance.whatsappServiceKey - && min.instance.webchatKey) { + if (min !== minBoot && minBoot.instance.whatsappServiceKey && min.instance.webchatKey) { min.whatsAppDirectLine = new WhatsappDirectLine( min, min.botId, @@ -882,26 +929,6 @@ export class GBMinService { WhatsappDirectLine.botsByNumber[botNumber] = min.whatsAppDirectLine; } - // Setups default BOT Framework dialogs. - - min.userProfile = conversationState.createProperty('userProfile'); - const dialogState = conversationState.createProperty('dialogState'); - - min.dialogs = new DialogSet(dialogState); - min.dialogs.add(new TextPrompt('textPrompt')); - min.dialogs.add(new AttachmentPrompt('attachmentPrompt')); - - min.dialogs.add(new ConfirmPrompt('confirmPrompt')); - if (process.env.ENABLE_AUTH) { - min.dialogs.add( - new OAuthPrompt('oAuthPrompt', { - connectionName: 'OAuth2', - text: 'Please sign in to General Bots.', - title: 'Sign in', - timeout: 300000 - }) - ); - } return { min, adapter, conversationState }; } @@ -1087,7 +1114,10 @@ export class GBMinService { const startDialog = min.core.getParam(min.instance, 'Start Dialog', null); if (startDialog) { await sec.setParam(userId, 'welcomed', 'true'); - GBLogEx.info(min, `Auto start (teams) dialog is now being called: ${startDialog} for ${min.instance.botId}...`); + GBLogEx.info( + min, + `Auto start (teams) dialog is now being called: ${startDialog} for ${min.instance.botId}...` + ); await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid); } } @@ -1095,7 +1125,8 @@ export class GBMinService { // Required for F0 handling of persisted conversations. - GBLogEx.info(min, + GBLogEx.info( + min, `Input> ${context.activity.text} (type: ${context.activity.type}, name: ${context.activity.name}, channelId: ${context.activity.channelId})` ); @@ -1104,7 +1135,6 @@ export class GBMinService { const startDialog = min.core.getParam(min.instance, 'Start Dialog', null); - if (context.activity.type === 'installationUpdate') { GBLogEx.info(min, `Bot installed on Teams.`); } else if (context.activity.type === 'conversationUpdate' && context.activity.membersAdded.length > 0) { @@ -1133,7 +1163,8 @@ export class GBMinService { ) { min['conversationWelcomed'][step.context.activity.conversation.id] = true; - GBLogEx.info(min, + GBLogEx.info( + min, `Auto start (web 1) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...` ); await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid); @@ -1147,7 +1178,6 @@ export class GBMinService { } else if (context.activity.type === 'message') { // Processes messages activities. - await this.processMessageActivity(context, min, step, pid); } else if (context.activity.type === 'event') { // Processes events activities. @@ -1155,8 +1185,9 @@ export class GBMinService { await this.processEventActivity(min, user, context, step); } } catch (error) { - const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${error.error ? (error.error.stack ? error.error.stack : '') : '' - }`; + const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${ + error.error ? (error.error.stack ? error.error.stack : '') : '' + }`; GBLog.error(msg); await min.conversationalService.sendText( @@ -1170,7 +1201,17 @@ export class GBMinService { }; try { - await adapter['processActivity'](req, res, handler); + if (!GBConfigService.get('STORAGE_NAME')) { + const context = adapter['createContext'](req); + context['_activity'] = context.activity.body; + await handler(context); + // Return status + res.status(200); + + res.end(); + } else { + await adapter['processActivity'](req, res, handler); + } } catch (error) { if (error.code === 401) { GBLog.error('Calling processActivity due to Signing Key could not be retrieved error.'); @@ -1209,7 +1250,10 @@ export class GBMinService { const startDialog = min.core.getParam(min.instance, 'Start Dialog', null); if (startDialog && !min['conversationWelcomed'][step.context.activity.conversation.id]) { user.welcomed = true; - GBLogEx.info(min, `Auto start (web 2) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`); + GBLogEx.info( + min, + `Auto start (web 2) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...` + ); await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid); } } else if (context.activity.name === 'updateToken') { @@ -1263,7 +1307,6 @@ export class GBMinService { } private async handleUploads(min, step, user, params, autoSave) { - // Prepare Promises to download each attachment and then execute each Promise. if ( @@ -1294,7 +1337,6 @@ export class GBMinService { GBServer.globals.files[handle] = gbfile; if (!min.cbMap[user.userId] && autoSave) { - const result = await t['internalAutoSave']({ min: min, handle: handle }); await min.conversationalService.sendText( min, @@ -1303,12 +1345,9 @@ export class GBMinService { ); return; - } - else { + } else { return gbfile; } - - } else { await this.sendActivity('Error uploading file. Please,start again.'); } @@ -1367,7 +1406,8 @@ export class GBMinService { context.activity.text = context.activity.text.trim(); const member = context.activity.from; - let memberId, email; + let memberId = null, + email = null; // Processes e-mail from id in case of Teams messages. @@ -1399,10 +1439,8 @@ export class GBMinService { 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(); @@ -1420,7 +1458,6 @@ export class GBMinService { userId, context.activity.text ); - } } @@ -1439,7 +1476,8 @@ export class GBMinService { ) { await sec.setParam(userId, 'welcomed', 'true'); min['conversationWelcomed'][step.context.activity.conversation.id] = true; - GBLogEx.info(min, + GBLogEx.info( + min, `Auto start (4) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...` ); await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid); @@ -1500,21 +1538,18 @@ export class GBMinService { } else { // Removes unwanted chars in input text. - step.context.activity['originalText'] = context.activity.text; const text = await GBConversationalService.handleText(min, user, step, context.activity.text); - step.context.activity['originalText'] + step.context.activity['originalText']; step.context.activity['text'] = text; - - if (notes && text && text !== "") { + if (notes && text && text !== '') { const sys = new SystemKeywords(); await sys.note({ pid, text }); await step.context.sendActivity('OK.'); return; } - // Checks for bad words on input text. const hasBadWord = wash.check(step.context.activity.locale, text); @@ -1549,7 +1584,7 @@ export class GBMinService { } } else { if (min.cbMap[userId] && min.cbMap[userId].promise === '!GBHEAR') { - min.cbMap[userId].promise = step.context.activity['originalText'];; + min.cbMap[userId].promise = step.context.activity['originalText']; } // If there is a dialog in course, continue to the next step. @@ -1557,8 +1592,9 @@ export class GBMinService { try { await step.continueDialog(); } catch (error) { - const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${error.error ? (error.error.stack ? error.error.stack : '') : '' - }`; + const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${ + error.error ? (error.error.stack ? error.error.stack : '') : '' + }`; GBLog.error(msg); await min.conversationalService.sendText( min, @@ -1601,7 +1637,6 @@ export class GBMinService { } public async ensureAPI() { - const mins = GBServer.globals.minInstances; function getRemoteId(ctx: Koa.Context) { @@ -1611,14 +1646,11 @@ export class GBMinService { const close = async () => { return new Promise(resolve => { if (GBServer.globals.server.apiServer) { - GBServer.globals.server.apiServer.close( - cb => { - resolve(true); - GBLogEx.info(0, 'Reloading General Bots API...'); - } - ); - } - else { + GBServer.globals.server.apiServer.close(cb => { + resolve(true); + GBLogEx.info(0, 'Reloading General Bots API...'); + }); + } else { resolve(true); GBLogEx.info(0, 'Loading General Bots API...'); } @@ -1629,11 +1661,9 @@ export class GBMinService { let proxies = {}; await CollectionUtil.asyncForEach(mins, async min => { - let dialogs = {}; await CollectionUtil.asyncForEach(Object.values(min.scriptMap), async script => { - - dialogs[script] = async (data) => { + dialogs[script] = async data => { let sec = new SecService(); const user = await sec.ensureUser( min, @@ -1649,13 +1679,7 @@ export class GBMinService { if (script === 'start') { pid = GBVMService.createProcessInfo(user, min, 'api', null); - - const client = await new SwaggerClient({ - spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')), - requestInterceptor: req => { - req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; - } - }); + const client = await GBUtil.getDirectLineClient(min); const response = await client.apis.Conversations.Conversations_StartConversation(); min['apiConversations'][pid] = { conversation: response.obj, client: client }; @@ -1668,7 +1692,7 @@ export class GBMinService { ret = pid; } return ret; - } + }; }); const proxy = { @@ -1686,10 +1710,10 @@ export class GBMinService { pingSendTimeout: null, keepAliveTimeout: null, listeners: { - unsubscribed(subscriptions: number): void { }, - subscribed(subscriptions: number): void { }, - disconnected(remoteId: string, connections: number): void { }, - connected(remoteId: string, connections: number): void { }, + unsubscribed(subscriptions: number): void {}, + subscribed(subscriptions: number): void {}, + disconnected(remoteId: string, connections: number): void {}, + connected(remoteId: string, connections: number): void {}, messageIn(...params): void { params.shift(); }, @@ -1699,16 +1723,8 @@ export class GBMinService { } }; - GBServer.globals.server.apiServer = createKoaHttpServer( - GBVMService.API_PORT, - getRemoteId, { prefix: `api/v3` }); - - createRpcServer( - proxies, - GBServer.globals.server.apiServer, - opts - ); + GBServer.globals.server.apiServer = createKoaHttpServer(GBVMService.API_PORT, getRemoteId, { prefix: `api/v3` }); + createRpcServer(proxies, GBServer.globals.server.apiServer, opts); } - -} \ No newline at end of file +} diff --git a/packages/core.gbapp/services/GBSSR.ts b/packages/core.gbapp/services/GBSSR.ts index ff0bbf69..0b58fccf 100644 --- a/packages/core.gbapp/services/GBSSR.ts +++ b/packages/core.gbapp/services/GBSSR.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/core.gbapp/services/router/bridge.ts b/packages/core.gbapp/services/router/bridge.ts new file mode 100644 index 00000000..07ad1e4b --- /dev/null +++ b/packages/core.gbapp/services/router/bridge.ts @@ -0,0 +1,360 @@ +import bodyParser from 'body-parser'; +import express from 'express'; +import fetch from 'isomorphic-fetch'; +import moment from 'moment'; +import * as uuidv4 from 'uuid'; + +import { IActivity, IBotData, IConversation, IConversationUpdateActivity, IMessageActivity } from './types'; +import { GBConfigService } from '../GBConfigService.js'; + +const expiresIn = 1800; +const conversationsCleanupInterval = 10000; +const conversations: { [key: string]: IConversation } = {}; +const botDataStore: { [key: string]: IBotData } = {}; + +export const getRouter = ( + serviceUrl: string, + botUrl: string, + conversationInitRequired = true, + botId +): express.Router => { + const router = express.Router(); + + router.use(bodyParser.json()); // for parsing application/json + router.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded + router.use((req, res, next) => { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, PATCH, OPTIONS'); + res.header( + 'Access-Control-Allow-Headers', + 'Origin, X-Requested-With, Content-Type, Accept, Authorization, x-ms-bot-agent' + ); + next(); + }); + + // CLIENT ENDPOINT + router.options(`/directline/${botId}/`, (req, res) => { + res.status(200).end(); + }); + + // Creates a conversation + const reqs = (req, res) => { + const conversationId: string = uuidv4.v4().toString(); + conversations[conversationId] = { + conversationId, + history: [] + }; + console.log('Created conversation with conversationId: ' + conversationId); + + const activity = createConversationUpdateActivity(serviceUrl, conversationId); + fetch(botUrl, { + method: 'POST', + body: JSON.stringify(activity), + headers: { + 'Content-Type': 'application/json' + } + }).then(response => { + res.status(response.status).send({ + conversationId, + expiresIn + }); + }); + }; + + router.post('/v3/directline/conversations', reqs); + router.post(`/directline/${botId}/conversations`, reqs); + router.post(`/directline/conversations`, reqs); + + // Reconnect API + router.get('/v3/directline/conversations/:conversationId', (req, res) => { + const conversation = getConversation(req.params.conversationId, conversationInitRequired); + if (conversation) { + res.status(200).send(conversation); + } else { + // Conversation was never initialized + res.status(400).send(); + } + + console.warn('/v3/directline/conversations/:conversationId not implemented'); + }); + + // Gets activities from store (local history array for now) + router.get(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => { + const watermark = req.query.watermark && req.query.watermark !== 'null' ? Number(req.query.watermark) : 0; + + const conversation = getConversation(req.params.conversationId, conversationInitRequired); + + if (conversation) { + // If the bot has pushed anything into the history array + if (conversation.history.length > watermark) { + const activities = conversation.history.slice(watermark); + res.status(200).json({ + activities, + watermark: watermark + activities.length + }); + } else { + res.status(200).send({ + activities: [], + watermark + }); + } + } else { + // Conversation was never initialized + res.status(400).send(); + } + }); + + // Sends message to bot. Assumes message activities + router.post(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => { + const incomingActivity = req.body; + // Make copy of activity. Add required fields + const activity = createMessageActivity(incomingActivity, serviceUrl, req.params.conversationId); + + const conversation = getConversation(req.params.conversationId, conversationInitRequired); + + if (conversation) { + conversation.history.push(activity); + fetch(botUrl, { + method: 'POST', + body: JSON.stringify(activity), + headers: { + 'Content-Type': 'application/json' + } + }).then(response => { + res.status(response.status).json({ id: activity.id }); + }); + } else { + // Conversation was never initialized + res.status(400).send(); + } + }); + + router.post('/v3/directline/conversations/:conversationId/upload', (req, res) => { + console.warn('/v3/directline/conversations/:conversationId/upload not implemented'); + }); + router.get('/v3/directline/conversations/:conversationId/stream', (req, res) => { + console.warn('/v3/directline/conversations/:conversationId/stream not implemented'); + }); + + // BOT CONVERSATION ENDPOINT + + router.post('/v3/conversations', (req, res) => { + console.warn('/v3/conversations not implemented'); + }); + + router.post('/v3/conversations/:conversationId/activities', (req, res) => { + let activity: IActivity; + + activity = req.body; + activity.id = uuidv4.v4(); + activity.from = { id: 'id', name: 'Bot' }; + + const conversation = getConversation(req.params.conversationId, conversationInitRequired); + if (conversation) { + conversation.history.push(activity); + res.status(200).send(); + } else { + // Conversation was never initialized + res.status(400).send(); + } + }); + + router.post('/v3/conversations/:conversationId/activities/:activityId', (req, res) => { + let activity: IActivity; + + activity = req.body; + activity.id = uuidv4.v4(); + activity.from = { id: 'id', name: 'Bot' }; + + const conversation = getConversation(req.params.conversationId, conversationInitRequired); + if (conversation) { + conversation.history.push(activity); + res.status(200).send(); + } else { + // Conversation was never initialized + res.status(400).send(); + } + }); + + router.get('/v3/conversations/:conversationId/members', (req, res) => { + console.warn('/v3/conversations/:conversationId/members not implemented'); + }); + router.get('/v3/conversations/:conversationId/activities/:activityId/members', (req, res) => { + console.warn('/v3/conversations/:conversationId/activities/:activityId/members'); + }); + + // BOTSTATE ENDPOINT + + router.get('/v3/botstate/:channelId/users/:userId', (req, res) => { + console.log('Called GET user data'); + getBotData(req, res); + }); + + router.get('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => { + console.log('Called GET conversation data'); + getBotData(req, res); + }); + + router.get('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => { + console.log('Called GET private conversation data'); + getBotData(req, res); + }); + + router.post('/v3/botstate/:channelId/users/:userId', (req, res) => { + console.log('Called POST setUserData'); + setUserData(req, res); + }); + + router.post('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => { + console.log('Called POST setConversationData'); + setConversationData(req, res); + }); + + router.post('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => { + setPrivateConversationData(req, res); + }); + + router.delete('/v3/botstate/:channelId/users/:userId', (req, res) => { + console.log('Called DELETE deleteStateForUser'); + deleteStateForUser(req, res); + }); + + return router; +}; + +/** + * @param app The express app where your offline-directline endpoint will live + * @param port The port where your offline-directline will be hosted + * @param botUrl The url of the bot (e.g. http://127.0.0.1:3978/api/messages) + * @param conversationInitRequired Requires that a conversation is initialized before it is accessed, returning a 400 + * when not the case. If set to false, a new conversation reference is created on the fly. This is true by default. + */ +export const initializeRoutes = ( + app: express.Express, + port: number, + botUrl: string, + conversationInitRequired = true, + botId +) => { + conversationsCleanup(); + + const directLineEndpoint = `http://127.0.0.1:${port}`; + const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired, botId); + + app.use(router); +}; + +const getConversation = (conversationId: string, conversationInitRequired: boolean) => { + // Create conversation on the fly when needed and init not required + if (!conversations[conversationId] && !conversationInitRequired) { + conversations[conversationId] = { + conversationId, + history: [] + }; + } + return conversations[conversationId]; +}; + +const getBotDataKey = (channelId: string, conversationId: string, userId: string) => { + return `$${channelId || '*'}!${conversationId || '*'}!${userId || '*'}`; +}; + +const setBotData = (channelId: string, conversationId: string, userId: string, incomingData: IBotData): IBotData => { + const key = getBotDataKey(channelId, conversationId, userId); + const newData: IBotData = { + eTag: new Date().getTime().toString(), + data: incomingData.data + }; + + if (incomingData) { + botDataStore[key] = newData; + } else { + delete botDataStore[key]; + newData.eTag = '*'; + } + + return newData; +}; + +const getBotData = (req: express.Request, res: express.Response) => { + const key = getBotDataKey(req.params.channelId, req.params.conversationId, req.params.userId); + console.log('Data key: ' + key); + + res.status(200).send(botDataStore[key] || { data: null, eTag: '*' }); +}; + +const setUserData = (req: express.Request, res: express.Response) => { + res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body)); +}; + +const setConversationData = (req: express.Request, res: express.Response) => { + res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body)); +}; + +const setPrivateConversationData = (req: express.Request, res: express.Response) => { + res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body)); +}; + +export const start = (server, botId) => { + const port = GBConfigService.getServerPort(); + initializeRoutes(server, Number(port), `http://127.0.0.1:${port}/api/messages/${botId}`, null, botId); + + if (botId === 'default') { + initializeRoutes(server, Number(port), `http://127.0.0.1:${port}/api/messages`, null, botId); + } +}; + +const deleteStateForUser = (req: express.Request, res: express.Response) => { + Object.keys(botDataStore).forEach(key => { + if (key.endsWith(`!{req.query.userId}`)) { + delete botDataStore[key]; + } + }); + res.status(200).send(); +}; + +// CLIENT ENDPOINT HELPERS +const createMessageActivity = ( + incomingActivity: IMessageActivity, + serviceUrl: string, + conversationId: string +): IMessageActivity => { + return { + ...incomingActivity, + channelId: 'emulator', + serviceUrl, + conversation: { id: conversationId }, + id: uuidv4.v4() + }; +}; + +const createConversationUpdateActivity = (serviceUrl: string, conversationId: string): IConversationUpdateActivity => { + const activity: IConversationUpdateActivity = { + type: 'conversationUpdate', + channelId: 'emulator', + serviceUrl, + conversation: { id: conversationId }, + id: uuidv4.v4(), + membersAdded: [], + membersRemoved: [], + from: { id: 'offline-directline', name: 'Offline Directline Server' } + }; + return activity; +}; + +const conversationsCleanup = () => { + setInterval(() => { + const expiresTime = moment().subtract(expiresIn, 'seconds'); + Object.keys(conversations).forEach(conversationId => { + if (conversations[conversationId].history.length > 0) { + const lastTime = moment( + conversations[conversationId].history[conversations[conversationId].history.length - 1].localTimestamp + ); + if (lastTime < expiresTime) { + delete conversations[conversationId]; + console.log('deleted cId: ' + conversationId); + } + } + }); + }, conversationsCleanupInterval); +}; diff --git a/packages/core.gbapp/services/router/types.ts b/packages/core.gbapp/services/router/types.ts new file mode 100644 index 00000000..f6e6f4a9 --- /dev/null +++ b/packages/core.gbapp/services/router/types.ts @@ -0,0 +1,66 @@ +export interface IUser { + id: string, + name: string +} + +export interface IChannelAccount { + id?: string, + name?: string, +} + +export interface IConversationAccount extends IChannelAccount { + isGroup?: boolean, +} + +export interface IAttachment { + contentType?: string, + contentUrl?: string, + content?: any, + name?: string, + thumbnailUrl?: string, +} + +export interface IEntity { + type?: string, +} + +export interface IActivity { + type?: string, + id?: string, + serviceUrl?: string, + timestamp?: string, + localTimestamp?: string, + channelId?: string, + from?: IChannelAccount, + conversation?: IConversationAccount, + recipient?: IChannelAccount, + replyToId?: string, + channelData?: any, +} + +export interface IMessageActivity extends IActivity { + locale?: string, + text?: string, + summary?: string, + textFormat?: string, + attachmentLayout?: string, + attachments?: IAttachment[], + entities?: IEntity[], +} + +export interface IBotData { + eTag: string; + data: any; +} + +export interface IConversation { + conversationId: string, + history?: IActivity[] +} + +export interface IConversationUpdateActivity extends IActivity { + membersAdded?: IChannelAccount[], + membersRemoved?: IChannelAccount[], + topicName?: string, + historyDisclosed?: boolean, +} \ No newline at end of file diff --git a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts index 4df8ca44..2d8e2e1a 100644 --- a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts +++ b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/customer-satisfaction.gbapp/dialogs/QualityDialog.ts b/packages/customer-satisfaction.gbapp/dialogs/QualityDialog.ts index e4a06b0e..c713dac5 100644 --- a/packages/customer-satisfaction.gbapp/dialogs/QualityDialog.ts +++ b/packages/customer-satisfaction.gbapp/dialogs/QualityDialog.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/customer-satisfaction.gbapp/index.ts b/packages/customer-satisfaction.gbapp/index.ts index fd459aba..15c080aa 100644 --- a/packages/customer-satisfaction.gbapp/index.ts +++ b/packages/customer-satisfaction.gbapp/index.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/customer-satisfaction.gbapp/models/index.ts b/packages/customer-satisfaction.gbapp/models/index.ts index 39814ab0..4231ee96 100644 --- a/packages/customer-satisfaction.gbapp/models/index.ts +++ b/packages/customer-satisfaction.gbapp/models/index.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/customer-satisfaction.gbapp/services/CSService.ts b/packages/customer-satisfaction.gbapp/services/CSService.ts index 278086a5..c7cb0811 100644 --- a/packages/customer-satisfaction.gbapp/services/CSService.ts +++ b/packages/customer-satisfaction.gbapp/services/CSService.ts @@ -5,7 +5,7 @@ | ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ | | █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ | | | -| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | +| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. | | Licensed under the AGPL-3.0. | | | | According to our dual licensing model, this program can be used either | @@ -21,7 +21,7 @@ | 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.cloud. | +| "General Bots" is a registered trademark of pragmatismo.cloud. | | 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. | diff --git a/packages/default.gbdialog/bot.vbs.gbignore b/packages/default.gbdialog/bot.vbs.gbignore deleted file mode 100644 index 7a6734c2..00000000 --- a/packages/default.gbdialog/bot.vbs.gbignore +++ /dev/null @@ -1,77 +0,0 @@ -' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0. -' Rules from http://jsfiddle.net/roderick/dym05hsy - -talk "How many installments do you want to pay your Credit?" -hear installments - -if installments > 60 then - talk "The maximum number of payments is 60" -else - talk "What is the amount requested?" - hear amount - - if amount >100000 then - talk "We are sorry, we can only accept proposals bellow 100k" - else - - talk "What is the best due date?" - hear dueDate - - interestRate = 0 - adjustment = 0 - - if installments < 12 then - interestRate = 1.60 - adjustment = 0.09748 - end if - - if installments > 12 and installments < 18 then - interestRate = 1.66 - adjustment = 0.06869 - end if - - if installments > 18 and installments < 36 then - interestRate = 1.64 - adjustment = 0.05397 - end if - - if installments > 36 and installments < 48 then - interestRate = 1.62 - adjustment = 0.03931 - end if - - if installments > 48 and installments < 60 then - interestRate = 1.70 - adjustment = 0.03270 - end if - - if installments = 60 then - interestRate = 1.79 - adjustment = 0.02916 - end if - - if installments > 60 then - talk "The maximum number of payments is 60" - end if - - nInstallments = parseInt(installments) - vamount = parseFloat(amount) - initialPayment = vamount * 0.3 ' 30% of the value - tac = 800 - adjustment = 1.3 - - totalValue = amount - initialPayment + tac - paymentValue = totalValue * adjustment - finalValue = paymentValue * nInstallments + initialPayment - - talk "Congratulations! Your credit analysis is **done**:" - talk "First payment: **" + initialPayment + "**" - talk "Payment value: **" + paymentValue + "**" - talk "Interest Rate: **" + interestRate + "%**" - talk "Total Value: **" + totalValue + "**" - talk "Final Value: **" + finalValue + "**" - - - - end if -end if diff --git a/packages/default.gbdialog/delivery.vbs.gbignore b/packages/default.gbdialog/delivery.vbs.gbignore deleted file mode 100644 index e119cda2..00000000 --- a/packages/default.gbdialog/delivery.vbs.gbignore +++ /dev/null @@ -1,50 +0,0 @@ -' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0. - -talk "Quer pagar quanto?" -hear amount - -talk "Para onde?" -hear address - -if amount < 5 then - talk "O mínimo que vendo este produto é 5." -else - - if address is in "Rio" then - get payment amount - delivery to address - else - talk "Vou ver se tenho um parceiro para entregar aí e te falo. Eu só entrego no Rio." - end if -end if - -talk "Valeu!" - - - -Falar "Qual seu nome?" -Ouvir nome - -Falar "Informe seu CEP, por favor:" -Ouvir CEP - -Address = CEP - -Confira seu endereço: - -Address.Street -Address.Number - - -Falar "Manda sua localização para eu pedir a alguém para sair agora com o seu pedido" -Hear Location - -SAve "Pedidos.xlsx", Nome, From, Location.Street, Location.Number - - - -Falar "Manda sua localização que eu encontro o posto mais próximo" -Hear Location - -Find "Postos.xlsx", "Endereço=" + Location - \ No newline at end of file diff --git a/packages/default.gbdialog/find-on-excel.vbs b/packages/default.gbdialog/find-on-excel.vbs deleted file mode 100644 index a8418aa0..00000000 --- a/packages/default.gbdialog/find-on-excel.vbs +++ /dev/null @@ -1,29 +0,0 @@ - - -if consulta = "cpf" then - talk "Qual seu CPF?" - hear cpf - talk "Aguarde alguns instantes que eu localizo seu cadastro..." - row = find "Cadastro.xlsx", "CPF=" + cpf - if row != null then - talk "Oi, " + row.Nome + "Tudo bem? " - talk "Seu código de cliente é " + row.Cod - talk "Vamos te enviar o pedido para seu endereço em: " + row.Endereço - send file "boleta.pdf", "Pague já e evite multas!" - else - talk "Tente novamente." - end if -else - talk "Qual seria seu código?" - hear cod - talk "Aguarde alguns instantes que eu localizo seu cadastro..." - row = find "Cadastro.xlsx", "Cod=" + cod - if row != null then - talk "Oi, " + row.Nome + "Tudo bem? " - talk "Seu CPF é " + row.CPF - talk "Vamos te enviar o pedido para seu endereço em: " + row.Endereço - send file "boleta.pdf", "Pague já e evite multas!" - else - talk "Tente novamente." - end if -end if diff --git a/packages/default.gbdialog/find-or-talk.vbs.gbignore b/packages/default.gbdialog/find-or-talk.vbs.gbignore deleted file mode 100644 index 084b0bf1..00000000 --- a/packages/default.gbdialog/find-or-talk.vbs.gbignore +++ /dev/null @@ -1,5 +0,0 @@ -talk “Olá! Seja bem vinda(o)!” - -X = find “campanhas.xlsx”, “nome=1239” OR TALK “Desculpe-me, não localizei seu nome.” - -talk “opa, vamos lá!” + x.nome diff --git a/packages/default.gbdialog/get-payment.vbs.gbignore b/packages/default.gbdialog/get-payment.vbs.gbignore deleted file mode 100644 index 75ea3531..00000000 --- a/packages/default.gbdialog/get-payment.vbs.gbignore +++ /dev/null @@ -1,12 +0,0 @@ -' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0. - -talk "Quer pagar quanto?" -hear amount - -if amount < 5 then - talk "O mínimo que vendo este produto é 5." -else - get payment amount -end if - -talk "Valeu!" \ No newline at end of file diff --git a/packages/default.gbdialog/get-set-excel.vbs b/packages/default.gbdialog/get-set-excel.vbs deleted file mode 100644 index 40e024d7..00000000 --- a/packages/default.gbdialog/get-set-excel.vbs +++ /dev/null @@ -1,9 +0,0 @@ -value = get "list.xslx", "A1:A1" - -set "list.xslx", "A1:A1", "value" - -myVar = find "chamadosbug748.xlsx", "CHAMADO=" + "5521979047667-44129-10" -status="alterado" -set "chamadosbug748.xlsx", "E" + myVar.line + ":E" + myVar.line, status -res = get "chamadosbug748.xlsx", "E" + myVar.line + ":E" + myVar.line -talk "Obrigado e até a próxima e veja bem, o resultado é esse: " + res diff --git a/packages/default.gbdialog/http-get-and-post.vbs b/packages/default.gbdialog/http-get-and-post.vbs deleted file mode 100644 index 8454dfd7..00000000 --- a/packages/default.gbdialog/http-get-and-post.vbs +++ /dev/null @@ -1,6 +0,0 @@ - -user = get "http://server/path" - -user = post "http://server/path", "data" - -Talk “ The user area is” + user.area, user.validuser, user.user \ No newline at end of file diff --git a/packages/default.gbdialog/lab.vbs.gbignore b/packages/default.gbdialog/lab.vbs.gbignore deleted file mode 100644 index d07d07df..00000000 --- a/packages/default.gbdialog/lab.vbs.gbignore +++ /dev/null @@ -1,26 +0,0 @@ -talk "Qual seu pedido?" -hear pedido -talk "Qual seu e-mail?" -hear email -talk "Obrigado, seu pedido será processado e retornamos." -ask payment - - -talk "Qual seu pedido?" -hear pedido -talk "Obrigado. Agora informe seu nome:" -Hear nome -Talk "Obrigado" + nome + "! Agora falta saber onde vamos entregar. Qual seu endereço?" -Hear endereço -Save "BistroBot.gbdata\pedidos.xlsx", nome, pedido, endereço, phone -Talk "Aguarde, enquanto eu calculo o valor total do seu pedido. Volto em alguns minutos, aguarde!" -Total = Ask "+5521999995555", "Qual o valor para o pedido da(o)" + nome +"?" -ask payment Total - -Talk "Qual seunome? " -Hear nome -Talk "Qual o valor pedido?" -Hear pedido -Save "Contoso.gbdata\ Aprovações.xlsx", nome, pedido, phone -Ask "+5521999995555", "Aprove por favor o pedido tal " -Talk "Sua aprovação foi enviada, aguarde." diff --git a/packages/default.gbdialog/save-on-excel.vbs.gbignore b/packages/default.gbdialog/save-on-excel.vbs.gbignore deleted file mode 100644 index 27504192..00000000 --- a/packages/default.gbdialog/save-on-excel.vbs.gbignore +++ /dev/null @@ -1,11 +0,0 @@ - -talk "O seu nome, por favor?" -hear nome - -talk "Qual seu pedido?" -hear details - -talk "Valeu " + nome + "! Agora falta saber onde vamos entregar. \nQual seu endereço?" -hear address - -save "Pedidos.xlsx", id, nome, from, address, details, today diff --git a/packages/default.gbdialog/sys-bot-farm-creation.vbs.gbignore b/packages/default.gbdialog/sys-bot-farm-creation.vbs.gbignore deleted file mode 100644 index 95a20666..00000000 --- a/packages/default.gbdialog/sys-bot-farm-creation.vbs.gbignore +++ /dev/null @@ -1,37 +0,0 @@ -' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0. - -talk "Please, tell me what is the Bot name?" -hear title - -talk "If you tell me your username/password, I can show service subscription list to you." -talk "What is your Username (eg.: human@domain.bot)" -hear email - -talk "What is your Password" -hear password - -talk "Your password? (Will be discarded after sigining process)" -talk "Can you describe in a few words what the bot is about?" -hear description - -talk "Please, paste the Subscription ID (Azure):" -hear subscriptionId - -talk "Please, provide the cloud location just like 'westus'?" -hear location - -talk "Please, provide the Authoring Key for NLP service (LUIS)?" -hear authoringKey - -talk "Sorry, this part cannot be automated yet due to Microsoft schedule, please go to https://apps.dev.microsoft.com/portal/register-app to generate manually an App ID and App Secret." -wait 5 - -talk "Please, provide the App ID you just generated:" -hear appId - -talk "Please, provide the Generated Password:" -hear appPassword - -talk "Now, I am going to create a Bot farm... Wait 5 minutes or more..." - -create a bot farm using title, email, password, location, authoringKey, appId, appPassword, subscriptionId diff --git a/packages/default.gbdialog/templates.vbs b/packages/default.gbdialog/templates.vbs deleted file mode 100644 index 55cccb41..00000000 --- a/packages/default.gbdialog/templates.vbs +++ /dev/null @@ -1,25 +0,0 @@ - - -talk "qual seu nome?" -hear nome -talk "qual seu e-mail?" -hear email - -documento = "meutemplate.docx", nome, email, - -send file documento - -save file documento, "curriculos/nome" + ".docx" - -' $name - -'$trabalho - -'Experiência -'$ano1 -'$oquefoifeitoAno1 -'$ano2 -'$oquefoifeitoAno2 -'$ano3 -'$oquefoifeitoAno1 - diff --git a/packages/default.gbdialog/translator.gbignore b/packages/default.gbdialog/translator.gbignore deleted file mode 100644 index bbd32df1..00000000 --- a/packages/default.gbdialog/translator.gbignore +++ /dev/null @@ -1,13 +0,0 @@ -rem hi - -talk "Qual seu nome?" -hear name - -talk "Qual seu CPF?" -hear CPF - -talk "Por que você abrirá este chamado?" -hear translated motivo - -talk "Seu nome: " + name -talk "Você disse em Português " + motivo. \ No newline at end of file diff --git a/packages/default.gbkb/draft.md b/packages/default.gbkb/draft.md deleted file mode 100644 index 3e56b0b6..00000000 --- a/packages/default.gbkb/draft.md +++ /dev/null @@ -1,3 +0,0 @@ - ltimas notcias - Contato - Ofertas diff --git a/packages/default.gbkb/package.json b/packages/default.gbkb/package.json deleted file mode 100644 index 6d8fb717..00000000 --- a/packages/default.gbkb/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "botId":"pragmatismo-ai-prd", - "version": "1.0.0", - "description": "Bot pragmatismo.", - "license": "Private" -} \ No newline at end of file diff --git a/packages/default.gbkb/subjects.json b/packages/default.gbkb/subjects.json deleted file mode 100644 index 0afc084b..00000000 --- a/packages/default.gbkb/subjects.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "children": [ - { - "title": "Bots & AI", - "description": "Bots & inteligência artificial.", - "id": "bots-ai", - "children": [ - { - "title": "General Bots", - "description": "Plataforma de bots da pragmatismo.cloud.", - "id": "general-bots" - }, - { - "title": "Cortana Intelligence Suite", - "description": "Suite de Big Data da Microsoft.", - "id": "cortana" - } - ] - }, - { - "title": "Produtividade", - "description": "Artigos sobre sistemas Internos.", - "id": "produtividade", - "children": [ - { - "title": "Microsoft Project Online", - "description": "Artigos sobre o Microsoft Project Online.", - "id": "msproject" - }, - { - "title": "SharePoint", - "description": "SharePoint, sites e serviços.", - "id": "sharepoint" - }, - { - "title": "Office 365", - "description": "Plataforma colaborativa moderna da Microsoft.", - "id": "office365" - }, - { - "title": "Microsoft Dynamics", - "description": "Artigos sobre plataforma de CRM da Microsoft.", - "id": "msdynamics" - }, - { - "title": "Power BI", - "description": "Dashboards modernos e intuitivos.", - "id": "powerbi" - } - ] - }, - { - "title": "Sobre", - "description": "Artigos sobre o Bot da pragmatismo.cloud", - "id": "sobre" - } - ] -} \ No newline at end of file diff --git a/packages/default.gbkb/subjects/bots-ai.png b/packages/default.gbkb/subjects/bots-ai.png deleted file mode 100644 index 5c9197f7..00000000 Binary files a/packages/default.gbkb/subjects/bots-ai.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/cortana.png b/packages/default.gbkb/subjects/cortana.png deleted file mode 100644 index 96445174..00000000 Binary files a/packages/default.gbkb/subjects/cortana.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/general-bots.png b/packages/default.gbkb/subjects/general-bots.png deleted file mode 100644 index 1a68418e..00000000 Binary files a/packages/default.gbkb/subjects/general-bots.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/msdynamics.png b/packages/default.gbkb/subjects/msdynamics.png deleted file mode 100644 index 6076c093..00000000 Binary files a/packages/default.gbkb/subjects/msdynamics.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/msproject.png b/packages/default.gbkb/subjects/msproject.png deleted file mode 100644 index 7df4e3d1..00000000 Binary files a/packages/default.gbkb/subjects/msproject.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/office365.png b/packages/default.gbkb/subjects/office365.png deleted file mode 100644 index f9aae394..00000000 Binary files a/packages/default.gbkb/subjects/office365.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/powerbi.png b/packages/default.gbkb/subjects/powerbi.png deleted file mode 100644 index f9aae394..00000000 Binary files a/packages/default.gbkb/subjects/powerbi.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/produtividade.png b/packages/default.gbkb/subjects/produtividade.png deleted file mode 100644 index 8e4d6c1a..00000000 Binary files a/packages/default.gbkb/subjects/produtividade.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/sharepoint.png b/packages/default.gbkb/subjects/sharepoint.png deleted file mode 100644 index a1423ae9..00000000 Binary files a/packages/default.gbkb/subjects/sharepoint.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/skype.png b/packages/default.gbkb/subjects/skype.png deleted file mode 100644 index 7ee1402e..00000000 Binary files a/packages/default.gbkb/subjects/skype.png and /dev/null differ diff --git a/packages/default.gbkb/subjects/sobre.png b/packages/default.gbkb/subjects/sobre.png deleted file mode 100644 index 9e0f1b76..00000000 Binary files a/packages/default.gbkb/subjects/sobre.png and /dev/null differ diff --git a/packages/default.gbkb/tabular/min.tsv b/packages/default.gbkb/tabular/min.tsv deleted file mode 100644 index 7eca9c7a..00000000 Binary files a/packages/default.gbkb/tabular/min.tsv and /dev/null differ diff --git a/packages/default.gbtest/first-test.xlsx b/packages/default.gbtest/first-test.xlsx deleted file mode 100644 index a6bad648..00000000 Binary files a/packages/default.gbtest/first-test.xlsx and /dev/null differ diff --git a/packages/default.gbtheme/css/App.css b/packages/default.gbtheme/css/App.css deleted file mode 100644 index 5fa8a7c5..00000000 --- a/packages/default.gbtheme/css/App.css +++ /dev/null @@ -1,171 +0,0 @@ -body { - background-color: #dadada !important; -} - -.loader { - opacity: 1 !important; - filter: opacity(100%); -} - - -.gb-quality-button-yes { - width: 54px; - text-decoration: none; - text-transform: uppercase; - background-color: green; - color: white; - padding: 2px; - cursor: pointer; - transition: 0.9s; - transition-delay: 0.3s; - border: none; -} - -.gb-quality-button-no { - width: 54px; - text-decoration: none; - text-transform: uppercase; - background-color: red; - color: white; - padding: 2px; - cursor: pointer; - transition: 0.9s; - transition-delay: 0.3s; - border: none; -} - -.gb-markdown-player-quality { - background-color: #f5e4a8; - padding: 4px; - position: absolute; - bottom: 14px; - left: -9px; - width: 100%; - border-radius: 5px; - color: #52514e; - border: 1px solid #b2a46e; - text-align: center; -} - -.media-player { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif !important; -} - -.media-player-container { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; -} - -.media-player-link { - cursor: pointer !important; -} - -.gb-bullet-player { - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif !important; - background: white; - height: 95%; - overflow-y: scroll; -} - -.gb-bullet-player-item { - cursor: pointer; -} - -.gb-image-player-outter-div {} - -.gb-image-player-img {} - -.gb-bullet-player-outter-div {} - -.gb-video-player-wrapper { - width: 100%; - height: 100%; -} - -.gb-video-react-player { - - position: relative; - left: 50%; - transform: translateX(-50%); -} - -body { - display: flex; -} - -.App { - min-height: 100vh; -} - -.App .body { - display: flex; - flex-direction: row; -} - -.body { - flex-basis: 12em; - /* Default value of the element before distribuing the remaing space */ - flex-grow: 0; - /* Defined the ability to groe */ - flex-shrink: 0; - /* Defines the ability to shrink */ - max-width: 12em; - order: -1; -} - -body { - margin: 0; - overflow: hidden; -} - -.media-player-container { - overflow: auto; - max-height: 90%; - font-family: "Open Sans", sans-serif; - background: white; -} - -.media-player-scroll { - height: 1500px; -} - -@media screen and (max-width: 1000px) { - .media-player-scroll h1 { - font-size: 15px; - } - .media-player-scroll p { - font-size: 12px; - } - .media-player-scroll li { - font-size: 12px; - } -} - -@media screen and (max-width: 451px) { - .media-player { - position: relative; - zoom: 90%; - height: 94% !important; - width: 95% !important; - background-repeat: no-repeat; - margin-top: 10px; - margin-left: 10px; - margin-right: -40px; - } - .gb-markdown-player-quality { - bottom: -1px; - left: -3px; - } -} - -@media screen and (min-width: 451px) { - .media-player { - position: relative; - zoom: 90%; - height: 100% !important; - width: 95% !important; - background-repeat: no-repeat; - margin-top: 10px; - margin-left: 20px; - margin-right: -40px; - } -} \ No newline at end of file diff --git a/packages/default.gbtheme/css/ChatPane.css b/packages/default.gbtheme/css/ChatPane.css deleted file mode 100644 index 42ad5bc5..00000000 --- a/packages/default.gbtheme/css/ChatPane.css +++ /dev/null @@ -1,47 +0,0 @@ -.webchat > div { - height: 100%; - width: 100%; -} - -.webchat { - background-color: white !important; - left: 57%; - right: 0%; - top: 0; - bottom: 0; - overflow: auto !important; -} - -@media screen and (max-width: 1000px) { - .webchat { - display: inline-block !important; - width: 96% !important; - height: 57% !important; - font-family: 'Open Sans', sans-serif; - font-size: 14px; - left: 50%; - top: 41%; - - position: absolute; - margin-left: -48%; - } -} - -@media screen and (min-width: 1000px) { - .webchat { - display: inline-block !important; - width: 50% !important; - font-family: 'Open Sans', sans-serif; - font-size: 14px; - top: 1% !important; - - height: 96%; - position: absolute; - right: 0; - margin-left: -8%; - position: absolute; - top: 0; - bottom: 0; - border-bottom: 4px solid #4f4f4f; - } -} diff --git a/packages/default.gbtheme/css/Content.css b/packages/default.gbtheme/css/Content.css deleted file mode 100644 index 987a3986..00000000 --- a/packages/default.gbtheme/css/Content.css +++ /dev/null @@ -1,18 +0,0 @@ -.body .container { padding: 1em;width: 100%;height: 100% } - -.body .ms-Breadcrumb { - margin-bottom: 1em; - margin-top: 0; -} - -.body .selection { - height: calc(100vh - 16.5em); - overflow-x: auto; -} - -.body .selection .selection-item { - display: flex; - padding: 0.5em; -} - -.body .selection .selection-item .name { margin-left: 1em; } diff --git a/packages/default.gbtheme/css/Footer.css b/packages/default.gbtheme/css/Footer.css deleted file mode 100644 index 3033d6d4..00000000 --- a/packages/default.gbtheme/css/Footer.css +++ /dev/null @@ -1,8 +0,0 @@ -.footer { - align-items: center; - background-color: #450a64; - display: flex; - justify-content: center; -} - -.footer-container { color: white; } \ No newline at end of file diff --git a/packages/default.gbtheme/css/GifPlayer.css b/packages/default.gbtheme/css/GifPlayer.css deleted file mode 100644 index 727c752a..00000000 --- a/packages/default.gbtheme/css/GifPlayer.css +++ /dev/null @@ -1,31 +0,0 @@ -@media screen and (max-width: 1000px) { - .player { - width: 93% !important; - height: 26% !important; - border: 7px solid #272727; - position: absolute; - top: 9%; - left: 50%; - margin-left: -48%; - background: url(../images/general-bot-background.jpg), WHITE; - background-repeat: no-repeat; - background-size: contain; - background-position: center; - } -} - -@media screen and (min-width: 1000px) { - .player { - display: inline-block; - width: 46% !important; - height: 81% !important; - border: 7px solid #272727; - background: url(../images/general-bot-background.jpg), WHITE; - background-repeat: no-repeat; - background-size: contain; - background-position: center; - position: absolute; - left: 1%; - top: 15%; - } -} \ No newline at end of file diff --git a/packages/default.gbtheme/css/MediaPlayer.css b/packages/default.gbtheme/css/MediaPlayer.css deleted file mode 100644 index a193c839..00000000 --- a/packages/default.gbtheme/css/MediaPlayer.css +++ /dev/null @@ -1,7 +0,0 @@ -.media { - margin-top: 20px; - height: 280px !important; - width: 200px !important; - - } - diff --git a/packages/default.gbtheme/css/NavBar.css b/packages/default.gbtheme/css/NavBar.css deleted file mode 100644 index 6aa3d64e..00000000 --- a/packages/default.gbtheme/css/NavBar.css +++ /dev/null @@ -1,22 +0,0 @@ -.NavBar { - align-items: center; - display: flex; - justify-content: space-between; - padding: 0.2em 0.5em; - border-bottom-width: 1px; - color:black; - height: 100%; -} - -/* -.logo { - padding-top: 4em; -} -*/ - -.NavBar .searchbox { width: 20em; } - -.NavBar .searchbox .ms-SearchBox { - background-color: white; - margin-bottom: 0; -} diff --git a/packages/default.gbtheme/css/SideBarMenu.css b/packages/default.gbtheme/css/SideBarMenu.css deleted file mode 100644 index b1de09f1..00000000 --- a/packages/default.gbtheme/css/SideBarMenu.css +++ /dev/null @@ -1,199 +0,0 @@ -.ms-Nav { - background: #222; - color: white; - margin-top: 20px; -} - -.ms-Nav-link { - color: white !important; - background-color: #222222 !important; -} - -.ms-Nav-link a:active { - border-right: 2px solid white; -} - -.ms-Nav-compositeLink .ms-Nav-chevronButton.ms-Nav-chevronButton--link { - background: #222222 !important; -} - -.ms-Nav-compositeLink.is-selected .ms-Nav-chevronButton, -.ms-Nav-compositeLink.is-selected a { - padding-left: 70px !important; -} - -html[dir="ltr"] .ms-Nav-compositeLink.is-selected .ms-Nav-chevronButton:after, -html[dir="ltr"] .ms-Nav-compositeLink.is-selected a:after { - border-left: none !important; -} - -@media screen and (max-width: 419px) { - .sidebar { - display: inline-block !important; - background-color: #3f3f3f !important; - height: 8%; - width: 100% !important; - position: absolute; - top: 0; - left: 0; - } - - .tittleSideBarMenu { - display: none; - } - - .iconMenu { - color: #d1d1d1; - font-size: 13px; - display: inline; - margin-right: 20px; - } - .iconMenu:hover { - color: white; - } - - .IconsMenu { - position: absolute; - top: 50%; - margin-top: -23px; - height: 22px; - width: 300px; - left: 50%; - margin-left: -150px; - text-align: center; - font-family: "Open Sans", sans-serif; - } - - .iconText { - cursor: pointer; - } -} - -@media screen and (min-width: 520px) and (max-width:1000px) { - .tittleSideBarMenu { - display: none; - } - .sidebar { - display: inline-block !important; - background-color: #3f3f3f !important; - height: 8%; - width: 100% !important; - position: absolute; - top: 0; - left: 0; - background-image: url(../images/bot-logo.png); - background-position: 2px 2px; - background-repeat: no-repeat; - background-size: contain; - } - .IconsMenu { - position: absolute; - top: 50%; - margin-top: -11px; - height: 22px; - width: 416px; - left: 100px !important; - margin-left: 0px !important; - text-align: center; - font-family: "Open Sans", sans-serif; - } - .iconMenu { - color: #d1d1d1; - } - .iconMenu:hover { - color: white; - } -} - -@media screen and (min-width: 420px) and (max-width: 1000px) { - .sidebar { - display: inline-block !important; - background-color: #3f3f3f !important; - height: 8%; - width: 100% !important; - position: absolute; - top: 0; - left: 0; - } - .tittleSideBarMenu { - display: none; - } - - .iconMenu { - color: #d1d1d1; - font-size: 14px; - display: inline; - margin-right: 20px; - } - .iconMenu:hover { - color: white; - } - - .IconsMenu { - position: absolute; - top: 50%; - margin-top: -11px; - height: 22px; - width: 416px; - left: 50%; - margin-left: -208px; - text-align: center; - font-family: "Open Sans", sans-serif; - } - - .iconText { - cursor: pointer; - } -} - - -@media screen and (min-width: 1000px) { - .sidebar { - display: inline-block !important; - background-color: #3f3f3f !important; - height: 15%; - position: absolute; - top: 1%; - left: 1%; - width: 46% !important; - border-right: 14px solid #3f3f3f !important; - } - - .tittleSideBarMenu { - color: white; - text-align: center; - } - - .iconMenu { - color: #d1d1d1; - font-size: 14px; - text-align: center; - margin-right: 20px; - margin-left: 20px; - } - .iconMenu:hover { - color: white; - } - - .IconsMenu { - width: 520px; - display: inline-flex; - position: absolute; - left: 50%; - margin-left: -249px; - bottom: 10px; - height: 22px; - font-family: "Open Sans", sans-serif; - } - - .iconText { - cursor: pointer; - } -} - - - -.iconText:hover { - cursor: pointer; - -} \ No newline at end of file diff --git a/packages/default.gbtheme/css/index.css b/packages/default.gbtheme/css/index.css deleted file mode 100644 index a0f01045..00000000 --- a/packages/default.gbtheme/css/index.css +++ /dev/null @@ -1,41 +0,0 @@ -body { - font-family: 'Open Sans', sans-serif; - font-size: 14px; - margin: 0; - padding: 0; -} - - - -/** Main Layout rules */ - -.App { min-height: 100vh; } - -.App { - display: flex; - flex: 1; - flex-direction: column; -} - -.App .body { - display: flex; - flex: 1; - flex-direction: row; -} - -.body .sidebar { order: -1; } - -.body .content { flex: 1; } - -.body .sidebar { - flex: 0 0 12em; - max-width: 12em; -} - -.App .header { height: 4em; } - -.App .footer { height: 4em; } - -/** Text */ - -.text-red { color: red; } \ No newline at end of file diff --git a/packages/default.gbtheme/css/webchat-style.json b/packages/default.gbtheme/css/webchat-style.json deleted file mode 100644 index a731280a..00000000 --- a/packages/default.gbtheme/css/webchat-style.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "accent": "Red", - "avatarSize": 40, - - "backgroundColor": "White", - - "bubbleBackground": "White", - "bubbleBorder": "solid 1px #E6E6E6", - "bubbleBorderRadius": 2, - "bubbleFromUserBackground": "White", - "bubbleFromUserBorder": "solid 1px #E6E6E6", - "bubbleFromUserBorderRadius": 2, - "bubbleFromUserTextColor": "Black", - "bubbleImageHeight": 240, - "bubbleMaxWidth": 480, - "bubbleMinHeight": 40, - "bubbleMinWidth": 250, - "bubbleTextColor": "Black", - - "hideSendBox": false, - - "microphoneButtonColorOnDictate": "#F33", - - "paddingRegular": 10, - "paddingWide": 20, - - "sendBoxButtonColor": "#999", - "sendBoxButtonColorOnDisabled": "#CCC", - "sendBoxButtonColorOnFocus": "#333", - "sendBoxButtonColorOnHover": "#333", - - "sendBoxHeight": 40, - - "showSpokenText": false, - - "suggestedActionBackground": "White", - "suggestedActionBorder": "solid 2px", - "suggestedActionBorderRadius": 0, - "suggestedActionDisabledBackground": "White", - "suggestedActionDisabledBorder": "solid 2px #E6E6E6", - "suggestedActionHeight": 40, - "transcriptOverlayButtonBackground": "rgba(0, 0, 0, .6)", - "transcriptOverlayButtonBackgroundOnFocus": "rgba(0, 0, 0, .8)", - "transcriptOverlayButtonBackgroundOnHover": "rgba(0, 0, 0, .8)", - "transcriptOverlayButtonColor": "White", - "transcriptOverlayButtonColorOnFocus": "White", - "transcriptOverlayButtonColorOnHover": "White", - - "videoHeight": 270 -} diff --git a/packages/default.gbtheme/images/bot-logo-chat.png b/packages/default.gbtheme/images/bot-logo-chat.png deleted file mode 100644 index eff66af3..00000000 Binary files a/packages/default.gbtheme/images/bot-logo-chat.png and /dev/null differ diff --git a/packages/default.gbtheme/images/bot-logo.png b/packages/default.gbtheme/images/bot-logo.png deleted file mode 100644 index 68f43a6c..00000000 Binary files a/packages/default.gbtheme/images/bot-logo.png and /dev/null differ diff --git a/packages/default.gbtheme/images/bot-tv-on.png b/packages/default.gbtheme/images/bot-tv-on.png deleted file mode 100644 index 3dc4d075..00000000 Binary files a/packages/default.gbtheme/images/bot-tv-on.png and /dev/null differ diff --git a/packages/default.gbtheme/images/bot-tv-on2.png b/packages/default.gbtheme/images/bot-tv-on2.png deleted file mode 100644 index 3feffa66..00000000 Binary files a/packages/default.gbtheme/images/bot-tv-on2.png and /dev/null differ diff --git a/packages/default.gbtheme/images/bot-tv.png b/packages/default.gbtheme/images/bot-tv.png deleted file mode 100644 index ddb76e8c..00000000 Binary files a/packages/default.gbtheme/images/bot-tv.png and /dev/null differ diff --git a/packages/default.gbtheme/images/chat-background.png b/packages/default.gbtheme/images/chat-background.png deleted file mode 100644 index df3a0645..00000000 Binary files a/packages/default.gbtheme/images/chat-background.png and /dev/null differ diff --git a/packages/default.gbtheme/images/chat-header-logo.png b/packages/default.gbtheme/images/chat-header-logo.png deleted file mode 100644 index 60a4b6cb..00000000 Binary files a/packages/default.gbtheme/images/chat-header-logo.png and /dev/null differ diff --git a/packages/default.gbtheme/images/chat-header.png b/packages/default.gbtheme/images/chat-header.png deleted file mode 100644 index 12375d90..00000000 Binary files a/packages/default.gbtheme/images/chat-header.png and /dev/null differ diff --git a/packages/default.gbtheme/images/general-bot-background.jpg b/packages/default.gbtheme/images/general-bot-background.jpg deleted file mode 100644 index bb82ff17..00000000 Binary files a/packages/default.gbtheme/images/general-bot-background.jpg and /dev/null differ diff --git a/packages/default.gbtheme/images/logo-Pragmatismo.png b/packages/default.gbtheme/images/logo-Pragmatismo.png deleted file mode 100644 index 27c055cf..00000000 Binary files a/packages/default.gbtheme/images/logo-Pragmatismo.png and /dev/null differ diff --git a/packages/default.gbtheme/images/logo.jpg b/packages/default.gbtheme/images/logo.jpg deleted file mode 100644 index 80af5455..00000000 Binary files a/packages/default.gbtheme/images/logo.jpg and /dev/null differ diff --git a/packages/default.gbtheme/images/pragmatismo-logo.png b/packages/default.gbtheme/images/pragmatismo-logo.png deleted file mode 100644 index af20dea8..00000000 Binary files a/packages/default.gbtheme/images/pragmatismo-logo.png and /dev/null differ diff --git a/packages/default.gbtheme/images/pragmatismo-powered-by.png b/packages/default.gbtheme/images/pragmatismo-powered-by.png deleted file mode 100644 index ed6242f4..00000000 Binary files a/packages/default.gbtheme/images/pragmatismo-powered-by.png and /dev/null differ diff --git a/packages/default.gbtheme/images/projector-background.jpg b/packages/default.gbtheme/images/projector-background.jpg deleted file mode 100644 index 8b70a5de..00000000 Binary files a/packages/default.gbtheme/images/projector-background.jpg and /dev/null differ diff --git a/packages/default.gbtheme/images/projetor_tela.png b/packages/default.gbtheme/images/projetor_tela.png deleted file mode 100644 index b984ff5a..00000000 Binary files a/packages/default.gbtheme/images/projetor_tela.png and /dev/null differ diff --git a/packages/default.gbtheme/images/screen.png b/packages/default.gbtheme/images/screen.png deleted file mode 100644 index 7ecac2d8..00000000 Binary files a/packages/default.gbtheme/images/screen.png and /dev/null differ diff --git a/packages/default.gbtheme/images/tela-01.png b/packages/default.gbtheme/images/tela-01.png deleted file mode 100644 index 2b596533..00000000 Binary files a/packages/default.gbtheme/images/tela-01.png and /dev/null differ diff --git a/packages/default.gbtheme/package.json b/packages/default.gbtheme/package.json deleted file mode 100644 index 45d5f79f..00000000 --- a/packages/default.gbtheme/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": "1.0.0", - "description": "Default General Bots theme.", - "authors": "pragmatismo.cloud", - "license": "AGPL-3.0" - -} \ No newline at end of file diff --git a/packages/default.gbui/public/index.html b/packages/default.gbui/public/index.html index bcbc9559..3aba650e 100644 --- a/packages/default.gbui/public/index.html +++ b/packages/default.gbui/public/index.html @@ -1,13 +1,12 @@ @@ -48,7 +48,7 @@ - + {title} - General Bots Community Edition