Migration to Rust removal of Azure.
|
|
@ -1,10 +1,10 @@
|
|||
name: GBCI
|
||||
run: git config --global http.sslVerify false
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['main']
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ['main']
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
@ -16,30 +16,21 @@ jobs:
|
|||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# - name: Setup Node.js
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: '20'
|
||||
# cache: 'npm'
|
||||
- name: Install Rust
|
||||
uses: msrd0/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Copy files to deployment location
|
||||
- name: Run build
|
||||
run: |
|
||||
echo "[General Bots Deployer] Copying files to deploy location..."
|
||||
sudo rm -rf /opt/gbo/bin/bot/botserver/dist
|
||||
sudo rm -f /opt/gbo/bin/bot/botserver/package-lock.json
|
||||
sudo cp -r ./* /opt/gbo/bin/bot/botserver
|
||||
sudo cp /opt/gbo/bin/system/.env .
|
||||
cargo build --locked
|
||||
|
||||
- name: Building BotServer
|
||||
- name: Deploy binary and restart
|
||||
run: |
|
||||
echo "[General Bots Deployer] Building BotServer..."
|
||||
lxc exec bot:pragmatismo-system -- systemctl stop system
|
||||
|
||||
rm -rf /opt/gbo/bin/bot/botserver/node_modules
|
||||
cd /opt/gbo/bin/bot/botserver
|
||||
sudo npm i
|
||||
npm run build-server
|
||||
npm run build-gbui
|
||||
sudo cp ./target/debug/gbserver /opt/gbo/bin/system
|
||||
sudo chmod +x /opt/gbo/bin/system/gbserver
|
||||
|
||||
- name: Restart Bots Deployer
|
||||
run: |
|
||||
echo "[General Bots Deployer] Restarting..."
|
||||
lxc restart pragmatismo-bot
|
||||
lxc exec bot:pragmatismo-system -- systemctl start system
|
||||
|
|
|
|||
28
.gitignore
vendored
|
|
@ -1,28 +1,4 @@
|
|||
/.coveralls.yml
|
||||
/.env
|
||||
/.npmrc
|
||||
/.nyc_output
|
||||
/coverage
|
||||
/dist
|
||||
/docs
|
||||
/guaribas.sqlite
|
||||
/node_modules
|
||||
/packages/default.gbui/build
|
||||
/packages/default.gbui/.env
|
||||
/packages/default.gbui/node_modules
|
||||
/packages/default.gbui/package-lock.json
|
||||
/packages/default.gbui/yarn-lock.json
|
||||
/work
|
||||
*.vbs.compiled
|
||||
*.vbs.js
|
||||
*.vbs.ts
|
||||
target
|
||||
.env
|
||||
*.env
|
||||
.vscode/launch.json
|
||||
.wwebjs_auth
|
||||
yarn-error.log
|
||||
yarn-lock.json
|
||||
logo.svg
|
||||
screenshot.png
|
||||
data.db
|
||||
.wwebjs_cache
|
||||
work
|
||||
|
|
|
|||
9
.hintrc
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"extends": [
|
||||
"development"
|
||||
],
|
||||
"hints": {
|
||||
"typescript-config/strict": "off",
|
||||
"typescript-config/consistent-casing": "off"
|
||||
}
|
||||
}
|
||||
15
.npmignore
|
|
@ -1,15 +0,0 @@
|
|||
# This file must be a copy of .gitignore except for the WILLSHIP commented lines below.
|
||||
/.coveralls.yml
|
||||
/.env
|
||||
/.npmrc
|
||||
# WILLSHIP /.nyc_output
|
||||
/coverage
|
||||
# WILLSHIP /dist
|
||||
/guaribas.log
|
||||
/guaribas.sqlite
|
||||
/node_modules
|
||||
# WILLSHIP /packages/default.gbui/build
|
||||
/packages/default.gbui/.env
|
||||
/packages/default.gbui/node_modules
|
||||
/tmp
|
||||
/work
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120,
|
||||
"arrowParens": "avoid",
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
import { expect, test } from 'vitest';
|
||||
import { GBServer } from './src/app';
|
||||
import { RootData } from './src/RootData';
|
||||
import { GBMinInstance } from 'botlib-legacy';
|
||||
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 } };
|
||||
}
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
|
||||
|
||||
# 2.0.0
|
||||
|
||||
``` SQL
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
agentSystemId nvarchar(16) NULL,
|
||||
agentMode nvarchar(16) NULL,
|
||||
agentContacted datetime NULL
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [phone]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [internalAddress]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [currentBotId]
|
||||
GO
|
||||
|
||||
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [authenticatorClientId]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [authenticatorClientSecret]
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
locale nvarchar(5) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
translatorKey nvarchar(64) NULL
|
||||
translatorEndpoint nvarchar(64) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
activationCode nvarchar(16) NULL
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
params nvarchar(4000) NULL
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
state nvarchar(16) NULL
|
||||
GO
|
||||
UPDATE dbo.GuaribasInstance SET state= 'active'
|
||||
|
||||
# 2.0.3
|
||||
|
||||
``` SQL
|
||||
|
||||
ALTER TABLE dbo.GuaribasPackage ADD
|
||||
params custom(512) NULL
|
||||
GO
|
||||
|
||||
```
|
||||
|
||||
|
||||
# 2.0.56
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
hearOnDialog nvarchar(64) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasConversation ADD
|
||||
instanceId int,
|
||||
feedback nvarchar(512) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [translatorendpoint]
|
||||
GO
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
translatorEndpoint nvarchar(128) NULL
|
||||
GO
|
||||
|
||||
|
||||
# 2.0.108
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [agentSystemId]
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
agentSystemId nvarchar(255) NULL,
|
||||
GO
|
||||
|
||||
# 2.0.115
|
||||
|
||||
ALTER TABLE dbo.GuaribasQuestion ADD
|
||||
skipIndex bit NULL
|
||||
GO
|
||||
|
||||
# 2.0.116 >
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
googleBotKey nvarchar(255) NULL,
|
||||
googleChatApiKey nvarchar(255) NULL,
|
||||
googleChatSubscriptionName nvarchar(255) NULL,
|
||||
googleClientEmail nvarchar(255) NULL,
|
||||
googlePrivateKey nvarchar(4000) NULL,
|
||||
googleProjectId nvarchar(255) NULL
|
||||
GO
|
||||
|
||||
# 2.0.119
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
facebookWorkplaceVerifyToken nvarchar(255) NULL,
|
||||
facebookWorkplaceAppSecret nvarchar(255) NULL,
|
||||
facebookWorkplaceAccessToken nvarchar(512) NULL
|
||||
GO
|
||||
|
||||
|
||||
# 2.0.140
|
||||
|
||||
/****** Object: Table [dbo].[GuaribasSchedule] Script Date: 25/08/2021 03:53:15 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[GuaribasSchedule]
|
||||
[id] [int] IDENTITY(1,1) NOT NULL,
|
||||
[name] [nvarchar](255) NULL,
|
||||
[schedule] [nvarchar](255) NULL,
|
||||
[instanceId] [int] NULL,
|
||||
[createdAt] [datetimeoffset](7) NULL,
|
||||
[updatedAt] [datetimeoffset](7) NULL
|
||||
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD botKey nvarchar(64) NULL;
|
||||
|
||||
# 2.3.9
|
||||
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
params nvarchar(4000) NULL
|
||||
GO
|
||||
79
WARNINGS.md
|
|
@ -1,79 +0,0 @@
|
|||
# default.gbui
|
||||
|
||||
https://github.com/microsoft/BotFramework-WebChat/pull/4524
|
||||
warning botframework-directlinejs > core-js@3.15.2: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||
warning botframework-webchat > botframework-webchat-component > @emotion/css > @emotion/babel-plugin > @babel/plugin-syntax-jsx@7.18.6" has unmet peer dependency "@babel/core@^7.0.0-0".
|
||||
warning botframework-webchat > botframework-webchat-component > @emotion/css > @emotion/babel-plugin@11.10.5" has unmet peer dependency "@babel/core@^7.0.0".
|
||||
warning botframework-webchat > botframework-webchat-component > react-film > core-js@3.12.1: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||
warning botframework-webchat > botframework-webchat-component > react-scroll-to-bottom > core-js@3.18.3: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||
warning botframework-webchat > botframework-webchat-core > redux-devtools-extension@2.13.9: Package moved to @redux-devtools/extension.
|
||||
warning botframework-webchat > microsoft-cognitiveservices-speech-sdk > asn1.js-rfc2560@5.0.1" has unmet peer dependency "asn1.js@^5.0.0".
|
||||
warning botframework-webchat > web-speech-cognitive-services@7.1.2" has incorrect peer dependency "microsoft-cognitiveservices-speech-sdk@~1.17.0".
|
||||
|
||||
https://github.com/microsoft/powerbi-client-react
|
||||
warning react-powerbi@0.9.1" has incorrect peer dependency "react@^16.8.0".
|
||||
|
||||
warning react-scripts > @svgr/webpack > @svgr/plugin-svgo > svgo > stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
|
||||
warning react-scripts > @svgr/webpack > @svgr/plugin-svgo > svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x.
|
||||
warning react-scripts > css-minimizer-webpack-plugin > cssnano > cssnano-preset-default > postcss-svgo > svgo > stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
|
||||
warning react-scripts > eslint-config-react-app > @typescript-eslint/eslint-plugin > tsutils@3.21.0" has unmet peer dependency "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta".
|
||||
warning react-scripts > eslint-config-react-app > eslint-plugin-flowtype@8.0.3" has unmet peer dependency "@babel/plugin-syntax-flow@^7.14.5".
|
||||
warning react-scripts > eslint-config-react-app > eslint-plugin-flowtype@8.0.3" has unmet peer dependency "@babel/plugin-transform-react-jsx@^7.14.9".
|
||||
warning react-scripts > jest > @jest/core > jest-config > jest-environment-jsdom > jsdom > w3c-hr-time@1.0.2: Use your platform's native performance.now() and performance.timeOrigin.
|
||||
warning react-scripts > react-dev-utils > fork-ts-checker-webpack-plugin@6.5.2" has unmet peer dependency "typescript@>= 2.7".
|
||||
|
||||
# BotServer
|
||||
|
||||
docxtemplater is not working in more modern versions. Stay with 3.9.7.
|
||||
|
||||
nodejs/node-gyp#2756
|
||||
warning npm > node-gyp > make-fetch-happen > cacache > @npmcli/move-file@2.0.1: This functionality has been moved to @npmcli/fs
|
||||
|
||||
vasyas/typescript-rest-rpc#20
|
||||
warning typescript-rest-rpc > ts-morph > globby > fast-glob > micromatch > snapdragon > source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
|
||||
|
||||
#279
|
||||
warning tslint@6.1.3: TSLint has been deprecated in favor of ESLint. Please see palantir/tslint#4534 for more information.
|
||||
|
||||
AlaSQL/alasql#1541
|
||||
warning alasql > request@2.88.2: request has been deprecated, see request/request#3142
|
||||
|
||||
#281
|
||||
warning c3-chart-maker > data-forge > promised-mongo > mongodb-core > bson@0.4.23: Fixed a critical issue with BSON serialization documented in CVE-2019-2391, see https://bit.ly/2KcpXdo for more details
|
||||
|
||||
#280
|
||||
warning swagger-client > url > querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
|
||||
|
||||
bahmutov/ggit#157
|
||||
warning ban-sensitive-files > ggit > debug@3.2.6: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (debug-js/debug#797)
|
||||
|
||||
#283
|
||||
warning nexmo > uuid@2.0.3: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
|
||||
|
||||
https://github.com/microsoft/botbuilder-js/issues/4370
|
||||
warning botbuilder-ai > @azure/cognitiveservices-luis-runtime > @azure/ms-rest-js > uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
|
||||
|
||||
https://github.com/Azure/azure-sdk-for-node/issues/5221
|
||||
warning ms-rest-azure > request@2.88.2: request has been deprecated, see request/request#3142
|
||||
|
||||
https://github.com/MontassarLaribi/ssr-for-bots/issues/1
|
||||
warning ssr-for-bots > tslint@6.1.3: TSLint has been deprecated in favor of ESLint. Please see palantir/tslint#4534 for more information.
|
||||
|
||||
https://github.com/vasyas/typescript-rest-rpc/issues/20
|
||||
warning typescript-rest-rpc > ts-morph > globby > fast-glob > micromatch > snapdragon > source-map-resolve > urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
|
||||
|
||||
https://github.com/ash-developer/winston-logs-display/issues/8
|
||||
warning winston-logs-display > jade > transformers@2.1.0: Deprecated, use jstransformer
|
||||
|
||||
https://github.com/softwarescales/git-issues/issues/29
|
||||
warning git-issues > request@2.88.2: request has been deprecated, see request/request#3142
|
||||
|
||||
https://github.com/GeneralBots/BotServer/issues/284
|
||||
warning license-checker > read-installed > readdir-scoped-modules@1.1.0: This functionality has been moved to @npmcli/fs
|
||||
|
||||
https://github.com/semantic-release/semantic-release/issues/1260
|
||||
warning semantic-release > @semantic-release/npm > npm > readdir-scoped-modules@1.1.0: This functionality has been moved to @npmcli/fs
|
||||
|
||||
https://github.com/GeneralBots/BotServer/issues/277
|
||||
warning travis-deploy-once@3.3.0: We recommend to use Travis Build Stages instead
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "General Bots API",
|
||||
"description": "General Bots API description in Swagger format",
|
||||
"version": "1.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://generalbots.online/api",
|
||||
"description": "General Bots Online"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
blank.docx
BIN
blank.xlsx
57
boot.mjs
|
|
@ -1,57 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
process.stdout.write(`General Bots 5 VM: node@${process.version.replace('v', '')}, ${process.platform} ${process.arch} `);
|
||||
|
||||
import fs from 'fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'path';
|
||||
import { exec } from 'child_process';
|
||||
|
||||
import {GBUtil} from './dist/src/util.js'
|
||||
|
||||
// Displays version of Node JS being used at runtime and others attributes.
|
||||
|
||||
console.log(`\nLoading General Bots VM...`);
|
||||
|
||||
var __dirname = process.env.PWD || process.cwd();
|
||||
try {
|
||||
var run = async () => {
|
||||
|
||||
import('./dist/src/app.js').then(async (gb)=> {
|
||||
await gb.GBServer.run()
|
||||
});
|
||||
};
|
||||
var processDist = async () => {
|
||||
if (!await GBUtil.exists('dist')) {
|
||||
console.log(`\n`);
|
||||
console.log(`General Bots: Compiling...`);
|
||||
exec(path.join(__dirname, 'node_modules/.bin/tsc'), async (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
await run();
|
||||
});
|
||||
} else {
|
||||
await run();
|
||||
}
|
||||
};
|
||||
|
||||
// Installing modules if it has not been done yet.
|
||||
|
||||
if (!await GBUtil.exists('node_modules')) {
|
||||
console.log(`\n`);
|
||||
console.log(`General Bots: Installing modules for the first time, please wait...`);
|
||||
exec('npm install', async (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
await processDist();
|
||||
});
|
||||
} else {
|
||||
await processDist();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
150
deploy.cmd
|
|
@ -1,150 +0,0 @@
|
|||
@if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off
|
||||
|
||||
:: ----------------------
|
||||
:: General Bots deployment.
|
||||
:: -------------
|
||||
|
||||
:: Verify node.js installed
|
||||
where node 2>nul >nul
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment.
|
||||
goto error
|
||||
)
|
||||
|
||||
:: Setup
|
||||
:: -----
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
SET ARTIFACTS=%~dp0%..\artifacts
|
||||
|
||||
IF NOT DEFINED DEPLOYMENT_SOURCE (
|
||||
SET DEPLOYMENT_SOURCE=%~dp0%.
|
||||
)
|
||||
|
||||
IF NOT DEFINED DEPLOYMENT_TARGET (
|
||||
SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot
|
||||
)
|
||||
|
||||
IF NOT DEFINED NEXT_MANIFEST_PATH (
|
||||
SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest
|
||||
|
||||
IF NOT DEFINED PREVIOUS_MANIFEST_PATH (
|
||||
SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest
|
||||
)
|
||||
)
|
||||
|
||||
IF NOT DEFINED KUDU_SYNC_CMD (
|
||||
:: Install kudu sync
|
||||
echo Installing Kudu Sync
|
||||
call npm install kudusync -g --silent
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
|
||||
:: Locally just running "kuduSync" would also work
|
||||
SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd
|
||||
)
|
||||
goto Deployment
|
||||
|
||||
:: Utility Functions
|
||||
:: -----------------
|
||||
|
||||
:SelectNodeVersion
|
||||
|
||||
IF DEFINED KUDU_SELECT_NODE_VERSION_CMD (
|
||||
:: The following are done only on Windows Azure Websites environment
|
||||
call %KUDU_SELECT_NODE_VERSION_CMD% "%DEPLOYMENT_SOURCE%" "%DEPLOYMENT_TARGET%" "%DEPLOYMENT_TEMP%"
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
|
||||
IF EXIST "%DEPLOYMENT_TEMP%\__nodeVersion.tmp" (
|
||||
SET /p NODE_EXE=<"%DEPLOYMENT_TEMP%\__nodeVersion.tmp"
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
)
|
||||
|
||||
IF EXIST "%DEPLOYMENT_TEMP%\__npmVersion.tmp" (
|
||||
SET /p NPM_JS_PATH=<"%DEPLOYMENT_TEMP%\__npmVersion.tmp"
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
)
|
||||
|
||||
IF NOT DEFINED NODE_EXE (
|
||||
SET NODE_EXE=node
|
||||
)
|
||||
|
||||
SET NPM_CMD="!NODE_EXE!" "!NPM_JS_PATH!"
|
||||
) ELSE (
|
||||
SET NPM_CMD=npm
|
||||
SET NODE_EXE=node
|
||||
)
|
||||
|
||||
goto :EOF
|
||||
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
:: Deployment
|
||||
:: ----------
|
||||
|
||||
:Deployment
|
||||
echo Handling node.js deployment.
|
||||
|
||||
:: 1. KuduSync
|
||||
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
|
||||
call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
)
|
||||
|
||||
:: 2. Select node version
|
||||
call :SelectNodeVersion
|
||||
|
||||
:: 3. Install npm packages
|
||||
IF EXIST "%DEPLOYMENT_TARGET%\package.json" (
|
||||
pushd "%DEPLOYMENT_TARGET%"
|
||||
echo [General Bots Deployer] Installing packages for server...
|
||||
call :ExecuteCmd !NPM_CMD! install --production
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
popd
|
||||
)
|
||||
|
||||
:: 3.1 Install npm packages on UI
|
||||
IF EXIST "%DEPLOYMENT_TARGET%\deploy\default.gbui\package.json" (
|
||||
call :ExecuteCmd !NPM_CMD! config set scripts-prepend-node-path true
|
||||
pushd "%DEPLOYMENT_TARGET%\deploy\default.gbui"
|
||||
echo [General Bots Deployer] Installing packages for default.gbui...
|
||||
call :ExecuteCmd !NPM_CMD! install
|
||||
echo [General Bots Deployer] Building default.gbui...
|
||||
call :ExecuteCmd !NPM_CMD! run build
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
RMDIR /s /q "%DEPLOYMENT_TARGET%\deploy\default.gbui\node_modules"
|
||||
popd
|
||||
)
|
||||
|
||||
:: 4. Install TypeScript
|
||||
echo [General Bots Deployer] Transpiling...
|
||||
call :ExecuteCmd node %DEPLOYMENT_TARGET%\node_modules\typescript\bin\tsc -v
|
||||
call :ExecuteCmd node %DEPLOYMENT_TARGET%\node_modules\typescript\bin\tsc -p "%DEPLOYMENT_TARGET%"
|
||||
|
||||
echo [General Bots Deployer] Deployment Finished.
|
||||
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
goto end
|
||||
|
||||
:: Execute command routine that will echo out when error
|
||||
:ExecuteCmd
|
||||
setlocal
|
||||
set _CMD_=%*
|
||||
call %_CMD_%
|
||||
if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_%
|
||||
exit /b %ERRORLEVEL%
|
||||
|
||||
:error
|
||||
endlocal
|
||||
echo An error has occurred during web site deployment.
|
||||
call :exitSetErrorLevel
|
||||
call :exitFromFunction 2>nul
|
||||
|
||||
:exitSetErrorLevel
|
||||
exit /b 1
|
||||
|
||||
:exitFromFunction
|
||||
()
|
||||
|
||||
:end
|
||||
endlocal
|
||||
echo Finished successfully.
|
||||
96
deploy.sh
|
|
@ -1,96 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# ------------------------
|
||||
# General Bots deployment.
|
||||
# ------------------------
|
||||
|
||||
# Helpers
|
||||
# -------
|
||||
|
||||
exitWithMessageOnError () {
|
||||
if [ ! $? -eq 0 ]; then
|
||||
echo "[General Bots Deployer]An error has occurred during web site deployment."
|
||||
echo $1
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Prerequisites
|
||||
# -------------
|
||||
|
||||
# Verify node.js installed
|
||||
hash node 2>/dev/null
|
||||
exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment."
|
||||
|
||||
# Setup
|
||||
# -----
|
||||
|
||||
SCRIPT_DIR="${BASH_SOURCE[0]%\\*}"
|
||||
SCRIPT_DIR="${SCRIPT_DIR%/*}"
|
||||
ARTIFACTS=$SCRIPT_DIR/../artifacts
|
||||
KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"}
|
||||
|
||||
if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then
|
||||
DEPLOYMENT_SOURCE=$SCRIPT_DIR
|
||||
fi
|
||||
|
||||
if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then
|
||||
NEXT_MANIFEST_PATH=$ARTIFACTS/manifest
|
||||
|
||||
if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then
|
||||
PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then
|
||||
DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot
|
||||
else
|
||||
KUDU_SERVICE=true
|
||||
fi
|
||||
|
||||
if [[ ! -n "$KUDU_SYNC_CMD" ]]; then
|
||||
# Install kudu sync
|
||||
echo Installing Kudu Sync
|
||||
npm install kudusync -g --silent
|
||||
exitWithMessageOnError "npm failed"
|
||||
|
||||
if [[ ! -n "$KUDU_SERVICE" ]]; then
|
||||
# In case we are running locally this is the correct location of kuduSync
|
||||
KUDU_SYNC_CMD=kuduSync
|
||||
else
|
||||
# In case we are running on kudu service this is the correct location of kuduSync
|
||||
KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync
|
||||
fi
|
||||
fi
|
||||
|
||||
##################################################################################################################################
|
||||
# Deployment
|
||||
# ----------
|
||||
|
||||
# 1. Install npm packages
|
||||
if [ -e "$DEPLOYMENT_SOURCE/package.json" ]; then
|
||||
echo "[General Bots Deployer] Running npm install..."
|
||||
cd "$DEPLOYMENT_SOURCE"
|
||||
eval npm install
|
||||
echo "[General Bots Deployer] OK."
|
||||
exitWithMessageOnError "npm failed"
|
||||
cd - > /dev/null
|
||||
fi
|
||||
|
||||
|
||||
# 2. Install TypeScript
|
||||
echo "[General Bots Deployer] Transpiling..."
|
||||
eval ./node_modules/typescript/bin/tsc -v
|
||||
eval ./node_modules/typescript/bin/tsc -p "$DEPLOYMENT_SOURCE"
|
||||
|
||||
|
||||
echo "[General Bots Deployer] OK."
|
||||
|
||||
# 4. KuduSync
|
||||
if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then
|
||||
"$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh"
|
||||
exitWithMessageOnError "Kudu Sync failed"
|
||||
fi
|
||||
|
||||
##################################################################################################################################
|
||||
echo "[General Bots Deployer] Finished successfully."
|
||||
1263
directline-v2.json
|
|
@ -1 +0,0 @@
|
|||
theme: jekyll-theme-minimal
|
||||
|
Before Width: | Height: | Size: 1 MiB |
|
Before Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 261 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 480 B |
|
Before Width: | Height: | Size: 855 B |
|
|
@ -1 +0,0 @@
|
|||
window.searchData = {"kinds":{"128":"Class","512":"Constructor","1024":"Property","2048":"Method"},"rows":[{"id":0,"kind":128,"name":"RootData","url":"classes/rootdata.html","classes":"tsd-kind-class"},{"id":1,"kind":512,"name":"constructor","url":"classes/rootdata.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class","parent":"RootData"},{"id":2,"kind":1024,"name":"publicAddress","url":"classes/rootdata.html#publicaddress","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":3,"kind":1024,"name":"server","url":"classes/rootdata.html#server","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":4,"kind":1024,"name":"sysPackages","url":"classes/rootdata.html#syspackages","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":5,"kind":1024,"name":"appPackages","url":"classes/rootdata.html#apppackages","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":6,"kind":1024,"name":"minService","url":"classes/rootdata.html#minservice","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":7,"kind":1024,"name":"bootInstance","url":"classes/rootdata.html#bootinstance","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":8,"kind":1024,"name":"minInstances","url":"classes/rootdata.html#mininstances","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":9,"kind":1024,"name":"minBoot","url":"classes/rootdata.html#minboot","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":10,"kind":1024,"name":"wwwroot","url":"classes/rootdata.html#wwwroot","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":11,"kind":1024,"name":"entryPointDialog","url":"classes/rootdata.html#entrypointdialog","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":12,"kind":128,"name":"GBServer","url":"classes/gbserver.html","classes":"tsd-kind-class"},{"id":13,"kind":1024,"name":"globals","url":"classes/gbserver.html#globals","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-static","parent":"GBServer"},{"id":14,"kind":2048,"name":"run","url":"classes/gbserver.html#run","classes":"tsd-kind-method tsd-parent-kind-class tsd-is-static","parent":"GBServer"},{"id":15,"kind":512,"name":"constructor","url":"classes/gbserver.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class","parent":"GBServer"}],"index":{"version":"2.3.9","fields":["name","parent"],"fieldVectors":[["name/0",[0,3.075]],["parent/0",[]],["name/1",[1,19.169]],["parent/1",[0,0.291]],["name/2",[2,24.277]],["parent/2",[0,0.291]],["name/3",[3,24.277]],["parent/3",[0,0.291]],["name/4",[4,24.277]],["parent/4",[0,0.291]],["name/5",[5,24.277]],["parent/5",[0,0.291]],["name/6",[6,24.277]],["parent/6",[0,0.291]],["name/7",[7,24.277]],["parent/7",[0,0.291]],["name/8",[8,24.277]],["parent/8",[0,0.291]],["name/9",[9,24.277]],["parent/9",[0,0.291]],["name/10",[10,24.277]],["parent/10",[0,0.291]],["name/11",[11,24.277]],["parent/11",[0,0.291]],["name/12",[12,13.291]],["parent/12",[]],["name/13",[13,24.277]],["parent/13",[12,1.256]],["name/14",[14,24.277]],["parent/14",[12,1.256]],["name/15",[1,19.169]],["parent/15",[12,1.256]]],"invertedIndex":[["apppackages",{"_index":5,"name":{"5":{}},"parent":{}}],["bootinstance",{"_index":7,"name":{"7":{}},"parent":{}}],["constructor",{"_index":1,"name":{"1":{},"15":{}},"parent":{}}],["entrypointdialog",{"_index":11,"name":{"11":{}},"parent":{}}],["gbserver",{"_index":12,"name":{"12":{}},"parent":{"13":{},"14":{},"15":{}}}],["globals",{"_index":13,"name":{"13":{}},"parent":{}}],["minboot",{"_index":9,"name":{"9":{}},"parent":{}}],["mininstances",{"_index":8,"name":{"8":{}},"parent":{}}],["minservice",{"_index":6,"name":{"6":{}},"parent":{}}],["publicaddress",{"_index":2,"name":{"2":{}},"parent":{}}],["rootdata",{"_index":0,"name":{"0":{}},"parent":{"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{},"10":{},"11":{}}}],["run",{"_index":14,"name":{"14":{}},"parent":{}}],["server",{"_index":3,"name":{"3":{}},"parent":{}}],["syspackages",{"_index":4,"name":{"4":{}},"parent":{}}],["wwwroot",{"_index":10,"name":{"10":{}},"parent":{}}]],"pipeline":[]}}
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
<!doctype html>
|
||||
<html class="default no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>General Bots Open Core</title>
|
||||
<meta name="description" content="Documentation for General Bots Open Core">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="assets/css/main.css">
|
||||
<script async src="assets/js/search.js" id="search-script"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="tsd-page-toolbar">
|
||||
<div class="container">
|
||||
<div class="table-wrap">
|
||||
<div class="table-cell" id="tsd-search" data-index="assets/js/search.json" data-base=".">
|
||||
<div class="field">
|
||||
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
|
||||
<input id="tsd-search-field" type="text" />
|
||||
</div>
|
||||
<ul class="results">
|
||||
<li class="state loading">Preparing search index...</li>
|
||||
<li class="state failure">The search index is not available</li>
|
||||
</ul>
|
||||
<a href="index.html" class="title">General Bots Open Core</a>
|
||||
</div>
|
||||
<div class="table-cell" id="tsd-widgets">
|
||||
<div id="tsd-filter">
|
||||
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
|
||||
<div class="tsd-filter-group">
|
||||
<div class="tsd-select" id="tsd-filter-visibility">
|
||||
<span class="tsd-select-label">All</span>
|
||||
<ul class="tsd-select-list">
|
||||
<li data-value="public">Public</li>
|
||||
<li data-value="protected">Public/Protected</li>
|
||||
<li data-value="private" class="selected">All</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="checkbox" id="tsd-filter-inherited" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
|
||||
<input type="checkbox" id="tsd-filter-externals" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-externals">Externals</label>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tsd-page-title">
|
||||
<div class="container">
|
||||
<h1>General Bots Open Core</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="container container-main">
|
||||
<div class="row">
|
||||
<div class="col-8 col-content">
|
||||
<div class="tsd-panel tsd-typography">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Area</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td>Releases</td>
|
||||
<td><a href="https://www.npmjs.com/package/botserver/"><img src="https://img.shields.io/npm/dt/botserver.svg?logo=npm&label=botserver" alt="General Bots"></a> <a href="https://www.npmjs.com/package/botlib/"><img src="https://img.shields.io/npm/dt/botlib.svg?logo=npm&label=botlib" alt=".gbapp lib"></a> <a href="https://github.com/semantic-release/semantic-release"><img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg" alt="semantic-release"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Community</td>
|
||||
<td><a href="https://stackoverflow.com/questions/tagged/generalbots"><img src="https://img.shields.io/stackexchange/stackoverflow/t/generalbots.svg" alt="StackExchange"></a> <a href="https://badges.frapsoft.com"><img src="https://badges.frapsoft.com/os/v2/open-source.svg" alt="Open-source"></a> <a href="http://makeapullrequest.com"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs Welcome"></a> <a href="https://github.com/GeneralBots/BotServer/blob/master/LICENSE.txt"><img src="https://img.shields.io/badge/license-AGPL-blue.svg" alt="License"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Management</td>
|
||||
<td><a href="https://gitHub.com/GeneralBots/BotServer/graphs/commit-activity"><img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg" alt="Maintenance"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td><a href="https://snyk.io/test/github/GeneralBots/BotServer"><img src="https://snyk.io/test/github/GeneralBots/BotServer/badge.svg" alt="Known Vulnerabilities"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Building & Quality</td>
|
||||
<td><a href="https://travis-ci.com/GeneralBots/BotServer"><img src="https://travis-ci.com/GeneralBots/BotServer.svg?branch=master" alt="Build Status"></a> <a href="https://coveralls.io/github/GeneralBots/BotServer"><img src="https://coveralls.io/repos/github/GeneralBots/BotServer/badge.svg" alt="Coverage Status"></a> <a href="https://github.com/prettier/prettier"><img src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square" alt="code style: prettier"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Packaging</td>
|
||||
<td><a href="https://badge.fury.io"><img src="https://badge.fury.io/js/botserver.svg" alt="forthebadge"></a> <a href="https://github.com/GeneralBots/BotServer/releases/latest"><img src="https://camo.githubusercontent.com/0150c0f148d50fe9750ebc5d313581da699a8c50/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7a69702d646f776e6c6f61642d626c75652e737667" alt="ZipFile"></a> <a href="https://david-dm.org"><img src="https://david-dm.org/GeneralBots/botserver.svg" alt="Dependencies"></a> <a href="http://commitizen.github.io/cz-cli/"><img src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg" alt="Commitizen friendly"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Samples</td>
|
||||
<td><a href="https://github.com/GeneralBots/BotServer/tree/master/packages/default.gbdialog">VBA</a> or <a href="https://github.com/GeneralBots/AzureADPasswordReset.gbapp"><img src="https://badges.frapsoft.com/typescript/code/typescript.svg?v=101" alt="TypeScript"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/lpicanco/docker-botserver">Docker Image</a></td>
|
||||
<td><img src="https://img.shields.io/docker/automated/lpicanco/botserver.svg" alt="Docker Automated build"> <img src="https://img.shields.io/docker/build/lpicanco/botserver.svg" alt="Docker Build Status"> <img src="https://img.shields.io/microbadger/image-size/lpicanco/botserver.svg" alt="MicroBadger Size"> <img src="https://img.shields.io/microbadger/layers/lpicanco/botserver.svg" alt="MicroBadger Layers"> <img src="https://img.shields.io/docker/pulls/lpicanco/botserver.svg" alt="Docker Pulls"> <br/> <em>Provided by <a href="https://github.com/lpicanco/docker-botserver">@lpicanco</a></em></td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<a href="#general-bots" id="general-bots" style="color: inherit; text-decoration: none;">
|
||||
<h2>General Bots</h2>
|
||||
</a>
|
||||
<p><img src="https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/logo.png" alt="General Bot Logo"></p>
|
||||
<p>General Bot is a strongly typed package based chat bot server focused in convention over configuration and code-less approaches, which brings software packages and application server concepts to help parallel bot development.</p>
|
||||
<a href="#what-is-a-bot-server" id="what-is-a-bot-server" style="color: inherit; text-decoration: none;">
|
||||
<h2>What is a Bot Server?</h2>
|
||||
</a>
|
||||
<p>Bot Server accelerates the process of developing a bot. It provisions all code
|
||||
base, resources and deployment to the cloud, and gives you templates you can
|
||||
choose from whenever you need a new bot. The server has a database and service
|
||||
backend allowing you to further modify your bot package directly by downloading
|
||||
a zip file, editing and uploading it back to the server (deploying process) with
|
||||
no code. The Bot Server also provides a framework to develop bot packages in a more
|
||||
advanced fashion writing custom code in editors like Visual Studio Code, Atom or Brackets.</p>
|
||||
<p>Everyone can create bots by just copying and pasting some files and using their
|
||||
favorite tools from Office (or any text editor) or Photoshop (or any image
|
||||
editor). BASIC can be used to build custom dialogs so Bot can be extended just like VBA for Excel (currently in alpha).</p>
|
||||
<p><img src="https://raw.githubusercontent.com/GeneralBots/BotBook/master/images/general-bots-reference-architecture.png" alt="General Bot Reference Architecture"></p>
|
||||
<a href="#samples" id="samples" style="color: inherit; text-decoration: none;">
|
||||
<h2>Samples</h2>
|
||||
</a>
|
||||
<p>Several samples, including a Bot for AD Password Reset, are avaiable on the <a href="https://github.com/GeneralBots">repository list</a>.</p>
|
||||
<a href="#guide" id="guide" style="color: inherit; text-decoration: none;">
|
||||
<h2>Guide</h2>
|
||||
</a>
|
||||
<p><a href="https://github.com/GeneralBots/BotBook/tree/master/book">Read the General Bots BotBook Guide</a>.</p>
|
||||
<a href="#videos" id="videos" style="color: inherit; text-decoration: none;">
|
||||
<h1>Videos</h1>
|
||||
</a>
|
||||
<p>Now with the General Bots server you can press F5 on Visual Studio to get a bot factory on your environment* published on November 10th, 2018.</p>
|
||||
<p><a href="https://www.youtube.com/watch?v=AfKTwljoMOs"><img src="https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/docs/images/video-01-thumb.jpg" alt="General Bot Video"></a></p>
|
||||
<p>See how easy is to use 'hear' and 'talk' to build Microsoft BOT Framework v4 logic with plain BASIC * published on December 3rd, 2018.</p>
|
||||
<p><a href="https://www.youtube.com/watch?v=yX1sF9n9628"><img src="https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/docs/images/video-02-thumb.jpg" alt="See how easy is to use 'hear' and 'talk' to build Microsoft BOT Framework v4 logic with plain BASIC"></a></p>
|
||||
<a href="#contributing" id="contributing" style="color: inherit; text-decoration: none;">
|
||||
<h1>Contributing</h1>
|
||||
</a>
|
||||
<p>This project welcomes contributions and suggestions.
|
||||
See our <a href="https://github.com/pragmatismo-io/BotServer/blob/master/CONTRIBUTING.md">Contribution Guidelines</a> for more details.</p>
|
||||
<a href="#reporting-security-issues" id="reporting-security-issues" style="color: inherit; text-decoration: none;">
|
||||
<h1>Reporting Security Issues</h1>
|
||||
</a>
|
||||
<p>Security issues and bugs should be reported privately, via email, to the Pragmatismo.io Security
|
||||
team at <a href="mailto:security@pragmatismo.io">security@pragmatismo.io</a>. You should
|
||||
receive a response within 24 hours. If for some reason you do not, please follow up via
|
||||
email to ensure we received your original message. </p>
|
||||
<a href="#license-amp-warranty" id="license-amp-warranty" style="color: inherit; text-decoration: none;">
|
||||
<h1>License & Warranty</h1>
|
||||
</a>
|
||||
<p>General Bot Copyright (c) Pragmatismo.io. All rights reserved.
|
||||
Licensed under the AGPL-3.0. </p>
|
||||
<p>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. </p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>"General Bot" is a registered trademark of Pragmatismo.io.
|
||||
The licensing of the program under the AGPLv3 does not imply a
|
||||
trademark license. Therefore any rights, title and interest in
|
||||
our trademarks remain entirely with us.</p>
|
||||
<p><a href="https://stackoverflow.com/questions/ask?tags=generalbots">:speech_balloon: Ask a question</a> <a href="https://github.com/GeneralBots/BotBook">:book: Read the Docs</a></p>
|
||||
<p>General Bots Code Name is <a href="https://en.wikipedia.org/wiki/Guaribas">Guaribas</a>, the name of a city in Brazil, state of Piaui.
|
||||
<a href="http://www.robertounger.com/en/">Roberto Mangabeira Unger</a>: "No one should have to do work that can be done by a machine".</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
|
||||
<nav class="tsd-navigation primary">
|
||||
<ul>
|
||||
<li class=" ">
|
||||
<a href="modules.html">Exports</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="tsd-navigation secondary menu-sticky">
|
||||
<ul class="before-current">
|
||||
<li class=" tsd-kind-class">
|
||||
<a href="classes/gbserver.html" class="tsd-kind-icon">GBServer</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-class">
|
||||
<a href="classes/rootdata.html" class="tsd-kind-icon">Root<wbr>Data</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="with-border-bottom">
|
||||
<div class="container">
|
||||
<h2>Legend</h2>
|
||||
<div class="tsd-legend-group">
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-class"><span class="tsd-kind-icon">Property</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<div class="container tsd-generator">
|
||||
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
|
||||
</div>
|
||||
<div class="overlay"></div>
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
382
extensions.json
|
|
@ -1,382 +0,0 @@
|
|||
[
|
||||
{
|
||||
"extension": "aac",
|
||||
"description": "AAC audio",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "abw",
|
||||
"description": "AbiWord document",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "arc",
|
||||
"description": "Archive document (multiple files embedded)",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "avif",
|
||||
"description": "AVIF image",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "avi",
|
||||
"description": "AVI: Audio Video Interleave",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "azw",
|
||||
"description": "Amazon Kindle eBook format",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "bin",
|
||||
"description": "Any kind of binary data",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "bmp",
|
||||
"description": "Windows OS/2 Bitmap Graphics",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "bz",
|
||||
"description": "BZip archive",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "bz2",
|
||||
"description": "BZip2 archive",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "cda",
|
||||
"description": "CD audio",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "csh",
|
||||
"description": "C-Shell script",
|
||||
"category": "Executable"
|
||||
},
|
||||
{
|
||||
"extension": "css",
|
||||
"description": "Cascading Style Sheets (CSS)",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "csv",
|
||||
"description": "Comma-separated values (CSV)",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "doc",
|
||||
"description": "Microsoft Word",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "docx",
|
||||
"description": "Microsoft Word (OpenXML)",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "eot",
|
||||
"description": "MS Embedded OpenType fonts",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "epub",
|
||||
"description": "Electronic publication (EPUB)",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "gz",
|
||||
"description": "GZip Compressed Archive",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "gif",
|
||||
"description": "Graphics Interchange Format (GIF)",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "htm",
|
||||
"description": "HyperText Markup Language (HTML)",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "html",
|
||||
"description": "HyperText Markup Language (HTML)",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "ico",
|
||||
"description": "Icon format",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "ics",
|
||||
"description": "iCalendar format",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "jar",
|
||||
"description": "Java Archive (JAR)",
|
||||
"category": "Executable"
|
||||
},
|
||||
{
|
||||
"extension": "jpeg",
|
||||
"description": "JPEG images",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "jpg",
|
||||
"description": "JPEG images",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "js",
|
||||
"description": "JavaScript",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "json",
|
||||
"description": "JSON format",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "jsonld",
|
||||
"description": "JSON-LD format",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "mid",
|
||||
"description": "Musical Instrument Digital Interface (MIDI)",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "midi",
|
||||
"description": "Musical Instrument Digital Interface (MIDI)",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "mjs",
|
||||
"description": "JavaScript module",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "mp3",
|
||||
"description": "MP3 audio",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "mp4",
|
||||
"description": "MP4 video",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "mpeg",
|
||||
"description": "MPEG Video",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "mpkg",
|
||||
"description": "Apple Installer Package",
|
||||
"category": "Application"
|
||||
},
|
||||
{
|
||||
"extension": "odp",
|
||||
"description": "OpenDocument presentation document",
|
||||
"category": "Presentation"
|
||||
},
|
||||
{
|
||||
"extension": "ods",
|
||||
"description": "OpenDocument spreadsheet document",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "odt",
|
||||
"description": "OpenDocument text document",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "oga",
|
||||
"description": "OGG audio",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "ogv",
|
||||
"description": "OGG video",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "ogx",
|
||||
"description": "OGG",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "opus",
|
||||
"description": "Opus audio",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "otf",
|
||||
"description": "OpenType font",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "png",
|
||||
"description": "Portable Network Graphics",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "pdf",
|
||||
"description": "Adobe Portable Document Format (PDF)",
|
||||
"category": "PDF"
|
||||
},
|
||||
{
|
||||
"extension": "php",
|
||||
"description": "Hypertext Preprocessor (Personal Home Page)",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "ppt",
|
||||
"description": "Microsoft PowerPoint",
|
||||
"category": "Presentation"
|
||||
},
|
||||
{
|
||||
"extension": "pptx",
|
||||
"description": "Microsoft PowerPoint (OpenXML)",
|
||||
"category": "Presentation"
|
||||
},
|
||||
{
|
||||
"extension": "rar",
|
||||
"description": "RAR archive",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "rtf",
|
||||
"description": "Rich Text Format (RTF)",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "sh",
|
||||
"description": "Bourne shell script",
|
||||
"category": "Executable"
|
||||
},
|
||||
{
|
||||
"extension": "svg",
|
||||
"description": "Scalable Vector Graphics (SVG)",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "tar",
|
||||
"description": "Tape Archive (TAR)",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "tif",
|
||||
"description": "Tagged Image File Format (TIFF)",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "tiff",
|
||||
"description": "Tagged Image File Format (TIFF)",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "ts",
|
||||
"description": "MPEG transport stream",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "ttf",
|
||||
"description": "TrueType Font",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "txt",
|
||||
"description": "Text, (generally ASCII or ISO 8859-n)",
|
||||
"category": "Text"
|
||||
},
|
||||
{
|
||||
"extension": "vsd",
|
||||
"description": "Microsoft Visio",
|
||||
"category": "Application"
|
||||
},
|
||||
{
|
||||
"extension": "wav",
|
||||
"description": "Waveform Audio Format",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "weba",
|
||||
"description": "WEBM audio",
|
||||
"category": "Music"
|
||||
},
|
||||
{
|
||||
"extension": "webm",
|
||||
"description": "WEBM video",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "webp",
|
||||
"description": "WEBP image",
|
||||
"category": "Image"
|
||||
},
|
||||
{
|
||||
"extension": "woff",
|
||||
"description": "Web Open Font Format (WOFF)",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "woff2",
|
||||
"description": "Web Open Font Format (WOFF)",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "xhtml",
|
||||
"description": "XHTML",
|
||||
"category": "Other"
|
||||
},
|
||||
{
|
||||
"extension": "xls",
|
||||
"description": "Microsoft Excel",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "xlsx",
|
||||
"description": "Microsoft Excel (OpenXML)",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "xml",
|
||||
"description": "XML",
|
||||
"category": "Document"
|
||||
},
|
||||
{
|
||||
"extension": "xul",
|
||||
"description": "XUL",
|
||||
"category": "Application"
|
||||
},
|
||||
{
|
||||
"extension": "zip",
|
||||
"description": "ZIP archive",
|
||||
"category": "Application"
|
||||
},
|
||||
{
|
||||
"extension": "3gp",
|
||||
"description": "3GPP audio/video container",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "3g2",
|
||||
"description": "3GPP2 audio/video container",
|
||||
"category": "Movie"
|
||||
},
|
||||
{
|
||||
"extension": "7z",
|
||||
"description": "7-zip archive",
|
||||
"category": "Application"
|
||||
}
|
||||
]
|
||||
24625
package-lock.json
generated
353
package.json
|
|
@ -1,353 +0,0 @@
|
|||
{
|
||||
"name": "botserver",
|
||||
"version": "5.1.1",
|
||||
"description": "General Bot Community Edition open-core server.",
|
||||
"main": "./boot.mjs",
|
||||
"type": "module",
|
||||
"bugs": "https://github.com/pragmatismo-io/BotServer/issues",
|
||||
"homepage": "https://github.com/pragmatismo-io/BotServer/#readme",
|
||||
"contributors": [
|
||||
"Rodrigo Rodriguez <me@rodrigorodriguez.com>",
|
||||
"João Ferreira <joao.parana@gmail.com>",
|
||||
"Jorge Ramos <jramos@pobox.com>",
|
||||
"PH <ph.an@outlook.com>",
|
||||
"Dário Vieira <dario.junior3@gmail.com>",
|
||||
"Alan Perdomo <alanperdomo@hotmail.com>"
|
||||
],
|
||||
"opencv4nodejs": {
|
||||
"disableAutoBuild": "1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "=22.19.0"
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"preferGlobal": true,
|
||||
"private": false,
|
||||
"bin": {
|
||||
"gbot": "./boot.mjs"
|
||||
},
|
||||
"readme": "README.md",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GeneralBots/BotServer.git"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf node_modules/ dist/ docs/reference",
|
||||
"tslint": "tslint --fix ./src/*.ts ./packages/**/*.ts -t verbose",
|
||||
"build": "npm install && npm run build-server && npm run build-gbui",
|
||||
"build-server": "tsc",
|
||||
"build-gbui": "cd packages/default.gbui && echo SKIP_PREFLIGHT_CHECK=true >.env && npm install && npm run build",
|
||||
"build-docs": "typedoc --options typedoc.json src/",
|
||||
"test": "vitest",
|
||||
"start": "NODE_NO_WARNINGS=1 node ./boot.mjs --loader ts-node/esm --require ./suppress-node-warnings.cjs",
|
||||
"debug": "NODE_NO_WARNINGS=1 node ./boot.mjs --loader ts-node/esm --require ./suppress-node-warnings.cjs --inspect",
|
||||
"watch:build": "tsc --watch"
|
||||
},
|
||||
"jest": {
|
||||
"workerIdleMemoryLimit": "4096MB",
|
||||
"transform": {
|
||||
".+\\.tsx?$": "ts-jest"
|
||||
},
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"jsx",
|
||||
"json"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/cognitiveservices-computervision": "8.2.0",
|
||||
"@azure/ms-rest-js": "2.7.0",
|
||||
"@azure/msal-node": "3.8.0",
|
||||
"@azure/openai": "2.0.0",
|
||||
"@azure/search-documents": "12.1.0",
|
||||
"@azure/storage-blob": "12.28.0",
|
||||
"@google-cloud/pubsub": "5.2.0",
|
||||
"@google-cloud/translate": "9.2.0",
|
||||
"@koa/cors": "5.0.0",
|
||||
"@koa/router": "14.0.0",
|
||||
"@langchain/anthropic": "0.3.28",
|
||||
"@langchain/community": "0.3.56",
|
||||
"@langchain/core": "0.3.77",
|
||||
"@langchain/openai": "0.6.13",
|
||||
"@microsoft/microsoft-graph-client": "3.0.7",
|
||||
"@push-rpc/core": "1.9.3",
|
||||
"@push-rpc/http": "1.9.3",
|
||||
"@push-rpc/openapi": "1.9.3",
|
||||
"@push-rpc/websocket": "1.9.3",
|
||||
"@sequelize/core": "7.0.0-alpha.46",
|
||||
"@sequelize/postgres": "7.0.0-alpha.46",
|
||||
"@types/validator": "13.15.3",
|
||||
"adm-zip": "0.5.16",
|
||||
"alasql": "4.6.6",
|
||||
"any-shell-escape": "0.1.1",
|
||||
"arraybuffer-to-buffer": "0.0.7",
|
||||
"async-mutex": "0.5.0",
|
||||
"async-promises": "0.2.3",
|
||||
"async-retry": "1.3.3",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcrypt": "6.0.0",
|
||||
"billboard.js": "3.17.0",
|
||||
"bluebird": "3.7.2",
|
||||
"body-parser": "2.2.0",
|
||||
"botbuilder": "4.23.3",
|
||||
"botbuilder-ai": "4.23.3",
|
||||
"botbuilder-dialogs": "4.23.3",
|
||||
"botframework-connector": "4.23.3",
|
||||
"botlib-legacy": "5.3.0",
|
||||
"cd": "0.3.3",
|
||||
"chalk-animation": "2.0.3",
|
||||
"chrome-remote-interface": "0.33.3",
|
||||
"cli-progress": "3.12.0",
|
||||
"cli-spinner": "0.2.10",
|
||||
"core-js": "3.45.1",
|
||||
"cors": "2.8.5",
|
||||
"csv-database": "0.9.2",
|
||||
"data-forge": "1.10.4",
|
||||
"date-diff": "1.0.2",
|
||||
"docximager": "0.0.4",
|
||||
"docxtemplater": "3.66.3",
|
||||
"dotenv-extended": "2.9.0",
|
||||
"exceljs": "4.4.0",
|
||||
"express": "^5.1.0",
|
||||
"express-remove-route": "1.0.0",
|
||||
"facebook-nodejs-business-sdk": "23.0.2",
|
||||
"ffmpeg-static": "5.2.0",
|
||||
"final-stream": "2.0.4",
|
||||
"formidable": "3.5.4",
|
||||
"glob": "11.0.3",
|
||||
"google-libphonenumber": "3.2.43",
|
||||
"googleapis": "160.0.0",
|
||||
"hnswlib-node": "3.0.0",
|
||||
"html-to-md": "0.8.8",
|
||||
"http-proxy": "1.18.1",
|
||||
"ibm-watson": "11.0.0",
|
||||
"icojs": "0.19.5",
|
||||
"iso-639-1": "3.1.5",
|
||||
"isomorphic-fetch": "3.0.0",
|
||||
"jimp": "1.6.0",
|
||||
"js-md5": "0.8.3",
|
||||
"json-schema-to-zod": "2.6.1",
|
||||
"jsqr": "1.4.0",
|
||||
"just-indent": "0.0.1",
|
||||
"keyv": "5.5.3",
|
||||
"koa": "3.0.1",
|
||||
"koa-body": "6.0.1",
|
||||
"koa-ratelimit": "6.0.0",
|
||||
"langchain": "0.3.34",
|
||||
"language-tags": "2.1.0",
|
||||
"line-replace": "2.0.1",
|
||||
"livekit-server-sdk": "2.13.3",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.7.2",
|
||||
"mammoth": "1.11.0",
|
||||
"mariadb": "3.4.5",
|
||||
"marked": "16.3.0",
|
||||
"mime-types": "3.0.1",
|
||||
"minio": "8.0.6",
|
||||
"moment": "2.30.1",
|
||||
"mysql": "2.18.1",
|
||||
"node-cron": "4.2.1",
|
||||
"node-gyp": "^11.4.2",
|
||||
"node-html-parser": "7.0.1",
|
||||
"node-nlp": "4.27.0",
|
||||
"nodemailer": "7.0.6",
|
||||
"nodemon": "3.1.10",
|
||||
"npm": "11.6.1",
|
||||
"office-text-extractor": "3.0.3",
|
||||
"open": "10.2.0",
|
||||
"open-docxtemplater-image-module": "1.0.3",
|
||||
"openai": "5.23.1",
|
||||
"pdf-extraction": "1.0.2",
|
||||
"pdf-parse": "1.1.1",
|
||||
"pdf-to-png-converter": "3.10.0",
|
||||
"pdfjs-dist": "5.4.149",
|
||||
"pg": "8.16.3",
|
||||
"phone": "3.1.67",
|
||||
"pizzip": "3.2.0",
|
||||
"pptxtemplater": "1.0.5",
|
||||
"prism-media": "1.3.5",
|
||||
"public-ip": "8.0.0",
|
||||
"punycode": "2.3.1",
|
||||
"puppeteer": "24.22.3",
|
||||
"puppeteer-extra": "3.3.6",
|
||||
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
||||
"qr-scanner": "1.4.2",
|
||||
"qrcode": "1.5.4",
|
||||
"qrcode-reader": "1.0.4",
|
||||
"qrcode-terminal": "0.12.0",
|
||||
"readline": "1.3.0",
|
||||
"reflect-metadata": "0.2.2",
|
||||
"rimraf": "6.0.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"scanf": "1.2.0",
|
||||
"sequelize": "6.37.7",
|
||||
"sequelize-cli": "6.6.3",
|
||||
"sequelize-typescript": "2.1.6",
|
||||
"simple-git": "3.28.0",
|
||||
"speakingurl": "14.0.1",
|
||||
"strict-password-generator": "1.1.2",
|
||||
"stripe": "18.5.0",
|
||||
"super-strong-password-generator": "2.0.2",
|
||||
"super-strong-password-generator-es": "2.0.2",
|
||||
"swagger-client": "3.35.7",
|
||||
"swagger-ui-dist": "5.29.0",
|
||||
"tabulator-tables": "6.3.1",
|
||||
"tedious": "18.6.1",
|
||||
"twilio": "5.10.1",
|
||||
"twitter-api-v2": "1.27.0",
|
||||
"typeorm": "0.3.27",
|
||||
"typescript": "5.9.2",
|
||||
"url-join": "5.0.0",
|
||||
"vhost": "3.0.2",
|
||||
"walk-promise": "0.2.0",
|
||||
"washyourmouthoutwithsoap": "1.0.2",
|
||||
"webdav-server": "2.6.2",
|
||||
"webp-converter": "2.3.3",
|
||||
"whatsapp-cloud-api": "0.3.1",
|
||||
"whatsapp-web.js": "1.34.1",
|
||||
"ws": "8.18.3",
|
||||
"yaml": "2.8.1",
|
||||
"yarn": "1.22.22",
|
||||
"zod-to-json-schema": "3.24.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "4.17.20",
|
||||
"@types/node": "24.5.2",
|
||||
"@types/qrcode": "1.5.5",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"tsx": "4.20.6",
|
||||
"vitest": "3.2.4"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"mocha": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
},
|
||||
"rules": {
|
||||
"indent": "off",
|
||||
"linebreak-style": [
|
||||
"warn",
|
||||
"unix"
|
||||
],
|
||||
"no-unused-vars": [
|
||||
"warn"
|
||||
],
|
||||
"no-undef": [
|
||||
"warn"
|
||||
],
|
||||
"no-console": [
|
||||
"warn"
|
||||
],
|
||||
"no-case-declarations": [
|
||||
"warn"
|
||||
],
|
||||
"no-extra-semi": [
|
||||
"warn"
|
||||
],
|
||||
"no-unreachable": [
|
||||
"warn"
|
||||
],
|
||||
"no-redeclare": [
|
||||
"warn"
|
||||
],
|
||||
"no-useless-escape": [
|
||||
"warn"
|
||||
],
|
||||
"no-constant-condition": [
|
||||
"warn"
|
||||
]
|
||||
}
|
||||
},
|
||||
"release": {
|
||||
"tagFormat": "${version}",
|
||||
"debug": true,
|
||||
"branches": [
|
||||
"main"
|
||||
],
|
||||
"verifyConditions": [
|
||||
"@semantic-release/github"
|
||||
],
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/changelog"
|
||||
],
|
||||
"prepare": [
|
||||
"@semantic-release/npm",
|
||||
{
|
||||
"path": "@semantic-release/exec",
|
||||
"cmd": "git status"
|
||||
},
|
||||
"@semantic-release/changelog",
|
||||
{
|
||||
"path": "@semantic-release/git",
|
||||
"assets": [
|
||||
"package.json",
|
||||
"CHANGELOG.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"publish": [
|
||||
"@semantic-release/npm",
|
||||
"@semantic-release/github"
|
||||
],
|
||||
"analyzeCommits": "simple-commit-message"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
},
|
||||
"pre-git": {
|
||||
"commit-msg": "simple",
|
||||
"pre-commit": [],
|
||||
"pre-push": [],
|
||||
"post-commit": [],
|
||||
"post-checkout": [],
|
||||
"post-merge": []
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"lodash.trimend": "npm:lodash@4.17.21",
|
||||
"lodash.isequal": "npm:lodash@4.17.21",
|
||||
"node-domexception": "npm:whatwg-url@11.0.0",
|
||||
"csv-database": {
|
||||
"fast-csv": "4.3.6"
|
||||
},
|
||||
"sequelize-typescript": {
|
||||
"glob": "~9.0.0"
|
||||
},
|
||||
"tough-cookie": "4.1.3",
|
||||
"phin": "3.7.1",
|
||||
"xmldom": "npm:@xmldom/xmldom@0.8.10",
|
||||
"form-data": "2.5.5",
|
||||
"uuid": "9.0.1",
|
||||
"har-validator": "5.1.5",
|
||||
"yaeti": "npm:events@3.3.0",
|
||||
"text-encoding": "npm:text-encoder-lite@1.0.1",
|
||||
"docximager": {
|
||||
"xml2js": "0.5.0"
|
||||
},
|
||||
"tar-fs": "3.1.0",
|
||||
"ws": "8.18.3",
|
||||
"xml2js": "0.6.2",
|
||||
"inflight": "npm:lru-cache@10.2.0",
|
||||
"rimraf": "6.0.1",
|
||||
"glob": "11.0.3",
|
||||
"fstream": "npm:fs-extra@11.0.0",
|
||||
"openai": "5.23.1",
|
||||
"puppeteer": "24.22.3",
|
||||
"fluent-ffmpeg": "npm:ffmpeg-static@5.0.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz",
|
||||
"@nlpjs/xtables": {
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,468 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import crypto from 'crypto';
|
||||
import urlJoin from 'url-join';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||
import { GBImporter } from '../../core.gbapp/services/GBImporterService.js';
|
||||
import { Messages } from '../strings.js';
|
||||
import { GBAdminService } from '../services/GBAdminService.js';
|
||||
|
||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService.js';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
|
||||
class AdminDialog extends IGBDialog {
|
||||
public static isIntentYes(locale, utterance) {
|
||||
return utterance.toLowerCase().match(Messages[locale].affirmative_sentences);
|
||||
}
|
||||
|
||||
public static isIntentNo(locale, utterance) {
|
||||
return utterance.toLowerCase().match(Messages[locale].negative_sentences);
|
||||
}
|
||||
|
||||
public static setup(min: GBMinInstance) {
|
||||
const importer = new GBImporter(min.core);
|
||||
const deployer = new GBDeployer(min.core, importer);
|
||||
|
||||
AdminDialog.setupSecurityDialogs(min);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/admin-auth', [
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].authenticate;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, prompt);
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale = step.context.activity.locale;
|
||||
const sensitive = step.context.activity['originalText'];
|
||||
|
||||
if (await GBUtil.comparePassword(sensitive, min.instance.adminPass)) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].welcome);
|
||||
|
||||
return await step.endDialog(true);
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].wrong_password);
|
||||
return await step.replaceDialog('/admin-auth');
|
||||
}
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/admin', [
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].authenticate;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, prompt);
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale = step.context.activity.locale;
|
||||
const sensitive = step.context.activity['originalText'];
|
||||
|
||||
if (await GBUtil.comparePassword(sensitive, min.instance.adminPass)) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].welcome);
|
||||
|
||||
return await min.conversationalService.prompt(min, step, Messages[locale].which_task);
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].wrong_password);
|
||||
|
||||
return await step.endDialog();
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale: string = step.context.activity.locale;
|
||||
const text: string = step.context.activity['originalText'];
|
||||
const cmdName = text.split(' ')[0];
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].working(cmdName));
|
||||
let unknownCommand = false;
|
||||
|
||||
try {
|
||||
if (text === 'quit') {
|
||||
return await step.replaceDialog('/');
|
||||
} else if (cmdName === 'setupSecurity') {
|
||||
return await step.beginDialog('/setupSecurity');
|
||||
} else {
|
||||
unknownCommand = true;
|
||||
}
|
||||
|
||||
if (unknownCommand) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].unknown_command);
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].finished_working);
|
||||
}
|
||||
} catch (error) {
|
||||
await min.conversationalService.sendText(min, step, error.message ? error.message : error);
|
||||
}
|
||||
await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/install', [
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
step.activeDialog.state.options.args = (step.options as any).args;
|
||||
if (step.activeDialog.state.options.confirm) {
|
||||
return await step.next('sim');
|
||||
} else {
|
||||
const locale = step.context.activity.locale;
|
||||
return await min.conversationalService.prompt(min, step, Messages[locale].publish_type_yes);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
if (AdminDialog.isIntentYes(locale, step.result)) {
|
||||
const list = min.core.getParam(min.instance, '.gbapp List', null);
|
||||
const items = list ? list.split(';') : [];
|
||||
|
||||
step.activeDialog.state.options.args;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
for (let j = 0; j < min.appPackages.length; j++) {
|
||||
if (items[i] === min.appPackages[j]['name']) {
|
||||
const element = min.appPackages[i];
|
||||
await element.onExchangeData(min, 'install', null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].publish_canceled);
|
||||
}
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/logs', [
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const logs = await min.core['getLatestLogs']();
|
||||
await min.conversationalService.sendText(min, step, logs);
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/publish', [
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
step.activeDialog.state.options.confirm = true;
|
||||
if (step.activeDialog.state.options.confirm || process.env.ADMIN_OPEN_PUBLISH === 'true') {
|
||||
return await step.next('sim');
|
||||
} else {
|
||||
const locale = step.context.activity.locale;
|
||||
return await min.conversationalService.prompt(min, step, Messages[locale].publish_type_yes);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
if (AdminDialog.isIntentYes(locale, step.result)) {
|
||||
let from = step.context.activity.from.id;
|
||||
|
||||
let canPublish: Boolean;
|
||||
if (step.activeDialog.state.options.firstTime) {
|
||||
canPublish = true;
|
||||
} else {
|
||||
canPublish = AdminDialog.canPublish(min, from) || process.env.ADMIN_OPEN_PUBLISH === 'true';
|
||||
}
|
||||
|
||||
if (!canPublish) {
|
||||
await step.beginDialog('/admin-auth');
|
||||
} else {
|
||||
await step.next(true);
|
||||
}
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].publish_canceled);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const locale = step.context.activity.locale;
|
||||
if (!step.result) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].publish_must_be_admin);
|
||||
|
||||
return step.endDialog();
|
||||
}
|
||||
|
||||
const botId = min.instance.botId;
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].working('Publishing'));
|
||||
|
||||
step.activeDialog.state.options.args = (step.options as any).args;
|
||||
const filename = step.activeDialog.state.options.args
|
||||
? step.activeDialog.state.options.args.split(' ')[0]
|
||||
: null;
|
||||
|
||||
const packages = [];
|
||||
let skipError = false;
|
||||
if (!filename || filename === '') {
|
||||
await min.conversationalService.sendText(min, step, `Starting publishing for ${botId} packages...`);
|
||||
packages.push(`${botId}.gbot`);
|
||||
packages.push(`${botId}.gbtheme`);
|
||||
packages.push(`${botId}.gbdrive`);
|
||||
packages.push(`${botId}.gbdata`);
|
||||
packages.push(`${botId}.gbkb`);
|
||||
packages.push(`${botId}.gbdialog`);
|
||||
skipError = true;
|
||||
} else {
|
||||
packages.push(filename);
|
||||
}
|
||||
|
||||
await GBUtil.asyncForEach(packages, async packageName => {
|
||||
let cmd1;
|
||||
|
||||
if (
|
||||
packageName.toLowerCase() === 'gbdialog' ||
|
||||
packageName.toLowerCase() === 'gbdrive' ||
|
||||
packageName.toLowerCase() === 'gbdata' ||
|
||||
packageName.toLowerCase() === 'gbkb' ||
|
||||
packageName.toLowerCase() === 'gbot' ||
|
||||
packageName.toLowerCase() === 'gbtheme'
|
||||
) {
|
||||
packageName = `${min.botId}.${packageName}`;
|
||||
}
|
||||
|
||||
if (packageName.indexOf('.') !== -1) {
|
||||
cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${GBConfigService.get('STORAGE_LIBRARY')}/${botId}.gbai/${packageName}`;
|
||||
} else {
|
||||
cmd1 = `deployPackage ${packageName}`;
|
||||
}
|
||||
if (
|
||||
(await (deployer as any).getStoragePackageByName(min.instance.instanceId, packageName)) !== null &&
|
||||
!process.env.DONT_DOWNLOAD
|
||||
) {
|
||||
const cmd2 = `undeployPackage ${packageName}`;
|
||||
await GBAdminService.undeployPackageCommand(cmd2, min);
|
||||
}
|
||||
let sec = new SecService();
|
||||
const member = step.context.activity.from;
|
||||
const user = await sec.ensureUser(min, member.id, member.name, '', 'web', member.name, null);
|
||||
|
||||
await GBAdminService.deployPackageCommand(min, user, cmd1, deployer);
|
||||
|
||||
// .gbot updates severals keys in instantece, so min must be updated.
|
||||
|
||||
const activeMin = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
|
||||
if (activeMin) {
|
||||
min = activeMin;
|
||||
}
|
||||
});
|
||||
await min.conversationalService.sendText(min, step, `Training is finished.`);
|
||||
|
||||
if (!step.activeDialog.state.options.confirm) {
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
} else {
|
||||
return await step.endDialog();
|
||||
}
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
public static canPublish(min: GBMinInstance, phone: string): Boolean {
|
||||
if (process.env.SECURITY_CAN_PUBLISH !== undefined) {
|
||||
let list = process.env.SECURITY_CAN_PUBLISH.split(';');
|
||||
|
||||
const canPublish = min.core.getParam(min.instance, 'Can Publish', null);
|
||||
if (canPublish) {
|
||||
list = list.concat(canPublish.split(';'));
|
||||
}
|
||||
|
||||
let result = list.includes(phone);
|
||||
|
||||
if (!result && min.instance.params) {
|
||||
const params = JSON.parse(min.instance.params);
|
||||
if (params) {
|
||||
return list.includes(params['Can Publish']);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static setupSecurityDialogs(min: GBMinInstance) {
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/setupSecurity', [
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
const tokenName = (step.activeDialog.state.tokenName = step.options['args']);
|
||||
if (tokenName) {
|
||||
((step.activeDialog.state.clientId = min.core.getParam<string>(
|
||||
min.instance,
|
||||
`${tokenName} Client ID`,
|
||||
null
|
||||
)),
|
||||
(step.activeDialog.state.host = min.core.getParam<string>(min.instance, `${tokenName} Host`, null)),
|
||||
(step.activeDialog.state.tenant = min.core.getParam<string>(min.instance, `${tokenName} Tenant`, null)));
|
||||
}
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
if (step.activeDialog.state.tokenName) {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].enter_authenticator_tenant;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, prompt);
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
if (step.activeDialog.state.tokenName) {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
step.activeDialog.state.authenticatorTenant = step.context.activity['originalText'];
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].enter_authenticator_authority_host_url;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, prompt);
|
||||
},
|
||||
async step => {
|
||||
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
|
||||
step.activeDialog.state.authenticatorAuthorityHostUrl = step.context.activity['originalText'];
|
||||
|
||||
const tokenName = step.activeDialog.state.tokenName;
|
||||
|
||||
if (!tokenName) {
|
||||
min.instance.authenticatorAuthorityHostUrl = step.activeDialog.state.authenticatorAuthorityHostUrl;
|
||||
min.instance.authenticatorTenant = step.activeDialog.state.authenticatorTenant;
|
||||
|
||||
await min.adminService.updateSecurityInfo(
|
||||
min.instance.instanceId,
|
||||
tokenName ? step.activeDialog.state.tenant : step.activeDialog.state.authenticatorTenant,
|
||||
tokenName ? step.activeDialog.state.host : step.activeDialog.state.authenticatorAuthorityHostUrl
|
||||
);
|
||||
}
|
||||
const locale = step.context.activity.locale;
|
||||
const buf = Buffer.alloc(16);
|
||||
const state = `${min.instance.instanceId}${crypto.randomFillSync(buf).toString('hex')}`;
|
||||
|
||||
min.adminService.setValue(min.instance.instanceId, `${tokenName}AntiCSRFAttackState`, state);
|
||||
|
||||
const redirectUri = urlJoin(
|
||||
process.env.BOT_URL,
|
||||
min.instance.botId,
|
||||
tokenName ? `/token?value=${tokenName}` : '/token'
|
||||
);
|
||||
const scope = tokenName ? '' : 'https://graph.microsoft.com/.default';
|
||||
const host = tokenName ? step.activeDialog.state.host : 'https://login.microsoftonline.com';
|
||||
const tenant = tokenName ? step.activeDialog.state.tenant : min.instance.authenticatorTenant;
|
||||
const clientId = tokenName
|
||||
? step.activeDialog.state.clientId
|
||||
: min.instance.marketplaceId
|
||||
? min.instance.marketplaceId
|
||||
: GBConfigService.get('MARKETPLACE_ID');
|
||||
const oauth2 = tokenName ? 'oauth' : 'oauth2';
|
||||
const url = `${host}/${tenant}/${oauth2}/authorize?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&scope=${scope}&state=${state}&response_mode=query`;
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].consent(url));
|
||||
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { AdminDialog };
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib-legacy';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { AdminDialog } from './dialogs/AdminDialog.js';
|
||||
import { GuaribasAdmin } from './models/AdminModel.js';
|
||||
import { GBLogEx } from '../core.gbapp/services/GBLogEx.js';
|
||||
|
||||
|
||||
/**
|
||||
* The package for admin.gbapp.
|
||||
*/
|
||||
export class GBAdminPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
|
||||
public async getDialogs (min: GBMinInstance) {
|
||||
GBLogEx.verbose(min,`getDialogs called.`);
|
||||
}
|
||||
public async unloadPackage (core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async unloadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLogEx.verbose(min,`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLogEx.verbose(min, `onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
|
||||
GBLogEx.verbose(min,`onExchangeData called.`);
|
||||
}
|
||||
|
||||
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
core.sequelize.addModels([GuaribasAdmin]);
|
||||
}
|
||||
|
||||
public async loadBot (min: GBMinInstance): Promise<void> {
|
||||
AdminDialog.setup(min);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Column, CreatedAt, DataType, Model, Table, UpdatedAt } from 'sequelize-typescript';
|
||||
|
||||
/**
|
||||
* General settings store.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasAdmin extends Model<GuaribasAdmin> {
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare key: string;
|
||||
|
||||
@Column(DataType.STRING(4000))
|
||||
declare value: string;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
|
|
@ -1,341 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
GBError,
|
||||
GBLog,
|
||||
GBMinInstance,
|
||||
IGBAdminService,
|
||||
IGBCoreService,
|
||||
IGBDeployer,
|
||||
IGBInstance
|
||||
} from 'botlib-legacy';
|
||||
import { FindOptions } from 'sequelize/types';
|
||||
import urlJoin from 'url-join';
|
||||
import { GuaribasInstance } from '../../core.gbapp/models/GBModel.js';
|
||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService.js';
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||
import { GBImporter } from '../../core.gbapp/services/GBImporterService.js';
|
||||
import { GBSharePointService } from '../../sharepoint.gblib/services/SharePointService.js';
|
||||
import { GuaribasAdmin } from '../models/AdminModel.js';
|
||||
import path from 'path';
|
||||
import { caseSensitive_Numbs_SpecialCharacters_PW, lowercase_PW } from 'super-strong-password-generator';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs/promises';
|
||||
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';
|
||||
|
||||
let msRestAzure: any = null;
|
||||
|
||||
try {
|
||||
const msRestAzure = require('ms-rest-azure');
|
||||
} catch (error) {}
|
||||
|
||||
let AuthenticationContext: any = null;
|
||||
|
||||
try {
|
||||
const adal = require('adal-node');
|
||||
AuthenticationContext = adal.AuthenticationContext;
|
||||
} catch (error) {}
|
||||
|
||||
/**
|
||||
* Services for server administration.
|
||||
*/
|
||||
export class GBAdminService implements IGBAdminService {
|
||||
public static GB_PROMPT: string = 'GeneralBots: ';
|
||||
public static masterBotInstanceId = 0;
|
||||
|
||||
public static StrongRegex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})');
|
||||
|
||||
public core: IGBCoreService;
|
||||
|
||||
constructor(core: IGBCoreService) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public static generateUuid(): string {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
public static async getNodeVersion() {
|
||||
const packageJson = urlJoin(process.cwd(), 'package.json');
|
||||
const pkg = JSON.parse(await fs.readFile(packageJson, 'utf8'));
|
||||
return pkg.engines.node.replace('=', '');
|
||||
}
|
||||
|
||||
public static async getADALTokenFromUsername(username: string, password: string) {
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
|
||||
|
||||
return (credentials as any).tokenCache._entries[0].accessToken;
|
||||
}
|
||||
|
||||
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;
|
||||
s.split('').forEach(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.');
|
||||
}
|
||||
|
||||
const min = 10 ** (digits - 1);
|
||||
const max = 10 ** digits - 1;
|
||||
const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
return randomNumber.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://stackoverflow.com/a/52171480
|
||||
*/
|
||||
public static getHash(str: string, seed = 0) {
|
||||
let h1 = 0xdeadbeef ^ seed,
|
||||
h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||
}
|
||||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||
}
|
||||
|
||||
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);
|
||||
const packagePath = GBUtil.getGBAIPath(min.botId, null, packageName);
|
||||
const localFolder = path.join('work', packagePath);
|
||||
await deployer.undeployPackageFromLocalPath(min.instance, localFolder);
|
||||
}
|
||||
|
||||
public static isSharePointPath(path: string) {
|
||||
return path.indexOf('sharepoint.com') !== -1;
|
||||
}
|
||||
public static async deployPackageCommand(
|
||||
min: GBMinInstance,
|
||||
user: GuaribasUser,
|
||||
text: string,
|
||||
deployer: IGBDeployer
|
||||
) {
|
||||
const packageName = text.split(' ')[1];
|
||||
|
||||
const folderName = text.substring(text.indexOf(packageName) + packageName.length + 1);
|
||||
const packageType = path.extname(folderName).substr(1);
|
||||
const gbaiPath = GBUtil.getGBAIPath(min.instance.botId, packageType, null);
|
||||
const localFolder = path.join('work', gbaiPath);
|
||||
|
||||
await deployer['deployPackage2'](min, user, localFolder, true);
|
||||
}
|
||||
|
||||
public async setValue(instanceId: number, key: string, value: string) {
|
||||
const options = <FindOptions>{ where: {} };
|
||||
options.where = { key: key, instanceId: instanceId };
|
||||
let admin = await GuaribasAdmin.findOne(options);
|
||||
if (admin === null) {
|
||||
admin = new GuaribasAdmin();
|
||||
admin.key = key;
|
||||
}
|
||||
admin.value = value;
|
||||
admin.instanceId = instanceId;
|
||||
await admin.save();
|
||||
}
|
||||
|
||||
public async updateSecurityInfo(
|
||||
instanceId: number,
|
||||
authenticatorTenant: string,
|
||||
authenticatorAuthorityHostUrl: string
|
||||
): Promise<IGBInstance> {
|
||||
const options = <FindOptions>{ where: {} };
|
||||
options.where = { instanceId: instanceId };
|
||||
const item = await GuaribasInstance.findOne(options);
|
||||
item.authenticatorTenant = authenticatorTenant;
|
||||
item.authenticatorAuthorityHostUrl = authenticatorAuthorityHostUrl;
|
||||
|
||||
return item.save();
|
||||
}
|
||||
|
||||
public async getValue(instanceId: number, key: string): Promise<string> {
|
||||
const options = <FindOptions>{ where: {} };
|
||||
options.where = { key: key, instanceId: instanceId };
|
||||
const obj = await GuaribasAdmin.findOne(options);
|
||||
return obj.value;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
GBLogEx.info(instanceId, `Acquiring token for instanceId: ${instanceId} ${tokenName} (root: ${root}).`);
|
||||
|
||||
let expiresOnV;
|
||||
try {
|
||||
expiresOnV = await this.getValue(instanceId, `${tokenName}expiresOn`);
|
||||
} catch (error) {
|
||||
throw new Error(`/setupSecurity is required before running /publish.`);
|
||||
}
|
||||
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
const instance = await this.core.loadInstanceById(instanceId);
|
||||
|
||||
const expiresOn = new Date(expiresOnV);
|
||||
if (expiresOn.getTime() > new Date().getTime()) {
|
||||
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 buff = new Buffer(`${clientId}:${clientSecret}`);
|
||||
const base64 = buff.toString('base64');
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: '1.0',
|
||||
Authorization: `Basic ${base64}`,
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: refreshToken
|
||||
})
|
||||
};
|
||||
const result = await fetch(url, options);
|
||||
|
||||
if (result.status != 200) {
|
||||
const text = await result.text();
|
||||
throw new Error(`acquireElevatedToken refreshing token: ${result.status}: ${result.statusText} ${text}.`);
|
||||
}
|
||||
|
||||
const text = await result.text();
|
||||
const token = JSON.parse(text);
|
||||
|
||||
// Saves token to the database.
|
||||
|
||||
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}AntiCSRFAttackState`, null);
|
||||
|
||||
resolve(token['access_token']);
|
||||
} else {
|
||||
const oauth2 = tokenName ? 'oauth' : 'oauth2';
|
||||
const authorizationUrl = urlJoin(
|
||||
tokenName ? host : instance.authenticatorAuthorityHostUrl,
|
||||
tokenName ? tenant : instance.authenticatorTenant,
|
||||
`/${oauth2}/authorize`
|
||||
);
|
||||
|
||||
const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`);
|
||||
const resource = tokenName ? '' : 'https://graph.microsoft.com';
|
||||
const authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||
|
||||
authenticationContext.acquireTokenWithRefreshToken(
|
||||
refreshToken,
|
||||
tokenName ? clientId : instance.marketplaceId,
|
||||
tokenName ? clientSecret : instance.marketplacePassword,
|
||||
resource,
|
||||
async (err, res) => {
|
||||
if (err !== null) {
|
||||
reject(err);
|
||||
} else {
|
||||
const token = res;
|
||||
try {
|
||||
await this.setValue(instanceId, `${tokenName}accessToken`, token.accessToken);
|
||||
await this.setValue(instanceId, `${tokenName}refreshToken`, token.refreshToken);
|
||||
await this.setValue(instanceId, `${tokenName}expiresOn`, token.expiresOn.toString());
|
||||
resolve(token.accessToken);
|
||||
} catch (error) {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise<void> {}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
export const Messages = {
|
||||
'en-US': {
|
||||
authenticate: 'Please, authenticate:',
|
||||
welcome: 'Welcome to pragmatismo.com.br GeneralBots Administration.',
|
||||
which_task: 'Which task do you wanna run now?',
|
||||
working: command => `I'm working on ${command}...`,
|
||||
finished_working: 'Done.',
|
||||
unknown_command: text =>
|
||||
`Well, but ${text} is not a administrative General Bots command, I will try to search for it.`,
|
||||
hi: text => `Hello, ${text}.`,
|
||||
undeployPackage: text => `Undeploying package ${text}...`,
|
||||
deployPackage: text => `Deploying package ${text}...`,
|
||||
redeployPackage: text => `Redeploying package ${text}...`,
|
||||
packageUndeployed: text => `√ Package ${text} undeployed...`,
|
||||
consent: url => `Please, consent access to this app at: [Microsoft Online](${url}).`,
|
||||
wrong_password: 'Sorry, wrong password. Please, try again.',
|
||||
enter_authenticator_tenant: 'Enter the Authenticator Tenant (eg.: domain.onmicrosoft.com):',
|
||||
enter_authenticator_authority_host_url: 'Enter the Authority Host URL (eg.: https://login.microsoftonline.com): ',
|
||||
enter_authenticator_client_id: `Enter the Client Id GUID: Get from
|
||||
[this url](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview)`,
|
||||
enter_authenticator_client_secret: 'Enter the Client Secret:',
|
||||
publish_must_be_admin: 'Seu telefone precisa estar com privilégios administrativos para realizar publicação.',
|
||||
publish_success: 'Publicação realizada.',
|
||||
publish_type_yes: 'Por favor, digite *Sim* para continuar com a publicação.',
|
||||
publish_canceled: 'Publicação cancelada.'
|
||||
},
|
||||
'pt-BR': {
|
||||
authenticate: 'Please, authenticate:',
|
||||
welcome: 'Welcome to pragmatismo.com.br GeneralBots Administration.',
|
||||
which_task: 'Which task do you wanna run now?',
|
||||
working: command => `I'm working on ${command}...`,
|
||||
finished_working: 'Done.',
|
||||
unknown_command: text =>
|
||||
`Well, but ${text} is not a administrative General Bots command, I will try to search for it.`,
|
||||
hi: text => `Hello, ${text}.`,
|
||||
undeployPackage: text => `Undeploying package ${text}...`,
|
||||
deployPackage: text => `Deploying package ${text}...`,
|
||||
redeployPackage: text => `Redeploying package ${text}...`,
|
||||
packageUndeployed: text => `Package ${text} undeployed...`,
|
||||
consent: url => `Please, consent access to this app at: [Microsoft Online](${url}).`,
|
||||
wrong_password: 'Sorry, wrong password. Please, try again.',
|
||||
enter_authenticator_tenant: 'Enter the Authenticator Tenant (eg.: domain.onmicrosoft.com):',
|
||||
enter_authenticator_authority_host_url: 'Enter the Authority Host URL (eg.: https://login.microsoftonline.com): ',
|
||||
enter_authenticator_client_id: `Enter the Client Id GUID: Get from
|
||||
[this url](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview)`,
|
||||
enter_authenticator_client_secret: 'Enter the Client Secret:',
|
||||
publish_must_be_admin: 'Seu telefone precisa estar com privilégios administrativos para realizar publicação.',
|
||||
publish_success: 'Publicação realizada.',
|
||||
publish_type_yes: 'Por favor, digite *Sim* para continuar com a publicação.',
|
||||
publish_canceled: 'Publicação cancelada.'
|
||||
}
|
||||
};
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib-legacy';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { GuaribasConversation, GuaribasConversationMessage } from './models/index.js';
|
||||
|
||||
/**
|
||||
* .gblib Package handler.
|
||||
*/
|
||||
export class GBAnalyticsPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
public async getDialogs (min: GBMinInstance) {
|
||||
GBLog.verbose(`getDialogs called.`);
|
||||
}
|
||||
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
GBLog.verbose(`loadPackage called.`);
|
||||
core.sequelize.addModels([GuaribasConversation, GuaribasConversationMessage]);
|
||||
}
|
||||
public async unloadPackage (core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async loadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`loadBot called.`);
|
||||
}
|
||||
public async unloadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLog.verbose(`onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
|
||||
GBLog.verbose(`onExchangeData called.`);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
BelongsToMany,
|
||||
Column,
|
||||
CreatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
HasMany,
|
||||
IsUUID,
|
||||
Length,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
Sequelize,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasChannel, GuaribasInstance } from '../../core.gbapp/models/GBModel.js';
|
||||
import { GuaribasSubject } from '../../kb.gbapp/models/index.js';
|
||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||
|
||||
/**
|
||||
* A conversation that groups many messages.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasConversation extends Model<GuaribasConversation> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column(DataType.INTEGER)
|
||||
declare conversationId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasSubject)
|
||||
@Column(DataType.INTEGER)
|
||||
declare startSubjectId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasSubject)
|
||||
declare startSubject: GuaribasSubject;
|
||||
|
||||
@ForeignKey(() => GuaribasChannel)
|
||||
@Column(DataType.INTEGER)
|
||||
declare channelId: string;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
declare rateDate: Date;
|
||||
|
||||
@Column(DataType.FLOAT)
|
||||
declare rate: number;
|
||||
|
||||
@Column(DataType.STRING(512))
|
||||
declare feedback: string;
|
||||
|
||||
@CreatedAt
|
||||
@Column(DataType.DATE)
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare text: string;
|
||||
|
||||
@ForeignKey(() => GuaribasUser)
|
||||
@Column(DataType.INTEGER)
|
||||
declare startedByUserId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasUser)
|
||||
declare startedBy: GuaribasUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single message in a conversation.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasConversationMessage extends Model<GuaribasConversationMessage> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column(DataType.INTEGER)
|
||||
declare conversationMessageId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasSubject)
|
||||
@Column(DataType.INTEGER)
|
||||
declare subjectId: number;
|
||||
|
||||
@Column(DataType.TEXT)
|
||||
declare content: string;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
|
||||
//tslint:disable-next-line:no-use-before-declare
|
||||
@ForeignKey(() => GuaribasConversation)
|
||||
@Column(DataType.INTEGER)
|
||||
declare conversationId: number;
|
||||
|
||||
//tslint:disable-next-line:no-use-before-declare
|
||||
@BelongsTo(() => GuaribasConversation)
|
||||
declare conversation: GuaribasConversation;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasUser)
|
||||
@Column(DataType.INTEGER)
|
||||
declare userId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasUser)
|
||||
declare user: GuaribasUser;
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
import { FindOptions } from 'sequelize/types';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||
import { GuaribasConversation, GuaribasConversationMessage } from '../models/index.js';
|
||||
|
||||
/**
|
||||
* Base services for Bot Analytics.
|
||||
*/
|
||||
export class AnalyticsService {
|
||||
public async createConversation(user: GuaribasUser): Promise<GuaribasConversation> {
|
||||
const conversation = new GuaribasConversation();
|
||||
conversation.startedBy = user;
|
||||
conversation.startedByUserId = user.userId;
|
||||
conversation.instanceId = user.instanceId;
|
||||
|
||||
return await conversation.save();
|
||||
}
|
||||
|
||||
public async updateConversationSuggestion(
|
||||
instanceId: number,
|
||||
conversationId: string,
|
||||
feedback: string,
|
||||
locale: string
|
||||
): Promise<number> {
|
||||
const minBoot = GBServer.globals.minBoot as any;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async createMessage(
|
||||
instanceId: number,
|
||||
conversationId: number,
|
||||
userId: number,
|
||||
content: string
|
||||
): Promise<GuaribasConversationMessage> {
|
||||
const message = GuaribasConversationMessage.build();
|
||||
message.content = typeof content === 'object' ? JSON.stringify(content) : content;
|
||||
message.instanceId = instanceId;
|
||||
message.userId = userId;
|
||||
message.conversationId = conversationId;
|
||||
|
||||
return await message.save();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
*This is a General Bots open core package, more information can be found on the [BotServer](https://github.com/pragmatismo-io/BotServer) repository.*
|
||||
|
||||
This alpha version is using a hack in form of converter to
|
||||
translate BASIC to TS and string replacements to emulate await code.
|
||||
See http://jsfiddle.net/roderick/dym05hsy for more info on vb2ts, so
|
||||
http://stevehanov.ca/blog/index.php?id=92 should be used to run it without
|
||||
translation and enhance classic BASIC experience.
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib-legacy';
|
||||
import { GuaribasSchedule } from '../core.gbapp/models/GBModel.js';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import Koa from 'koa';
|
||||
import cors from '@koa/cors';
|
||||
import { createKoaHttpMiddleware } from '@push-rpc/http';
|
||||
import { GBServer } from '../../src/app.js';
|
||||
import { SocketServer } from '@push-rpc/core';
|
||||
import * as koaBody from 'koa-body';
|
||||
import ratelimit from 'koa-ratelimit';
|
||||
|
||||
export function createKoaHttpServer(port: number, getRemoteId: (ctx: Koa.Context) => string, opts: {}): SocketServer {
|
||||
const { onError, onConnection, middleware } = createKoaHttpMiddleware(getRemoteId);
|
||||
|
||||
const app = new Koa();
|
||||
|
||||
// Apply the rate-limiting middleware
|
||||
app.use(
|
||||
ratelimit({
|
||||
driver: 'memory', // Use 'memory' for in-memory store
|
||||
duration: 60000, // 1 minute window
|
||||
errorMessage: 'Slow down your requests',
|
||||
id: ctx => ctx.ip, // Identify client by IP address
|
||||
headers: {
|
||||
remaining: 'X-RateLimit-Remaining',
|
||||
reset: 'X-RateLimit-Reset',
|
||||
total: 'X-RateLimit-Limit'
|
||||
},
|
||||
max: 100, // Limit each IP to 100 requests per window
|
||||
disableHeader: false
|
||||
})
|
||||
);
|
||||
|
||||
app.use(cors({ origin: '*' }));
|
||||
app.use(koaBody.koaBody({ jsonLimit: '1024mb', textLimit: '1024mb', formLimit: '1024mb', multipart: true }));
|
||||
app.use(middleware);
|
||||
const server = app.listen(port);
|
||||
const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set.
|
||||
server.timeout = SERVER_TIMEOUT;
|
||||
|
||||
return {
|
||||
onError,
|
||||
onConnection,
|
||||
close(cb) {
|
||||
server.close(cb);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Package for core.gbapp.
|
||||
*/
|
||||
|
||||
export class GBBasicPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
public CurrentEngineName = 'guaribas-1.0.0';
|
||||
|
||||
public async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
core.sequelize.addModels([GuaribasSchedule]);
|
||||
}
|
||||
|
||||
public async getDialogs(min: GBMinInstance) {
|
||||
GBLog.verbose(`getDialogs called.`);
|
||||
}
|
||||
public async unloadPackage(core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async unloadBot(min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLog.verbose(`onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
|
||||
GBLog.verbose(`onExchangeData called.`);
|
||||
}
|
||||
public async loadBot(min: GBMinInstance): Promise<void> {
|
||||
const botId = min.botId;
|
||||
GBServer.globals.debuggers[botId] = {};
|
||||
GBServer.globals.debuggers[botId].state = 0;
|
||||
GBServer.globals.debuggers[botId].breaks = [];
|
||||
GBServer.globals.debuggers[botId].stateInfo = 'Stopped';
|
||||
GBServer.globals.debuggers[botId].childProcess = null;
|
||||
GBServer.globals.debuggers[botId].client = null;
|
||||
GBServer.globals.debuggers[botId].conversationId = null;
|
||||
GBServer.globals.debuggers[botId].watermarkMap = {};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
Column,
|
||||
CreatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasInstance } from '../../core.gbapp/models/GBModel.js';
|
||||
|
||||
@Table
|
||||
//tslint:disable-next-line:max-classes-per-file
|
||||
export class GuaribasSchedule extends Model<GuaribasSchedule> {
|
||||
@Column(DataType.STRING(255))
|
||||
name: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
schedule: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBSSR }from '../../core.gbapp/services/GBSSR.js';
|
||||
|
||||
export class ChartServices {
|
||||
/**
|
||||
* Generate chart image screenshot
|
||||
* @param {object} options billboard.js generation option object
|
||||
* @param {string} path screenshot image full path with file name
|
||||
*/
|
||||
public static async screenshot (args, path) {
|
||||
const browser = await GBSSR.createBrowser(null);
|
||||
const page = await browser.newPage();
|
||||
|
||||
// load billboard.js assets from CDN.
|
||||
await page.addStyleTag({ url: 'https://cdn.jsdelivr.net/npm/billboard.js/dist/theme/datalab.min.css' });
|
||||
await page.addScriptTag({ url: 'https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.pkgd.min.js' });
|
||||
|
||||
await page.evaluate(`bb.generate(${JSON.stringify(args)});`);
|
||||
|
||||
const content = await page.$('.bb');
|
||||
|
||||
await content.screenshot({
|
||||
path,
|
||||
omitBackground: true
|
||||
});
|
||||
|
||||
await page.close();
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,216 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBLog, GBMinInstance } from 'botlib-legacy';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import fs from 'fs/promises';
|
||||
import SwaggerClient from 'swagger-client';
|
||||
import { spawn } from 'child_process';
|
||||
import { CodeServices } from '../../llm.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.
|
||||
*/
|
||||
export class DebuggerService {
|
||||
|
||||
public async setBreakpoint({ botId, line }) {
|
||||
GBLogEx.info(botId, `Enabled breakpoint for ${botId} on ${line}.`);
|
||||
GBServer.globals.debuggers[botId].breaks.push(Number.parseInt(line));
|
||||
}
|
||||
|
||||
public async refactor({ botId, code, change }) {
|
||||
const service = new CodeServices();
|
||||
return await service.refactor(code, change);
|
||||
}
|
||||
|
||||
public async resume({ botId }) {
|
||||
if (GBServer.globals.debuggers[botId].state === 2) {
|
||||
const client = GBServer.globals.debuggers[botId].client;
|
||||
await client.Debugger.resume();
|
||||
GBServer.globals.debuggers[botId].state = 1;
|
||||
GBServer.globals.debuggers[botId].stateInfo = 'Running (Debug)';
|
||||
return { status: 'OK' };
|
||||
} else {
|
||||
const error = 'Invalid call to resume and state not being debug(2).';
|
||||
return { error: error };
|
||||
}
|
||||
}
|
||||
|
||||
public async stop({ botId }) {
|
||||
GBServer.globals.debuggers[botId].state = 0;
|
||||
GBServer.globals.debuggers[botId].stateInfo = 'Stopped';
|
||||
|
||||
const kill = ref => {
|
||||
spawn('sh', ['-c', `pkill -9 -f ${ref}`]);
|
||||
};
|
||||
|
||||
kill(GBServer.globals.debuggers[botId].childProcess);
|
||||
|
||||
return { status: 'OK' };
|
||||
}
|
||||
|
||||
public async step({ botId }) {
|
||||
if (GBServer.globals.debuggers[botId].state === 2) {
|
||||
GBServer.globals.debuggers[botId].stateInfo = 'Break';
|
||||
const client = GBServer.globals.debuggers[botId].client;
|
||||
await client.Debugger.stepOver();
|
||||
return { status: 'OK' };
|
||||
} else {
|
||||
const error = 'Invalid call to stepOver and state not being debug(2).';
|
||||
return { error: error };
|
||||
}
|
||||
}
|
||||
|
||||
public async getContext({ botId }) {
|
||||
const conversationsMap = GBServer.globals.debuggers[botId].conversationsMap;
|
||||
const watermarkMap = GBServer.globals.debuggers[botId].watermarkMap;
|
||||
|
||||
const conversationId = conversationsMap[botId];
|
||||
let messages = [];
|
||||
const client = GBServer.globals.debuggers[botId].client;
|
||||
if (client) {
|
||||
const response = await client.apis.Conversations.Conversations_GetActivities({
|
||||
conversationId: conversationId,
|
||||
watermark: watermarkMap[botId]
|
||||
});
|
||||
watermarkMap[botId] = response.obj.watermark;
|
||||
let activities = response.obj.activites;
|
||||
|
||||
if (activities && activities.length) {
|
||||
activities = activities.filter(m => m.from.id === botId && m.type === 'message');
|
||||
if (activities.length) {
|
||||
activities.forEach(activity => {
|
||||
messages.push({ text: activity.text });
|
||||
GBLogEx.info(botId, `Debugger sending text to API: ${activity.text}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let messagesText = messages.join('\n');
|
||||
|
||||
return {
|
||||
status: 'OK',
|
||||
state: GBServer.globals.debuggers[botId].state,
|
||||
messages: messagesText,
|
||||
scope: GBServer.globals.debuggers[botId].scope,
|
||||
scopeInfo: GBServer.globals.debuggers[botId].stateInfo
|
||||
};
|
||||
}
|
||||
|
||||
public async start({ botId, botApiKey, scriptName }) {
|
||||
const conversationsMap = GBServer.globals.debuggers[botId].conversationsMap;
|
||||
|
||||
let error;
|
||||
if (!GBServer.globals.debuggers[botId]) {
|
||||
GBServer.globals.debuggers[botId] = {};
|
||||
}
|
||||
|
||||
if (!scriptName) {
|
||||
scriptName = 'start';
|
||||
}
|
||||
|
||||
if (GBServer.globals.debuggers[botId].state === 1) {
|
||||
error = `Cannot DEBUG an already running process. ${botId}`;
|
||||
return { error: error };
|
||||
} else if (GBServer.globals.debuggers[botId].state === 2) {
|
||||
GBLogEx.info(botId, `Releasing execution ${botId} in DEBUG mode.`);
|
||||
await this.resume({ botId });
|
||||
return { status: 'OK' };
|
||||
} else {
|
||||
GBLogEx.info(botId, `Running ${botId} in DEBUG mode.`);
|
||||
GBServer.globals.debuggers[botId].state = 1;
|
||||
GBServer.globals.debuggers[botId].stateInfo = 'Running (Debug)';
|
||||
|
||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
||||
|
||||
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;
|
||||
GBServer.globals.debuggers[botId].conversationId = conversationId;
|
||||
|
||||
client.apis.Conversations.Conversations_PostActivity({
|
||||
conversationId: conversationId,
|
||||
activity: {
|
||||
textFormat: 'plain',
|
||||
text: `/calldbg ${scriptName}`,
|
||||
type: 'message',
|
||||
from: {
|
||||
id: 'word',
|
||||
name: 'word'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { status: 'OK' };
|
||||
}
|
||||
}
|
||||
|
||||
public async sendMessage({ botId, botApiKey, text }) {
|
||||
const conversationsMap = GBServer.globals.debuggers[botId].conversationsMap;
|
||||
|
||||
let error;
|
||||
if (!GBServer.globals.debuggers[botId]) {
|
||||
GBServer.globals.debuggers[botId] = {};
|
||||
}
|
||||
|
||||
if (GBServer.globals.debuggers[botId].state != 1) {
|
||||
error = `Cannot sendMessage to an stopped process. ${botId}`;
|
||||
return { error: error };
|
||||
}
|
||||
|
||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
||||
|
||||
const client = GBServer.globals.debuggers[botId].client;
|
||||
const conversationId = GBServer.globals.debuggers[botId].conversationId;
|
||||
|
||||
client.apis.Conversations.Conversations_PostActivity({
|
||||
conversationId: conversationId,
|
||||
activity: {
|
||||
textFormat: 'plain',
|
||||
text: text,
|
||||
type: 'message',
|
||||
from: {
|
||||
id: 'word',
|
||||
name: 'word'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { status: 'OK' };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import path from 'path';
|
||||
import { GBLog, GBMinInstance } from 'botlib-legacy';
|
||||
import { DialogKeywords } from './DialogKeywords.js';
|
||||
|
||||
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 { GBUtil } from '../../../src/util.js';
|
||||
import fs from 'fs/promises';
|
||||
import { AzureOpenAI } from 'openai';
|
||||
import { OpenAIClient } from '@langchain/openai';
|
||||
|
||||
/**
|
||||
* Image processing services of conversation to be called by BASIC.
|
||||
*/
|
||||
export class ImageProcessingServices {
|
||||
/**
|
||||
* Sharpen the image.
|
||||
*
|
||||
* @example file = SHARPEN file
|
||||
*/
|
||||
public async sharpen({ pid, file: file }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
GBLogEx.info(min, `Image Processing SHARPEN ${file}.`);
|
||||
|
||||
const gbfile = DialogKeywords.getFileByHandle(file);
|
||||
|
||||
// TODO: sharp.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* SET ORIENTATION VERTICAL
|
||||
*
|
||||
* file = MERGE file1, file2, file3
|
||||
*/
|
||||
public async mergeImage({ pid, files }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
let paths = [];
|
||||
await GBUtil.asyncForEach(files, async file => {
|
||||
const gbfile = DialogKeywords.getFileByHandle(file);
|
||||
paths.push(gbfile.path);
|
||||
});
|
||||
|
||||
const botId = min.instance.botId;
|
||||
const packagePath = GBUtil.getGBAIPath(min.botId);
|
||||
// TODO: const img = await joinImages(paths);
|
||||
const localName = path.join(
|
||||
'work',
|
||||
packagePath,
|
||||
'cache',
|
||||
`img-mrg${GBAdminService.getRndReadableIdentifier()}.png`
|
||||
);
|
||||
const url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName));
|
||||
// img.toFile(localName);
|
||||
|
||||
return { localName: localName, url: url, data: null };
|
||||
}
|
||||
|
||||
/**
|
||||
* Sharpen the image.
|
||||
*
|
||||
* @example file = BLUR file
|
||||
*/
|
||||
public async blur({ pid, file: file }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
GBLogEx.info(min, `Image Processing SHARPEN ${file}.`);
|
||||
|
||||
const gbfile = DialogKeywords.getFileByHandle(file);
|
||||
return;
|
||||
}
|
||||
|
||||
public async getImageFromPrompt({ pid, prompt }) {
|
||||
const { min, user, params } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
GBLogEx.info(min, `DALL-E: ${prompt}.`);
|
||||
|
||||
const azureOpenAIKey = await min.core.getParam(min.instance, 'Azure Open AI Key', null, true);
|
||||
const azureOpenAIEndpoint = await min.core.getParam(min.instance, 'Azure Open AI Endpoint', null, true);
|
||||
const azureOpenAIVersion = await (min.core as any)['getParam'](min.instance, 'Azure Open AI Version', null, true);
|
||||
const azureOpenAIImageModel = await (min.core as any)['getParam'](min.instance, 'Azure Open AI Image Model', null, true);
|
||||
|
||||
|
||||
if (azureOpenAIKey) {
|
||||
// Initialize the Azure OpenAI client
|
||||
|
||||
const client = new AzureOpenAI({
|
||||
endpoint: azureOpenAIEndpoint,
|
||||
deployment: azureOpenAIImageModel,
|
||||
apiVersion: azureOpenAIVersion,
|
||||
apiKey: azureOpenAIKey
|
||||
});
|
||||
|
||||
// Make a request to the image generation endpoint
|
||||
|
||||
const response = await client.images.generate({
|
||||
|
||||
prompt: prompt,
|
||||
n: 1, // Don't include for DALL-E 3 (always generates 1 image)
|
||||
style: 'vivid', // optional ('natural' or 'vivid')
|
||||
size: '1024x1024',
|
||||
quality: 'standard', // optional
|
||||
});
|
||||
const gbaiName = GBUtil.getGBAIPath(min.botId);
|
||||
const localName = path.join('work', gbaiName, 'cache', `DALL-E${GBAdminService.getRndReadableIdentifier()}.png`);
|
||||
|
||||
const url = response.data[0].url;
|
||||
const res = await fetch(url);
|
||||
let buf: any = Buffer.from(await res.arrayBuffer());
|
||||
await fs.writeFile(localName, buf, { encoding: null });
|
||||
|
||||
GBLogEx.info(min, `DALL-E: ${url} - ${response.data[0].revised_prompt}.`);
|
||||
|
||||
return { localName, url };
|
||||
}
|
||||
}
|
||||
|
||||
public async getCaptionForImage({ pid, imageUrl }) {
|
||||
const { min, user, params } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const azureOpenAIKey = await min.core.getParam(min.instance, 'Azure Open AI Key', null);
|
||||
const azureOpenAITextModel = 'gpt-4'; // Specify GPT-4 model here
|
||||
const azureOpenAIEndpoint = await min.core.getParam(min.instance, 'Azure Open AI Endpoint', null);
|
||||
const azureOpenAIVersion = await (min.core as any)['getParam'](min.instance, 'Azure Open AI Version', null, true);
|
||||
|
||||
if (azureOpenAIKey && azureOpenAITextModel && imageUrl) {
|
||||
const client = new AzureOpenAI({
|
||||
apiVersion: azureOpenAIVersion,
|
||||
apiKey: azureOpenAIKey,
|
||||
baseURL: azureOpenAIEndpoint
|
||||
});
|
||||
|
||||
const prompt = `Provide a descriptive caption for the image at the following URL: ${imageUrl}`;
|
||||
|
||||
const response = await client.completions.create({
|
||||
|
||||
model: azureOpenAITextModel,
|
||||
prompt: prompt,
|
||||
max_tokens: 50
|
||||
});
|
||||
|
||||
const caption = response['data'].choices[0].text.trim();
|
||||
GBLogEx.info(min, `Generated caption: ${caption}`);
|
||||
|
||||
return { caption };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBLog, GBMinInstance, GBService } from 'botlib-legacy';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
|
||||
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
|
||||
import { GuaribasSchedule } from '../../core.gbapp/models/GBModel.js';
|
||||
|
||||
import cron from 'node-cron';
|
||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
|
||||
/**
|
||||
* @fileoverview Schedule Services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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, `Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and update user agent information to a next available person.
|
||||
*/
|
||||
public async createOrUpdateSchedule(min: GBMinInstance, schedule: string, name: string): Promise<GuaribasSchedule> {
|
||||
let record = await GuaribasSchedule.findOne({
|
||||
where: {
|
||||
instanceId: min.instance.instanceId,
|
||||
name: name
|
||||
}
|
||||
});
|
||||
|
||||
if (record === null) {
|
||||
record = await GuaribasSchedule.create(<GuaribasSchedule>{
|
||||
instanceId: min.instance.instanceId,
|
||||
name: name,
|
||||
schedule: schedule
|
||||
});
|
||||
} else {
|
||||
record.schedule = schedule;
|
||||
await record.save();
|
||||
}
|
||||
|
||||
this.ScheduleItem(record, min);
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all cached schedule from BASIC SET SCHEDULE keyword.
|
||||
*/
|
||||
public async scheduleAll() {
|
||||
let schedules;
|
||||
try {
|
||||
schedules = await GuaribasSchedule.findAll();
|
||||
let i = 0;
|
||||
let lastName = '';
|
||||
|
||||
await GBUtil.asyncForEach(schedules, async item => {
|
||||
if (item.name === lastName) {
|
||||
item.name = item.name + ++i;
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(
|
||||
p => p.instance.instanceId === item.instanceId
|
||||
)[0];
|
||||
|
||||
if (min) {
|
||||
this.ScheduleItem(item, min);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Cannot schedule: ${error.message}.`);
|
||||
}
|
||||
return schedules;
|
||||
}
|
||||
|
||||
private ScheduleItem(item: GuaribasSchedule, min: GBMinInstance) {
|
||||
GBLogEx.info(min, `Scheduling ${item.name} on ${min.botId}...`);
|
||||
try {
|
||||
const options = {
|
||||
scheduled: true,
|
||||
timezone: 'America/Sao_Paulo'
|
||||
};
|
||||
|
||||
const task = min['scheduleMap'][item.name];
|
||||
if (task) {
|
||||
task.stop();
|
||||
min['scheduleMap'][item.name] = null;
|
||||
}
|
||||
|
||||
min['scheduleMap'][item.name] = cron.schedule(
|
||||
item.schedule,
|
||||
function () {
|
||||
const finalData = async () => {
|
||||
let script = item.name.split(';')[0];
|
||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(
|
||||
p => p.instance.instanceId === item.instanceId
|
||||
)[0];
|
||||
GBLogEx.info(min, `Running .gbdialog word ${item.name} on:${item.schedule}...`);
|
||||
|
||||
const pid = GBVMService.createProcessInfo(null, min, 'batch', null);
|
||||
await GBVMService.callVM(script, min, null, pid);
|
||||
};
|
||||
(async () => {
|
||||
await finalData();
|
||||
})();
|
||||
},
|
||||
options
|
||||
);
|
||||
} catch (error) {
|
||||
GBLogEx.error(min, `Running .gbdialog word ${item.name} : ${error}...`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,504 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import urlJoin from 'url-join';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
import { GBLog } from 'botlib-legacy';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||
import { GBSSR } from '../../core.gbapp/services/GBSSR.js';
|
||||
import { DialogKeywords } from './DialogKeywords.js';
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||
import { Mutex } from 'async-mutex';
|
||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||
import { SystemKeywords } from './SystemKeywords.js';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
|
||||
/**
|
||||
* Web Automation services of conversation to be called by BASIC.
|
||||
*/
|
||||
export class WebAutomationServices {
|
||||
static isSelector(name: any) {
|
||||
return name.startsWith('.') || name.startsWith('#') || name.startsWith('[');
|
||||
}
|
||||
|
||||
public static cyrb53 ({pid, str, seed = 0}) {
|
||||
let h1 = 0xdeadbeef ^ seed,
|
||||
h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||
}
|
||||
|
||||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||
|
||||
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||
};
|
||||
|
||||
public async closeHandles({ pid }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
await DialogKeywords.setOption({ pid, name: "filter", value: null });
|
||||
|
||||
// Releases previous allocated OPEN semaphores.
|
||||
|
||||
let keys = Object.keys(GBServer.globals.webSessions);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const session = GBServer.globals.webSessions[keys[i]];
|
||||
if (session.activePid === pid) {
|
||||
session.semaphore.release();
|
||||
GBLogEx.info(min, `Release for PID: ${pid} done.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page object.
|
||||
*
|
||||
* @example OPEN "https://wikipedia.org"
|
||||
*/
|
||||
|
||||
public async openPage({ pid, handle, sessionKind, sessionName, url, username, password }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
GBLogEx.info(min, `Web Automation OPEN ${sessionName ? sessionName : ''} ${url}.`);
|
||||
|
||||
// Try to find an existing handle.
|
||||
|
||||
let session;
|
||||
if (handle) {
|
||||
session = GBServer.globals.webSessions[handle];
|
||||
}
|
||||
else if (sessionName) {
|
||||
let keys = Object.keys(GBServer.globals.webSessions);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (GBServer.globals.webSessions[keys[i]].sessionName === sessionName) {
|
||||
session = GBServer.globals.webSessions[keys[i]];
|
||||
handle = keys[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let page;
|
||||
if (session) {
|
||||
page = session.page;
|
||||
|
||||
// Semaphore logic to block multiple entries on the same session.
|
||||
|
||||
if (sessionName) {
|
||||
GBLogEx.info(min, `Acquiring (1) for PID: ${pid}...`);
|
||||
const release = await session.semaphore.acquire();
|
||||
GBLogEx.info(min, `Acquire (1) for PID: ${pid} done.`);
|
||||
try {
|
||||
session.activePid = pid;
|
||||
session.release = release;
|
||||
} catch {
|
||||
release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Creates the page if it is the first time.
|
||||
|
||||
let browser;
|
||||
if (!page) {
|
||||
browser = await GBSSR.createBrowser(null);
|
||||
page = (await browser.pages())[0];
|
||||
if (username || password) {
|
||||
await page.authenticate({ pid, username: username, password: password });
|
||||
}
|
||||
}
|
||||
|
||||
// There is no session yet or it is an unamed session.
|
||||
|
||||
if ((!session && sessionKind === 'AS') || !sessionName) {
|
||||
// A new web session is being created.
|
||||
|
||||
handle = WebAutomationServices.cyrb53({pid, str:min.botId + url});
|
||||
|
||||
session = {};
|
||||
session.sessionName = sessionName;
|
||||
session.page = page;
|
||||
session.browser = browser;
|
||||
session.semaphore = new Mutex();
|
||||
session.activePid = pid;
|
||||
|
||||
GBServer.globals.webSessions[handle] = session;
|
||||
|
||||
// Only uses semaphore logic in named web sessions.
|
||||
|
||||
if (sessionName) {
|
||||
GBLogEx.info(min, `Acquiring (2) for PID: ${pid}...`);
|
||||
const release = await session.semaphore.acquire();
|
||||
session.release = release;
|
||||
GBLogEx.info(min, `Acquire (2) for PID: ${pid} done.`);
|
||||
}
|
||||
}
|
||||
|
||||
// WITH is only valid in a previously defined session.
|
||||
|
||||
if (!session && sessionKind == 'WITH') {
|
||||
const error = `NULL session for OPEN WITH #${sessionName}.`;
|
||||
GBLogEx.error(min, error);
|
||||
}
|
||||
|
||||
await page.goto(url);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
public static getPageByHandle(handle) {
|
||||
return GBServer.globals.webSessions[handle].page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find element on page DOM.
|
||||
*
|
||||
* @example GET "selector"
|
||||
*/
|
||||
public async getBySelector({ handle, selector, pid }) {
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
GBLogEx.info(min, `Web Automation GET element: ${selector}.`);
|
||||
await page.waitForSelector(selector);
|
||||
let elements = await page.$$(selector);
|
||||
if (elements && elements.length > 1) {
|
||||
return elements;
|
||||
} else {
|
||||
const el = elements[0];
|
||||
el['originalSelector'] = selector;
|
||||
el['href'] = await page.evaluate(e => e.getAttribute('href'), el);
|
||||
el['value'] = await page.evaluate(e => e.getAttribute('value'), el);
|
||||
el['name'] = await page.evaluate(e => e.getAttribute('name'), el);
|
||||
el['class'] = await page.evaluate(e => e.getAttribute('class'), el);
|
||||
return el;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find element on page DOM.
|
||||
*
|
||||
* @example GET page,"frameSelector,"elementSelector"
|
||||
*/
|
||||
public async getByFrame({pid, handle, frame, selector }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation GET element by frame: ${selector}.`);
|
||||
await page.waitForSelector(frame);
|
||||
let frameHandle = await page.$(frame);
|
||||
const f = await frameHandle.contentFrame();
|
||||
await f.waitForSelector(selector);
|
||||
const element = await f.$(selector);
|
||||
element['originalSelector'] = selector;
|
||||
element['href'] = await f.evaluate(e => e.getAttribute('href'), element);
|
||||
element['value'] = await f.evaluate(e => e.getAttribute('value'), element);
|
||||
element['name'] = await f.evaluate(e => e.getAttribute('name'), element);
|
||||
element['class'] = await f.evaluate(e => e.getAttribute('class'), element);
|
||||
element['frame'] = f;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates a mouse hover an web page element.
|
||||
*/
|
||||
public async hover({ pid, handle, selector }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation HOVER element: ${selector}.`);
|
||||
await this.getBySelector({ handle, selector: selector, pid });
|
||||
await page.hover(selector);
|
||||
await this.debugStepWeb(pid, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on an element in a web page.
|
||||
*
|
||||
* @example CLICK "#idElement"
|
||||
*/
|
||||
public async click({ pid, handle, frameOrSelector, selector }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation CLICK element: ${frameOrSelector}.`);
|
||||
if (selector) {
|
||||
await page.waitForSelector(frameOrSelector);
|
||||
let frameHandle = await page.$(frameOrSelector);
|
||||
const f = await frameHandle.contentFrame();
|
||||
await f.waitForSelector(selector);
|
||||
await f.click(selector);
|
||||
} else {
|
||||
await page.waitForSelector(frameOrSelector);
|
||||
await page.click(frameOrSelector);
|
||||
}
|
||||
await this.debugStepWeb(pid, page);
|
||||
}
|
||||
|
||||
private async debugStepWeb(pid, page) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
let debugWeb, lastDebugWeb; // TODO: Add this to pid bag.
|
||||
|
||||
let refresh = true;
|
||||
if (lastDebugWeb) {
|
||||
refresh = new Date().getTime() - lastDebugWeb.getTime() > 5000;
|
||||
}
|
||||
|
||||
if (debugWeb && refresh) {
|
||||
const mobile = min.core.getParam(min.instance, 'Bot Admin Number', null);
|
||||
const filename = page;
|
||||
if (mobile) {
|
||||
await new DialogKeywords().sendFileTo({ pid: pid, mobile, filename, caption: 'General Bots Debugger' });
|
||||
}
|
||||
lastDebugWeb = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Press ENTER in a web page,useful for logins.
|
||||
*
|
||||
* @example PRESS ENTER ON page
|
||||
*/
|
||||
public async pressKey({pid, handle, char, frame }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation PRESS ${char} ON element: ${frame}.`);
|
||||
if (char.toLowerCase() === 'enter') {
|
||||
char = '\n';
|
||||
}
|
||||
if (frame) {
|
||||
await page.waitForSelector(frame);
|
||||
let frameHandle = await page.$(frame);
|
||||
const f = await frameHandle.contentFrame();
|
||||
await f.keyboard.press(char);
|
||||
} else {
|
||||
await page.keyboard.press(char);
|
||||
}
|
||||
}
|
||||
|
||||
public async linkByText({ pid, handle, text, index }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation CLICK LINK TEXT: ${text} ${index}.`);
|
||||
if (!index) {
|
||||
index = 1;
|
||||
}
|
||||
const els = await page.$x(`//a[contains(.,'${text}')]`);
|
||||
await els[index - 1].click();
|
||||
await this.debugStepWeb(pid, page);
|
||||
}
|
||||
|
||||
public async clickButton({ pid, handle, text, index }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation CLICK BUTTON: ${text} ${index}.`);
|
||||
if (!index) {
|
||||
index = 1;
|
||||
}
|
||||
const els = await page.$x(`//button[contains(.,'${text}')]`);
|
||||
await els[index - 1].click();
|
||||
await this.debugStepWeb(pid, page);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the screenshot of page or element
|
||||
*
|
||||
* @example file = SCREENSHOT "#selector"
|
||||
*/
|
||||
public async screenshot({ pid, handle, selector }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation SCREENSHOT ${selector}.`);
|
||||
|
||||
const gbaiName = GBUtil.getGBAIPath(min.botId);
|
||||
const localName = path.join('work', gbaiName, 'cache', `screen-${GBAdminService.getRndReadableIdentifier()}.jpg`);
|
||||
|
||||
await page.screenshot({ path: localName });
|
||||
|
||||
const url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName));
|
||||
GBLogEx.info(min, `WebAutomation: Screenshot captured at ${url}.`);
|
||||
|
||||
return { data: null, localName: localName, url: url };
|
||||
}
|
||||
|
||||
/**
|
||||
* Types the text into the text field.
|
||||
*
|
||||
* @example SET page,"selector","text"
|
||||
*/
|
||||
public async setElementText({ pid, handle, selector, text }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
text = `${text}`;
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation TYPE on ${selector}: ${text}.`);
|
||||
const e = await this.getBySelector({ handle, selector, pid });
|
||||
await e.click({ clickCount: 3 });
|
||||
await page.keyboard.press('Backspace');
|
||||
await e.type(text, { delay: 200 });
|
||||
await this.debugStepWeb(pid, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the download to the .gbdrive Download folder.
|
||||
*
|
||||
* @example file = DOWNLOAD element, folder
|
||||
*/
|
||||
public async download({ pid, handle, selector, folder }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
|
||||
const element = await this.getBySelector({ handle, selector, pid });
|
||||
// https://github.com/GeneralBots/BotServer/issues/311
|
||||
const container = element['_frame'] ? element['_frame'] : element['_page'];
|
||||
await page.setRequestInterception(true);
|
||||
await container.click(element.originalSelector);
|
||||
|
||||
const xRequest = await new Promise(resolve => {
|
||||
page.on('request', interceptedRequest => {
|
||||
interceptedRequest.abort(); //stop intercepting requests
|
||||
resolve(interceptedRequest);
|
||||
});
|
||||
});
|
||||
|
||||
const options = {
|
||||
encoding: null,
|
||||
method: xRequest['._method'],
|
||||
uri: xRequest['_url'],
|
||||
body: xRequest['_postData'],
|
||||
headers: xRequest['_headers']
|
||||
};
|
||||
|
||||
const cookies = await page.cookies();
|
||||
options.headers.Cookie = cookies.map(ck => ck.name + '=' + ck.value).join(';');
|
||||
GBLogEx.info(min, `DOWNLOADING '${options.uri}...'`);
|
||||
|
||||
let local;
|
||||
let filename;
|
||||
if (options.uri.indexOf('file://') != -1) {
|
||||
local = url.fileURLToPath(options.uri);
|
||||
filename = path.basename(local);
|
||||
} else {
|
||||
const getBasenameFormUrl = urlStr => {
|
||||
const url = new URL(urlStr);
|
||||
return path.basename(url.pathname);
|
||||
};
|
||||
filename = getBasenameFormUrl(options.uri);
|
||||
}
|
||||
|
||||
let result: Buffer;
|
||||
if (local) {
|
||||
result = await fs.readFile(local);
|
||||
} else {
|
||||
const res = await fetch(options.uri, options);
|
||||
result = Buffer.from(await res.arrayBuffer());
|
||||
}
|
||||
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||
const botId = min.instance.botId;
|
||||
|
||||
// Normalizes all slashes.
|
||||
|
||||
folder = folder.replace(/\\/gi, '/');
|
||||
|
||||
// Determines full path at source and destination.
|
||||
const packagePath = GBUtil.getGBAIPath(min.botId, `gbdrive`);
|
||||
const root = packagePath;
|
||||
const dstPath = urlJoin(root, folder, filename);
|
||||
|
||||
// Checks if the destination contains subfolders that
|
||||
// need to be created.
|
||||
|
||||
folder = await new SystemKeywords().createFolder(folder);
|
||||
|
||||
// Performs the conversion operation getting a reference
|
||||
// to the source and calling /content on drive API.
|
||||
let file;
|
||||
try {
|
||||
file = await client.api(`${baseUrl}/drive/root:/${dstPath}:/content`).put(result);
|
||||
} catch (error) {
|
||||
if (error.code === 'nameAlreadyExists') {
|
||||
GBLogEx.info(min, `DOWNLOAD destination file already exists: ${dstPath}.`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
private async recursiveFindInFrames(inputFrame, selector) {
|
||||
const frames = inputFrame.childFrames();
|
||||
const results = await Promise.all(
|
||||
frames.map(async frame => {
|
||||
const el = await frame.$(selector);
|
||||
if (el) return el;
|
||||
if (frame.childFrames().length > 0) {
|
||||
return await this.recursiveFindInFrames(frame, selector);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
);
|
||||
|
||||
return results.find(Boolean);
|
||||
}
|
||||
|
||||
|
||||
public async getTextOf({ pid, handle, frameOrSelector, selector }) {
|
||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLogEx.info(min, `Web Automation CLICK element: ${frameOrSelector}.`);
|
||||
if (frameOrSelector) {
|
||||
const result = await page.$eval(
|
||||
frameOrSelector,
|
||||
(ul) => {
|
||||
let items = "";
|
||||
for (let i = 0; i < ul.children.length; i++) {
|
||||
items = `${ul.children[i].textContent}\n`;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
)
|
||||
await this.debugStepWeb(pid, page);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
import crypto2 from 'crypto';
|
||||
import { spawn } from 'child_process';
|
||||
import CDP from 'chrome-remote-interface';
|
||||
import {} from 'child_process';
|
||||
import net from 'net';
|
||||
import { GBLog } from 'botlib-legacy';
|
||||
|
||||
import { GBServer } from '../../../../src/app.js';
|
||||
import { DebuggerService } from '../DebuggerService.js';
|
||||
import { GBLogEx } from '../../../core.gbapp/services/GBLogEx.js';
|
||||
import { GBUtil } from '../../../../src/util.js';
|
||||
|
||||
let finalStream: any = null;
|
||||
try {
|
||||
finalStream = require('final-stream');
|
||||
} catch {}
|
||||
|
||||
const waitUntil = condition => {
|
||||
if (condition()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
const interval = setInterval(() => {
|
||||
if (!condition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearInterval(interval);
|
||||
resolve(0);
|
||||
}, 0);
|
||||
});
|
||||
};
|
||||
|
||||
const systemVariables = [
|
||||
'AggregateError',
|
||||
'Array',
|
||||
'ArrayBuffer',
|
||||
'Atomics',
|
||||
'BigInt',
|
||||
'BigInt64Array',
|
||||
'BigUint64Array',
|
||||
'Boolean',
|
||||
'DataView',
|
||||
'Date',
|
||||
'Error',
|
||||
'EvalError',
|
||||
'FinalizationRegistry',
|
||||
'Float32Array',
|
||||
'Float64Array',
|
||||
'Function',
|
||||
'Headers',
|
||||
'Infinity',
|
||||
'Int16Array',
|
||||
'Int32Array',
|
||||
'Int8Array',
|
||||
'Intl',
|
||||
'JSON',
|
||||
'Map',
|
||||
'Math',
|
||||
'NaN',
|
||||
'Number',
|
||||
'Object',
|
||||
'Promise',
|
||||
'Proxy',
|
||||
'RangeError',
|
||||
'ReferenceError',
|
||||
'Reflect',
|
||||
'RegExp',
|
||||
'Request',
|
||||
'Response',
|
||||
'Set',
|
||||
'SharedArrayBuffer',
|
||||
'String',
|
||||
'Symbol',
|
||||
'SyntaxError',
|
||||
'TypeError',
|
||||
'URIError',
|
||||
'Uint16Array',
|
||||
'Uint32Array',
|
||||
'Uint8Array',
|
||||
'Uint8ClampedArray',
|
||||
'VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL',
|
||||
'WeakMap',
|
||||
'WeakRef',
|
||||
'WeakSet',
|
||||
'WebAssembly',
|
||||
'__defineGetter__',
|
||||
'__defineSetter__',
|
||||
'__lookupGetter__',
|
||||
'__lookupSetter__',
|
||||
'__proto__',
|
||||
'clearImmediate',
|
||||
'clearInterval',
|
||||
'clearTimeout',
|
||||
'console',
|
||||
'constructor',
|
||||
'decodeURI',
|
||||
'decodeURIComponent',
|
||||
'dss',
|
||||
'encodeURI',
|
||||
'encodeURIComponent',
|
||||
'escape',
|
||||
'eval',
|
||||
'fetch',
|
||||
'global',
|
||||
'globalThis',
|
||||
'hasOwnProperty',
|
||||
'isFinite',
|
||||
'isNaN',
|
||||
'isPrototypeOf',
|
||||
'parseFloat',
|
||||
'parseInt',
|
||||
'process',
|
||||
'propertyIsEnumerable',
|
||||
'setImmediate',
|
||||
'setInterval',
|
||||
'setTimeout',
|
||||
'toLocaleString',
|
||||
'toString',
|
||||
'undefined',
|
||||
'unescape',
|
||||
'valueOf'
|
||||
];
|
||||
|
||||
export const createVm2Pool = ({ min, max, ...limits }) => {
|
||||
limits = Object.assign(
|
||||
{
|
||||
cpu: 100,
|
||||
memory: 2000,
|
||||
time: 4000
|
||||
},
|
||||
limits
|
||||
);
|
||||
|
||||
let limitError = null;
|
||||
|
||||
const ref = crypto2.randomBytes(20).toString('hex');
|
||||
|
||||
const kill = x => {
|
||||
spawn('sh', ['-c', `pkill -9 -f ${ref}`]);
|
||||
};
|
||||
|
||||
let stderrCache = '';
|
||||
|
||||
const run = async (code: any, scope: any) => {
|
||||
// Configure environment variables
|
||||
const env = Object.assign({}, process.env, {
|
||||
NODE_ENV: 'production',
|
||||
NODE_OPTIONS: '' // Clear NODE_OPTIONS if needed
|
||||
});
|
||||
|
||||
const childProcess = spawn(
|
||||
'/usr/bin/cpulimit',
|
||||
[
|
||||
'-ql',
|
||||
limits.cpu,
|
||||
'--',
|
||||
'node',
|
||||
`${limits.debug ? '--inspect=' + limits.debuggerPort : ''}`,
|
||||
`--experimental-fetch`,
|
||||
`--max-old-space-size=${limits.memory}`,
|
||||
limits.script,
|
||||
ref
|
||||
],
|
||||
{ cwd: limits.cwd, shell: true, env: env }
|
||||
);
|
||||
|
||||
childProcess.stdout.on('data', data => {
|
||||
childProcess['socket'] = childProcess['socket'] || data.toString().trim();
|
||||
});
|
||||
|
||||
childProcess.stderr.on('data', data => {
|
||||
stderrCache = stderrCache + data.toString();
|
||||
if (stderrCache.includes('failed: address already in use')) {
|
||||
limitError = stderrCache;
|
||||
kill(process);
|
||||
GBServer.globals.debuggers[limits.botId].state = 0;
|
||||
GBServer.globals.debuggers[limits.botId].stateInfo = stderrCache;
|
||||
} else if (
|
||||
stderrCache.includes('FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory')
|
||||
) {
|
||||
limitError = 'code execution exceeed allowed memory';
|
||||
kill(process);
|
||||
GBServer.globals.debuggers[limits.botId].state = 0;
|
||||
GBServer.globals.debuggers[limits.botId].stateInfo = 'Fail';
|
||||
} else if (stderrCache.includes('Debugger attached.')) {
|
||||
GBLogEx.info(min, `General Bots Debugger attached to Node .gbdialog process for ${limits.botId}.`);
|
||||
}
|
||||
});
|
||||
|
||||
let socket = null;
|
||||
await waitUntil(() => childProcess['socket']);
|
||||
|
||||
GBServer.globals.debuggers[limits.botId].childProcess = ref;
|
||||
|
||||
// Only attach if called by debugger/run.
|
||||
|
||||
if (limits.debug) {
|
||||
const debug = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
CDP(async client => {
|
||||
const { Debugger, Runtime } = client;
|
||||
try {
|
||||
GBServer.globals.debuggers[limits.botId].client = client;
|
||||
|
||||
await client.Debugger.paused(async ({ callFrames, reason, hitBreakpoints }) => {
|
||||
const frame = callFrames[0];
|
||||
|
||||
// Build variable list ignoring system variables of script.
|
||||
|
||||
const scopeObjectId = frame.scopeChain[2].object.objectId;
|
||||
const variables = await Runtime.getProperties({ objectId: scopeObjectId });
|
||||
let variablesText = '';
|
||||
if (variables && variables.result) {
|
||||
await GBUtil.asyncForEach(variables.result, async v => {
|
||||
if (!systemVariables.filter(x => x === v.name)[0]) {
|
||||
if (v.value.value) {
|
||||
variablesText = `${variablesText} \n ${v.name}: ${v.value.value}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
GBServer.globals.debuggers[limits.botId].scope = variablesText;
|
||||
GBLogEx.info(min, `Breakpoint variables: ${variablesText}`); // (zero-based)
|
||||
// Processes breakpoint hits.
|
||||
|
||||
if (hitBreakpoints.length >= 1) {
|
||||
GBLogEx.info(min, `Break at line ${frame.location.lineNumber + 1}`); // (zero-based)
|
||||
|
||||
GBServer.globals.debuggers[limits.botId].state = 2;
|
||||
GBServer.globals.debuggers[limits.botId].stateInfo = 'Break';
|
||||
} else {
|
||||
GBLog.verbose(`Configuring breakpoints if any for ${limits.botId}...`);
|
||||
// Waits for debugger and setup breakpoints.
|
||||
|
||||
await GBUtil.asyncForEach(GBServer.globals.debuggers[limits.botId].breaks, async brk => {
|
||||
try {
|
||||
const { breakpointId } = await client.Debugger.setBreakpoint({
|
||||
location: {
|
||||
scriptId: frame.location.scriptId,
|
||||
lineNumber: brk
|
||||
}
|
||||
});
|
||||
GBLogEx.info(min, `BASIC break defined ${breakpointId} for ${limits.botId}`);
|
||||
} catch (error) {
|
||||
GBLogEx.info(min, `BASIC error defining ${brk} for ${limits.botId}. ${error}`);
|
||||
}
|
||||
});
|
||||
await client.Debugger.resume();
|
||||
}
|
||||
});
|
||||
|
||||
await client.Runtime.runIfWaitingForDebugger();
|
||||
await client.Debugger.enable();
|
||||
await client.Runtime.enable();
|
||||
|
||||
resolve(1);
|
||||
} catch (error) {
|
||||
GBLog.error(error);
|
||||
kill(childProcess);
|
||||
GBServer.globals.debuggers[limits.botId].state = 0;
|
||||
GBServer.globals.debuggers[limits.botId].stateInfo = 'Stopped';
|
||||
}
|
||||
}).on('error', err => {
|
||||
console.error(err);
|
||||
kill(childProcess);
|
||||
GBServer.globals.debuggers[limits.botId].state = 0;
|
||||
GBServer.globals.debuggers[limits.botId].stateInfo = 'Stopped';
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
await debug();
|
||||
}
|
||||
socket = net.createConnection(childProcess['socket']);
|
||||
socket.write(JSON.stringify({ code, scope }) + '\n');
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
limitError = 'code execution took too long and was killed';
|
||||
|
||||
kill(childProcess);
|
||||
GBServer.globals.debuggers[limits.botId].state = 0;
|
||||
GBServer.globals.debuggers[limits.botId].stateInfo = limitError;
|
||||
}, limits.time);
|
||||
|
||||
try {
|
||||
let data = await finalStream(socket);
|
||||
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (!data.length) {
|
||||
return null;
|
||||
}
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
return data.result;
|
||||
} catch (error) {
|
||||
throw new Error(limitError || error);
|
||||
} finally {
|
||||
kill(childProcess);
|
||||
|
||||
GBServer.globals.debuggers[limits.botId].state = 0;
|
||||
GBServer.globals.debuggers[limits.botId].stateInfo = 'Stopped';
|
||||
clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
run
|
||||
};
|
||||
};
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
import crypto1 from 'crypto';
|
||||
import net1 from 'net';
|
||||
|
||||
let NodeVM, VMScript;
|
||||
|
||||
try {
|
||||
const NodeVM = require('vm2').NodeVM;
|
||||
const VMScript = require('vm2').VMScript;
|
||||
} catch {}
|
||||
|
||||
const evaluate = async (script, scope) => {
|
||||
const vm = new NodeVM({
|
||||
allowAsync: true,
|
||||
sandbox: {},
|
||||
console: 'inherit',
|
||||
wrapper: 'none',
|
||||
require: {
|
||||
builtin: ['stream', 'http', 'https', 'url', 'buffer', 'zlib', 'isomorphic-fetch', 'punycode', 'encoding', 'net'],
|
||||
root: ['./'],
|
||||
external: true,
|
||||
context: 'sandbox'
|
||||
}
|
||||
});
|
||||
|
||||
const s = new VMScript(script, scope);
|
||||
return await vm.run(script, scope);
|
||||
};
|
||||
|
||||
const socketName = crypto1.randomBytes(20).toString('hex');
|
||||
|
||||
const server = net1.createServer(socket => {
|
||||
const buffer = [];
|
||||
|
||||
const sync = async () => {
|
||||
const request = buffer.join('').toString();
|
||||
console.log(request);
|
||||
if (request.includes('\n')) {
|
||||
try {
|
||||
const { code, scope } = JSON.parse(request);
|
||||
|
||||
const result = await evaluate(code, {
|
||||
...scope,
|
||||
module: null
|
||||
});
|
||||
|
||||
console.log(JSON.stringify({ result }));
|
||||
socket.write(JSON.stringify({ result }) + '\n');
|
||||
socket.end();
|
||||
} catch (error) {
|
||||
console.log(`RUNTIME: ${error.message}, ${error.stack}`);
|
||||
socket.write(JSON.stringify({ error: error.message }) + '\n');
|
||||
socket.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
socket.on('error', err => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
socket.on('data', data => {
|
||||
buffer.push(data);
|
||||
sync();
|
||||
});
|
||||
});
|
||||
|
||||
server.on('listening', () => {
|
||||
console.log(`/tmp/vm2-${socketName}.sock`);
|
||||
});
|
||||
|
||||
server.listen(`/tmp/vm2-${socketName}.sock`);
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
export const Messages = {
|
||||
'en-US': {
|
||||
affirmative_sentences: /^(\bsim\b|\bs\b|\bpositivo\b|\bafirmativo\b|\bclaro\b|\bevidente\b|\bsem dúvida\b|\bconfirmo\b|\bconfirmar\b|\bconfirmado\b|\buhum\b|\bsi\b|\by\b|\byes\b|\bsure\b)/i,
|
||||
choices: 'Please, select one:'
|
||||
},
|
||||
'pt-BR': {
|
||||
affirmative_sentences: /^(\bsim\b|\bs\b|\bpositivo\b|\bafirmativo\b|\bclaro\b|\bevidente\b|\bsem dúvida\b|\bconfirmo\b|\bconfirmar\b|\bconfirmado\b|\buhum\b|\bsi\b|\by\b|\byes\b|\bsure\b)/i,
|
||||
choices: 'Por favor, selecione:'
|
||||
}
|
||||
};
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
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");
|
||||
});
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
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"
|
||||
}});
|
||||
|
||||
});
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
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'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"theme": "default.gbtheme",
|
||||
"ui": "default.gbui",
|
||||
"kb": "default.gbkb",
|
||||
"title": "Default General Bot",
|
||||
"description": "Default General Bot",
|
||||
"whoAmIVideo": "TODO.mp4",
|
||||
"author": "pragmatismo.com.br",
|
||||
"license": "AGPL",
|
||||
"engineName": "guaribas-1.0.0"
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"groups": [{}]
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
{
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"enabledAdmin": "true",
|
||||
"searchScore": ".45",
|
||||
"nlpScore": ".80",
|
||||
"state":"active",
|
||||
"autoPackageSync": "gbdialog, gbot, gbtheme"
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
*This is a General Bots BASIC ackage, more information can be found on the [BotServer](https://github.com/GeneralBots/BotServer) repository.*
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
import { Messages } from '../strings.js';
|
||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBConversationalService } from '../services/GBConversationalService.js';
|
||||
/**
|
||||
* Dialog for the bot explains about itself.
|
||||
*/
|
||||
export class BroadcastDialog extends IGBDialog {
|
||||
/**
|
||||
* Setup dialogs flows and define services call.
|
||||
*
|
||||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
public static setup (bot: BotAdapter, min: GBMinInstance) {
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/gb-broadcast', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, 'Type the message and the broadcast will start.');
|
||||
},
|
||||
async step => {
|
||||
// DISABLED: await min.conversationalService['broadcast'](min, step.result);
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
import { Messages } from '../strings.js';
|
||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBConversationalService } from '../services/GBConversationalService.js';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
|
||||
/**
|
||||
* Dialog for the bot explains about itself.
|
||||
*/
|
||||
export class LanguageDialog extends IGBDialog {
|
||||
/**
|
||||
* Setup dialogs flows and define services call.
|
||||
*
|
||||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/language', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, Messages[locale].which_language);
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
const list = [
|
||||
{ name: 'english', code: 'en' },
|
||||
{ name: 'inglês', code: 'en' },
|
||||
{ name: 'portuguese', code: 'pt' },
|
||||
{ name: 'português', code: 'pt' },
|
||||
{ name: 'français', code: 'fr' },
|
||||
{ name: 'francês', code: 'fr' },
|
||||
{ name: 'french', code: 'fr' },
|
||||
{ name: 'português', code: 'pt' },
|
||||
{ name: 'spanish', code: 'es' },
|
||||
{ name: 'espanõl', code: 'es' },
|
||||
{ name: 'espanhol', code: 'es' },
|
||||
{ name: 'german', code: 'de' },
|
||||
{ name: 'deutsch', code: 'de' },
|
||||
{ name: 'alemão', code: 'de' }
|
||||
];
|
||||
let translatorLocale = null;
|
||||
const text = step.context.activity['originalText'];
|
||||
|
||||
await GBUtil.asyncForEach(list, async item => {
|
||||
if (
|
||||
GBConversationalService.kmpSearch(text.toLowerCase(), item.name.toLowerCase()) != -1 ||
|
||||
GBConversationalService.kmpSearch(text.toLowerCase(), item.code.toLowerCase()) != -1
|
||||
) {
|
||||
translatorLocale = item.code;
|
||||
}
|
||||
});
|
||||
|
||||
let sec = new SecService();
|
||||
let user = await sec.getUserFromSystemId(step.context.activity.from.id);
|
||||
user = await sec.updateUserLocale(user.userId, translatorLocale);
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].language_chosen);
|
||||
|
||||
await step.replaceDialog('/ask', { firstTime: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||
import { GBConversationalService } from '../services/GBConversationalService.js';
|
||||
import { Messages } from '../strings.js';
|
||||
/**
|
||||
* Dialog for the bot explains about itself.
|
||||
*/
|
||||
export class SwitchBotDialog extends IGBDialog {
|
||||
/**
|
||||
* Setup dialogs flows and define services call.
|
||||
*
|
||||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
public static setup (bot: BotAdapter, min: GBMinInstance) {
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/bot', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, 'Qual seria o código de ativação?');
|
||||
},
|
||||
async step => {
|
||||
const sec = new SecService();
|
||||
const from = step.context.activity.from.id;
|
||||
const botId = step.result;
|
||||
const instance = await min.core.loadInstanceByBotId(botId);
|
||||
await sec.updateUserInstance(from, instance.instanceId);
|
||||
await min.conversationalService.sendText(min, step, `Opa, vamos lá!`);
|
||||
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { Messages } from '../strings.js';
|
||||
import { GBLogEx } from '../services/GBLogEx.js';
|
||||
import { GBConfigService } from '../services/GBConfigService.js';
|
||||
|
||||
/**
|
||||
* Dialog for Welcoming people.
|
||||
*/
|
||||
export class WelcomeDialog extends IGBDialog {
|
||||
/**
|
||||
* Setup dialogs flows and define services call.
|
||||
*
|
||||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
public static setup (bot: BotAdapter, min: GBMinInstance) {
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
if (
|
||||
GBServer.globals.entryPointDialog !== null &&
|
||||
min.instance.botId === GBConfigService.get('BOT_ID')
|
||||
) {
|
||||
return step.replaceDialog(GBServer.globals.entryPointDialog);
|
||||
}
|
||||
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
if (
|
||||
// TODO: https://github.com/GeneralBots/BotServer/issues/9 !user.once &&
|
||||
step.context.activity.channelId === 'webchat' &&
|
||||
min.core.getParam<boolean>(min.instance, 'HelloGoodX', true) === 'true'
|
||||
) {
|
||||
// user.once = true;
|
||||
const a = new Date();
|
||||
const date = a.getHours();
|
||||
const msg =
|
||||
date < 12
|
||||
? Messages[locale].good_morning
|
||||
: date < 18
|
||||
? Messages[locale].good_evening
|
||||
: Messages[locale].good_night;
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].hi(msg));
|
||||
|
||||
await step.replaceDialog('/ask', { firstTime: true });
|
||||
|
||||
if (
|
||||
step.context.activity !== undefined &&
|
||||
step.context.activity.type === 'message' &&
|
||||
step.context.activity.text !== ''
|
||||
) {
|
||||
GBLogEx.info(min, `/answer being called from WelcomeDialog.`);
|
||||
await step.replaceDialog('/answer', { query: step.context.activity.text });
|
||||
}
|
||||
}
|
||||
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
import { GBConversationalService } from '../services/GBConversationalService.js';
|
||||
import { Messages } from '../strings.js';
|
||||
/**
|
||||
* Dialog for the bot explains about itself.
|
||||
*/
|
||||
export class WhoAmIDialog extends IGBDialog {
|
||||
/**
|
||||
* Setup dialogs flows and define services call.
|
||||
*
|
||||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/whoAmI', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
await min.conversationalService.sendText(min, step, `${min.instance.description}`);
|
||||
|
||||
if (min.instance.whoAmIVideo !== undefined) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].show_video);
|
||||
await min.conversationalService.sendEvent(min, step, 'play', {
|
||||
playerType: 'video',
|
||||
data: min.instance.whoAmIVideo.trim()
|
||||
});
|
||||
}
|
||||
|
||||
await step.replaceDialog('/ask', { isReturning: true });
|
||||
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib-legacy';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { BroadcastDialog } from './dialogs/BroadcastDialog.js';
|
||||
import { LanguageDialog } from './dialogs/LanguageDialog.js';
|
||||
import { SwitchBotDialog } from './dialogs/SwitchBot.js';
|
||||
import { WelcomeDialog } from './dialogs/WelcomeDialog.js';
|
||||
import { WhoAmIDialog } from './dialogs/WhoAmIDialog.js';
|
||||
import { GuaribasApplications, GuaribasChannel, GuaribasInstance, GuaribasLog, GuaribasPackage } from './models/GBModel.js';
|
||||
|
||||
/**
|
||||
* Package for core.gbapp.
|
||||
*/
|
||||
export class GBCorePackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
public CurrentEngineName = 'guaribas-1.0.0';
|
||||
|
||||
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
core.sequelize.addModels([GuaribasInstance, GuaribasPackage, GuaribasChannel, GuaribasLog, GuaribasApplications]);
|
||||
}
|
||||
|
||||
public async getDialogs (min: GBMinInstance) {
|
||||
GBLog.verbose(`getDialogs called.`);
|
||||
}
|
||||
public async unloadPackage (core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async unloadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLog.verbose(`onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
|
||||
GBLog.verbose(`onExchangeData called.`);
|
||||
}
|
||||
|
||||
public async loadBot (min: GBMinInstance): Promise<void> {
|
||||
WelcomeDialog.setup(min.bot, min);
|
||||
WhoAmIDialog.setup(min.bot, min);
|
||||
SwitchBotDialog.setup(min.bot, min);
|
||||
BroadcastDialog.setup(min.bot, min);
|
||||
LanguageDialog.setup(min.bot, min);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
Column,
|
||||
CreatedAt,
|
||||
ForeignKey,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
import { GuaribasInstance } from './GBModel.js';
|
||||
|
|
@ -1,400 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
Column,
|
||||
CreatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { IGBInstance } from 'botlib-legacy';
|
||||
|
||||
/**
|
||||
* Base instance data for a bot.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasInstance extends Model<GuaribasInstance> implements IGBInstance {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare botEndpoint: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare whoAmIVideo: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare botId: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare title: string;
|
||||
|
||||
@Column({ type: DataType.STRING(16) })
|
||||
declare activationCode: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare description: string;
|
||||
|
||||
@Column({ type: DataType.STRING(16) })
|
||||
declare state: string;
|
||||
|
||||
declare version: string;
|
||||
|
||||
@Column(DataType.STRING(64))
|
||||
declare botKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare enabledAdmin: boolean;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare engineName: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare marketplaceId: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare textAnalyticsKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare textAnalyticsEndpoint: string;
|
||||
|
||||
@Column({ type: DataType.STRING(64) })
|
||||
declare translatorKey: string;
|
||||
|
||||
@Column({ type: DataType.STRING(128) })
|
||||
declare translatorEndpoint: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare marketplacePassword: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare webchatKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare authenticatorTenant: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare authenticatorAuthorityHostUrl: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare cloudSubscriptionId: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare cloudUsername: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare cloudPassword: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare cloudLocation: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare googleBotKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare googleChatApiKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare googleChatSubscriptionName: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare googleClientEmail: string;
|
||||
|
||||
@Column({ type: DataType.STRING(4000) })
|
||||
declare googlePrivateKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare googleProjectId: string;
|
||||
|
||||
@Column({ type: DataType.STRING(255) })
|
||||
declare facebookWorkplaceVerifyToken: string;
|
||||
|
||||
@Column({ type: DataType.STRING(255) })
|
||||
declare facebookWorkplaceAppSecret: string;
|
||||
|
||||
@Column({ type: DataType.STRING(512) })
|
||||
declare facebookWorkplaceAccessToken: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare whatsappBotKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare whatsappServiceKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare whatsappServiceNumber: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare whatsappServiceUrl: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare smsKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare smsSecret: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare smsServiceNumber: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare speechKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare speechEndpoint: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare spellcheckerKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare spellcheckerEndpoint: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare theme: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare ui: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare kb: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare nlpAppId: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare nlpKey: string;
|
||||
|
||||
@Column({ type: DataType.STRING(512) })
|
||||
declare nlpEndpoint: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare nlpAuthoringKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare deploymentPaths: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare searchHost: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare searchKey: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare searchIndex: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare searchIndexer: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare storageUsername: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare storagePassword: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare storageName: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare storageServer: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare storageDialect: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare storagePath: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare adminPass: string;
|
||||
|
||||
@Column(DataType.FLOAT)
|
||||
declare searchScore: number;
|
||||
|
||||
@Column(DataType.FLOAT)
|
||||
declare nlpScore: number;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
|
||||
@Column(DataType.STRING(4000))
|
||||
declare params: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each packaged listed for use in a bot instance.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasPackage extends Model<GuaribasPackage> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column(DataType.INTEGER)
|
||||
declare packageId: number;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare packageName: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
declare instance: GuaribasInstance;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
|
||||
@Column({ type: DataType.STRING(512) })
|
||||
declare custom: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bot channel.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasChannel extends Model<GuaribasChannel> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column(DataType.INTEGER)
|
||||
declare channelId: number;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare title: string;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* An exception that has been thrown.
|
||||
*/
|
||||
@Table
|
||||
//tslint:disable-next-line:max-classes-per-file
|
||||
export class GuaribasLog extends Model<GuaribasLog> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column(DataType.INTEGER)
|
||||
declare logId: number;
|
||||
|
||||
@Column(DataType.STRING(1024))
|
||||
declare message: string;
|
||||
|
||||
@Column(DataType.STRING(1))
|
||||
declare kind: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
declare instance: GuaribasInstance;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
|
||||
@Table
|
||||
//tslint:disable-next-line:max-classes-per-file
|
||||
export class GuaribasApplications extends Model<GuaribasApplications> {
|
||||
@Column(DataType.STRING(255))
|
||||
declare name: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
declare instance: GuaribasInstance;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
|
||||
@Table
|
||||
//tslint:disable-next-line:max-classes-per-file
|
||||
export class GuaribasSchedule extends Model<GuaribasSchedule> {
|
||||
@Column(DataType.STRING(255))
|
||||
declare name: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
declare schedule: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
declare instance: GuaribasInstance;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBLog } from 'botlib-legacy';
|
||||
import * as en from 'dotenv-extended';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base configuration for the server like storage.
|
||||
*/
|
||||
export class GBConfigService {
|
||||
public static getBoolean(value: string): boolean {
|
||||
return this.get(value) as unknown as boolean;
|
||||
}
|
||||
public static getServerPort(): string {
|
||||
if (process.env.PORT) {
|
||||
return process.env.PORT;
|
||||
}
|
||||
if (process.env.port) {
|
||||
return process.env.port;
|
||||
}
|
||||
|
||||
return '4242';
|
||||
}
|
||||
|
||||
public static init(): any {
|
||||
try {
|
||||
en.load({
|
||||
encoding: 'utf8',
|
||||
silent: true,
|
||||
path: '.env',
|
||||
defaults: '.env.defaults',
|
||||
schema: '.env.schema',
|
||||
errorOnMissing: true,
|
||||
errorOnExtra: false,
|
||||
errorOnRegex: true,
|
||||
includeProcessEnv: false,
|
||||
assignToProcessEnv: true,
|
||||
overrideProcessEnv: true
|
||||
});
|
||||
} catch (e) {
|
||||
GBLog.error(e.message);
|
||||
process.exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
public static get(key: string) {
|
||||
let value = GBConfigService.tryGet(key);
|
||||
|
||||
if (!value) {
|
||||
switch (key) {
|
||||
case 'PORT':
|
||||
value = this.getServerPort();
|
||||
break;
|
||||
case 'GBVM':
|
||||
value = true;
|
||||
break;
|
||||
case 'STORAGE_NAME':
|
||||
value = null;
|
||||
break;
|
||||
case 'WEBDAV_USERNAME':
|
||||
value = null;
|
||||
break;
|
||||
case 'WEBDAV_PASSWORD':
|
||||
value = null;
|
||||
break;
|
||||
case 'CLOUD_USERNAME':
|
||||
value = undefined;
|
||||
break;
|
||||
|
||||
case 'CLOUD_PASSWORD':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'STORAGE_LIBRARY':
|
||||
value = path.join(process.env.PWD, 'templates');
|
||||
break;
|
||||
case 'BOT_ID':
|
||||
value = 'default';
|
||||
break;
|
||||
case 'CLOUD_SUBSCRIPTIONID':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'CLOUD_LOCATION':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'MARKETPLACE_ID':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'LOG_ON_STORAGE':
|
||||
value = false;
|
||||
break;
|
||||
case 'MARKETPLACE_SECRET':
|
||||
value = undefined;
|
||||
break;
|
||||
|
||||
case 'STORAGE_DIALECT':
|
||||
value = 'sqlite';
|
||||
break;
|
||||
case 'STORAGE_FILE':
|
||||
value = './data.db';
|
||||
break;
|
||||
case 'GBKB_AUTO_DEPLOY':
|
||||
value = false;
|
||||
break;
|
||||
case 'ADDITIONAL_DEPLOY_PATH':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'STORAGE_SYNC':
|
||||
value = 'true';
|
||||
break;
|
||||
case 'STORAGE_SYNC_ALTER':
|
||||
value = 'false';
|
||||
break;
|
||||
case 'STORAGE_SYNC_FORCE':
|
||||
value = 'false';
|
||||
break;
|
||||
case 'STORAGE_LOGGING':
|
||||
value = 'false';
|
||||
break;
|
||||
case 'STORAGE_ENCRYPT':
|
||||
value = 'true';
|
||||
break;
|
||||
case 'REVERSE_PROXY':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'DISABLE_WEB':
|
||||
value = 'false';
|
||||
break;
|
||||
case 'STORAGE_ACQUIRE_TIMEOUT':
|
||||
value = 40000;
|
||||
break;
|
||||
case 'LOCALE':
|
||||
value = 'en';
|
||||
break;
|
||||
case 'LANGUAGE_DETECTOR':
|
||||
value = false;
|
||||
break;
|
||||
case 'DEFAULT_USER_LANGUAGE':
|
||||
value = 'en';
|
||||
break;
|
||||
case 'DEFAULT_CONTENT_LANGUAGE':
|
||||
value = 'en';
|
||||
break;
|
||||
case 'ENABLE_SPELLING_CHECKER':
|
||||
value = false;
|
||||
break;
|
||||
case 'DEV_GBAI':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'FREE_TIER':
|
||||
value = true;
|
||||
break;
|
||||
case 'BOT_URL':
|
||||
value = 'http://localhost:4242';
|
||||
break;
|
||||
case 'STORAGE_SERVER':
|
||||
value = undefined;
|
||||
break;
|
||||
default:
|
||||
GBLog.warn(`Invalid key on .env file: '${key}'`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static tryGet(key: string): any {
|
||||
let value = process.env[`container:${key}`];
|
||||
if (value === undefined) {
|
||||
value = process.env[key];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,861 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBLog, GBMinInstance, IGBCoreService, IGBInstallationDeployer, IGBInstance, IGBPackage } from 'botlib-legacy';
|
||||
import fs from 'fs/promises';
|
||||
import { Sequelize, SequelizeOptions } from 'sequelize-typescript';
|
||||
import { Op, Dialect } from 'sequelize';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBAdminPackage } from '../../admin.gbapp/index.js';
|
||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||
import { GBAnalyticsPackage } from '../../analytics.gblib/index.js';
|
||||
import { GBCorePackage } from '../../core.gbapp/index.js';
|
||||
import { GBCustomerSatisfactionPackage } from '../../customer-satisfaction.gbapp/index.js';
|
||||
import { GBKBPackage } from '../../kb.gbapp/index.js';
|
||||
import { GBSecurityPackage } from '../../security.gbapp/index.js';
|
||||
import { v2 as webdav } from 'webdav-server';
|
||||
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 { GBSharePointPackage } from '../../sharepoint.gblib/index.js';
|
||||
|
||||
import { GBBasicPackage } from '../../basic.gblib/index.js';
|
||||
import { GBGoogleChatPackage } from '../../google-chat.gblib/index.js';
|
||||
import path from 'path';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
import { GBLogEx } from './GBLogEx.js';
|
||||
import { GBDeployer } from './GBDeployer.js';
|
||||
import { SystemKeywords } from '../../basic.gblib/services/SystemKeywords.js';
|
||||
import csvdb from 'csv-database';
|
||||
import { SaaSPackage } from '../../saas.gbapp/index.js';
|
||||
import { Client } from 'minio';
|
||||
|
||||
/**
|
||||
* GBCoreService contains main logic for handling storage services related
|
||||
* to instance handling. When the server starts a instance is needed and
|
||||
* if no instance is found a boot instance is created. After that high-level
|
||||
* instance management methods can be created.
|
||||
* Core scheduling, base network services are also handled in this service.
|
||||
*/
|
||||
export class GBCoreService implements IGBCoreService {
|
||||
/**
|
||||
* Data access layer instance.
|
||||
*/
|
||||
public sequelize: Sequelize;
|
||||
|
||||
/**
|
||||
* Administrative services.
|
||||
*/
|
||||
public adminService: GBAdminService;
|
||||
|
||||
/**
|
||||
* Allows filtering on SQL generated before send to the database.
|
||||
*/
|
||||
private queryGenerator: any;
|
||||
|
||||
/**
|
||||
* Custom create table query.
|
||||
*/
|
||||
private createTableQuery: (tableName: string, attributes: any, options: any) => string;
|
||||
|
||||
/**
|
||||
* Custom change column query.
|
||||
*/
|
||||
private changeColumnQuery: (tableName: string, attributes: any) => string;
|
||||
|
||||
/**
|
||||
* Dialect used. Tested: mssql and sqlite.
|
||||
*/
|
||||
private dialect: string;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
this.adminService = new GBAdminService(this);
|
||||
}
|
||||
public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) {}
|
||||
|
||||
/**
|
||||
* Gets database config and connect to storage. Currently two databases
|
||||
* are available: SQL Server and SQLite.
|
||||
*/
|
||||
public async initStorage(): Promise<any> {
|
||||
this.dialect = GBConfigService.get('STORAGE_DIALECT');
|
||||
|
||||
let port: number | undefined;
|
||||
let host: string | undefined;
|
||||
let database: string | undefined;
|
||||
let username: string | undefined;
|
||||
let password: string | undefined;
|
||||
let storage: string | undefined;
|
||||
|
||||
if (!['mssql', 'postgres', 'sqlite'].includes(this.dialect)) {
|
||||
throw new Error(`Unknown or unsupported dialect: ${this.dialect}.`);
|
||||
}
|
||||
|
||||
if (this.dialect === 'mssql' || this.dialect === 'postgres') {
|
||||
host = GBConfigService.get('STORAGE_SERVER');
|
||||
database = GBConfigService.get('STORAGE_NAME');
|
||||
username = GBConfigService.get('STORAGE_USERNAME');
|
||||
password = GBConfigService.get('STORAGE_PASSWORD');
|
||||
|
||||
const portStr = GBConfigService.get('STORAGE_PORT');
|
||||
port = portStr ? parseInt(portStr, 10) : undefined;
|
||||
|
||||
if (!host || !database || !username || !password || !port) {
|
||||
throw new Error(`Missing required configuration for ${this.dialect}.`);
|
||||
}
|
||||
} else if (this.dialect === 'sqlite') {
|
||||
storage = GBConfigService.get('STORAGE_FILE');
|
||||
|
||||
if (!storage) {
|
||||
throw new Error('STORAGE_FILE is required for SQLite.');
|
||||
}
|
||||
|
||||
if (!(await GBUtil.exists(storage))) {
|
||||
process.env.STORAGE_SYNC = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
const logging: boolean | Function =
|
||||
GBConfigService.get('STORAGE_LOGGING') === 'true'
|
||||
? (str: string): void => {
|
||||
GBLogEx.info(0, str);
|
||||
}
|
||||
: false;
|
||||
|
||||
const encrypt: boolean = GBConfigService.get('STORAGE_ENCRYPT') === 'true';
|
||||
|
||||
const acquireStr = GBConfigService.get('STORAGE_ACQUIRE_TIMEOUT');
|
||||
const acquire = acquireStr ? parseInt(acquireStr, 10) : 10000; // Valor padrão de 10 segundos
|
||||
|
||||
const sequelizeOptions: SequelizeOptions = {
|
||||
define: {
|
||||
freezeTableName: true,
|
||||
timestamps: false
|
||||
},
|
||||
host: host,
|
||||
port: port,
|
||||
logging: logging as boolean,
|
||||
dialect: this.dialect as Dialect,
|
||||
storage: storage,
|
||||
quoteIdentifiers: this.dialect === 'postgres',
|
||||
dialectOptions:
|
||||
this.dialect === 'mssql'
|
||||
? {
|
||||
options: {
|
||||
trustServerCertificate: true,
|
||||
encrypt: encrypt
|
||||
}
|
||||
}
|
||||
: {},
|
||||
pool: {
|
||||
max: 5,
|
||||
min: 0,
|
||||
idle: 10000,
|
||||
evict: 10000,
|
||||
acquire: acquire
|
||||
}
|
||||
};
|
||||
|
||||
this.sequelize = new Sequelize(database, username, password, sequelizeOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks wheather storage is acessible or not and opens firewall
|
||||
* in case of any connection block.
|
||||
*/
|
||||
public async checkStorage(installationDeployer: IGBInstallationDeployer) {
|
||||
try {
|
||||
await this.sequelize.authenticate();
|
||||
} catch (error) {
|
||||
GBLogEx.info(0, 'Opening storage firewall on infrastructure...');
|
||||
// tslint:disable:no-unsafe-any
|
||||
if (error.parent.code === 'ELOGIN') {
|
||||
await this.openStorageFrontier(installationDeployer);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
// tslint:ensable:no-unsafe-any
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncronizes structure between model and tables in storage.
|
||||
*/
|
||||
public async syncDatabaseStructure() {
|
||||
if (GBConfigService.get('STORAGE_SYNC') === 'true') {
|
||||
const alter = GBConfigService.get('STORAGE_SYNC_ALTER') === 'true';
|
||||
GBLogEx.info(0, 'Syncing database...');
|
||||
|
||||
return await this.sequelize.sync({
|
||||
alter: alter,
|
||||
force: false // Keep it false due to data loss danger.
|
||||
});
|
||||
} else {
|
||||
const msg = `Database synchronization is disabled.`;
|
||||
GBLogEx.info(0, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all items to start several listeners.
|
||||
*/
|
||||
public async getLatestLogs(instanceId: number): Promise<string> {
|
||||
const options = {
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
state: 'active',
|
||||
created: {
|
||||
[Op.gt]: new Date(Date.now() - 60 * 60 * 1000 * 48) // Latest 48 hours.
|
||||
}
|
||||
}
|
||||
};
|
||||
const list = await GuaribasLog.findAll(options);
|
||||
let out = 'General Bots Log\n';
|
||||
await GBUtil.asyncForEach(list, async e => {
|
||||
out = `${out}\n${e.createdAt} - ${e.message}`;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all items to start several listeners.
|
||||
*/
|
||||
public async loadInstances(): Promise<IGBInstance[]> {
|
||||
if (process.env.LOAD_ONLY) {
|
||||
const bots = process.env.LOAD_ONLY.split(`;`);
|
||||
const and = [];
|
||||
await GBUtil.asyncForEach(bots, async e => {
|
||||
and.push({ botId: e });
|
||||
});
|
||||
|
||||
const options = {
|
||||
where: {
|
||||
[Op.or]: and
|
||||
},
|
||||
order: [['instanceId', 'ASC']]
|
||||
};
|
||||
return await GuaribasInstance.findAll(options as any);
|
||||
} else {
|
||||
const options = {
|
||||
where: { state: 'active' },
|
||||
|
||||
order: [['instanceId', 'ASC']]
|
||||
};
|
||||
return await GuaribasInstance.findAll(options as any);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads just one Bot instance by its internal Id.
|
||||
*/
|
||||
public async loadInstanceById(instanceId: number): Promise<IGBInstance> {
|
||||
const options = { where: { instanceId: instanceId, state: 'active' } };
|
||||
|
||||
return await GuaribasInstance.findOne(options);
|
||||
}
|
||||
/**
|
||||
* Loads just one Bot instance.
|
||||
*/
|
||||
public async loadInstanceByActivationCode(code: string): Promise<IGBInstance> {
|
||||
let options = { where: { activationCode: code, state: 'active' } };
|
||||
|
||||
return await GuaribasInstance.findOne(options);
|
||||
}
|
||||
/**
|
||||
* Loads just one Bot instance.
|
||||
*/
|
||||
public async loadInstanceByBotId(botId: string): Promise<IGBInstance> {
|
||||
const options = { where: {} };
|
||||
options.where = { botId: botId, state: 'active' };
|
||||
|
||||
return await GuaribasInstance.findOne(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes .env required to start the full server. Used during
|
||||
* first startup, when user is asked some questions to create the
|
||||
* full base environment.
|
||||
*/
|
||||
public async writeEnv(instance: IGBInstance) {
|
||||
const env = `
|
||||
ADDITIONAL_DEPLOY_PATH=
|
||||
BOT_ID=${instance.botId}
|
||||
CLOUD_SUBSCRIPTIONID=${instance.cloudSubscriptionId}
|
||||
CLOUD_LOCATION=${instance.cloudLocation}
|
||||
CLOUD_USERNAME=${instance.cloudUsername}
|
||||
CLOUD_PASSWORD=${instance.cloudPassword}
|
||||
MARKETPLACE_ID=${instance.marketplaceId}
|
||||
MARKETPLACE_SECRET=${instance.marketplacePassword}
|
||||
STORAGE_DIALECT=${instance.storageDialect}
|
||||
STORAGE_SERVER=${instance.storageServer}
|
||||
STORAGE_NAME=${instance.storageName}
|
||||
STORAGE_USERNAME=${instance.storageUsername}
|
||||
STORAGE_PASSWORD=${instance.storagePassword}
|
||||
STORAGE_SYNC=true
|
||||
STORAGE_SYNC_ALTER=true
|
||||
ENDPOINT_UPDATE=true
|
||||
`;
|
||||
|
||||
await fs.writeFile('.env', env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup generic web hooks so .gbapps can expose application logic
|
||||
* and get called on demand.
|
||||
*/
|
||||
public installWebHook(isGet: boolean, url: string, callback: any) {
|
||||
if (isGet) {
|
||||
GBServer.globals.server.get(url, (req, res) => {
|
||||
callback(req, res);
|
||||
});
|
||||
} else {
|
||||
GBServer.globals.server.post(url, (req, res) => {
|
||||
callback(req, res);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the entry point dialog to be called whenever a user
|
||||
* starts talking to the bot.
|
||||
*/
|
||||
public setEntryPointDialog(dialogName: string) {
|
||||
GBServer.globals.entryPointDialog = dialogName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the default web application root path used to start the GB
|
||||
* with a custom home page.
|
||||
*/
|
||||
public setWWWRoot(localPath: string) {
|
||||
GBServer.globals.wwwroot = localPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a bot instance from storage.
|
||||
*/
|
||||
public async deleteInstance(botId: string) {
|
||||
const options = { where: {} };
|
||||
options.where = { botId: botId };
|
||||
await GuaribasInstance.destroy(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a bot instance object to the storage handling
|
||||
* multi-column JSON based store 'params' field.
|
||||
*/
|
||||
public async saveInstance(fullInstance: any) {
|
||||
const options = { where: {} };
|
||||
options.where = { botId: fullInstance.botId };
|
||||
let instance = await GuaribasInstance.findOne(options);
|
||||
// tslint:disable-next-line:prefer-object-spread
|
||||
if (instance) {
|
||||
instance = Object.assign(instance, fullInstance);
|
||||
} else {
|
||||
instance = Object.assign(new GuaribasInstance(), fullInstance);
|
||||
}
|
||||
try {
|
||||
instance.params = JSON.stringify(JSON.parse(instance.params));
|
||||
} catch (error) {
|
||||
instance.params = JSON.stringify(instance.params);
|
||||
}
|
||||
return await instance.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all bot instances from object storage, if it's formatted.
|
||||
*/
|
||||
public async getApplicationsByInstanceId(appPackages, instanceId: number) {
|
||||
const options = { where: { instanceId: instanceId } };
|
||||
const apps = await GuaribasApplications.findAll(options);
|
||||
|
||||
let matchingAppPackages = [];
|
||||
await GBUtil.asyncForEach(appPackages, async appPackage => {
|
||||
const filenameOnly = path.basename(appPackage.name);
|
||||
const matchedApp = apps.find(app => app.name === filenameOnly);
|
||||
if (matchedApp || filenameOnly.endsWith('.gblib')) {
|
||||
matchingAppPackages.push(appPackage);
|
||||
}
|
||||
});
|
||||
|
||||
return matchingAppPackages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all bot instances from object storage, if it's formatted.
|
||||
*/
|
||||
public async loadAllInstances(
|
||||
core: IGBCoreService,
|
||||
installationDeployer: IGBInstallationDeployer,
|
||||
proxyAddress: string
|
||||
) {
|
||||
GBLogEx.info(0, `Loading instances from storage...`);
|
||||
let instances: IGBInstance[];
|
||||
try {
|
||||
instances = await core.loadInstances();
|
||||
if (process.env.ENDPOINT_UPDATE === 'true') {
|
||||
const group = GBConfigService.get('CLOUD_GROUP') ?? GBConfigService.get('BOT_ID');
|
||||
await GBUtil.asyncForEach(instances, async instance => {
|
||||
GBLogEx.info(instance.instanceId, `Updating bot endpoint for ${instance.botId}...`);
|
||||
try {
|
||||
await installationDeployer.updateBotProxy(
|
||||
instance.botId,
|
||||
group,
|
||||
`${proxyAddress}/api/messages/${instance.botId}`
|
||||
);
|
||||
} catch (error) {
|
||||
if (error.code === 'ResourceNotFound') {
|
||||
GBLog.warn(`Bot ${instance.botId} not found on resource group ${GBConfigService.get('BOT_ID')}.`);
|
||||
} else {
|
||||
throw new Error(`Error updating bot proxy, details: ${error}.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.parent === undefined) {
|
||||
throw new Error(`Cannot connect to operating storage: ${error.message}.`);
|
||||
} else {
|
||||
// Check if storage is empty and needs formatting.
|
||||
const isInvalidObject = error.parent.number === 208 || error.parent.errno === 1; // MSSQL or SQLITE.
|
||||
if (isInvalidObject) {
|
||||
if (GBConfigService.get('STORAGE_SYNC') !== 'true') {
|
||||
throw new Error(
|
||||
`Operating storage is out of sync or there is a storage connection error.
|
||||
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.`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Cannot connect to operating storage: ${error.message}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all system packages from 'packages' folder.
|
||||
*/
|
||||
public async loadSysPackages(core: GBCoreService): Promise<IGBPackage[]> {
|
||||
// NOTE: if there is any code before this line a semicolon
|
||||
// will be necessary before this line.
|
||||
// Loads all system packages.
|
||||
const sysPackages: IGBPackage[] = [];
|
||||
|
||||
await GBUtil.asyncForEach(
|
||||
[
|
||||
GBAdminPackage,
|
||||
GBCorePackage,
|
||||
GBSecurityPackage,
|
||||
GBKBPackage,
|
||||
GBCustomerSatisfactionPackage,
|
||||
GBAnalyticsPackage,
|
||||
GBWhatsappPackage,
|
||||
GBSharePointPackage,
|
||||
GBGoogleChatPackage,
|
||||
GBBasicPackage,
|
||||
SaaSPackage
|
||||
],
|
||||
async e => {
|
||||
GBLogEx.info(0, `Loading sys package: ${e.name}...`);
|
||||
|
||||
const p = Object.create(e.prototype) as IGBPackage;
|
||||
sysPackages.push(p);
|
||||
|
||||
await p.loadPackage(core, core.sequelize);
|
||||
}
|
||||
);
|
||||
|
||||
return sysPackages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that an complex global password has been specified
|
||||
* before starting the server.
|
||||
*/
|
||||
public ensureAdminIsSecured() {}
|
||||
|
||||
public async createBootInstance(
|
||||
core: GBCoreService,
|
||||
installationDeployer: IGBInstallationDeployer,
|
||||
proxyAddress: string
|
||||
) {}
|
||||
|
||||
public async openBrowserInDevelopment() {}
|
||||
|
||||
private createTableQueryOverride(tableName, attributes, options): string {
|
||||
let sql: string = this.createTableQuery.apply(this.queryGenerator, [tableName, attributes, options]);
|
||||
const re1 = /CREATE\s+TABLE\s+\[([^\]]*)\]/;
|
||||
const matches = re1.exec(sql);
|
||||
if (matches !== null) {
|
||||
const table = matches[1];
|
||||
const re2 = /PRIMARY\s+KEY\s+\(\[[^\]]*\](?:,\s*\[[^\]]*\])*\)/;
|
||||
sql = sql.replace(re2, (match: string, ...args: any[]): string => {
|
||||
return `CONSTRAINT [${table}_pk] ${match}`;
|
||||
});
|
||||
const re3 = /FOREIGN\s+KEY\s+\((\[[^\]]*\](?:,\s*\[[^\]]*\])*)\)/g;
|
||||
const re4 = /\[([^\]]*)\]/g;
|
||||
sql = sql.replace(re3, (match: string, ...args: any[]): string => {
|
||||
const fkcols = args[0];
|
||||
let fkname = table;
|
||||
let matches2 = re4.exec(fkcols);
|
||||
while (matches2 !== null) {
|
||||
fkname += `_${matches2[1]}`;
|
||||
matches2 = re4.exec(fkcols);
|
||||
}
|
||||
|
||||
return `CONSTRAINT [${fkname}_fk] FOREIGN KEY (${fkcols})`;
|
||||
});
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL:
|
||||
* let sql = '' +
|
||||
* 'ALTER TABLE [UserGroup]' +
|
||||
* ' ADD CONSTRAINT [invalid1] FOREIGN KEY ([userId1], [userId2], [userId3]) REFERENCES [User] ([userId1], [userId2], [userId3]) ON DELETE NO ACTION,' +
|
||||
* ' CONSTRAINT [invalid2] FOREIGN KEY ([groupId1], [groupId2]) REFERENCES [Group] ([groupId1], [groupId2]) ON DELETE NO ACTION, ' +
|
||||
* ' CONSTRAINT [invalid3] FOREIGN KEY ([instanceId1]) REFERENCES [Instance] ([instanceId1]) ON DELETE NO ACTION'
|
||||
*/
|
||||
private changeColumnQueryOverride(tableName, attributes): string {
|
||||
let sql: string = this.changeColumnQuery.apply(this.queryGenerator, [tableName, attributes]);
|
||||
const re1 = /ALTER\s+TABLE\s+\[([^\]]*)\]/;
|
||||
const matches = re1.exec(sql);
|
||||
if (matches !== null) {
|
||||
const table = matches[1];
|
||||
const re2 = /(ADD\s+)?CONSTRAINT\s+\[([^\]]*)\]\s+FOREIGN\s+KEY\s+\((\[[^\]]*\](?:,\s*\[[^\]]*\])*)\)/g;
|
||||
const re3 = /\[([^\]]*)\]/g;
|
||||
sql = sql.replace(re2, (match: string, ...args: any[]): string => {
|
||||
const fkcols = args[2];
|
||||
let fkname = table;
|
||||
let matches2 = re3.exec(fkcols);
|
||||
while (matches2 !== null) {
|
||||
fkname += `_${matches2[1]}`;
|
||||
matches2 = re3.exec(fkcols);
|
||||
}
|
||||
|
||||
return `${args[0] ? args[0] : ''}CONSTRAINT [${fkname}_fk] FOREIGN KEY (${fkcols})`;
|
||||
});
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens storage firewall used by the server when starting to get root bot instance.
|
||||
*/
|
||||
private async openStorageFrontier(installationDeployer: IGBInstallationDeployer) {
|
||||
const group = GBConfigService.get('BOT_ID');
|
||||
const serverName = GBConfigService.get('STORAGE_SERVER').split('.database.windows.net')[0];
|
||||
await installationDeployer.openStorageFirewall(group, serverName);
|
||||
}
|
||||
|
||||
public async setConfig(min, name: string, value: any): Promise<any> {
|
||||
if (GBConfigService.get('GB_MODE') === 'legacy') {
|
||||
// Handles calls for BASIC persistence on sheet files.
|
||||
GBLog.info(`Defining Config.xlsx variable ${name}= '${value}'...`);
|
||||
|
||||
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||
const maxLines = 512;
|
||||
const file = 'Config.xlsx';
|
||||
const packagePath = GBUtil.getGBAIPath(min.botId, `gbot`);
|
||||
|
||||
let document = await new SystemKeywords().internalGetDocument(client, baseUrl, packagePath, file);
|
||||
|
||||
// Creates book session that will be discarded.
|
||||
let sheets = await client.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`).get();
|
||||
|
||||
// Get the current rows in column A
|
||||
let results = await client
|
||||
.api(
|
||||
`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')`
|
||||
)
|
||||
.get();
|
||||
|
||||
const rows = results.values;
|
||||
let address = '';
|
||||
let lastEmptyRow = -1;
|
||||
let isEdit = false;
|
||||
|
||||
// Loop through column A to find the row where name matches, or find the next empty row
|
||||
for (let i = 7; i <= rows.length; i++) {
|
||||
let result = rows[i - 1][0];
|
||||
if (result && result.toLowerCase() === name.toLowerCase()) {
|
||||
address = `B${i}:B${i}`; // Match found, update value in column B
|
||||
isEdit = true; // We are in editing mode
|
||||
break;
|
||||
} else if (!result && lastEmptyRow === -1) {
|
||||
lastEmptyRow = i; // Store the first empty row if no match is found
|
||||
}
|
||||
}
|
||||
|
||||
// If no match was found and there's an empty row, add a new entry
|
||||
if (!isEdit && lastEmptyRow !== -1) {
|
||||
address = `A${lastEmptyRow}:B${lastEmptyRow}`; // Add new entry in columns A and B
|
||||
}
|
||||
|
||||
// Prepare the request body based on whether it's an edit or add operation
|
||||
let body = { values: isEdit ? [[value]] : [[name, value]] };
|
||||
|
||||
// Update or add the new value in the found address
|
||||
await client
|
||||
.api(
|
||||
`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`
|
||||
)
|
||||
.patch(body);
|
||||
} else if (GBConfigService.get('GB_MODE') === 'local') {
|
||||
let packagePath = GBUtil.getGBAIPath(min.botId, `gbot`);
|
||||
const config = path.join(GBConfigService.get('STORAGE_LIBRARY'), packagePath, 'config.csv');
|
||||
|
||||
const db = await csvdb(config, ['name', 'value'], ',');
|
||||
if (await db.get({ name: name })) {
|
||||
await db.edit({ name: name }, { name, value });
|
||||
} else {
|
||||
await db.add({ name, value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dynamic param from instance. Dynamic params are defined in Config.xlsx
|
||||
* and loaded into the work folder from comida command.
|
||||
*
|
||||
* @param name Name of param to get from instance.
|
||||
* @param defaultValue Value returned when no param is defined in Config.xlsx.
|
||||
*/
|
||||
public getParam<T>(instance: IGBInstance, name: string, defaultValue?: T, platform = false): any {
|
||||
let value = null;
|
||||
let params;
|
||||
name = name.trim();
|
||||
|
||||
// Gets .gbot Params from specified bot.
|
||||
|
||||
if (instance.params) {
|
||||
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
params = GBUtil.caseInsensitive(params);
|
||||
value = params ? params[name] : defaultValue;
|
||||
}
|
||||
|
||||
// Gets specified bot instance values.
|
||||
|
||||
params = GBUtil.caseInsensitive(instance['dataValues']);
|
||||
|
||||
if (params && !value) {
|
||||
// Retrieves the value from specified bot instance (no params collection).
|
||||
|
||||
value = instance['dataValues'][name];
|
||||
|
||||
// If still not found, get from boot bot params.
|
||||
|
||||
const minBoot = GBServer.globals.minBoot as any;
|
||||
|
||||
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);
|
||||
params = GBUtil.caseInsensitive(params);
|
||||
value = params ? params[name] : defaultValue;
|
||||
}
|
||||
|
||||
// If still did not found in boot bot params, try instance fields.
|
||||
|
||||
if (!value) {
|
||||
value = instance['dataValues'][name];
|
||||
}
|
||||
if (!value) {
|
||||
value = instance[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (!value && platform) {
|
||||
value = process.env[name.replace(/ /g, '_').toUpperCase()];
|
||||
}
|
||||
|
||||
if (value && typeof defaultValue === 'boolean') {
|
||||
return new Boolean(value ? value.toString().toLowerCase() === 'true' : defaultValue).valueOf();
|
||||
}
|
||||
if (value && typeof defaultValue === 'string') {
|
||||
return value ? value : defaultValue;
|
||||
}
|
||||
if (value && typeof defaultValue === 'number') {
|
||||
return new Number(value ? value : defaultValue ? defaultValue : 0).valueOf();
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
const ret = value ?? defaultValue;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a dynamic param from instance. *
|
||||
*/
|
||||
public async findParam<T>(instance: IGBInstance, criteria: string) {
|
||||
let params = null;
|
||||
const list = [];
|
||||
if (instance.params) {
|
||||
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
}
|
||||
|
||||
Object.keys(params).forEach(e => {
|
||||
if (e.toLowerCase().indexOf(criteria.toLowerCase()) !== -1) {
|
||||
list.push(e);
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async ensureProxy(port: any): Promise<string> {
|
||||
return '';
|
||||
} // Azure removed.
|
||||
|
||||
public async ensureFolders(instances, deployer: GBDeployer) {
|
||||
const storageMode = process.env.GB_MODE;
|
||||
let libraryPath = GBConfigService.get('STORAGE_LIBRARY');
|
||||
|
||||
if (storageMode === 'gbcluster') {
|
||||
const minioClient = new Client({
|
||||
endPoint: process.env.DRIVE_SERVER,
|
||||
port: parseInt(process.env.DRIVE_PORT),
|
||||
useSSL: process.env.DRIVE_USE_SSL === 'true',
|
||||
accessKey: process.env.DRIVE_ACCESSKEY,
|
||||
secretKey: process.env.DRIVE_SECRET
|
||||
});
|
||||
|
||||
await this.syncBotStorage(instances, 'default', deployer, libraryPath);
|
||||
|
||||
const bucketStream = await minioClient.listBuckets();
|
||||
|
||||
for await (const bucket of bucketStream) {
|
||||
if (bucket.name.endsWith('.gbai') && bucket.name.startsWith(process.env.DRIVE_ORG_PREFIX)) {
|
||||
const botId = bucket.name.replace('.gbai', '').replace(process.env.DRIVE_ORG_PREFIX, '');
|
||||
await this.syncBotStorage(instances, botId, deployer, libraryPath);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(await GBUtil.exists(libraryPath))) {
|
||||
mkdirp.sync(libraryPath);
|
||||
}
|
||||
|
||||
await this.syncBotStorage(instances, 'default', deployer, libraryPath);
|
||||
|
||||
const files = await fs.readdir(libraryPath);
|
||||
await GBUtil.asyncForEach(files, async file => {
|
||||
if (file.trim().toLowerCase() !== 'default.gbai' && file.charAt(0) !== '_') {
|
||||
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 (process.env.GB_MODE === 'local') {
|
||||
if (!instance) {
|
||||
GBLog.info(`Importing package ${botId}.gbai...`);
|
||||
|
||||
// Creates a bot.
|
||||
|
||||
let mobile = null,
|
||||
email = null;
|
||||
|
||||
instance = await deployer.deployBlankBot(botId, mobile, email);
|
||||
instances.push(instance);
|
||||
const gbaiPath = path.join(libraryPath, `${botId}.gbai`);
|
||||
|
||||
if (!(await GBUtil.exists(gbaiPath))) {
|
||||
fs.mkdir(gbaiPath, { recursive: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static async createWebDavServer(minInstances: GBMinInstance[]) {
|
||||
const userManager = new webdav.SimpleUserManager();
|
||||
const privilegeManager = new webdav.SimplePathPrivilegeManager();
|
||||
|
||||
// Create the WebDAV server
|
||||
const server = new webdav.WebDAVServer({
|
||||
port: 1900,
|
||||
httpAuthentication: new webdav.HTTPDigestAuthentication(userManager, 'Default realm'),
|
||||
privilegeManager: privilegeManager
|
||||
});
|
||||
GBServer.globals.webDavServer = server;
|
||||
|
||||
minInstances.forEach(min => {
|
||||
const user = min.core.getParam(min.instance, 'WebDav Username', GBConfigService.get('WEBDAV_USERNAME'));
|
||||
const pass = min.core.getParam(min.instance, 'WebDav Password', GBConfigService.get('WEBDAV_PASSWORD'));
|
||||
|
||||
if (user && pass) {
|
||||
const objUser = userManager.addUser(user, pass);
|
||||
|
||||
const virtualPath = '/' + min.botId;
|
||||
let path1 = GBUtil.getGBAIPath(min.botId, null);
|
||||
const gbaiRoot = path.join(GBConfigService.get('STORAGE_LIBRARY'), path1);
|
||||
|
||||
server.setFileSystem(virtualPath, new webdav.PhysicalFileSystem(gbaiRoot), successed => {
|
||||
GBLogEx.info(min.instance.instanceId, `WebDav online for ${min.botId}...`);
|
||||
});
|
||||
privilegeManager.setRights(objUser, virtualPath, ['all']);
|
||||
}
|
||||
});
|
||||
server.start(1900);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBMinInstance, IGBCoreService, IGBInstance } from 'botlib-legacy';
|
||||
import { CreateOptions } from 'sequelize/types';
|
||||
import fs from 'fs/promises';
|
||||
import urlJoin from 'url-join';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GuaribasInstance } from '../models/GBModel.js';
|
||||
import { GBConfigService } from './GBConfigService.js';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
|
||||
/**
|
||||
* Handles the importing of packages.
|
||||
*/
|
||||
export class GBImporter {
|
||||
public core: IGBCoreService;
|
||||
|
||||
constructor (core: IGBCoreService) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public async importIfNotExistsBotPackage (
|
||||
botId: string,
|
||||
packageName: string,
|
||||
localPath: string,
|
||||
additionalInstance: IGBInstance = null
|
||||
) {
|
||||
const file = urlJoin(localPath, 'settings.json');
|
||||
|
||||
let settingsJson = {botId: botId};
|
||||
if (await GBUtil.exists(file)){
|
||||
|
||||
settingsJson = JSON.parse(await fs.readFile(file, 'utf8'));
|
||||
if (botId === undefined) {
|
||||
botId = settingsJson.botId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let instance: IGBInstance;
|
||||
if (botId === undefined) {
|
||||
botId = GBConfigService.get('BOT_ID');
|
||||
instance = await this.core.loadInstanceByBotId(botId);
|
||||
if (!instance) {
|
||||
instance = <IGBInstance>{};
|
||||
instance.state = 'active';
|
||||
instance.adminPass = await GBUtil.hashPassword( GBConfigService.get('ADMIN_PASS'));
|
||||
instance.botId = GBConfigService.get('BOT_ID');
|
||||
instance.cloudSubscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
instance.cloudLocation = GBConfigService.get('CLOUD_LOCATION');
|
||||
instance.cloudUsername = GBConfigService.get('CLOUD_USERNAME');
|
||||
instance.cloudPassword = GBConfigService.get('CLOUD_PASSWORD');
|
||||
instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID');
|
||||
instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET');
|
||||
instance.storageDialect = GBConfigService.get('STORAGE_DIALECT');
|
||||
instance.storageServer = GBConfigService.get('STORAGE_SERVER');
|
||||
instance.storageName = GBConfigService.get('STORAGE_NAME');
|
||||
instance.storageUsername = GBConfigService.get('STORAGE_USERNAME');
|
||||
instance.storagePassword = GBConfigService.get('STORAGE_PASSWORD');
|
||||
}
|
||||
} else {
|
||||
instance = await this.core.loadInstanceByBotId(botId);
|
||||
}
|
||||
|
||||
if (instance != undefined && !instance.botId) {
|
||||
console.log(`Null BotId after load instance with botId: ${botId}.`);
|
||||
} else {
|
||||
instance = additionalInstance;
|
||||
}
|
||||
|
||||
return await this.createOrUpdateInstanceInternal(instance, botId, localPath, settingsJson);
|
||||
}
|
||||
|
||||
public async createBotInstance (botId: string) {
|
||||
const fullSettingsJson = <GuaribasInstance>{ };
|
||||
fullSettingsJson['botId'] = botId;
|
||||
|
||||
return await GuaribasInstance.create(fullSettingsJson);
|
||||
}
|
||||
|
||||
private async createOrUpdateInstanceInternal (
|
||||
instance: IGBInstance,
|
||||
botId: string,
|
||||
localPath: string,
|
||||
settingsJson: any
|
||||
) {
|
||||
|
||||
const fullSettingsJson = { ...GBServer.globals.bootInstance, ...settingsJson,
|
||||
description:"General Bot", title:botId
|
||||
};
|
||||
|
||||
if (botId !== undefined) {
|
||||
fullSettingsJson.botId = botId;
|
||||
}
|
||||
|
||||
if (instance !== null) {
|
||||
instance = { ...instance, ...fullSettingsJson };
|
||||
|
||||
return await this.core.saveInstance(instance);
|
||||
} else {
|
||||
return await GuaribasInstance.create(fullSettingsJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBLog, IGBInstance } from 'botlib-legacy';
|
||||
import { GuaribasLog } from '../models/GBModel.js';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBConfigService } from './GBConfigService.js';
|
||||
|
||||
export class GBLogEx {
|
||||
private static async logWithLevel(
|
||||
level: 'error' | 'debug' | 'info' | 'verbose',
|
||||
minOrInstanceId: any,
|
||||
message: string
|
||||
) {
|
||||
const instanceId = this.normalizeInstanceId(minOrInstanceId);
|
||||
GBLog[level](`${instanceId}: ${message}`);
|
||||
await this.log(instanceId, level.charAt(0), message);
|
||||
}
|
||||
|
||||
private static normalizeInstanceId(minOrInstanceId: any): string | number {
|
||||
if (typeof minOrInstanceId === 'object') {
|
||||
return minOrInstanceId.instance ? minOrInstanceId.instance.botId : minOrInstanceId.botId;
|
||||
}
|
||||
return minOrInstanceId === 0 ? 'default' : minOrInstanceId;
|
||||
}
|
||||
|
||||
public static async error(minOrInstanceId: any, message: string) {
|
||||
await this.logWithLevel('error', minOrInstanceId, message);
|
||||
}
|
||||
|
||||
public static async debug(minOrInstanceId: any, message: string) {
|
||||
await this.logWithLevel('debug', minOrInstanceId, message);
|
||||
}
|
||||
|
||||
public static async info(minOrInstanceId: any, message: string) {
|
||||
await this.logWithLevel('info', minOrInstanceId, message);
|
||||
}
|
||||
|
||||
public static async verbose(minOrInstanceId: any, message: string) {
|
||||
await this.logWithLevel('verbose', minOrInstanceId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and update user agent information to a next available person.
|
||||
*/
|
||||
public static async log(instance, kind: string, message: string): Promise<GuaribasLog> {
|
||||
if (GBConfigService.get('LOG_ON_STORAGE')) {
|
||||
message = message ? message.substring(0, 1023) : null;
|
||||
|
||||
return await GuaribasLog.create(<GuaribasLog>{
|
||||
instanceId: instance ? instance : 0,
|
||||
message: message,
|
||||
kind: kind
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,359 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots SSR support based on https://www.npmjs.com/package/ssr-for-bots.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs/promises';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import urljoin from 'url-join';
|
||||
import { GBMinInstance } from 'botlib-legacy';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBLogEx } from './GBLogEx.js';
|
||||
import urlJoin from 'url-join';
|
||||
import { GBDeployer } from './GBDeployer.js';
|
||||
import { GBMinService } from './GBMinService.js';
|
||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
const puppeteer = require('puppeteer-extra');
|
||||
const hidden = require('puppeteer-extra-plugin-stealth');
|
||||
const { executablePath } = require('puppeteer');
|
||||
|
||||
export class GBSSR {
|
||||
// https://hackernoon.com/tips-and-tricks-for-web-scraping-with-puppeteer-ed391a63d952
|
||||
// Dont download all resources, we just need the HTML
|
||||
// Also, this is huge performance/response time boost
|
||||
private static blockedResourceTypes = [
|
||||
'image',
|
||||
'media',
|
||||
'font',
|
||||
'texttrack',
|
||||
'object',
|
||||
'beacon',
|
||||
'csp_report',
|
||||
'imageset'
|
||||
];
|
||||
|
||||
// const whitelist = ["document", "script", "xhr", "fetch"];
|
||||
private static skippedResources = [
|
||||
'quantserve',
|
||||
'adzerk',
|
||||
'doubleclick',
|
||||
'adition',
|
||||
'exelator',
|
||||
'sharethrough',
|
||||
'cdn.api.twitter',
|
||||
'google-analytics',
|
||||
'googletagmanager',
|
||||
'google',
|
||||
'fontawesome',
|
||||
'facebook',
|
||||
'analytics',
|
||||
'optimizely',
|
||||
'clicktale',
|
||||
'mixpanel',
|
||||
'zedo',
|
||||
'clicksor',
|
||||
'tiqcdn'
|
||||
];
|
||||
|
||||
public static async preparePuppeteer(profilePath) {
|
||||
let args = [
|
||||
'--check-for-update-interval=2592000',
|
||||
'--disable-accelerated-2d-canvas',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-features=site-per-process',
|
||||
'--disable-gpu',
|
||||
'--no-first-run',
|
||||
'--no-sandbox',
|
||||
'--no-default-browser-check'
|
||||
];
|
||||
|
||||
if (profilePath) {
|
||||
args.push(`--user-data-dir=${profilePath}`);
|
||||
|
||||
const preferences = urljoin(profilePath, 'Default', 'Preferences');
|
||||
if (await GBUtil.exists(preferences)) {
|
||||
const file = await fs.readFile(preferences, 'utf8');
|
||||
const data = JSON.parse(file);
|
||||
data['profile']['exit_type'] = 'none';
|
||||
await fs.writeFile(preferences, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
args: args,
|
||||
ignoreHTTPSErrors: true,
|
||||
headless: process.env.CHROME_HEADLESS === 'true',
|
||||
defaultViewport: null,
|
||||
executablePath: process.env.CHROME_PATH ? process.env.CHROME_PATH : executablePath(),
|
||||
ignoreDefaultArgs: ['--enable-automation', '--enable-blink-features=IdleDetection']
|
||||
};
|
||||
}
|
||||
|
||||
public static async createBrowser(profilePath): Promise<any> {
|
||||
const opts = await this.preparePuppeteer(profilePath);
|
||||
puppeteer.use(hidden());
|
||||
puppeteer.use(require('puppeteer-extra-plugin-minmax')());
|
||||
const browser = await puppeteer.launch(opts);
|
||||
return browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTML of bot default.gbui.
|
||||
*/
|
||||
public static async getHTML(min: GBMinInstance) {
|
||||
const url = urljoin(GBServer.globals.publicAddress, min.botId);
|
||||
const browser = await GBSSR.createBrowser(null);
|
||||
const stylesheetContents = {};
|
||||
let html;
|
||||
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
await page.minimize();
|
||||
|
||||
await page.setUserAgent(
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
|
||||
);
|
||||
await page.setRequestInterception(true);
|
||||
page.on('request', request => {
|
||||
const requestUrl = request.url().split('?')[0].split('#')[0];
|
||||
if (
|
||||
GBSSR.blockedResourceTypes.indexOf(request.resourceType()) !== -1 ||
|
||||
GBSSR.skippedResources.some(resource => requestUrl.indexOf(resource) !== -1)
|
||||
) {
|
||||
request.abort();
|
||||
} else {
|
||||
request.continue();
|
||||
}
|
||||
});
|
||||
|
||||
page.on('response', async resp => {
|
||||
const responseUrl = resp.url();
|
||||
const sameOrigin = new URL(responseUrl).origin === new URL(url).origin;
|
||||
const isStylesheet = resp.request().resourceType() === 'stylesheet';
|
||||
if (sameOrigin && isStylesheet) {
|
||||
stylesheetContents[responseUrl] = await resp.text();
|
||||
}
|
||||
});
|
||||
|
||||
const response = await page.goto(url, {
|
||||
timeout: 120000,
|
||||
waitUntil: 'networkidle0'
|
||||
});
|
||||
|
||||
await GBUtil.sleep(6000);
|
||||
|
||||
// Inject <base> on page to relative resources load properly.
|
||||
|
||||
await page.evaluate(url => {
|
||||
const base = document.createElement('base');
|
||||
base.href = url;
|
||||
// Add to top of head, before all other resources.
|
||||
document.head.prepend(base);
|
||||
}, url);
|
||||
|
||||
// Remove scripts and html imports. They've already executed.
|
||||
|
||||
await page.evaluate(() => {
|
||||
const elements = document.querySelectorAll('script, link[rel="import"]');
|
||||
elements.forEach(e => {
|
||||
e.remove();
|
||||
});
|
||||
});
|
||||
|
||||
// Replace stylesheets in the page with their equivalent <style>.
|
||||
|
||||
await page.$$eval(
|
||||
'link[rel="stylesheet"]',
|
||||
(links, content) => {
|
||||
links.forEach((link: any) => {
|
||||
const cssText = content[link.href];
|
||||
if (cssText) {
|
||||
const style = document.createElement('style');
|
||||
style.textContent = cssText;
|
||||
link.replaceWith(style);
|
||||
}
|
||||
});
|
||||
},
|
||||
stylesheetContents
|
||||
);
|
||||
|
||||
html = await page.content();
|
||||
|
||||
// Close the page we opened here (not the browser).
|
||||
|
||||
await page.close();
|
||||
} catch (e) {
|
||||
const html = e.toString();
|
||||
GBLogEx.error(min, `URL: ${url} Failed with message: ${html}`);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
public static async ssrFilter(req: Request, res: Response, next) {
|
||||
let applyOptions = {
|
||||
prerender: [], // Array containing the user-agents that will trigger the ssr service
|
||||
exclude: [], // Array containing paths and/or extentions that will be excluded from being prerendered by the ssr service
|
||||
useCache: true, // Variable that determins if we will use page caching or not
|
||||
cacheRefreshRate: 86400 // Seconds of which the cache will be kept alive, pass 0 or negative value for infinite lifespan
|
||||
};
|
||||
|
||||
// Default user agents
|
||||
const prerenderArray = [
|
||||
'bot',
|
||||
'googlebot',
|
||||
'Chrome-Lighthouse',
|
||||
'DuckDuckBot',
|
||||
'ia_archiver',
|
||||
'bingbot',
|
||||
'yandex',
|
||||
'baiduspider',
|
||||
'Facebot',
|
||||
'facebookexternalhit',
|
||||
'facebookexternalhit/1.1',
|
||||
'twitterbot',
|
||||
'rogerbot',
|
||||
'linkedinbot',
|
||||
'embedly',
|
||||
'quora link preview',
|
||||
'showyoubot',
|
||||
'outbrain',
|
||||
'pinterest',
|
||||
'slackbot',
|
||||
'vkShare',
|
||||
'W3C_Validator'
|
||||
];
|
||||
|
||||
// default exclude array
|
||||
const excludeArray = ['.xml', '.ico', '.txt', '.json'];
|
||||
const userAgent: string = req.headers['user-agent'] || '';
|
||||
const prerender = new RegExp([...prerenderArray, ...applyOptions.prerender].join('|').slice(0, -1), 'i').test(
|
||||
userAgent
|
||||
);
|
||||
const exclude = !new RegExp([...excludeArray, ...applyOptions.exclude].join('|').slice(0, -1)).test(
|
||||
req.originalUrl
|
||||
);
|
||||
|
||||
// Tries to find botId from URL.
|
||||
|
||||
const minBoot = GBServer.globals.minBoot;
|
||||
|
||||
let onlyChars: any = /\/([A-Za-z0-9\-\_]+)\/*/.exec(req.originalUrl);
|
||||
onlyChars = onlyChars ? onlyChars[1] : minBoot.botId;
|
||||
|
||||
let botId = req.originalUrl && req.originalUrl === '/' ? minBoot.botId : onlyChars;
|
||||
|
||||
let min: GBMinInstance =
|
||||
req.url === '/'
|
||||
? minBoot
|
||||
: GBServer.globals.minInstances.filter(p => p.instance.botId.toLowerCase() === botId.toLowerCase())[0];
|
||||
if (!min) {
|
||||
min =
|
||||
req.url === '/'
|
||||
? minBoot
|
||||
: GBServer.globals.minInstances.filter(p =>
|
||||
p.instance.activationCode ? p.instance.activationCode.toLowerCase() === botId.toLowerCase() : null
|
||||
)[0];
|
||||
}
|
||||
if (!min) {
|
||||
botId = minBoot.botId;
|
||||
}
|
||||
|
||||
let packagePath = GBUtil.getGBAIPath(botId, `gbui`);
|
||||
|
||||
// Checks if the bot has an .gbui published or use default.gbui.
|
||||
|
||||
if (!(await GBUtil.exists(packagePath))) {
|
||||
packagePath = path.join(process.env.PWD, 'packages', `default.gbui`, 'build');
|
||||
}
|
||||
let parts = req.url.replace(`/${botId}`, '').split('?');
|
||||
let url = parts[0];
|
||||
|
||||
if (min && req.originalUrl && prerender && exclude && (await GBUtil.exists(packagePath))) {
|
||||
// Reads from static HTML when a bot is crawling.
|
||||
|
||||
packagePath = path.join(process.env.PWD, 'work', packagePath, 'index.html');
|
||||
const html = await fs.readFile(packagePath, 'utf8');
|
||||
res.status(200).send(html);
|
||||
return true;
|
||||
} else {
|
||||
// Servers default.gbui web application.
|
||||
|
||||
packagePath = path.join(
|
||||
process.env.PWD,
|
||||
GBDeployer.deployFolder,
|
||||
GBMinService.uiPackage,
|
||||
'build',
|
||||
url === '/' || url === '' ? `index.html` : url
|
||||
);
|
||||
if (GBServer.globals.wwwroot && url === '/') {
|
||||
packagePath = GBServer.globals.wwwroot + '/index.html'; // TODO.
|
||||
}
|
||||
if (!min && !url.startsWith('/images') && GBServer.globals.wwwroot) {
|
||||
packagePath = path.join(GBServer.globals.wwwroot, url);
|
||||
}
|
||||
if (!min && !url.startsWith('/static') && GBServer.globals.wwwroot) {
|
||||
packagePath = path.join(GBServer.globals.wwwroot, url);
|
||||
}
|
||||
if (await GBUtil.exists(packagePath)) {
|
||||
if (min) {
|
||||
let html = await fs.readFile(packagePath, 'utf8');
|
||||
html = html.replace(/\{p\}/gi, min.botId);
|
||||
html = html.replace(/\{botId\}/gi, min.botId);
|
||||
|
||||
const theme = `theme-${await (min.core as any)['getParam'](min.instance, 'Theme Color', 'grey')}`;
|
||||
|
||||
html = html.replace(/\{themeColor\}/gi, theme);
|
||||
|
||||
html = html.replace(/\{theme\}/gi, min.instance.theme ? min.instance.theme : 'default.gbtheme');
|
||||
html = html.replace(/\{title\}/gi, min.instance.title);
|
||||
res.send(html).end();
|
||||
} else {
|
||||
res.sendFile(packagePath);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
GBLogEx.verbose(min, `HTTP 404: ${req.url}.`);
|
||||
res.status(404);
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,479 +0,0 @@
|
|||
import fs from 'fs/promises';
|
||||
import formidable from 'formidable';
|
||||
import path from 'path';
|
||||
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';
|
||||
import { GBUtil } from '../../../../src/util.js';
|
||||
import urlJoin from 'url-join';
|
||||
import { GBServer } from '../../../../src/app.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);
|
||||
|
||||
let userId = req.query?.userSystemId ? req.query?.userSystemId : req.body?.user?.id;
|
||||
userId = userId ? userId : req.query.userId;
|
||||
|
||||
const activity = createConversationUpdateActivity(serviceUrl, conversationId, userId);
|
||||
|
||||
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(`/api/messages/${botId}/v3/directline/conversations/`, reqs);
|
||||
router.post(`/directline/${botId}/conversations/`, reqs);
|
||||
router.post(`/directline/conversations/`, reqs);
|
||||
|
||||
// Reconnect API
|
||||
const req3 = (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');
|
||||
};
|
||||
router.get('/v3/directline/conversations/:conversationId', req3);
|
||||
router.get(`/directline/${botId}/conversations/:conversationId`, req3);
|
||||
|
||||
// Gets activities from store (local history array for now)
|
||||
const req45 = (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();
|
||||
}
|
||||
};
|
||||
|
||||
const req34 = (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();
|
||||
}
|
||||
};
|
||||
|
||||
router.get(`/directline/${botId}/conversations/:conversationId/activities`, req34);
|
||||
router.get(`/api/messages/${botId}/v3/directline/conversations/:conversationId/activities`, req34);
|
||||
|
||||
// Sends message to bot. Assumes message activities
|
||||
|
||||
const res2 = (req, res) => {
|
||||
const incomingActivity = req.body;
|
||||
// Make copy of activity. Add required fields
|
||||
const activity = createMessageActivity(incomingActivity, serviceUrl, req.params.conversationId, req.params['pid']);
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
// import { createMessageActivity, getConversation } from './yourModule'; // Update this import as needed
|
||||
|
||||
const resupload = async (req, res) => {
|
||||
// Extract botId from the URL using the pathname
|
||||
const urlParts = req.url.split('/');
|
||||
const botId = urlParts[2]; // Assuming the URL is structured like /directline/{botId}/conversations/:conversationId/upload
|
||||
const conversationId = req.params.conversationId; // Extract conversationId from parameters
|
||||
|
||||
const uploadDir = path.join(process.cwd(), 'work', `${botId}.gbai`, 'cache'); // Create upload directory path
|
||||
|
||||
// Create the uploads directory if it doesn't exist
|
||||
|
||||
await fs.mkdir(uploadDir, { recursive: true });
|
||||
|
||||
const form = formidable({
|
||||
uploadDir, // Use the constructed upload directory
|
||||
keepExtensions: true, // Keep file extensions
|
||||
});
|
||||
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
if (err) {
|
||||
console.log(`Error parsing the file: ${GBUtil.toYAML(err)}.`);
|
||||
return res.status(400).send('Error parsing the file.');
|
||||
}
|
||||
|
||||
const incomingActivity = fields; // Get incoming activity data
|
||||
const file = files.file[0]; // Access the uploaded file
|
||||
|
||||
const fileName = file['newFilename'];
|
||||
const fileUrl = urlJoin(GBServer.globals.publicAddress, `${botId}.gbai`,'cache', fileName);
|
||||
|
||||
// Create the activity message
|
||||
let userId = req.query?.userSystemId ? req.query?.userSystemId : req.body?.user?.id;
|
||||
userId = userId ? userId : req.query?.userId;
|
||||
|
||||
const activity = createMessageActivity(incomingActivity, serviceUrl, conversationId, req.params['pid']);
|
||||
activity.from = { id: userId, name: 'webbot' };
|
||||
activity.attachments = [{
|
||||
contentType: 'application/octet-stream', // Adjust as necessary
|
||||
contentUrl: fileUrl,
|
||||
name: fileName, // Original filename
|
||||
}];
|
||||
const conversation = getConversation(conversationId, conversationInitRequired);
|
||||
|
||||
if (conversation) {
|
||||
// Add the uploaded file info to the activity
|
||||
activity['fileUrl'] = fileUrl; // Set the file URL
|
||||
|
||||
conversation.history.push(activity);
|
||||
|
||||
try {
|
||||
const response = await fetch(botUrl, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(activity),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
res.status(response.status).json({ id: activity.id });
|
||||
} catch (fetchError) {
|
||||
console.error('Error fetching bot:', fetchError);
|
||||
res.status(500).send('Error processing request.');
|
||||
}
|
||||
} else {
|
||||
// Conversation was never initialized
|
||||
res.status(400).send('Conversation not initialized.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
router.post(`/api/messages/${botId}/v3/directline/conversations/:conversationId/activities`, res2);
|
||||
router.post(`/directline/${botId}/conversations/:conversationId/activities`, res2);
|
||||
|
||||
router.post(`/directline/${botId}/conversations/:conversationId/upload`, resupload);
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
// TODO: Check duplicate. router.post(`/api/messages/${botId}/v3/directline/conversations/:conversationId/activities`, (req, res) => {
|
||||
// let activity: IActivity;
|
||||
|
||||
// activity = req.body;
|
||||
|
||||
// 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,
|
||||
pid
|
||||
): IMessageActivity => {
|
||||
const obj = {
|
||||
...incomingActivity,
|
||||
channelId: 'api',
|
||||
serviceUrl,
|
||||
conversation: { id: conversationId },
|
||||
id: uuidv4.v4()
|
||||
};
|
||||
return obj;
|
||||
};
|
||||
|
||||
const createConversationUpdateActivity = (serviceUrl: string, conversationId: string, userId: any): IConversationUpdateActivity => {
|
||||
const activity: IConversationUpdateActivity = {
|
||||
type: 'conversationUpdate',
|
||||
channelId: 'api',
|
||||
serviceUrl,
|
||||
conversation: { id: conversationId },
|
||||
id: uuidv4.v4(),
|
||||
membersAdded: [],
|
||||
membersRemoved: [],
|
||||
from: { id: userId, name: 'webbot' }
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
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,
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
export const Messages = {
|
||||
global_quit: /^(\bsair\b|\bsai\b|\bchega\b|\bexit\b|\bquit\b|\bfinish\b|\bend\b|\bausfahrt\b|\bverlassen\b)/i,
|
||||
'en-US': {
|
||||
show_video: 'I will show you a video, please wait...',
|
||||
good_morning: 'good morning',
|
||||
good_evening: 'good evening',
|
||||
good_night: 'good night',
|
||||
hi: msg => `Hello, ${msg}.`,
|
||||
very_sorry_about_error: `I'm sorry to inform that there was an error which was recorded to be solved.`,
|
||||
canceled: 'Canceled. If I can be useful, let me know how',
|
||||
whats_email: "What's your E-mail address?",
|
||||
which_language: 'Please, type the language name you would like to talk through.',
|
||||
validation_enter_valid_email: 'Please enter a valid e-mail.',
|
||||
language_chosen: "Very good, so let's go...",
|
||||
affirmative_sentences: /^(\bsim\b|\bs\b|\bpositivo\b|\bafirmativo\b|\bclaro\b|\bevidente\b|\bsem dúvida\b|\bconfirmo\b|\bconfirmar\b|\bconfirmado\b|\buhum\b|\bsi\b|\by\b|\byes\b|\bsure\b)/i,
|
||||
will_answer_projector: "I'll answer on the projector to a better experience..."
|
||||
},
|
||||
'pt-BR': {
|
||||
show_video: 'Vou te mostrar um vídeo. Por favor, aguarde...',
|
||||
good_morning: 'bom dia',
|
||||
good_evening: 'boa tarde',
|
||||
good_night: 'boa noite',
|
||||
hi: msg => `Oi, ${msg}.`,
|
||||
very_sorry_about_error: `Lamento, ocorreu um erro que já foi registrado para ser tratado.`,
|
||||
canceled: 'Cancelado, avise como posso ser útil novamente.',
|
||||
whats_email: 'Qual seu e-mail?',
|
||||
which_language: 'Por favor, digite o idioma que você gostaria de usar para conversarmos.',
|
||||
validation_enter_valid_email: 'Por favor digite um email válido.',
|
||||
language_chosen: 'Muito bem, então vamos lá...',
|
||||
affirmative_sentences: /^(\bsim\b|\bs\b|\bpositivo\b|\bafirmativo\b|\bclaro\b|\bevidente\b|\bsem dúvida\b|\bconfirmo\b|\bconfirmar\b|\bconfirmado\b|\buhum\b|\bsi\b|\by\b|\byes\b|\bsure\b)/i,
|
||||
will_answer_projector: 'Vou te responder na tela para melhor visualização...'
|
||||
}
|
||||
};
|
||||
|
|
@ -1,294 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
import { GBMinService } from '../../core.gbapp/services/GBMinService.js';
|
||||
import { AnalyticsService } from '../../analytics.gblib/services/AnalyticsService.js';
|
||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||
import { CSService } from '../services/CSService.js';
|
||||
import { Messages } from '../strings.js';
|
||||
|
||||
/**
|
||||
* Dialog for feedback collecting.
|
||||
*/
|
||||
export class FeedbackDialog extends IGBDialog {
|
||||
/**
|
||||
* Setup dialogs flows and define services call.
|
||||
*
|
||||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
const service = new CSService();
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/pleaseNoBadWords', [
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].please_no_bad_words);
|
||||
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/t', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const sec = new SecService();
|
||||
let from = GBMinService.userMobile(step);
|
||||
const profile = await min.userProfile.get(step.context, {});
|
||||
const args = step.activeDialog.state.options;
|
||||
|
||||
// Transfer to...
|
||||
|
||||
if (args && args.to) {
|
||||
// An user from Teams willing to transfer to a WhatsApp user.
|
||||
|
||||
await sec.ensureUser(min, args.to, 'Name', '', 'whatsapp', 'Name', null);
|
||||
|
||||
await sec.assignHumanAgent(min, args.to, profile.userSystemId);
|
||||
await min.conversationalService.sendText(
|
||||
min,
|
||||
step,
|
||||
Messages[locale].notify_agent_transfer_done(min.instance.botId)
|
||||
);
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].please_wait_transfering);
|
||||
const agentSystemId = await sec.assignHumanAgent(min, from);
|
||||
|
||||
await min.userProfile.set(step.context, profile);
|
||||
|
||||
if (agentSystemId.indexOf('@') !== -1) {
|
||||
// Agent is from Teams or Google Chat.
|
||||
|
||||
const agent = await sec.getUserFromSystemId(agentSystemId);
|
||||
await min.conversationalService['sendOnConversation'](
|
||||
min,
|
||||
agent,
|
||||
Messages[locale].notify_agent(step.context.activity.from.name)
|
||||
);
|
||||
} else {
|
||||
await min.whatsAppDirectLine.sendToDevice(
|
||||
agentSystemId,
|
||||
Messages[locale].notify_agent(step.context.activity.from.name)
|
||||
);
|
||||
}
|
||||
}
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/qt', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
const sec = new SecService();
|
||||
const userSystemId = GBMinService.userMobile(step);
|
||||
let user = await sec.getUserFromSystemId(userSystemId);
|
||||
|
||||
if (user.agentMode === 'self') {
|
||||
const manualUser = await sec.getUserFromAgentSystemId(userSystemId);
|
||||
|
||||
await min.whatsAppDirectLine.sendToDeviceEx(
|
||||
manualUser.userSystemId,
|
||||
Messages[locale].notify_end_transfer(min.instance.botId),
|
||||
locale,
|
||||
step.context.activity.conversation.id
|
||||
);
|
||||
|
||||
if (userSystemId.charAt(2) === ':' || userSystemId.indexOf('@') > -1) {
|
||||
// Agent is from Teams or Google Chat.
|
||||
await min.conversationalService.sendText(
|
||||
min,
|
||||
step,
|
||||
Messages[locale].notify_end_transfer(min.instance.botId)
|
||||
);
|
||||
} else {
|
||||
await min.whatsAppDirectLine.sendToDeviceEx(
|
||||
userSystemId,
|
||||
Messages[locale].notify_end_transfer(min.instance.botId),
|
||||
locale,
|
||||
step.context.activity.conversation.id
|
||||
);
|
||||
}
|
||||
|
||||
await sec.updateHumanAgent(userSystemId, min.instance.instanceId, null);
|
||||
await sec.updateHumanAgent(manualUser.userSystemId, min.instance.instanceId, null);
|
||||
} else if (user.agentMode === 'human') {
|
||||
const agent = await sec.getUserFromSystemId(user.agentSystemId);
|
||||
|
||||
await min.whatsAppDirectLine.sendToDeviceEx(
|
||||
user.userSystemId,
|
||||
Messages[locale].notify_end_transfer(min.instance.botId),
|
||||
locale,
|
||||
step.context.activity.conversation.id
|
||||
);
|
||||
|
||||
if (user.agentSystemId.indexOf('@') !== -1) {
|
||||
// Agent is from Teams or Google Chat.
|
||||
await min.conversationalService.sendText(
|
||||
min,
|
||||
step,
|
||||
Messages[locale].notify_end_transfer(min.instance.botId)
|
||||
);
|
||||
} else {
|
||||
await min.whatsAppDirectLine.sendToDeviceEx(
|
||||
user.agentSystemId,
|
||||
Messages[locale].notify_end_transfer(min.instance.botId),
|
||||
locale,
|
||||
step.context.activity.conversation.id
|
||||
);
|
||||
}
|
||||
|
||||
await sec.updateHumanAgent(user.userSystemId, min.instance.instanceId, null);
|
||||
await sec.updateHumanAgent(agent.userSystemId, min.instance.instanceId, null);
|
||||
} else {
|
||||
if (user.userSystemId.charAt(2) === ':' || userSystemId.indexOf('@') > -1) {
|
||||
// Agent is from Teams or Google Chat.
|
||||
await min.conversationalService.sendText(min, step, 'Nenhum atendimento em andamento.');
|
||||
} else {
|
||||
await min.whatsAppDirectLine.sendToDeviceEx(
|
||||
user.userSystemId,
|
||||
'Nenhum atendimento em andamento.',
|
||||
locale,
|
||||
step.context.activity.conversation.id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/feedbackNumber', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
return await step.next();
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const rate = step.result.entity;
|
||||
const user = await min.userProfile.get(step.context, {});
|
||||
await service.updateConversationRate(user.conversation, rate);
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].thanks);
|
||||
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/feedback', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].about_suggestions);
|
||||
step.activeDialog.state.cbId = (step.options as any).id;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, Messages[locale].what_about_service);
|
||||
},
|
||||
async step => {
|
||||
const fixedLocale = 'en-US';
|
||||
const user = await min.userProfile.get(step.context, {});
|
||||
let rate = 1;
|
||||
|
||||
if (process.env.PRIVACY_STORE_MESSAGES === 'true') {
|
||||
// Updates values to perform Bot Analytics.
|
||||
|
||||
const analytics = new AnalyticsService();
|
||||
let rate = await analytics.updateConversationSuggestion(
|
||||
min.instance.instanceId,
|
||||
user.conversation.conversationId,
|
||||
step.result,
|
||||
user.locale
|
||||
);
|
||||
}
|
||||
|
||||
if (rate > 0.5) {
|
||||
await min.conversationalService.sendText(min, step, Messages[fixedLocale].glad_you_liked);
|
||||
} else {
|
||||
const message = min.core.getParam<string>(
|
||||
min.instance,
|
||||
'Feedback Improve Message',
|
||||
Messages[fixedLocale].we_will_improve
|
||||
);
|
||||
|
||||
await min.conversationalService.sendText(min, step, message);
|
||||
}
|
||||
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBMinInstance, IGBDialog } from 'botlib-legacy';
|
||||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { AnalyticsService } from '../../analytics.gblib/services/AnalyticsService.js';
|
||||
import { CSService } from '../services/CSService.js';
|
||||
import { Messages } from '../strings.js';
|
||||
|
||||
/**
|
||||
* Dialog for collecting quality of answer.
|
||||
*/
|
||||
export class QualityDialog extends IGBDialog {
|
||||
/**
|
||||
* Setup dialogs flows and define services call.
|
||||
*
|
||||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
const service = new CSService();
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/report', [
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
await min.conversationalService.sendText(min, step, await min.whatsAppDirectLine.getLatestCampaignReport());
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/check', [
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].check_whatsapp_ok);
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/quality', [
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const user = await min.userProfile.get(step.context, {});
|
||||
|
||||
const score = step.result;
|
||||
|
||||
if (score === 0) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].im_sorry_lets_try);
|
||||
|
||||
return await step.next();
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].great_thanks);
|
||||
await min.conversationalService.sendEvent(min, step, 'play', {
|
||||
playerType: 'markdown',
|
||||
data: {
|
||||
content: Messages[locale].great_thanks
|
||||
}
|
||||
});
|
||||
await service.insertQuestionAlternate(min.instance.instanceId, user.lastQuestion, user.lastQuestionId);
|
||||
|
||||
// Updates values to perform Bot Analytics.
|
||||
if (process.env.PRIVACY_STORE_MESSAGES === 'true') {
|
||||
const analytics = new AnalyticsService();
|
||||
analytics.updateConversationSuggestion(
|
||||
min.instance.instanceId,
|
||||
user.conversation,
|
||||
step.result,
|
||||
user.locale
|
||||
);
|
||||
}
|
||||
// Goes to the ask loop.
|
||||
|
||||
return await step.replaceDialog('/ask', { emptyPrompt: true });
|
||||
}
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib-legacy';
|
||||
import urlJoin from 'url-join';
|
||||
import { FeedbackDialog } from './dialogs/FeedbackDialog.js';
|
||||
import { QualityDialog } from './dialogs/QualityDialog.js';
|
||||
import { GuaribasQuestionAlternate } from './models/index.js';
|
||||
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
|
||||
/**
|
||||
* Package for customer-satisfaction.gblib.
|
||||
*/
|
||||
export class GBCustomerSatisfactionPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
public async getDialogs (min: GBMinInstance) {
|
||||
GBLog.verbose(`getDialogs called.`);
|
||||
}
|
||||
public async unloadPackage (core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async unloadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLog.verbose(`onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
|
||||
GBLog.verbose(`onExchangeData called.`);
|
||||
}
|
||||
|
||||
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
core.sequelize.addModels([GuaribasQuestionAlternate]);
|
||||
}
|
||||
public async loadBot (min: GBMinInstance): Promise<void> {
|
||||
FeedbackDialog.setup(min.bot, min);
|
||||
QualityDialog.setup(min.bot, min);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { AutoIncrement, BelongsTo, Column, DataType, ForeignKey, Model, PrimaryKey, Table } from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasInstance } from '../../core.gbapp/models/GBModel.js';
|
||||
|
||||
/**
|
||||
* List of saved alternate questions.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasQuestionAlternate extends Model<GuaribasQuestionAlternate> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column(DataType.INTEGER)
|
||||
quickAnswerId: number;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
questionTyped: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
questionText: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance;
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
import { FindOptions, NonNullFindOptions } from 'sequelize/types';
|
||||
import { GuaribasQuestion } from '../../../packages/kb.gbapp/models/index.js';
|
||||
import { GuaribasConversation } from '../../analytics.gblib/models/index.js';
|
||||
import { GuaribasQuestionAlternate } from '../models/index.js';
|
||||
|
||||
/**
|
||||
* Customer Satisfaction Service Layer.
|
||||
*/
|
||||
export class CSService {
|
||||
public async getQuestionFromAlternateText (instanceId: number, text: string): Promise<GuaribasQuestion> {
|
||||
const questionAlternate = await GuaribasQuestionAlternate.findOne({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
questionTyped: text
|
||||
}
|
||||
});
|
||||
|
||||
let question: GuaribasQuestion = null;
|
||||
|
||||
if (questionAlternate !== null) {
|
||||
question = await GuaribasQuestion.findOne({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
questionId: questionAlternate.questionTyped
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return question;
|
||||
}
|
||||
|
||||
public async insertQuestionAlternate (
|
||||
instanceId: number,
|
||||
questionTyped: string,
|
||||
questionText: string
|
||||
): Promise<GuaribasQuestionAlternate> {
|
||||
return await GuaribasQuestionAlternate.create(<GuaribasQuestionAlternate>{
|
||||
questionTyped: questionTyped,
|
||||
questionText: questionText
|
||||
});
|
||||
}
|
||||
|
||||
public async updateConversationRate (
|
||||
conversation: GuaribasConversation,
|
||||
rate: number
|
||||
): Promise<GuaribasConversation> {
|
||||
conversation.rate = rate;
|
||||
|
||||
return conversation.save();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
export const Messages = {
|
||||
'en-US': {
|
||||
about_suggestions: 'Suggestions are welcomed and improve my quality...',
|
||||
what_about_service: 'What about my service?',
|
||||
glad_you_liked: "I'm glad you liked. I'm here for you.",
|
||||
we_will_improve: "Let's take note of that, thanks for sharing.",
|
||||
what_about_me: 'What about the service, please rate between 1 and 5.',
|
||||
thanks: 'Thanks!',
|
||||
im_sorry_lets_try: "I'm sorry. Let's try again...",
|
||||
great_thanks: 'Great, thanks for sharing your thoughts.',
|
||||
please_no_bad_words: 'Please, no bad words.',
|
||||
please_wait_transfering: 'Please, wait while I find an agent to answer you.',
|
||||
notify_agent: name =>
|
||||
`New call available for *${name}*, you can answer right here when you are finished, type /qt.`,
|
||||
notify_end_transfer: botName => `All messages will be now routed to user ${botName}.`,
|
||||
notify_agent_transfer_done: person => `Now talking directly to ${person}.`,
|
||||
check_whatsapp_ok: 'If you are seeing this message, WhatsApp API is OK.'
|
||||
},
|
||||
'pt-BR': {
|
||||
about_suggestions: 'Sugestões melhoram muito minha qualidade...',
|
||||
what_about_service: 'O que achou do meu atendimento?',
|
||||
glad_you_liked: 'Bom saber que você gostou. Conte comigo.',
|
||||
we_will_improve: 'Vamos registrar sua questão, obrigado pela sinceridade.',
|
||||
what_about_me: 'O que achou do meu atendimento, de 1 a 5?',
|
||||
thanks: 'Obrigado!',
|
||||
im_sorry_lets_try: 'Desculpe-me, vamos tentar novamente.',
|
||||
great_thanks: 'Ótimo, obrigado por contribuir com sua resposta.',
|
||||
please_no_bad_words: 'Por favor, sem palavrões!',
|
||||
please_wait_transfering: 'Por favor, aguarde enquanto eu localizo alguém para te atender.',
|
||||
notify_agent: name =>
|
||||
`Existe um novo atendimento para *${name}*, por favor, responda aqui mesmo para a pessoa. Para finalizar, digite /qt.`,
|
||||
notify_end_transfer: botName => `Falando novamente com o bot ${botName}.`,
|
||||
notify_agent_transfer_done: person => `Todas as mensagens agora sendo transmitidas para ${person}.`,
|
||||
check_whatsapp_ok: 'Se você está recebendo esta mensagem, significa que a API do WhatsApp está OK.'
|
||||
}
|
||||
};
|
||||
|
|
@ -1 +0,0 @@
|
|||
https://github.com/microsoft/BotFramework-WebChat/issues/5552 2025.09
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"name": "default.gbui",
|
||||
"version": "3.0.0",
|
||||
"private": false,
|
||||
"repository": "https://github.com/GeneralBots/BotServer",
|
||||
"description": "Default web interface for General Bots open-core",
|
||||
"license": "AGPL-3.0",
|
||||
"homepage": ".",
|
||||
"dependencies": {
|
||||
"@midudev/react-static-content": "1.0.4",
|
||||
"ajv": "8.17.1",
|
||||
"botframework-directlinejs": "0.15.5",
|
||||
"botframework-webchat": "4.18.0",
|
||||
"deep-extend": "0.6.0",
|
||||
"eslint": "9.10.0",
|
||||
"fetch": "1.1.0",
|
||||
"msal": "^1.4.18",
|
||||
"powerbi-client": "2.23.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-helmet": "6.1.0",
|
||||
"react-player": "2.16.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-super-seo": "1.1.9",
|
||||
"react-transition-group": "4.4.5",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rxjs": "7.8.1",
|
||||
"sourcemap-codec": "^1.4.8",
|
||||
"url-join": "5.0.0",
|
||||
"webpack": "5.94.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
],
|
||||
"overrides": {
|
||||
"postcss": "8.4.31",
|
||||
"webpack-dev-server": "5.2.2",
|
||||
"inflight": "lru-cache",
|
||||
"stable": "0.1.8",
|
||||
"rimraf": "5.0.0",
|
||||
"domexception": "4.0.0",
|
||||
"q": "2.0.0",
|
||||
"uuid": "10.0.0",
|
||||
"workbox-cacheable-response": "7.0.0",
|
||||
"workbox-background-sync": "7.0.0",
|
||||
"workbox-google-analytics": "7.0.0",
|
||||
"svgo": "3.0.0",
|
||||
"core-js": "3.38.0",
|
||||
"glob": "10.0.0"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 3 KiB |
|
|
@ -1,58 +0,0 @@
|
|||
<!--
|
||||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html style="width: 100%; height: 100%" class="{themeColor}">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="/themes/{theme}/css/colors.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/themes/{theme}/css/default.css" />
|
||||
|
||||
<title>{title} | General Bots</title>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
setTimeout(() => {
|
||||
const input = document.querySelector('.webchat__send-box-text-box__input');
|
||||
if (input) {
|
||||
input.focus();
|
||||
}
|
||||
}, 3000); // Adjust timing as needed
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body style="background-color: black">
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,386 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import GBMarkdownPlayer from './players/GBMarkdownPlayer.js';
|
||||
import GBImagePlayer from './players/GBImagePlayer.js';
|
||||
import GBVideoPlayer from './players/GBVideoPlayer.js';
|
||||
import GBUrlPlayer from './players/GBUrlPlayer.js';
|
||||
import GBMultiUrlPlayer from './players/GBMultiUrlPlayer.js';
|
||||
import GBLoginPlayer from './players/GBLoginPlayer.js';
|
||||
import GBBulletPlayer from './players/GBBulletPlayer.js';
|
||||
import SidebarMenu from './components/SidebarMenu.js';
|
||||
import SEO from './components/SEO.js';
|
||||
import GBCss from './components/GBCss.js';
|
||||
import { DirectLine } from 'botframework-directlinejs';
|
||||
import { ConnectionStatus } from 'botframework-directlinejs';
|
||||
import ReactWebChat from 'botframework-webchat';
|
||||
import { UserAgentApplication } from 'msal';
|
||||
import StaticContent from '@midudev/react-static-content';
|
||||
|
||||
class GBUIApp extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
line: null,
|
||||
token: null,
|
||||
instanceClient: null
|
||||
};
|
||||
window.user = this.getUser();
|
||||
}
|
||||
|
||||
generateRandomId(length) {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
const array = new Uint32Array(length);
|
||||
window.crypto.getRandomValues(array);
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(array[i] % characters.length);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
sendToken(token) {
|
||||
setTimeout(() => {
|
||||
window.line
|
||||
.postActivity({
|
||||
type: 'event',
|
||||
name: 'updateToken',
|
||||
data: token,
|
||||
locale: 'en-us',
|
||||
textFormat: 'plain',
|
||||
timestamp: new Date().toISOString(),
|
||||
from: this.getUser()
|
||||
})
|
||||
.subscribe(() => {
|
||||
window.userAgentApplication.logout();
|
||||
});
|
||||
}, 400);
|
||||
}
|
||||
|
||||
send(command) {
|
||||
window.line.postActivity({
|
||||
type: 'event',
|
||||
name: command,
|
||||
locale: 'en-us',
|
||||
textFormat: 'plain',
|
||||
timestamp: new Date().toISOString(),
|
||||
from: this.getUser()
|
||||
});
|
||||
}
|
||||
|
||||
getUser() {
|
||||
return { id: window.userId, name: 'You' };
|
||||
}
|
||||
|
||||
postMessage(value) {
|
||||
window.line.postActivity({
|
||||
type: 'message',
|
||||
text: value,
|
||||
from: this.getUser()
|
||||
});
|
||||
}
|
||||
|
||||
configureChat() {
|
||||
var botId = window.location.href.split('/')[3];
|
||||
if (botId.indexOf('#') !== -1) {
|
||||
botId = botId.split('#')[0];
|
||||
}
|
||||
|
||||
if (!botId || botId === '') {
|
||||
botId = '[default]';
|
||||
}
|
||||
|
||||
fetch('/instances/' + botId)
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
this.setupBotConnection(result);
|
||||
},
|
||||
error => {
|
||||
this.setState({
|
||||
isLoaded: false,
|
||||
err: error
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
authenticate() {
|
||||
if (this.state.instanceClient.authenticatorClientId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let _this_ = this;
|
||||
let authority = 'https://login.microsoftonline.com/' + this.state.instanceClient.authenticatorTenant;
|
||||
|
||||
let graphScopes = ['Directory.AccessAsUser.All'];
|
||||
|
||||
let userAgentApplication = new UserAgentApplication(
|
||||
this.state.instanceClient.authenticatorClientId,
|
||||
authority,
|
||||
function (errorDesc, token, error) {
|
||||
if (error) {
|
||||
_this_.sendToken(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
window.userAgentApplication = userAgentApplication;
|
||||
|
||||
if (
|
||||
!userAgentApplication.isCallback(window.location.hash) &&
|
||||
window.parent === window &&
|
||||
!window.opener &&
|
||||
userAgentApplication.getUser
|
||||
) {
|
||||
var user = userAgentApplication.getUser();
|
||||
if (user) {
|
||||
userAgentApplication.acquireTokenSilent(graphScopes).then(
|
||||
function (accessToken) {
|
||||
_this_.sendToken(accessToken);
|
||||
},
|
||||
function (error) {
|
||||
_this_.sendToken(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupBotConnection(instanceClient) {
|
||||
let _this_ = this;
|
||||
window['botchatDebug'] = true;
|
||||
window.userId = this.generateRandomId(16);
|
||||
|
||||
_this_.setState({ token: instanceClient.webchatToken });
|
||||
|
||||
const line = instanceClient.webchatToken
|
||||
? new DirectLine({
|
||||
userId:window.userId,
|
||||
userIdOnStartConversation: window.userId,
|
||||
token: instanceClient.webchatToken
|
||||
})
|
||||
: new DirectLine({
|
||||
domain: instanceClient.domain,
|
||||
userId:window.userId,
|
||||
userIdOnStartConversation: window.userId,
|
||||
secret: null,
|
||||
token: null,
|
||||
webSocket: false // defaults to true
|
||||
});
|
||||
line.setUserId(window.userId);
|
||||
|
||||
_this_.setState({ line: line });
|
||||
|
||||
line.connectionStatus$.subscribe(connectionStatus => {
|
||||
if (connectionStatus === ConnectionStatus.Online) {
|
||||
_this_.setState({ instanceClient: instanceClient });
|
||||
window['botConnection'] = line;
|
||||
}
|
||||
});
|
||||
|
||||
window.line = line;
|
||||
|
||||
line.activity$
|
||||
.filter(activity => activity.type === 'event' && activity.name === 'loadInstance')
|
||||
.subscribe(() => {
|
||||
_this_.send('startGB');
|
||||
_this_.authenticate();
|
||||
});
|
||||
|
||||
line.activity$
|
||||
.filter(activity => activity.type === 'event' && activity.name === 'stop')
|
||||
.subscribe(() => {
|
||||
if (_this_.player) {
|
||||
_this_.player.stop();
|
||||
}
|
||||
});
|
||||
|
||||
line.activity$
|
||||
.filter(activity => activity.type === 'event' && activity.name === 'play')
|
||||
.subscribe(activity => {
|
||||
_this_.setState({ playerType: activity.value.playerType });
|
||||
_this_.player.play(activity.value.data);
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.configureChat();
|
||||
}
|
||||
|
||||
webSpeechPonyfillFactory = 0;
|
||||
render() {
|
||||
let playerComponent = '';
|
||||
|
||||
if (this.state.playerType) {
|
||||
switch (this.state.playerType) {
|
||||
case 'markdown':
|
||||
playerComponent = (
|
||||
<GBMarkdownPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'bullet':
|
||||
playerComponent = (
|
||||
<GBBulletPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'video':
|
||||
playerComponent = (
|
||||
<GBVideoPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'url':
|
||||
playerComponent = (
|
||||
<GBUrlPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'multiurl':
|
||||
playerComponent = (
|
||||
<GBMultiUrlPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'image':
|
||||
playerComponent = (
|
||||
<GBImagePlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
/* case 'pbi':
|
||||
playerComponent = (
|
||||
<GBPowerBIPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break; */
|
||||
case 'login':
|
||||
playerComponent = (
|
||||
<GBLoginPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
playerComponent = <div>GBERROR: Unknow player type specified on message from server.</div>;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let chat = <div />;
|
||||
let gbCss = <div />;
|
||||
let seo = <div />;
|
||||
let sideBar = <div />;
|
||||
|
||||
if (this.state.line) {
|
||||
|
||||
chat = (
|
||||
<ReactWebChat
|
||||
ref={chat => {
|
||||
this.chat = chat;
|
||||
}}
|
||||
userID= {window.userId}
|
||||
locale={'en-us'}
|
||||
directLine={this.state.line}
|
||||
/>
|
||||
);
|
||||
|
||||
if (this.state.instanceClient) {
|
||||
|
||||
gbCss = <GBCss instance={this.state.instanceClient} />;
|
||||
seo = <SEO instance={this.state.instanceClient} />;
|
||||
|
||||
|
||||
document.body.style.setProperty('background-color', this.state.instanceClient.color2, 'important');
|
||||
|
||||
|
||||
sideBar = (
|
||||
<div
|
||||
className="sidebar"
|
||||
ref={node => {
|
||||
if (node) {
|
||||
node.style.setProperty('background-color', this.state.instanceClient.color1, 'important');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SidebarMenu chat={this.chat} instance={this.state.instanceClient} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<StaticContent>
|
||||
{seo}
|
||||
<div>
|
||||
{gbCss}
|
||||
{sideBar}
|
||||
<div className="player">{playerComponent}</div>
|
||||
<div className="webchat">{chat}</div>
|
||||
</div>
|
||||
</StaticContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default GBUIApp;
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.com.br. |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
import React from "react";
|
||||
import { Chat } from "botframework-webchat";
|
||||
|
||||
class ChatPane extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Chat
|
||||
ref={(chat) => { this.chat = chat; }}
|
||||
botConnection={this.props.botConnection}
|
||||
user={{ id: "webUser@gb", name: "You" }}
|
||||
bot={{ id: "bot@gb", name: "Bot" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ChatPane;
|
||||