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 |