Merge branch 'main' of https://github.com/GeneralBots/BotServer
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						| 
						 | 
				
			
			@ -29,3 +29,4 @@ package-lock.json
 | 
			
		|||
yarn-lock.json
 | 
			
		||||
logo.svg
 | 
			
		||||
screenshot.png
 | 
			
		||||
data.db
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										47
									
								
								.test-init.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -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}};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}`;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<string> {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    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<string>(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<void> { }
 | 
			
		||||
  public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise<void> {}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
   
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -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',
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +138,6 @@ export class GBVMService extends GBService {
 | 
			
		|||
    // 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<boolean>(
 | 
			
		||||
        min.instance,
 | 
			
		||||
        'Synchronize Database',
 | 
			
		||||
        false
 | 
			
		||||
      );
 | 
			
		||||
      const shouldSync = min.core.getParam<boolean>(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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -414,19 +401,21 @@ export class GBVMService extends GBService {
 | 
			
		|||
          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<string>(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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}...`);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
|                                                                             |
 | 
			
		||||
\*****************************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								packages/basic.gblib/tests/DialogKeywords.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -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");
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										43
									
								
								packages/basic.gblib/tests/GBVMService.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -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"
 | 
			
		||||
      }});      
 | 
			
		||||
   
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										36
									
								
								packages/basic.gblib/tests/SystemKeywords.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -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'
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<any> {
 | 
			
		||||
 | 
			
		||||
    if (step.context.activity.channelId !== 'msteams' && step.context.activity.channelId !== 'omnichannel') {
 | 
			
		||||
      GBLogEx.info(
 | 
			
		||||
        min,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<IGBInstance[]> {
 | 
			
		||||
    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<any> {
 | 
			
		||||
 | 
			
		||||
    // 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,27 +750,23 @@ 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];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -787,7 +784,7 @@ ENDPOINT_UPDATE=true
 | 
			
		|||
      return new Number(value ? value : defaultValue ? defaultValue : 0).valueOf();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const ret =  value ?? defaultValue;
 | 
			
		||||
    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
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<IGBInstance> {
 | 
			
		||||
  public async deployBotOnAzure(instance: IGBInstance, publicAddress: string): Promise<IGBInstance> {
 | 
			
		||||
    // 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,10 +315,6 @@ 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -344,7 +349,6 @@ export class GBDeployer implements IGBDeployer {
 | 
			
		|||
      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<void> {
 | 
			
		||||
    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<any> {
 | 
			
		||||
    const siteId = process.env.STORAGE_SITE_ID;
 | 
			
		||||
    const libraryId = process.env.STORAGE_LIBRARY;
 | 
			
		||||
  public async loadParamsFromTabular(min: GBMinInstance, path): Promise<any> {
 | 
			
		||||
    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 = [];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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://<gbhost>/<BotId>/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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										360
									
								
								packages/core.gbapp/services/router/bridge.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -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);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										66
									
								
								packages/core.gbapp/services/router/types.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
				
			
			@ -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,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.                                     |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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 
 | 
			
		||||
| 
						 | 
				
			
			@ -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!"
 | 
			
		||||
| 
						 | 
				
			
			@ -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 
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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." 
 | 
			
		||||
| 
						 | 
				
			
			@ -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 
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +0,0 @@
 | 
			
		|||
	Últimas notícias 
 | 
			
		||||
	Contato
 | 
			
		||||
	Ofertas
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
{
 | 
			
		||||
    "botId":"pragmatismo-ai-prd",
 | 
			
		||||
    "version": "1.0.0",
 | 
			
		||||
    "description": "Bot pragmatismo.",
 | 
			
		||||
    "license": "Private"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 3.8 KiB  | 
| 
		 Before Width: | Height: | Size: 12 KiB  | 
| 
		 Before Width: | Height: | Size: 18 KiB  | 
| 
		 Before Width: | Height: | Size: 10 KiB  | 
| 
		 Before Width: | Height: | Size: 2.8 KiB  | 
| 
		 Before Width: | Height: | Size: 8.8 KiB  | 
| 
		 Before Width: | Height: | Size: 8.8 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 3.9 KiB  | 
| 
		 Before Width: | Height: | Size: 5.1 KiB  | 
| 
		 Before Width: | Height: | Size: 2 KiB  | 
		
		
			
  | 
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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; }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
.footer {
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    background-color: #450a64;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.footer-container { color: white; }
 | 
			
		||||
| 
						 | 
				
			
			@ -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%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
.media { 
 | 
			
		||||
    margin-top: 20px; 
 | 
			
		||||
        height: 280px !important;
 | 
			
		||||
    width: 200px !important;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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; }
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 16 KiB  | 
| 
		 Before Width: | Height: | Size: 25 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 18 KiB  | 
| 
		 Before Width: | Height: | Size: 70 KiB  | 
| 
		 Before Width: | Height: | Size: 25 KiB  | 
| 
		 Before Width: | Height: | Size: 17 KiB  | 
| 
		 Before Width: | Height: | Size: 18 KiB  | 
| 
		 Before Width: | Height: | Size: 48 KiB  | 
| 
		 Before Width: | Height: | Size: 958 B  |