Compare commits

..

No commits in common. "main" and "2.0.153" have entirely different histories.

333 changed files with 45758 additions and 738558 deletions

2
.deployment Normal file
View file

@ -0,0 +1,2 @@
[config]
command = deploy.cmd

View file

@ -1,46 +0,0 @@
name: GBCI
run: git config --global http.sslVerify false
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: gbo
steps:
- name: Disable SSL verification (temporary)
run: git config --global http.sslVerify false
- uses: actions/checkout@v4
# - name: Setup Node.js
# uses: actions/setup-node@v4
# with:
# node-version: '20'
# cache: 'npm'
- name: Copy files to deployment location
run: |
echo "[General Bots Deployer] Copying files to deploy location..."
sudo rm -rf /opt/gbo/bin/bot/botserver/dist
sudo cp -r ./* /opt/gbo/bin/bot/botserver
- name: Building BotServer
run: |
echo "[General Bots Deployer] Building BotServer..."
# rm -rf /opt/gbo/bin/bot/botserver/node_modules
cd /opt/gbo/bin/bot/botserver
sudo npm ci --production
npm run build-server
npm run build-gbui
- name: Restart Bots Deployer
run: |
echo "[General Bots Deployer] Restarting..."
lxc restart pragmatismo-bot

9
.github/ISSUE_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,9 @@
<!-- File a GitHub issue only for bugs or feature requests related to the code **in this repository**. For other topics you can get more information in the README file. -->
### Observed Results:
<!-- This could be a description, error output, steps to reproduce, a feature missed, etc. -->
### Expected behavior:
<!-- What did you expect to happen? -->

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

7
.github/ISSUE_TEMPLATE/custom.md vendored Normal file
View file

@ -0,0 +1,7 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
---

View file

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

2
.github/ISSUE_TEMPLATE/requirement vendored Normal file
View file

@ -0,0 +1,2 @@
**Description**
A clear and concise description of what the requirement is.

16
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,16 @@
### Changes description
<!-- Describe results, user mentions, screenshots, screencast (gif) -->
### Checklist
Please check if your PR fulfills the following specifications:
- [ ] Tests for the changes have been added
- [ ] Docs have been added/updated
### References
<!-- issues related (for reference or to be closed) and/or links of discuss -->
Closes #N/A

3
.github/invite-contributors.yml vendored Normal file
View file

@ -0,0 +1,3 @@
isOutside: true
# Team Name
team: contributors

44
.github/settings.yml vendored Normal file
View file

@ -0,0 +1,44 @@
repository:
name: botserver
description: botserver
homepage: http://pragmatismo.io/general-bots
topics: node-module
private: false
has_issues: true
has_wiki: false
has_downloads: true
default_branch: develop
allow_squash_merge: true
allow_merge_commit: false
allow_rebase_merge: true
labels:
- name: bug
color: f44336
- name: build
color: 795548
- name: ci
color: fbca04
- name: documentation
color: 607d8b
- name: duplicate
color: 9e9e9e
- name: feature
color: 3f51b5
- name: invalid
color: cddc39
- name: performance
color: 009688
- name: question
color: ff5722
- name: refactor
color: 9c27b0
- name: style
color: 2196f3
- name: test
color: 8bc34a
- name: wontfix
color: ffffff
- name: help wanted
color: 33aa3f
- name: good first issue
color: 7057ff

14
.gitignore vendored
View file

@ -11,8 +11,6 @@
/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
@ -20,15 +18,3 @@
.env
*.env
.vscode/launch.json
.wwebjs_auth
GB.log
gb.log
GB.log.json
yarn-error.log
yarn-lock.json
logo.svg
screenshot.png
data.db
.wwebjs_cache
*doula*
*botpoc*

View file

@ -1,9 +0,0 @@
{
"extends": [
"development"
],
"hints": {
"typescript-config/strict": "off",
"typescript-config/consistent-casing": "off"
}
}

View file

@ -5,4 +5,4 @@
"arrowParens": "avoid",
"semi": true,
"singleQuote": true
}
}

View file

@ -1,47 +0,0 @@
import { expect, test } from 'vitest';
import { GBServer } from './src/app';
import { RootData } from './src/RootData';
import { GBMinInstance } from 'botlib';
import { Mutex } from 'async-mutex';
export default function init() {
const min = {
packages: null,
appPackages: null,
botId: 'gbtest',
instance: {botId: 'gbtest'},
core: {},
conversationalService: {},
kbService: {},
adminService: {},
deployService: {},
textServices: {},
bot: {},
dialogs: {},
userState: {},
userProfile: {},
whatsAppDirectLine: {},
cbMap: {},
scriptMap: {},
sandBoxMap: {},
gbappServices: {}
}
GBServer.globals = new RootData();
GBServer.globals.server = null;
GBServer.globals.httpsServer = null;
GBServer.globals.webSessions = {};
GBServer.globals.processes = [0, { pid: 1, proc: {step: {}}}];
GBServer.globals.files = {};
GBServer.globals.appPackages = [];
GBServer.globals.sysPackages = [];
GBServer.globals.minInstances = [min];
GBServer.globals.minBoot = min;
GBServer.globals.wwwroot = null;
GBServer.globals.entryPointDialog = null;
GBServer.globals.debuggers = [];
GBServer.globals.indexSemaphore = new Mutex();
GBServer.globals.users = {1: {userId: 1}};
}

31
.travis.yml Normal file
View file

@ -0,0 +1,31 @@
language: node_js
node_js:
- lts/*
notifications:
email: false
before_script:
- npm run build
branches:
only:
- master
- /^greenkeeper/.*$/
except:
- /^v\d+\.\d+\.\d+$/
after_success:
- npm run travis-deploy-once "npm run semantic-release"
- npm pack
deploy:
- provider: pages
skip_cleanup: true
local_dir: docs/reference
github_token: $GITHUB_TOKEN
on:
tags: false
branch: master

26
.vscode/launch.json.template vendored Normal file
View file

@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"sourceMaps": true,
"name": "Debug Program",
"program": "${workspaceRoot}/boot.js",
"cwd": "${workspaceRoot}",
"env": {
"NODE_ENV": "development"
},
"args": [
"--no-deprecation"
],
"skipFiles": [
"node_modules/**/*.js"
],
"outFiles": [
"${workspaceRoot}/dist/**/*.js"],
"stopOnEntry": false,
"console": "integratedTerminal"
}
]
}

3
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}

30
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,30 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "typescript",
"tsconfig": "tsconfig.json",
"option": "watch",
"problemMatcher": [
"$tsc-watch"
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "typescript",
"tsconfig": "tsconfig.json",
"problemMatcher": [
"$tsc"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View file

@ -1,836 +1,3 @@
## [2.4.42](https://github.com/GeneralBots/BotServer/compare/2.4.41...2.4.42) (2023-08-01)
### Bug Fixes
* **whatsapp.gblib:** Now using e-mail instead of Teams ID. ([5860000](https://github.com/GeneralBots/BotServer/commit/58600001c9b7c229ff1ccf3c66ed935a8eaf1986))
## [2.4.41](https://github.com/GeneralBots/BotServer/compare/2.4.40...2.4.41) (2023-08-01)
### Bug Fixes
* **all:** Minor changes in PROD. ([76c1efd](https://github.com/GeneralBots/BotServer/commit/76c1efd12d525381d77d12200d397afb644ce3ac))
## [2.4.40](https://github.com/GeneralBots/BotServer/compare/2.4.39...2.4.40) (2023-07-31)
### Bug Fixes
* **all:** Minor changes in PROD. ([9b88c33](https://github.com/GeneralBots/BotServer/commit/9b88c330c60e9646d72e1215f14d0c8ba3462cd2))
## [2.4.39](https://github.com/GeneralBots/BotServer/compare/2.4.38...2.4.39) (2023-07-31)
### Bug Fixes
* **all:** Minor changes in PROD. ([e5f41bc](https://github.com/GeneralBots/BotServer/commit/e5f41bca786f1637d1c3d35d5542b062c2372a44))
## [2.4.38](https://github.com/GeneralBots/BotServer/compare/2.4.37...2.4.38) (2023-07-29)
### Bug Fixes
* **all:** Minor changes in PROD. ([245e491](https://github.com/GeneralBots/BotServer/commit/245e491a25ebc94565854e5a02e2cd1d3ca95836))
## [2.4.37](https://github.com/GeneralBots/BotServer/compare/2.4.36...2.4.37) (2023-07-28)
### Bug Fixes
* **all:** Minor changes in PROD. ([e829f37](https://github.com/GeneralBots/BotServer/commit/e829f3725a69efc7e4a041f4f9e94936baf61649))
## [2.4.36](https://github.com/GeneralBots/BotServer/compare/2.4.35...2.4.36) (2023-07-28)
### Bug Fixes
* **all:** Minor changes in PROD. ([e415bb0](https://github.com/GeneralBots/BotServer/commit/e415bb01ca3d1e79b18b2e978a12b38cd541d01b))
## [2.4.35](https://github.com/GeneralBots/BotServer/compare/2.4.34...2.4.35) (2023-07-28)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([a585cf5](https://github.com/GeneralBots/BotServer/commit/a585cf51eaded13dcd5cddb3120a7f1e77ae6e25))
## [2.4.34](https://github.com/GeneralBots/BotServer/compare/2.4.33...2.4.34) (2023-07-26)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([5589095](https://github.com/GeneralBots/BotServer/commit/5589095f861bba6b5b19b70d5f4ca35247255c52))
## [2.4.33](https://github.com/GeneralBots/BotServer/compare/2.4.32...2.4.33) (2023-07-26)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([e5f5121](https://github.com/GeneralBots/BotServer/commit/e5f51210379c16427e784dbf829f175053cca3f8))
## [2.4.32](https://github.com/GeneralBots/BotServer/compare/2.4.31...2.4.32) (2023-07-26)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([ed96440](https://github.com/GeneralBots/BotServer/commit/ed9644089e481834b309f63bfe227ec5e5b0d854))
## [2.4.31](https://github.com/GeneralBots/BotServer/compare/2.4.30...2.4.31) (2023-07-26)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([0fe2bdb](https://github.com/GeneralBots/BotServer/commit/0fe2bdbe6fa3cc30355acbadab38747e800e050b))
## [2.4.30](https://github.com/GeneralBots/BotServer/compare/2.4.29...2.4.30) (2023-07-26)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([a652873](https://github.com/GeneralBots/BotServer/commit/a65287338a765b0293cb24af5335fe32bcafbecc))
## [2.4.29](https://github.com/GeneralBots/BotServer/compare/2.4.28...2.4.29) (2023-07-26)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([7a6d14c](https://github.com/GeneralBots/BotServer/commit/7a6d14cf3aa28aadea4a0e1d1905f96046a45cc0))
## [2.4.28](https://github.com/GeneralBots/BotServer/compare/2.4.27...2.4.28) (2023-07-26)
### Bug Fixes
* **core.gbapp:** FIX SSR errors and setOption impersonated. ([e596f31](https://github.com/GeneralBots/BotServer/commit/e596f31de64c477a913416ede1488da2cf0688e2))
## [2.4.27](https://github.com/GeneralBots/BotServer/compare/2.4.26...2.4.27) (2023-07-25)
### Bug Fixes
* **all:** Fix answers with dialog id working again. ([f34c7b1](https://github.com/GeneralBots/BotServer/commit/f34c7b1ac5227f27d2fae3b55810e38c493d52e6))
* **all:** Fix answers with dialog id working again. ([a24648c](https://github.com/GeneralBots/BotServer/commit/a24648cc9f7c3ad3ab740096f60b4581b595936b))
* **all:** Fix answers with dialog id working again. ([6b832c4](https://github.com/GeneralBots/BotServer/commit/6b832c42b6442178b68954cb6241b1b79dcf3285))
## [2.4.26](https://github.com/GeneralBots/BotServer/compare/2.4.25...2.4.26) (2023-07-25)
### Bug Fixes
* **all:** Fix answers with dialog id working again. ([2a6f64f](https://github.com/GeneralBots/BotServer/commit/2a6f64f238b6f7088c4a925e0dcd68b705c0e3e8))
* **all:** Fix answers with dialog id working again. ([ec172b0](https://github.com/GeneralBots/BotServer/commit/ec172b0554bd28ff447c5f8436bb81a9a20ad703))
## [2.4.25](https://github.com/GeneralBots/BotServer/compare/2.4.24...2.4.25) (2023-07-23)
### Bug Fixes
* **all:** Fix in AS IMAGE generation of single row. ([a9256d8](https://github.com/GeneralBots/BotServer/commit/a9256d8ecb2a82c47ccb2765cc2ea66b4a83d30c))
* **all:** Fix in AS IMAGE generation of single row. ([576e73b](https://github.com/GeneralBots/BotServer/commit/576e73b6258b313962136823b8753f2d10f3a30e))
* **all:** Fix in AS IMAGE generation of single row. ([4c5ccb2](https://github.com/GeneralBots/BotServer/commit/4c5ccb2fac5d25b95fe4fb1aca08a39d647ecb23))
## [2.4.24](https://github.com/GeneralBots/BotServer/compare/2.4.23...2.4.24) (2023-07-23)
### Bug Fixes
* **all:** Fix in AS IMAGE generation of single row. ([c646b2d](https://github.com/GeneralBots/BotServer/commit/c646b2d27bfaec15ffe65efe081362bc23125a27))
* **all:** Fix in AS IMAGE generation of single row. ([5827286](https://github.com/GeneralBots/BotServer/commit/5827286406fd1bdeb93ee2fe62ca8bc59e9ecec9))
## [2.4.23](https://github.com/GeneralBots/BotServer/compare/2.4.22...2.4.23) (2023-07-23)
### Bug Fixes
* **all:** Fix in AS IMAGE generation of single row. ([618ff5a](https://github.com/GeneralBots/BotServer/commit/618ff5a296f476f341a8e7ff82444406fa4eebc9))
## [2.4.22](https://github.com/GeneralBots/BotServer/compare/2.4.21...2.4.22) (2023-07-23)
### Bug Fixes
* **all:** Fix in AS IMAGE generation of single row. ([ee56768](https://github.com/GeneralBots/BotServer/commit/ee567681f122d94760270b904fb9782a0f13741b))
## [2.4.21](https://github.com/GeneralBots/BotServer/compare/2.4.20...2.4.21) (2023-07-23)
### Bug Fixes
* **all:** Fix in AS IMAGE generation of single row. ([6874869](https://github.com/GeneralBots/BotServer/commit/6874869ef8ce404b1bbef2980e5aef7efbf4a71a))
## [2.4.20](https://github.com/GeneralBots/BotServer/compare/2.4.19...2.4.20) (2023-07-23)
### Bug Fixes
* **all:** Fix in AS IMAGE generation of single row. ([ee6356d](https://github.com/GeneralBots/BotServer/commit/ee6356d83b256a61aa0a974f5802a727923ab4f8))
## [2.4.19](https://github.com/GeneralBots/BotServer/compare/2.4.18...2.4.19) (2023-07-23)
### Bug Fixes
* **all:** Fix in DATE filter. ([ad47305](https://github.com/GeneralBots/BotServer/commit/ad47305a025d97e0df77f9995ac44451da21f0e1))
## [2.4.18](https://github.com/GeneralBots/BotServer/compare/2.4.17...2.4.18) (2023-07-19)
### Bug Fixes
* **all:** Create bot working again. ([ed74c5b](https://github.com/GeneralBots/BotServer/commit/ed74c5b0039a6ad2a578382a4204824258bdbb54))
* **all:** Create bot working again. ([9852fa8](https://github.com/GeneralBots/BotServer/commit/9852fa8cb2867b9f141b77ee44c3e7bdbc99d8ec))
## [2.4.17](https://github.com/GeneralBots/BotServer/compare/2.4.16...2.4.17) (2023-07-19)
### Bug Fixes
* **all:** Create bot working again. ([b779f29](https://github.com/GeneralBots/BotServer/commit/b779f292129f94422075d03fa4e74a8534134832))
## [2.4.16](https://github.com/GeneralBots/BotServer/compare/2.4.15...2.4.16) (2023-07-19)
### Bug Fixes
* **all:** Create bot working again. ([3bbd732](https://github.com/GeneralBots/BotServer/commit/3bbd732fd44d47b90b28402de567d23443a412c9))
* **all:** Create bot working again. ([3fa53d0](https://github.com/GeneralBots/BotServer/commit/3fa53d072b5ce1291128aa486f8465b1a28ff50e))
* **all:** Minor changes in PROD. ([abe5f03](https://github.com/GeneralBots/BotServer/commit/abe5f0380187bc4da498f15a13c8b4ae741bf8ec))
## [2.4.15](https://github.com/GeneralBots/BotServer/compare/2.4.14...2.4.15) (2023-07-19)
### Bug Fixes
* **all:** Create bot working again. ([4eecd5a](https://github.com/GeneralBots/BotServer/commit/4eecd5acec56547e5b5ab064f52dc81eb451e1a4))
## [2.4.14](https://github.com/GeneralBots/BotServer/compare/2.4.13...2.4.14) (2023-07-18)
### Bug Fixes
* **all:** Create bot working again. ([fbc2416](https://github.com/GeneralBots/BotServer/commit/fbc2416a550148b4e9195b59d044ba6f59c0c0e2))
## [2.4.13](https://github.com/GeneralBots/BotServer/compare/2.4.12...2.4.13) (2023-07-18)
### Bug Fixes
* **all:** Create bot working again. ([c4f8d0a](https://github.com/GeneralBots/BotServer/commit/c4f8d0a064343e790c819da43f8f3d7df7551f5c))
## [2.4.12](https://github.com/GeneralBots/BotServer/compare/2.4.11...2.4.12) (2023-07-18)
### Bug Fixes
* **all:** Create bot working again. ([0ed3dce](https://github.com/GeneralBots/BotServer/commit/0ed3dce1d275d61ddb03d914e636cc7ce53407fa))
## [2.4.11](https://github.com/GeneralBots/BotServer/compare/2.4.10...2.4.11) (2023-07-18)
### Bug Fixes
* **all:** Create bot working again. ([3fd3213](https://github.com/GeneralBots/BotServer/commit/3fd3213740e766da510c37461d23877dc34e6cff))
* **all:** Create bot working again. ([88c8a29](https://github.com/GeneralBots/BotServer/commit/88c8a2999867e6c8d707a02c0d194aeda511930d))
* **all:** Create bot working again. ([91db185](https://github.com/GeneralBots/BotServer/commit/91db185b54713cc7dad2835cab6592a8b0e278c1))
## [2.4.10](https://github.com/GeneralBots/BotServer/compare/2.4.9...2.4.10) (2023-07-18)
### Bug Fixes
* **all:** Create bot working again. ([c3e6a3d](https://github.com/GeneralBots/BotServer/commit/c3e6a3da7a2395c68126d38dc24616bdf4353214))
## [2.4.9](https://github.com/GeneralBots/BotServer/compare/2.4.8...2.4.9) (2023-07-17)
### Bug Fixes
* **all:** [#123](https://github.com/GeneralBots/BotServer/issues/123) done. ([899696d](https://github.com/GeneralBots/BotServer/commit/899696d7e59fbb90964852c3838695ed52815040))
## [2.4.8](https://github.com/GeneralBots/BotServer/compare/2.4.7...2.4.8) (2023-07-17)
### Bug Fixes
* **all:** [#123](https://github.com/GeneralBots/BotServer/issues/123) done. ([2d1efeb](https://github.com/GeneralBots/BotServer/commit/2d1efeb0cce3da5ff73116139e64f693eda59ed9))
## [2.4.7](https://github.com/GeneralBots/BotServer/compare/2.4.6...2.4.7) (2023-07-15)
### Bug Fixes
* **all:** Create bot working again. ([46bbe87](https://github.com/GeneralBots/BotServer/commit/46bbe87bb4d5fc3ff83aac664c486f53178f4df2))
## [2.4.6](https://github.com/GeneralBots/BotServer/compare/2.4.5...2.4.6) (2023-07-15)
### Bug Fixes
* **all:** Create bot working again. ([9e49895](https://github.com/GeneralBots/BotServer/commit/9e498956f8b35e379f853f1a5f8a8a59ec712e2c))
## [2.4.5](https://github.com/GeneralBots/BotServer/compare/2.4.4...2.4.5) (2023-07-14)
### Bug Fixes
* **all:** Create bot working again. ([0f1acf6](https://github.com/GeneralBots/BotServer/commit/0f1acf66462861aa709c153435ad5d785ebab951))
* **all:** Create bot working again. ([f4ab703](https://github.com/GeneralBots/BotServer/commit/f4ab70396a6dc67c8cac2f53aa2e0c802dadbe72))
* **all:** Create bot working again. ([b92fbca](https://github.com/GeneralBots/BotServer/commit/b92fbca72ae819d2b7b417231d8b35d23ef7ec34))
## [2.4.4](https://github.com/GeneralBots/BotServer/compare/2.4.3...2.4.4) (2023-07-13)
### Bug Fixes
* **all:** Minor changes in PROD. ([671fe0c](https://github.com/GeneralBots/BotServer/commit/671fe0cc3e8a3a8cbc0f3f8675fe6c9d9d460b84))
## [2.4.3](https://github.com/GeneralBots/BotServer/compare/2.4.2...2.4.3) (2023-07-09)
### Bug Fixes
* **all:** Minor changes in PROD. ([c67ec3e](https://github.com/GeneralBots/BotServer/commit/c67ec3e696eea622e1cf171ce74ae98c52a3ebd1))
## [2.4.2](https://github.com/GeneralBots/BotServer/compare/2.4.1...2.4.2) (2023-07-09)
### Bug Fixes
* **all:** Minor changes in PROD. ([77d5b4e](https://github.com/GeneralBots/BotServer/commit/77d5b4ee68b079c1e84f76e06b888bfaff67d39c))
## [2.4.1](https://github.com/GeneralBots/BotServer/compare/2.4.0...2.4.1) (2023-07-09)
### Bug Fixes
* **all:** Minor changes in PROD. ([8a04ad2](https://github.com/GeneralBots/BotServer/commit/8a04ad2354f7242296ac8d90bfddb52081fef1d8))
# [2.4.0](https://github.com/GeneralBots/BotServer/compare/2.3.9...2.4.0) (2023-07-09)
### Bug Fixes
* **all:** CWD in Windows now working. ([6721c3d](https://github.com/GeneralBots/BotServer/commit/6721c3dcc31d604923f6c3ca0b7100c76f61d14d))
* **all:** Fixes in production. ([56b6877](https://github.com/GeneralBots/BotServer/commit/56b687792b6fa230f67adcd047011cfa536006cc))
* **all:** HTTP handler added. ([7c6a175](https://github.com/GeneralBots/BotServer/commit/7c6a1753b3944b0b1f95c7a7faa1556a60e8d0ad))
* **all:** Minor changes in PROD. ([f69b3f0](https://github.com/GeneralBots/BotServer/commit/f69b3f004cd87844b2339458cfe75bb6aef8662a))
* **all:** Minor changes in PROD. ([0b5fa3e](https://github.com/GeneralBots/BotServer/commit/0b5fa3eec28948ddb47e19b1a84f5fdcb64d0782))
* **all:** Minor changes in PROD. ([904691c](https://github.com/GeneralBots/BotServer/commit/904691ca8149b141855dc1d4098f486472ea473a))
* **all:** Minor changes in PROD. ([d7a5ef5](https://github.com/GeneralBots/BotServer/commit/d7a5ef5ef2cc662a9fab0ab95ddd90995ffc013b))
* **all:** Minor changes in PROD. ([892025e](https://github.com/GeneralBots/BotServer/commit/892025e5b2f7c3d861060f04880dd2fbca23aed6))
* **all:** Minor changes in PROD. ([76df151](https://github.com/GeneralBots/BotServer/commit/76df151507a66352d04de9dfcbf05599614a00cb))
* **all:** Minor changes in PROD. ([f20b5f6](https://github.com/GeneralBots/BotServer/commit/f20b5f6293377c906d1a2277bb7c1fc4197f6f5f))
* **all:** Minor changes in PROD. ([a60581b](https://github.com/GeneralBots/BotServer/commit/a60581bd320bdfa7abac5a7d8c27bc84cfa87cf5))
* **app.ts:** Preparing to use 4 or more SSL certificates. ([72b645f](https://github.com/GeneralBots/BotServer/commit/72b645fd2adbd221a74f9fd87d89c984aea78b8d))
* **azuredeployer.gbapp:** Adding Resource Providers (.Web/.Sql) ([6c9d124](https://github.com/GeneralBots/BotServer/commit/6c9d12452407faa0ad3eb6c0e8e61abd87331020))
* **azuredeployer.gbapp:** Create DB with basic cost. ([0ed600e](https://github.com/GeneralBots/BotServer/commit/0ed600edc3709a6a17ffe2072d22c1ff4b83782a))
* **azuredeployer.gblib:** FREE flag for database. ([1074ef7](https://github.com/GeneralBots/BotServer/commit/1074ef7240879007a2838ec814192b7bf727c0ce))
* **basic.gblib:** [#196](https://github.com/GeneralBots/BotServer/issues/196) Spellchecker in groups now working. ([45ad0c3](https://github.com/GeneralBots/BotServer/commit/45ad0c389495624adae04f9e47f9a75214548ec4))
* **basic.gblib:** [#269](https://github.com/GeneralBots/BotServer/issues/269) Fixing of group autostart behaviour. ([de77227](https://github.com/GeneralBots/BotServer/commit/de772279456591b2a94c206430788ecf8cabb7f3))
* **basic.gblib:** [#286](https://github.com/GeneralBots/BotServer/issues/286) fix token replaacement. ([a679786](https://github.com/GeneralBots/BotServer/commit/a67978621769abab001851609f6a5e3db7c65e3c))
* **basic.gblib:** [#286](https://github.com/GeneralBots/BotServer/issues/286) fix token replaacement. ([0e9c2e9](https://github.com/GeneralBots/BotServer/commit/0e9c2e9ebf9a0a9bf130e3d91268c009c3ad1fc0))
* **basic.gblib:** Debugger improvements. ([3e68858](https://github.com/GeneralBots/BotServer/commit/3e68858bb09d7d5b09a2f7cfbfe6e6c964950fd1))
* **basic.gblib:** Fixes in WebAutomation. ([d4cf165](https://github.com/GeneralBots/BotServer/commit/d4cf165165a82587041776c6e4c8aa7065df1fc1))
* **basic.gblib:** Fixes in WebAutomation. ([b576b6f](https://github.com/GeneralBots/BotServer/commit/b576b6f54deec2dfb779c8c3018af2da001d4196))
* **basic.gblib:** Fixes in WebAutomation. ([d1b9da2](https://github.com/GeneralBots/BotServer/commit/d1b9da21bae4a7c6c1d9fae69e1063d705ae0b38))
* **basic.gblib:** GBAI automatic retrieval. ([0ef0fc0](https://github.com/GeneralBots/BotServer/commit/0ef0fc01f57e9aaa3b4bc3ccf7093b7ad0cf6548))
* **basic.gblib:** GBAI automatic retrieval. ([04e69b9](https://github.com/GeneralBots/BotServer/commit/04e69b9d99f02c285d8082f7a41ee6283ac9e8e1))
* **basic.gblib:** GBAI automatic retrieval. ([6992bf0](https://github.com/GeneralBots/BotServer/commit/6992bf0ae5e83118a05a267c4f55636f8d081dbb))
* **basic.gblib:** [#170](https://github.com/GeneralBots/BotServer/issues/170) Fixing DATEDIFF. ([4314a37](https://github.com/GeneralBots/BotServer/commit/4314a37916ae475a248a2074c89145cecf184a95))
* **basic.gblib:** [#226](https://github.com/GeneralBots/BotServer/issues/226) testing. ([97df425](https://github.com/GeneralBots/BotServer/commit/97df425566f67a836427fdda8c2a9f8011d13c89))
* **basic.gblib:** [#226](https://github.com/GeneralBots/BotServer/issues/226) testing. ([4c037a7](https://github.com/GeneralBots/BotServer/commit/4c037a72053edeeeb81491e23f2a863a05d69ef9))
* **basic.gblib:** [#227](https://github.com/GeneralBots/BotServer/issues/227) - HEAR AS FILE and GET/SET PARAM. ([bc5c1b0](https://github.com/GeneralBots/BotServer/commit/bc5c1b0ced7971109642f86bb3055d81388d9b18))
* **basic.gblib:** [#227](https://github.com/GeneralBots/BotServer/issues/227) - HEAR AS FILE and GET/SET PARAM. ([2521117](https://github.com/GeneralBots/BotServer/commit/2521117a80f84e0d7c509579355b254b39df4823))
* **basic.gblib:** [#227](https://github.com/GeneralBots/BotServer/issues/227) - HEAR AS FILE and GET/SET PARAM. ([ceded7f](https://github.com/GeneralBots/BotServer/commit/ceded7fd5532e0c66758e73d3477d258d7d03017))
* **basic.gblib:** [#227](https://github.com/GeneralBots/BotServer/issues/227) - HEAR AS FILE defining where to save, per bot. ([b64a42f](https://github.com/GeneralBots/BotServer/commit/b64a42feaccf278b463fc1bc1ad106af72531292))
* **basic.gblib:** [#227](https://github.com/GeneralBots/BotServer/issues/227) - HEAR AS FILE defining where to save, per bot. ([473cd98](https://github.com/GeneralBots/BotServer/commit/473cd9871d82238532469ba32726be34027489fc))
* **basic.gblib:** [#227](https://github.com/GeneralBots/BotServer/issues/227) - HEAR AS FILE. ([c5290b9](https://github.com/GeneralBots/BotServer/commit/c5290b91aa1b8f35a82f0a3602c9f2d1cf06bcb0))
* **basic.gblib:** [#227](https://github.com/GeneralBots/BotServer/issues/227) - HEAR AS FILE. ([42dbba4](https://github.com/GeneralBots/BotServer/commit/42dbba40845f5a2232e35218825d5bd058c6f9e1))
* **basic.gblib:** [#282](https://github.com/GeneralBots/BotServer/issues/282) Fix SSR for Bots 3.0. ([866b361](https://github.com/GeneralBots/BotServer/commit/866b361292bd7775ee8f391052721c3fba123823))
* **basic.gblib:** [#282](https://github.com/GeneralBots/BotServer/issues/282) Fix SSR for Bots 3.0. ([7f3bd7d](https://github.com/GeneralBots/BotServer/commit/7f3bd7d8fec2a3e103253f60072873b2d40e91dd))
* **basic.gblib:** [#307](https://github.com/GeneralBots/BotServer/issues/307) - Fixed user context in API. ([cbce44f](https://github.com/GeneralBots/BotServer/commit/cbce44f20d7df70743057381e63229d015da3ad7))
* **basic.gblib:** [#307](https://github.com/GeneralBots/BotServer/issues/307) - Fixed user context in API. ([4496cef](https://github.com/GeneralBots/BotServer/commit/4496cefa18ed7f909f7284aacd90b975d74e2180))
* **basic.gblib:** Adjustment in package version. ([e66c481](https://github.com/GeneralBots/BotServer/commit/e66c4817612c270c637e2323248d947784dabe1f))
* **basic.gblib:** Correct web automation 'date' use. ([4809fec](https://github.com/GeneralBots/BotServer/commit/4809fec457b29af597bc48fa5ba3d05f21cb2abf))
* **basic.gblib:** Correcting the position of Parentheses ([a925c8e](https://github.com/GeneralBots/BotServer/commit/a925c8e8bf8c2bbb166d0ece4343c56d15ceef97))
* **basic.gblib:** FILL keyword can now template images and AS IMAGE can convert a DOCX to a PNG. ([41ceedf](https://github.com/GeneralBots/BotServer/commit/41ceedfc003d142bc8bf085dc9488d61328e6743))
* **basic.gblib:** FILL keyword can now template images and AS IMAGE can convert a DOCX to a PNG. ([16bdab6](https://github.com/GeneralBots/BotServer/commit/16bdab6bcc3cb1f13de549a825ef96aaf889a9d4))
* **basic.gblib:** fix dynamic parameter generation. ([11b0ea2](https://github.com/GeneralBots/BotServer/commit/11b0ea24e696d51990d04651f1f1bfd2a785d4d9))
* **basic.gblib:** Fix getNow return. ([f288987](https://github.com/GeneralBots/BotServer/commit/f2889879a623e585b62fe22d7ee52028876186c1))
* **basic.gblib:** Fix getNow return. ([5631ce9](https://github.com/GeneralBots/BotServer/commit/5631ce961017960f20bb5c9334f254f15e88c7c2))
* **basic.gblib:** Fix getToday return. ([0e33c97](https://github.com/GeneralBots/BotServer/commit/0e33c9785196ceac5cfa2ac6cb6d1c83ab4ef478))
* **basic.gblib:** Return the last information with getTextOf ([ececb0d](https://github.com/GeneralBots/BotServer/commit/ececb0d2ea89a9ed021fc1d2d8dea9688b3bedee))
* **basic.gblib:** Upgrade to https://github.com/vasyas/push-rpc from WS to HTTPS. ([5534b41](https://github.com/GeneralBots/BotServer/commit/5534b416da906be8953ff18ba52807964163760a))
* **basic.gblib:** Upgrade to https://github.com/vasyas/push-rpc from WS to HTTPS. ([f3c756b](https://github.com/GeneralBots/BotServer/commit/f3c756b01576ebbe5266ed9699e6c06ed3c05263))
* **basic.gblib:** Upgrade to https://github.com/vasyas/push-rpc. ([f3b7c1d](https://github.com/GeneralBots/BotServer/commit/f3b7c1d77e72fa9deb173b47777ed2cbf5bae2fc))
* **basic.gblib:** WA page bug removal. ([d902e14](https://github.com/GeneralBots/BotServer/commit/d902e14f78913626d3f8ac758a3b98776d1589b5))
* **core.gbapp:** [#195](https://github.com/GeneralBots/BotServer/issues/195) bind call to provide min context for uploads. ([b12a462](https://github.com/GeneralBots/BotServer/commit/b12a462e3e789e63691dcc80d83002e2fe18ed74))
* **core.gbapp:** [#195](https://github.com/GeneralBots/BotServer/issues/195) bind call to provide min context for uploads. ([b2f2c73](https://github.com/GeneralBots/BotServer/commit/b2f2c732aa1a5887a163fd510539e1d0c5223667))
* **core.gbapp:** [#336](https://github.com/GeneralBots/BotServer/issues/336) timeout in API fixed. ([0c44361](https://github.com/GeneralBots/BotServer/commit/0c443618a6551f35af1a0ea6e9fc5c560815e188))
* **core.gbapp:** [#336](https://github.com/GeneralBots/BotServer/issues/336) timeout in API fixed. ([eb6800e](https://github.com/GeneralBots/BotServer/commit/eb6800edce75bb0687fa446fb515a508a1b053f6))
* **core.gbapp:** [#341](https://github.com/GeneralBots/BotServer/issues/341) fix regarding COPY files. ([a292b77](https://github.com/GeneralBots/BotServer/commit/a292b7711668fa66875bc6eb7d9c6f74943ebabf))
* **core.gbapp:** [#344](https://github.com/GeneralBots/BotServer/issues/344) fix regarding SET FILTER keyword. ([db7ed36](https://github.com/GeneralBots/BotServer/commit/db7ed36707e567fa6801c748d4a28ebca76549c4))
* **core.gbapp:** /logs working again. ([d08e11f](https://github.com/GeneralBots/BotServer/commit/d08e11fef43275d78cbf339508256acd46f2055f))
* **core.gbapp:** fixed the use of GBLogEx to create GuaribasLog. ([2cb866b](https://github.com/GeneralBots/BotServer/commit/2cb866bc2f1f8a5157eddfdecf974e3a31f1280d))
* **core.gbapp:** Upload now saves the file in correct folder. ([e31cd4d](https://github.com/GeneralBots/BotServer/commit/e31cd4d819e5084a7cbbdb76ab5b4f59563ac822))
* **core.gblib:** SSR fixing about botId. ([799715a](https://github.com/GeneralBots/BotServer/commit/799715a9ee77606afcbcaf72a545d0ce473bd5e9))
* **default.gbui:** [#153](https://github.com/GeneralBots/BotServer/issues/153) fix. ([b6f6a50](https://github.com/GeneralBots/BotServer/commit/b6f6a50f136617948add923e0517988f67bfab31))
* **default.gbui:** [#263](https://github.com/GeneralBots/BotServer/issues/263) Loads menu.xlsx as subject.json alternative. ([00434bd](https://github.com/GeneralBots/BotServer/commit/00434bd788fc7ac6a09ed07844120dfb4b871e24))
* **default.gbui:** [#263](https://github.com/GeneralBots/BotServer/issues/263) Loads menu.xlsx as subject.json alternative. ([241596b](https://github.com/GeneralBots/BotServer/commit/241596b51f542b17ceb0b6b465e71a0b86c7f39c))
* **dependencies:** Whatsapp-web.js to "1.20.0". ([1857b51](https://github.com/GeneralBots/BotServer/commit/1857b51cf272120d6b7fbb04ca23cde455be2361))
* **gbapp\AskDialog:** Supress Echo Nothing_else ([4ee3012](https://github.com/GeneralBots/BotServer/commit/4ee30120b79d2bd8dd933accc1d2326a7b16d013))
* **gbapp\AskDialog.ts:** Supress anything_else ([6d8feca](https://github.com/GeneralBots/BotServer/commit/6d8feca8719874179a3a98ba4cbf976c2d3361f7))
* **kb.gbapp:** [#276](https://github.com/GeneralBots/BotServer/issues/276) use of NLP.js upgrade to v4. ([ec1c38f](https://github.com/GeneralBots/BotServer/commit/ec1c38f3783da8a67958c28c815948799f757d1f))
* **kb.gbapp:** [#276](https://github.com/GeneralBots/BotServer/issues/276) use of NLP.js upgrade to v4. ([5c48d39](https://github.com/GeneralBots/BotServer/commit/5c48d396207fae7ca74abc490250d6b7bac310da))
* **kb.gbapp:** [#297](https://github.com/GeneralBots/BotServer/issues/297) Spellchecker fixed after MSFT changes in service. ([80853f0](https://github.com/GeneralBots/BotServer/commit/80853f014c1e3a1c8c0cd1a8cdb1685f98f738b9))
* **kb.gbapp:** [#298](https://github.com/GeneralBots/BotServer/issues/298) search fix and params. ([78778da](https://github.com/GeneralBots/BotServer/commit/78778da3a7ca8e4045ec4367ac03678166c52d18))
* **kb.gbapp:** [#332](https://github.com/GeneralBots/BotServer/issues/332) fix STS. ([01cf280](https://github.com/GeneralBots/BotServer/commit/01cf2803a0f3a68528cb5cfd6750621056d5ad7e))
* **kb.gbapp:** /publish review, error handling improved and clean up. ([c94228c](https://github.com/GeneralBots/BotServer/commit/c94228cd8db9ac4e9a0b5df1f1acdb31b168c768))
* **kb.gbapp:** Dialog now are finished OK. ([a969abb](https://github.com/GeneralBots/BotServer/commit/a969abbcc44ca93fb2fb349e4ca67043f5c43f5f))
* **kb.gbapp:** Dialog now are finished OK. ([a7a1d47](https://github.com/GeneralBots/BotServer/commit/a7a1d47c24b4af4c0b1a62b4b06eaba23386faed))
* **kb.gbapp:** Download only if not in cache optimization. ([b30e016](https://github.com/GeneralBots/BotServer/commit/b30e0160c434ac5fb45425d9a80a45020c7955f5))
* **security.gblib:** Params support in users. ([82a9ba9](https://github.com/GeneralBots/BotServer/commit/82a9ba983ecc603f67a23775385e070b92881ddd))
* **whatsapp.gblib:** [#262](https://github.com/GeneralBots/BotServer/issues/262) wrong key value. ([565ad4a](https://github.com/GeneralBots/BotServer/commit/565ad4ab6d008454a7e008c568a0a78af06fd7e0))
* **whatsapp.gblib:** [#288](https://github.com/GeneralBots/BotServer/issues/288) fix list and buttons. ([6f62453](https://github.com/GeneralBots/BotServer/commit/6f62453f4e1f813e4686bece6419f42b6b73bf18))
* **whatsapp.gblib:** [#288](https://github.com/GeneralBots/BotServer/issues/288) unify puppteer params with GBSSR. ([b96a78e](https://github.com/GeneralBots/BotServer/commit/b96a78e810da07871dc91d6a6a017c21cb1440be))
* **whatsapp.gblib:** [#309](https://github.com/GeneralBots/BotServer/issues/309) unify channel detection. ([cfe3ab3](https://github.com/GeneralBots/BotServer/commit/cfe3ab30f47af4f5c058c1de4c7707140fbc2312))
* **Whatsapp.gblib:** fix "whatsapp-web.js" compatibility issues. ([cd97189](https://github.com/GeneralBots/BotServer/commit/cd97189477c452d44e9584f0152950b2aff23b88))
### Features
* **whatsapp.gblib:** add 'graphapi' option. ([ce84053](https://github.com/GeneralBots/BotServer/commit/ce84053d95b8ff69d0175a1da70ec89921493459))
## [2.3.9](https://github.com/GeneralBots/BotServer/compare/2.3.8...2.3.9) (2023-01-29)
### Bug Fixes
* **basic.gblib:** [#326](https://github.com/GeneralBots/BotServer/issues/326) align JS and BASIC map file. ([b572cc9](https://github.com/GeneralBots/BotServer/commit/b572cc9b8db624f4d686a9cb934cb5bbd8e41cc1))
## [2.3.8](https://github.com/GeneralBots/BotServer/compare/2.3.7...2.3.8) (2023-01-26)
### Bug Fixes
* **basic.gblib:** OPEN keyword fix. Magic number removal. ([e1c389c](https://github.com/GeneralBots/BotServer/commit/e1c389cbd03b1245deb1d2f37a415e371ed67481))
* **basic.gblib:** OPEN keyword fix. Magic number removal. ([fe2af84](https://github.com/GeneralBots/BotServer/commit/fe2af84b21d49e2d87247dd4cb0b078371c3dfa1))
## [2.3.7](https://github.com/GeneralBots/BotServer/compare/2.3.6...2.3.7) (2023-01-25)
### Bug Fixes
* **systemkeywords.ts:** injected security context inside systemkeywords.ts ([8a895d3](https://github.com/GeneralBots/BotServer/commit/8a895d3da1f9a2cfee680f09e79ea999cdf3db8d))
## [2.3.6](https://github.com/GeneralBots/BotServer/compare/2.3.5...2.3.6) (2023-01-25)
### Bug Fixes
* **dialogkeywords.ts:** injected security context inside DialogKeywords ([81953d7](https://github.com/GeneralBots/BotServer/commit/81953d7d9f48407968e2d35e686347f6f6005a0d))
## [2.3.5](https://github.com/GeneralBots/BotServer/compare/2.3.4...2.3.5) (2023-01-19)
### Bug Fixes
* **basic.gblib:** executionid and changed to pid and security context for HEAR([#322](https://github.com/GeneralBots/BotServer/issues/322)). ([9820bb3](https://github.com/GeneralBots/BotServer/commit/9820bb3f7a4905de34eb1d3fa002c8a4b098027c))
## [2.3.4](https://github.com/GeneralBots/BotServer/compare/2.3.3...2.3.4) (2023-01-19)
### Bug Fixes
* **basic.gblib:** executionid and changed to pid and security context for HEAR. ([1063739](https://github.com/GeneralBots/BotServer/commit/1063739cbeab3ebbc1210b1962f6275d619debdd))
## [2.3.3](https://github.com/GeneralBots/BotServer/compare/2.3.2...2.3.3) (2023-01-17)
### Bug Fixes
* **basic.gblib:** Refactoring processInfo into all methods. ([50d3fcc](https://github.com/GeneralBots/BotServer/commit/50d3fccd0dcb593662649d5cc1443017eb11227f))
## [2.3.2](https://github.com/GeneralBots/BotServer/compare/2.3.1...2.3.2) (2023-01-13)
### Bug Fixes
* **systemkeywords.ts:** executionid, and changed to pid ([274db0d](https://github.com/GeneralBots/BotServer/commit/274db0d389f6d145355ca38d9143da4b1b1694fa))
## [2.3.1](https://github.com/GeneralBots/BotServer/compare/2.3.0...2.3.1) (2023-01-13)
### Bug Fixes
* **gbminservice.ts:** swagger-client migration from 2.0 to 3.0 ([552e8b1](https://github.com/GeneralBots/BotServer/commit/552e8b14c41aa01c538e9eda1bb6666adb098b38))
# [2.3.0](https://github.com/GeneralBots/BotServer/compare/2.2.0...2.3.0) (2023-01-10)
### Features
* **systemkeywords.ts:** introducing executionid feature in api ([a65a82d](https://github.com/GeneralBots/BotServer/commit/a65a82dd8a8805a4e90dfb6d7b72a49fcc611419))
# [2.2.0](https://github.com/GeneralBots/BotServer/compare/2.1.5...2.2.0) (2023-01-10)
### Features
* **systemkeywords.ts:** introducing executionid feature in api ([52dea44](https://github.com/GeneralBots/BotServer/commit/52dea442d5fc00cebcc50ca0cb28ee4f8c12c4db))
## [2.1.5](https://github.com/GeneralBots/BotServer/compare/2.1.4...2.1.5) (2023-01-05)
### Bug Fixes
* **gbvmservices.ts:** Update ([c62d372](https://github.com/GeneralBots/BotServer/commit/c62d372ec6fdfd46bd7b1c48f9d3212f58d8c5e6))
## [2.1.4](https://github.com/GeneralBots/BotServer/compare/2.1.3...2.1.4) (2023-01-05)
### Bug Fixes
* **tscompiler.ts:** Update typescript import. ([f4209eb](https://github.com/GeneralBots/BotServer/commit/f4209eb4f0b89905fa463dbfe7354532b58a933e))
## [2.1.3](https://github.com/GeneralBots/BotServer/compare/2.1.2...2.1.3) (2023-01-04)
### Bug Fixes
* **AzureDeployerService:** accessToken ([07d9cf6](https://github.com/GeneralBots/BotServer/commit/07d9cf67dbf96afe1b6811dc80c20c34e43794b7))
* **azuredeployerservice.gbapp:** Update of password generator libs. ([57461ee](https://github.com/GeneralBots/BotServer/commit/57461ee0060e9e4224d674f07e96008419ff57b6))
* **basic.gblib:** Threat multiple spaces as one. ([0721a3f](https://github.com/GeneralBots/BotServer/commit/0721a3fa78776259f7b238d180ee55c823787237))
* **basic.gblib:** Threat multiple spaces as one. ([ac5911e](https://github.com/GeneralBots/BotServer/commit/ac5911ee02cc6e844d7a35788e962b8cef7a037e))
## [2.1.2](https://github.com/GeneralBots/BotServer/compare/2.1.1...2.1.2) (2023-01-02)
### Bug Fixes
* **azuredeployer.gbapp:** createInstance free ([1b41551](https://github.com/GeneralBots/BotServer/commit/1b41551ac553f7340f29a3f17214499084752296))
## [2.1.1](https://github.com/GeneralBots/BotServer/compare/2.1.0...2.1.1) (2023-01-01)
### Bug Fixes
* **admin.gbapp:** Fixing token generation issues. ([8fb35c2](https://github.com/GeneralBots/BotServer/commit/8fb35c2c2d4798b819e38bdf7c12ec5fe59d7f64))
* **admin.gbapp:** Fixing token generation issues. ([2a848f4](https://github.com/GeneralBots/BotServer/commit/2a848f4ea6b7fb3359bd0f9db9a9bdf167544cab))
* **admin.gbapp:** Fixing token generation issues. ([3de3bd6](https://github.com/GeneralBots/BotServer/commit/3de3bd6c01aaa80e38b57cdef63f80bf67fb785d))
* **all:** Finishing renaming to main branch. ([16d2101](https://github.com/GeneralBots/BotServer/commit/16d21019a081151db21e4726cb5c2eac3326336d))
* **all:** Finishing renaming to main branch. ([cac92cc](https://github.com/GeneralBots/BotServer/commit/cac92cca22a03b67326993f42e528900fa55a263))
* **all:** Finishing renaming to main branch. ([bff8bcf](https://github.com/GeneralBots/BotServer/commit/bff8bcf7e5fef6499f180d1a1bc9e57f131d6299))
* **all:** Finishing renaming to main branch. ([07f173e](https://github.com/GeneralBots/BotServer/commit/07f173ec7302a77945abc0bcd772af5ccd6c0761))
* **all:** Fixing bugs of 3.0 ([39eff93](https://github.com/GeneralBots/BotServer/commit/39eff935283883dcbdfcb5a38c599bd3d7153cd5))
* **all:** TODO items removed or moved to ALM. ([7348c54](https://github.com/GeneralBots/BotServer/commit/7348c5489433eb82a44af12b4a8f4e76f01998b4))
* **basic.gblib:** Renaming branch to main. ([c6d9662](https://github.com/GeneralBots/BotServer/commit/c6d96621455039a822f19746a1d8664c79e7ca28))
* **basic.gblib:** Renaming branch to main. ([203416c](https://github.com/GeneralBots/BotServer/commit/203416c47737c1a4cfb5e5110b4878a6534ecdcf))
* **basic.gblib:** TODO removal. ([2b08965](https://github.com/GeneralBots/BotServer/commit/2b0896521e537e22858d9d43b019bc95079af6b5))
* **basic.gblib:** TODO removal. ([c0133a8](https://github.com/GeneralBots/BotServer/commit/c0133a89606336824b93e453b60fce2630815c67))
* **basic.gblib:** TODO removal. ([9ad1d56](https://github.com/GeneralBots/BotServer/commit/9ad1d5693e954e88675c7e0605b6f64f2900f9d7))
# [2.1.0](https://github.com/GeneralBots/BotServer/compare/2.0.182...2.1.0) (2022-12-23)
### Features
* **all:** Cleaning package manager files. ([0cb406a](https://github.com/GeneralBots/BotServer/commit/0cb406ab7923761ad7476ef694d5079af059244c))
* **all:** Token retrieve optimized. ([6eb9d6c](https://github.com/GeneralBots/BotServer/commit/6eb9d6cbf466a18283285d6775e08aa488632762))
## [2.0.182](https://github.com/GeneralBots/BotServer/compare/2.0.181...2.0.182) (2022-12-23)
### Bug Fixes
* **all:** Node version info retrieval automated. ([9cbd8c1](https://github.com/GeneralBots/BotServer/commit/9cbd8c17de674547ed24a189084e8b99588ac69b))
## [2.0.181](https://github.com/GeneralBots/BotServer/compare/2.0.180...2.0.181) (2022-12-22)
### Bug Fixes
* **admin.gbapp:** .gbapp List param added to .gbot. ([48a1aa4](https://github.com/GeneralBots/BotServer/commit/48a1aa4d4695b480b6724f6c59830cfe3fa45f8c))
## [2.0.180](https://github.com/GeneralBots/BotServer/compare/2.0.179...2.0.180) (2022-12-16)
### Bug Fixes
* **all:** CI fixing. ([e4fc246](https://github.com/GeneralBots/BotServer/commit/e4fc246b252aaebd8da25b9fa6c642ad9d8d278d))
* **all:** CI fixing. ([fa32b51](https://github.com/GeneralBots/BotServer/commit/fa32b510d94a94a687a23cb72e74aeca8e122d54))
* **all:** fetch calls replaces request packages. ([ea6c721](https://github.com/GeneralBots/BotServer/commit/ea6c721cb53f1eaa4ab8f4b4a10ecf7329a473d6))
* **all:** Fixing [#294](https://github.com/GeneralBots/BotServer/issues/294). ([25ce766](https://github.com/GeneralBots/BotServer/commit/25ce766820ecd2a98e2fca9e1648ac41fbe76d38))
* **all:** Fixing bugs of 3.0 ([d09265e](https://github.com/GeneralBots/BotServer/commit/d09265e023b8b3ac746ba623cc0613c311f4c49c))
* **all:** Fixing bugs of 3.0 ([6cad39d](https://github.com/GeneralBots/BotServer/commit/6cad39d8c70e9827c41ea4afedefe8fa330c0295))
* **all:** Fixing bugs of 3.0. ([d180753](https://github.com/GeneralBots/BotServer/commit/d180753253a249958340dbdfeef94a1442e58675))
* **all:** Fixing bugs of 3.0. ([83d98c7](https://github.com/GeneralBots/BotServer/commit/83d98c794fe24c420949e355b438aab9f2f46fad))
* **all:** Fixing bugs of 3.0. ([bf705c7](https://github.com/GeneralBots/BotServer/commit/bf705c730b2bf7565e43003d4299513d1819ef38))
* **all:** Fixing CI integration bugs. ([0ce6bc5](https://github.com/GeneralBots/BotServer/commit/0ce6bc5d8c0b68f4079b64bf6b8916bb426a1b52))
* **all:** Fixing CI integration bugs. ([9c44e38](https://github.com/GeneralBots/BotServer/commit/9c44e385605ced77185f9b96c6f2cefb61559465))
* **all:** Fixing CI integration bugs. ([9acb055](https://github.com/GeneralBots/BotServer/commit/9acb05567a6991334c6586db4dad888cfb84b050))
* **all:** Fixing CI integration bugs. ([c323f5a](https://github.com/GeneralBots/BotServer/commit/c323f5a3e875448819b3d61e60c9f5b20d79aabd))
* **all:** Fixing CI integration bugs. ([b2c1dda](https://github.com/GeneralBots/BotServer/commit/b2c1dda2b2635ef808976593ec4df542fa292bb2))
* **all:** Fixing CI integration bugs. ([ae29dda](https://github.com/GeneralBots/BotServer/commit/ae29dda0fa027a9c59c3b6ffe57a2e9752c016ec))
* **all:** Fixing CI integration bugs. ([0ecac1a](https://github.com/GeneralBots/BotServer/commit/0ecac1a4b52c3dbafb1cfb943be1b6f77c1fc058))
* **all:** Fixing CI integration bugs. ([9f88210](https://github.com/GeneralBots/BotServer/commit/9f8821089a1a6f22505539ae95af3b378dfe59ae))
* **all:** Removal of warnings and erros after pkg update. ([663c85e](https://github.com/GeneralBots/BotServer/commit/663c85e7c51ce0e2d3f31e8cbe62fcb4039ca8f6))
* **all:** Update of arm packages and token usage. ([179b20a](https://github.com/GeneralBots/BotServer/commit/179b20a248c245e7b85635c4b3080b34ffa7c02b))
* **core.gbapp:** Lint of all. ([4a2f8b7](https://github.com/GeneralBots/BotServer/commit/4a2f8b7b43cb7550d11965719459d3fb336739ca))
* **core.gbapp:** Update of all packages and nodejs to 19.1.0. ([f8d2cd8](https://github.com/GeneralBots/BotServer/commit/f8d2cd895a31c41b7cdc4f688dd8dcbec6f56317))
* **core.gbapp:** Update of all packages and nodejs to 19.1.0. ([a315d21](https://github.com/GeneralBots/BotServer/commit/a315d21cfe3775de745910764bf60bff76043053))
* **core.gbapp:** Update of properties modifier with declare. ([21df92e](https://github.com/GeneralBots/BotServer/commit/21df92e280186b87c457e226b6f92d80bd0efa34))
* **core.gbapp:** WARNINGS.md ([f35a2ac](https://github.com/GeneralBots/BotServer/commit/f35a2aceba957339c607d22743c02f7690bd3a97))
## [2.0.179](https://github.com/GeneralBots/BotServer/compare/2.0.178...2.0.179) (2022-10-22)
### Bug Fixes
* **whatsapp.gblib:** FIX on HEAR ON after provider change. ([c66f9bf](https://github.com/GeneralBots/BotServer/commit/c66f9bfe041875bd2a528aef8eae884616de2e6b))
* **whatsapp.gblib:** FIX on HEAR ON after provider change. ([1d8e7e1](https://github.com/GeneralBots/BotServer/commit/1d8e7e1763c6fce6e7bad83f6ae036f17f3141f9))
* **whatsapp.gblib:** FIX on HEAR ON after provider change. ([916794f](https://github.com/GeneralBots/BotServer/commit/916794fc154cc16e1dce2dd7d7c523b25699e8d8))
## [2.0.178](https://github.com/GeneralBots/BotServer/compare/2.0.177...2.0.178) (2022-10-09)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE and WPP providers. ([3f7e024](https://github.com/GeneralBots/BotServer/commit/3f7e024b58660d0be0734dc5f3a3cd7884df3727))
## [2.0.177](https://github.com/GeneralBots/BotServer/compare/2.0.176...2.0.177) (2022-10-04)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE and WPP providers. ([c6de0f0](https://github.com/GeneralBots/BotServer/commit/c6de0f0fa1cf626bbe7ec86615b7283fafe2c946))
## [2.0.176](https://github.com/GeneralBots/BotServer/compare/2.0.175...2.0.176) (2022-09-12)
### Bug Fixes
* **basic.gblib:** SCREENSHOT keyword. ([0f1ee22](https://github.com/GeneralBots/BotServer/commit/0f1ee22467577c4237992d5d7bd3af8efd1ca300))
## [2.0.175](https://github.com/GeneralBots/BotServer/compare/2.0.174...2.0.175) (2022-09-04)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE and WPP providers. ([05260c0](https://github.com/GeneralBots/BotServer/commit/05260c0ee5cada86bae5dd30db48e8c65c3ed53e))
* **whatsapp.gblib:** SEND FILE and WPP providers. ([5261691](https://github.com/GeneralBots/BotServer/commit/5261691ba94708a9d75d9155898a13cf55137733))
## [2.0.174](https://github.com/GeneralBots/BotServer/compare/2.0.173...2.0.174) (2022-09-02)
### Bug Fixes
* **whatsapp.gblib:** .gbapp message subprocessing. ([c14a766](https://github.com/GeneralBots/BotServer/commit/c14a766047ec1cad9e52104a52a10afb93b8fd71))
## [2.0.173](https://github.com/GeneralBots/BotServer/compare/2.0.172...2.0.173) (2022-09-01)
### Bug Fixes
* **whatsapp.gblib:** .gbapp message subprocessing. ([e72b030](https://github.com/GeneralBots/BotServer/commit/e72b030e9554c6d442de643f73e9a3f19460973f))
* **whatsapp.gblib:** .gbapp message subprocessing. ([9c00ddd](https://github.com/GeneralBots/BotServer/commit/9c00dddd78eeebe6ef8b156f3cc9a044c7756b1c))
## [2.0.172](https://github.com/GeneralBots/BotServer/compare/2.0.171...2.0.172) (2022-09-01)
### Bug Fixes
* **whatsapp.gblib:** .gbapp message subprocessing. ([aeaaddc](https://github.com/GeneralBots/BotServer/commit/aeaaddc8ab53ae313c3aca687ada2fd5504398c5))
## [2.0.171](https://github.com/GeneralBots/BotServer/compare/2.0.170...2.0.171) (2022-09-01)
### Bug Fixes
* **whatsapp.gblib:** .gbapp message subprocessing. ([a5073e0](https://github.com/GeneralBots/BotServer/commit/a5073e020eba72c3b3057d4e154e9b89b26e0cf0))
## [2.0.170](https://github.com/GeneralBots/BotServer/compare/2.0.169...2.0.170) (2022-08-29)
### Bug Fixes
* **basic.gblib:** Impersonated SET MAX LINES. ([e9211d9](https://github.com/GeneralBots/BotServer/commit/e9211d92ac774bfdda383bb404eb0f1d4794ae6b))
## [2.0.169](https://github.com/GeneralBots/BotServer/compare/2.0.168...2.0.169) (2022-08-28)
### Bug Fixes
* **basic.gblib:** Impersonated SET MAX LINES. ([f058a4a](https://github.com/GeneralBots/BotServer/commit/f058a4a0c6cbdc63a6c1ba3b857ccd4c1f7db8a2))
* **basic.gblib:** Impersonated SET MAX LINES. ([8f373f3](https://github.com/GeneralBots/BotServer/commit/8f373f3691e029e415f280b81aa780a50dfc5b91))
## [2.0.168](https://github.com/GeneralBots/BotServer/compare/2.0.167...2.0.168) (2022-08-28)
### Bug Fixes
* **core.gbapp:** More information on bot creation. ([7e7fb27](https://github.com/GeneralBots/BotServer/commit/7e7fb277d7d530026e1df9df78dfc02f3b43a418))
* **core.gbapp:** More information on bot creation. ([e07152b](https://github.com/GeneralBots/BotServer/commit/e07152bc07beae48cc1217832951923fc6f0bc12))
## [2.0.167](https://github.com/GeneralBots/BotServer/compare/2.0.166...2.0.167) (2022-08-26)
### Bug Fixes
* **kb.gbapp:** Skips blank answers lines. ([004cc8f](https://github.com/GeneralBots/BotServer/commit/004cc8fef586c81de55181689b29a502fd0784a1))
## [2.0.166](https://github.com/GeneralBots/BotServer/compare/2.0.165...2.0.166) (2022-08-26)
### Bug Fixes
* **kb.gbapp:** Skips blank answers lines. ([796a412](https://github.com/GeneralBots/BotServer/commit/796a412e326982cd463863319931621301358079))
## [2.0.165](https://github.com/GeneralBots/BotServer/compare/2.0.164...2.0.165) (2022-08-26)
### Bug Fixes
* **kb.gbapp:** Skips blank answers lines. ([143e425](https://github.com/GeneralBots/BotServer/commit/143e425bfc649478e72ad6d80ccddb7e1c70f56b))
## [2.0.164](https://github.com/GeneralBots/BotServer/compare/2.0.163...2.0.164) (2022-08-26)
### Bug Fixes
* **kb.gbapp:** Skips blank answers lines. ([fa63a3e](https://github.com/GeneralBots/BotServer/commit/fa63a3eb6fc01e903ce42bf70f07ee41fa841ed6))
## [2.0.163](https://github.com/GeneralBots/BotServer/compare/2.0.162...2.0.163) (2022-08-26)
### Bug Fixes
* **kb.gbapp:** Skips blank answers lines. ([46fb424](https://github.com/GeneralBots/BotServer/commit/46fb4244c71c982bebcc9c32ae42ff04405672db))
## [2.0.162](https://github.com/GeneralBots/BotServer/compare/2.0.161...2.0.162) (2022-08-26)
### Bug Fixes
* **core.gbapp:** Translator off for two char phrases. ([bd20312](https://github.com/GeneralBots/BotServer/commit/bd20312bad29c10dbdb9ecebddd69fa845af1892))
## [2.0.161](https://github.com/GeneralBots/BotServer/compare/2.0.160...2.0.161) (2022-08-06)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE sending bug. ([7eeadfa](https://github.com/GeneralBots/BotServer/commit/7eeadfa92deea7e61c277c7a75c1d0b49d7dca5c))
## [2.0.160](https://github.com/GeneralBots/BotServer/compare/2.0.159...2.0.160) (2022-08-06)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE sending bug. ([08607e4](https://github.com/GeneralBots/BotServer/commit/08607e49bb41643f98e49759d20b33699be47251))
* **whatsapp.gblib:** SEND FILE sending bug. ([61183a3](https://github.com/GeneralBots/BotServer/commit/61183a365440c183a46620b8a1921937182c29e2))
* **whatsapp.gblib:** SEND FILE sending bug. ([ae96a4f](https://github.com/GeneralBots/BotServer/commit/ae96a4f1235dfab29ee7c21ddab9997cbbe7e90f))
## [2.0.159](https://github.com/GeneralBots/BotServer/compare/2.0.158...2.0.159) (2022-08-06)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE sending bug. ([9cb2852](https://github.com/GeneralBots/BotServer/commit/9cb285214c37e44bacc01b6a60d0847b8d545e3a))
## [2.0.158](https://github.com/GeneralBots/BotServer/compare/2.0.157...2.0.158) (2022-08-05)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE sending bug. ([bcc14de](https://github.com/GeneralBots/BotServer/commit/bcc14def9866ce23ac7cdced793ba5d784a37a4b))
## [2.0.157](https://github.com/GeneralBots/BotServer/compare/2.0.156...2.0.157) (2022-08-05)
### Bug Fixes
* **whatsapp.gblib:** SEND FILE sending bug. ([8194c79](https://github.com/GeneralBots/BotServer/commit/8194c798281d6d8b80e4d1f04dcf47ba4a6538fc))
## [2.0.156](https://github.com/GeneralBots/BotServer/compare/2.0.155...2.0.156) (2022-07-06)
### Bug Fixes
* **all:** CHART and IMAGE from GET HTTP calls. ([a3e99bb](https://github.com/GeneralBots/BotServer/commit/a3e99bb5533fb07f613e2fe1264045ff10880f3e))
## [2.0.155](https://github.com/GeneralBots/BotServer/compare/2.0.154...2.0.155) (2022-07-06)
### Bug Fixes
* **all:** CHART and IMAGE from GET HTTP calls. ([cf62b10](https://github.com/GeneralBots/BotServer/commit/cf62b101969bdb7dc9c816b45b43e8e55b8287ee))
## [2.0.154](https://github.com/GeneralBots/BotServer/compare/2.0.153...2.0.154) (2022-07-01)
### Bug Fixes
* **all:** /check added. ([7410085](https://github.com/GeneralBots/BotServer/commit/7410085e99ca4d72447d3cb8f7a93dacf71b383f))
* **all:** Added MSFT cognitive stack again to test if it is working now on Azure. ([4452a31](https://github.com/GeneralBots/BotServer/commit/4452a311b18db74dd2b32492a14cd87881a610de))
* **all:** Automated build errors. ([55ff686](https://github.com/GeneralBots/BotServer/commit/55ff686a3f44baa21c7d3f3ba1020069d1f9a155))
* **all:** Automated build errors. ([ce2b484](https://github.com/GeneralBots/BotServer/commit/ce2b484f8eb7dd84bcd67f7fb772374c0a89bcbc))
* **all:** Building failed as typedoc bugs. ([55bc5ef](https://github.com/GeneralBots/BotServer/commit/55bc5ef3826fddede16def11726b7a69e4a38769))
* **all:** Building failed as typedoc bugs. ([6778f2e](https://github.com/GeneralBots/BotServer/commit/6778f2eb59b8b2624db1bf9c938e3cb1a93a174a))
* **all:** Comparison of strings in FIND operators. ([47d553f](https://github.com/GeneralBots/BotServer/commit/47d553f8f0bce15f81c802409b3ada98ae559187))
* **all:** Compilation error in MS AZURE (again). ([88a908a](https://github.com/GeneralBots/BotServer/commit/88a908a1241a6854b425ddc7156ec844c200e682))
* **all:** Compilation error in MS AZURE (again). ([227c30a](https://github.com/GeneralBots/BotServer/commit/227c30ac339f71705fbccb4b09e4bc2fc5ebe0f7))
* **all:** Corrected dates o MS EXcel saving. ([1899b1c](https://github.com/GeneralBots/BotServer/commit/1899b1c755352ea8efce6a11501ef3a5b45de153))
* **all:** Corrected mobile number to WhatsApp while output md. ([55568e2](https://github.com/GeneralBots/BotServer/commit/55568e2ba8b13f57656abf13f53f8241a9edb0ae))
* **all:** Corrected mobile number to WhatsApp while output md. ([0fda382](https://github.com/GeneralBots/BotServer/commit/0fda382a43b6752a6d09dd6d1f7d47d186636a73))
* **all:** Corrected mobile number to WhatsApp while output md. ([f0ad1ae](https://github.com/GeneralBots/BotServer/commit/f0ad1aea655b7ba276069b38a45104b7667aeef6))
* **all:** Corrected mobile number to WhatsApp while output md. ([9257ac7](https://github.com/GeneralBots/BotServer/commit/9257ac72715c4b769218dcb1f5ee86dc89d216ab))
* **all:** Corrected mobile number to WhatsApp while output md. ([95524a9](https://github.com/GeneralBots/BotServer/commit/95524a902ce7fff4236362707d6041cc920e5552))
* **all:** Enable https in place. ([6b05405](https://github.com/GeneralBots/BotServer/commit/6b05405705f0e224ed342c0e90628c8ac4f68c0d))
* **all:** Enable https in place. ([722a950](https://github.com/GeneralBots/BotServer/commit/722a9500332720e97dadb71dc2c787881d60d9dc))
* **all:** Enable https in place. ([4779d49](https://github.com/GeneralBots/BotServer/commit/4779d4968f9a2698795a35e74242556cd20f164d))
* **all:** Enable https in place. ([41f3f8a](https://github.com/GeneralBots/BotServer/commit/41f3f8a5755d3d4ba2161c17d15cb29793621879))
* **all:** Enable https in place. ([1c26466](https://github.com/GeneralBots/BotServer/commit/1c26466a00ba8d370173a1f436cb2e8fa9a47b70))
* **all:** Group improvements and isolation. ([dcb1c47](https://github.com/GeneralBots/BotServer/commit/dcb1c47f07acf6f9998be4a5eb86f0b58f7c26d1))
* **all:** Group improvements, group type in from column. ([55fdcbb](https://github.com/GeneralBots/BotServer/commit/55fdcbb9b57b7d9af00cd086e772b4fb7f528c52))
* **all:** Migration to Linus. ([d8e950c](https://github.com/GeneralBots/BotServer/commit/d8e950c91dc7332885b9b38ab9bbc22cffe656f6))
* **all:** Migration to Linus. ([820942c](https://github.com/GeneralBots/BotServer/commit/820942c41b44b29cad20e4d565d9e34bdc9aa6dc))
* **all:** Migration to Linus. ([78ed13b](https://github.com/GeneralBots/BotServer/commit/78ed13bb5ea185fcd8d46da36994193af586fd39))
* **all:** Migration to Linus. ([d2b2f29](https://github.com/GeneralBots/BotServer/commit/d2b2f29d5577f1b21286c4b9d220091bb8ce1a5c))
* **all:** Migration to Linus. ([da881cb](https://github.com/GeneralBots/BotServer/commit/da881cbaaf577da170af1db9ad9c1e39ac307fcf))
* **all:** Migration to Linus. ([241b572](https://github.com/GeneralBots/BotServer/commit/241b5721425cee77b8e2057c65037af45e7f0897))
* **all:** Migration to Linus. ([8586ec5](https://github.com/GeneralBots/BotServer/commit/8586ec55cf6b47ed0c833182898deedb332243c5))
* **all:** Migration to Linus. ([15f9c61](https://github.com/GeneralBots/BotServer/commit/15f9c619830f56774e4a36d96ccf4b9f3497da2f))
* **all:** Migration to Linus. ([54c4769](https://github.com/GeneralBots/BotServer/commit/54c47694f76a58ffaca0eda78a7c672303cc312b))
* **all:** Migration to Linus. ([35a4e4d](https://github.com/GeneralBots/BotServer/commit/35a4e4d1d9400e47bf506d70ff7a0e7ac34cd476))
* **all:** Migration to Linus. ([ef5eb6c](https://github.com/GeneralBots/BotServer/commit/ef5eb6cea60d03b08247cff2fb0a0c9182ab136c))
* **all:** Migration to Linus. ([8dcea93](https://github.com/GeneralBots/BotServer/commit/8dcea9384d0373843718f39ab867694e13d8a844))
* **all:** Migration to Linus. ([905690e](https://github.com/GeneralBots/BotServer/commit/905690e987bebf428e78c6e5fef8d517dac2bc0b))
* **all:** Migration to Linus. ([fc0f5ae](https://github.com/GeneralBots/BotServer/commit/fc0f5aefe0e0a541adc3e152b1a0c7756d1a50e0))
* **all:** MSTeams fixes. ([d6f8574](https://github.com/GeneralBots/BotServer/commit/d6f8574ecbf921a2cf63443dea0ceeeb0a520c73))
* **all:** SEARCH error in MS AZURE (again). ([fb53be5](https://github.com/GeneralBots/BotServer/commit/fb53be5b64b4d44412ded41505e054e76a265309))
* **all:** TS issues. ([4a6917a](https://github.com/GeneralBots/BotServer/commit/4a6917a48d14666772dabc817de8e94f6b3fced8))
* **all:** yarn vs npm on MSFT. ([b116026](https://github.com/GeneralBots/BotServer/commit/b1160260b38cf569565773384c14a0f7c6915664))
* **all:** yarn vs npm on MSFT. ([97f5f15](https://github.com/GeneralBots/BotServer/commit/97f5f154c03733a30e3b45cacbc64e82ae11de4d))
* **azuredeployer.gblib:** Fix MSFT changes. ([64d9884](https://github.com/GeneralBots/BotServer/commit/64d9884b69256c77887d50c8e256f625234be916))
* **azuredeployer.gblib:** Fix MSFT changes. ([b017f32](https://github.com/GeneralBots/BotServer/commit/b017f32b04bece944b379226478b1007978f4e9d))
* **basic.gblib:** Get all text from webservice inside SEE TEXT keyword. ([932e131](https://github.com/GeneralBots/BotServer/commit/932e131a50b7f7b5d0e5548c7439658ecacbf18f))
* **basic.gblib:** Get all text from webservice inside SEE TEXT keyword. ([8d61ae5](https://github.com/GeneralBots/BotServer/commit/8d61ae5536c840e51122ad224689c1f7a58126a9))
* **basic.gblib:** Hear callback for login only active if ENABLE_AUTH is defined. ([a628948](https://github.com/GeneralBots/BotServer/commit/a6289483940eef2868ec1ed467cb42c0db13e6e5))
* **basic.gblib:** TALK TO bug after conversationId update. ([b45f737](https://github.com/GeneralBots/BotServer/commit/b45f7372da069c7644ad12ae305dcb1a05447ec2))
* **basic.gblib:** TALK TO bug after conversationId update. ([250b332](https://github.com/GeneralBots/BotServer/commit/250b3320a2698ceb8985087c2cbf82036bb48ead))
* **basic.gblib:** Username was not being retrived. ([0335b71](https://github.com/GeneralBots/BotServer/commit/0335b715cdb37db199e32a3815887ca62049fbbe))
* **core.gbapp:** Added IBM for TTS and removed MSFT while it does not compile on AZR. ([abe4281](https://github.com/GeneralBots/BotServer/commit/abe4281b73d049517e5032f24d693886169d6abc))
* **core.gbapp:** Added IBM for TTS and removed MSFT while it does not compile on AZR. ([12c9bea](https://github.com/GeneralBots/BotServer/commit/12c9bea16726a04b0d040fcc64e7e262786f26a3))
* **core.gbapp:** Added IBM for TTS and removed MSFT while it does not compile on AZR. ([2a81604](https://github.com/GeneralBots/BotServer/commit/2a816049bc7ac5c6056287459609499ebe4d7b79))
* **core.gbapp:** Added IBM for TTS and removed MSFT while it does not compile on AZR. ([bef4fea](https://github.com/GeneralBots/BotServer/commit/bef4fea9de887aec2a0cee89029c4aa9cc3d0050))
* **core.gbapp:** Added IBM for TTS and removed MSFT while it does not compile on AZR. ([596a6eb](https://github.com/GeneralBots/BotServer/commit/596a6ebba309878627009c956db7e7b332dbcff4))
* **core.gbapp:** Added IBM for TTS and removed MSFT while it does not compile on AZR. ([4dbc1eb](https://github.com/GeneralBots/BotServer/commit/4dbc1eb6a0d930c54c853dad253958e66d42e737))
* **core.gbapp:** Fixed no publish of artifacts. ([c12a7d7](https://github.com/GeneralBots/BotServer/commit/c12a7d736c18d9afdd69f4e13c98f7b0a85ea654))
* **core.gbapp:** Just compile what has been changed. ([df6f146](https://github.com/GeneralBots/BotServer/commit/df6f146fd93ad7c5282694f7d3d8246c5109f082))
* **security.gbalib:** Transfer issues fixed. ([fefcbb0](https://github.com/GeneralBots/BotServer/commit/fefcbb04bff2a40fbf0ce0df96f7566ee386d925))
* **security.gbalib:** Transfer issues fixed. ([6ebd38d](https://github.com/GeneralBots/BotServer/commit/6ebd38d3eb524c846db4f62bb7373de5d1374892))
* **security.gbalib:** Transfer issues fixed. ([660faaf](https://github.com/GeneralBots/BotServer/commit/660faafb530b362491a327d6e3921f71b94f0aa9))
## [2.0.153](https://github.com/GeneralBots/BotServer/compare/2.0.152...2.0.153) (2021-10-02)
@ -1081,8 +248,8 @@
* **all:** Packages updated and new DirectLine behaviour fixed. ([517689f](https://github.com/GeneralBots/BotServer/commit/517689fafee83f4461df1d9dfc530e969ac6fc9f))
* **all:** Removed security breach. ([0202ed0](https://github.com/GeneralBots/BotServer/commit/0202ed0ef54711181baf84525b730eee8fc62a44))
* **all:** Removed security breach. ([dad67d2](https://github.com/GeneralBots/BotServer/commit/dad67d27ba0963aa272837934a2ee6daa9145928))
* **all:** Sequelize base members demand keyword on timestamp fields. ([42719e7](https://github.com/GeneralBots/BotServer/commit/42719e7ba0cbb6df50880ee0cf626516424ab59b))
* **all:** Sequelize base members demand keyword on timestamp fields. ([493889b](https://github.com/GeneralBots/BotServer/commit/493889beb218eed8a1ed4dd9550d6d952714bb56))
* **all:** Sequelize base members demand declare keyword on timestamp fields. ([42719e7](https://github.com/GeneralBots/BotServer/commit/42719e7ba0cbb6df50880ee0cf626516424ab59b))
* **all:** Sequelize base members demand declare keyword on timestamp fields. ([493889b](https://github.com/GeneralBots/BotServer/commit/493889beb218eed8a1ed4dd9550d6d952714bb56))
* **azuredeployer.gbapp:** New pricing table. ([7f641bd](https://github.com/GeneralBots/BotServer/commit/7f641bd5df3fa5c88f34164193ff1bd6b1d7e956))
* **basic.gbapp:** Call to SEND FILE with .md files working OK. ([80b91c4](https://github.com/GeneralBots/BotServer/commit/80b91c437001a890131e509d67604e42c27cea2e))
* **basic.gblib:** Autostart bug, more logging. ([3d90bd8](https://github.com/GeneralBots/BotServer/commit/3d90bd872e093d24336df4d83991b67dc90d1d80))

View file

@ -1,48 +0,0 @@
# Código de Conduta do Convênio do Colaborador
## Nosso Compromisso
No interesse de promover um ambiente aberto e acolhedor, nós, como colaboradores e mantenedores, nos comprometemos a tornar a participação em nosso projeto e em nossa comunidade uma experiência livre de assédio para todos, independentemente de idade, raça, etnia, origem nacional, ascendência, sexo, sexo identidade ou apresentação, orientação sexual, aparência física, afiliação religiosa, credo, estado civil ou familiar, não tolerará abuso ou assédio discriminatório ou sexual contra qualquer pessoa durante quaisquer atividades relacionadas à conferência, incluindo, entre outros, envio, revisão, tutoriais, oficinas ou eventos sociais. O abuso inclui qualquer ação dirigida a um indivíduo que (a) interfira substancialmente na participação dessa pessoa ou (b) faça com que essa pessoa tema por sua segurança pessoal. Isso inclui ameaças, intimidação, intimidação, perseguição ou outros tipos de abuso. Assédio discriminatório inclui qualquer conduta que discrimine ou denigra um indivíduo com base em idade, raça, etnia, nacionalidade, ascendência, gênero, identidade ou apresentação de gênero, orientação sexual, aparência física, afiliação religiosa, credo, estado civil ou familiar, deficiência , características pessoais ou quaisquer outros fatores diferenciadores, bem como qualquer outra característica protegida por lei no local onde ocorre a atividade da conferência. Assédio sexual inclui (mas não se limita a) investidas sexuais indesejadas repetidas, pedidos de favores sexuais ou outra conduta verbal ou física de natureza sexual, deficiência, características pessoais ou quaisquer outros fatores de diferenciação, bem como qualquer outra característica protegida por lei no local onde a atividade ocorre.
## Nossos Padrões
Exemplos de comportamento que contribuem para criar um ambiente positivo incluem:
* Usando linguagem padrão (sem expressões idiomáticas), acolhedora e inclusiva
* Ser respeitoso com os diferentes pontos de vista e experiências
* Aceitar graciosamente críticas construtivas
* Focar no que é melhor para a comunidade
* Mostrar empatia para com outros membros da comunidade
* Escrever trechos gerais de código para que possam ser amplamente utilizados.
Exemplos de comportamento inaceitável por parte dos participantes incluem:
* O uso de linguagem ou imagens sexualizadas e atenção ou avanços sexuais indesejados
* Trolling, comentários insultuosos/depreciativos e ataques pessoais ou políticos
* Assédio (harassment) público ou privado / perseguição (stalking) / intimidação (bullying) / mobbing (group bullying or gang stalking)
* Publicar informações privadas de outras pessoas, como endereço físico ou eletrônico, sem permissão explícita
* Outra conduta que possa ser razoavelmente considerada inadequada em um ambiente profissional
* Chamar uma pessoa de nome diferente do declarado pela pessoa
## Nossas responsabilidades
Os mantenedores do projeto são responsáveis por esclarecer os padrões de comportamento aceitável e devem tomar ações corretivas apropriadas e justas em resposta a quaisquer instâncias de comportamento inaceitável.
Os mantenedores do projeto têm o direito e a responsabilidade de remover, editar ou rejeitar comentários, confirmações, códigos, edições wiki, problemas e outras contribuições que não estejam alinhadas com este Código de Conduta, ou banir temporária ou permanentemente qualquer colaborador por outros comportamentos que eles considerem inapropriado, ameaçador, ofensivo ou prejudicial.
## Escopo
Este Código de Conduta se aplica tanto em espaços do projeto quanto em espaços públicos quando um indivíduo representa o projeto ou sua comunidade. Exemplos de representação de um projeto ou comunidade incluem o uso de um endereço de e-mail oficial do projeto, postagem por meio de uma conta de mídia social oficial ou atuação como um representante nomeado em um evento online ou offline. A representação de um projeto pode ser posteriormente definida e esclarecida pelos mantenedores do projeto.
## Aplicação
Instâncias de comportamento abusivo, de assédio ou inaceitável podem ser relatadas entrando em contato com a equipe de segurança da Pragmatismo em c. A equipe do projeto analisará e investigará todas as reclamações e responderá da maneira que julgar apropriada às circunstâncias. A equipe do projeto é obrigada a manter a confidencialidade em relação ao relator de um incidente. Mais detalhes sobre políticas de execução específicas podem ser publicados separadamente.
Os mantenedores do projeto que não seguirem ou aplicarem o Código de Conduta de boa fé podem enfrentar repercussões temporárias ou permanentes conforme determinado por outros membros da liderança do projeto.
## Atribuição
Este Código de Conduta foi adaptado do [Acordo do Colaborador][homepage], versão 1.4, disponível em [http://contributor-covenant.org/version/1/4][version] e Código de Conduta ICAPS.
[página inicial]: http://contributor-covenant.org
[versão]: http://contributor-covenant.org/version/1/4/

View file

@ -2,7 +2,7 @@
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, race, ethnicity, national origin, ancestry, gender, gender identity or presentation, sexual orientation, physical appearance, religious affiliation, creed, marital or familial status, will not tolerate abuse or discriminatory or sexual harassment toward any person during any conference-related activities, including but not limited to submission, reviewing, tutorials, workshops, or social events. Abuse includes any action directed at an individual that (a) interferes substantially with that persons participation or (b) causes that person to fear for their personal safety. This includes threats, intimidation, bullying, stalking, or other types of abuse. Discriminatory harassment includes any conduct that discriminates or denigrates an individual on the basis of age, race, ethnicity, national origin, ancestry, gender, gender identity or presentation, sexual orientation, physical appearance, religious affiliation, creed, marital or familial status, disability, personal characteristics, or any other differentiating factors, as well as any other characteristic protected by law in the location where conference activity takes place. Sexual harassment includes (but is not limited to) repeated unwelcome sexual advances, requests for sexual favors, or other verbal or physical conduct of a sexual nature, disability, personal characteristics, or any other differentiating factors, as well as any other characteristic protected by law in the location where activity takes place.
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
@ -19,7 +19,7 @@ Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment / stalking / bullying / mobbing (group bullying or gang stalking)
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
* Call a person other name than that declared by the person
@ -36,14 +36,13 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Pragmatismo security team at c. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Pragmatismo.io security team at security@pragmatismo.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] and ICAPS Code of Conduct.
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View file

@ -32,7 +32,7 @@ In general, things we find useful when reviewing suggestions are:
## Contributing bug fixes
General Bots is current in early preview. We're still accepting contributions in the form of bug fixes.
A bug must have an issue tracking it in the issue tracker that has been approved by the pragmatismo.com.br team. Your pull request should include a link to the bug that you are fixing. If you've submitted a PR for a bug, please post a comment in the bug to avoid duplication of effort.
A bug must have an issue tracking it in the issue tracker that has been approved by the Pragmatismo.io team. Your pull request should include a link to the bug that you are fixing. If you've submitted a PR for a bug, please post a comment in the bug to avoid duplication of effort.
## Contributing features
@ -40,7 +40,7 @@ Please open an issue with the `Schema` label to get a discussion started.
## Legal
We appreciate community contributions to code repositories open sourced by pragmatismo.com.br. By signing a contributor license agreement, we ensure that the community is free to use your contributions.
We appreciate community contributions to code repositories open sourced by Pragmatismo.io. By signing a contributor license agreement, we ensure that the community is free to use your contributions.
## Housekeeping

View file

@ -136,13 +136,3 @@ CREATE TABLE [dbo].[GuaribasSchedule]
[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

8
FEATURES.md Normal file
View file

@ -0,0 +1,8 @@
# General Bots Features
| Feature | BF | GB |
|----------------------------------------------------------------------------|----|----|
| Use of conversational administration to manage bot packages (Talk to admin | - | X |
| F5 to run on VSCode | - | X |
| Isolated code on packages | - | X |
| Breaking changes protected | - | X |

View file

@ -1,5 +1,5 @@
General Bots is licensed under a dual license. To check which license
edition of General bots you have installed, please ask info@pragmatismo.com.br
edition of General bots you have installed, please ask info@pragmatismo.io
informing your Customer ID.
If you modify this Program, or any covered work, by combining it

7
LOCALIZATION.md Normal file
View file

@ -0,0 +1,7 @@
# Localization in General Bots
## .gbapp
The localization is done by adding a strings.ts file to the root of the .gbapp package.

151
README.md
View file

@ -1,36 +1,20 @@
### Key Facts
- LLM Orchestrator AGPL licensed (to use as custom-label SaaS, contributing back)
- True community governance
- No single corporate control
- 5+ years of stability
- Never changed license
- Enterprise-grad
- Hosted locally or Multicloud
## Contributors
<a href="https://github.com/generalbots/botserver/graphs/contributors">
<img src="https://contrib.rocks/image?repo=generalbots/botserver" />
</a>
## Overview
| Area | Status |
|------------------------------|----------------------------------------------------------------------------------------------------|
| Releases | [![General Bots](https://img.shields.io/npm/dt/botserver.svg?logo=npm&label=botserver)](https://www.npmjs.com/package/botserver/) [![.gbapp lib](https://img.shields.io/npm/dt/botlib.svg?logo=npm&label=botlib)](https://www.npmjs.com/package/botlib/) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)|
| Community | [![StackExchange](https://img.shields.io/stackexchange/stackoverflow/t/generalbots.svg)](https://stackoverflow.com/questions/tagged/generalbots) [![Open-source](https://badges.frapsoft.com/os/v2/open-source.svg)](https://badges.frapsoft.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![License](https://img.shields.io/badge/license-AGPL-blue.svg)](https://github.com/GeneralBots/BotServer/blob/master/LICENSE.txt)|
| Management | [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://gitHub.com/GeneralBots/BotServer/graphs/commit-activity) |
| Security | [![Known Vulnerabilities](https://snyk.io/test/github/GeneralBots/BotServer/badge.svg)](https://snyk.io/test/github/GeneralBots/BotServer) |
| Building & Quality | [![Coverage Status](https://coveralls.io/repos/github/GeneralBots/BotServer/badge.svg)](https://coveralls.io/github/GeneralBots/BotServer) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) |
| Packaging | [![forthebadge](https://badge.fury.io/js/botserver.svg)](https://badge.fury.io) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) |
| Samples | [BASIC](https://github.com/GeneralBots/BotServer/tree/master/packages/default.gbdialog) or [![TypeScript](https://badges.frapsoft.com/typescript/code/typescript.svg?v=101)](https://github.com/GeneralBots/AzureADPasswordReset.gbapp)
| [Docker Image](https://github.com/lpicanco/docker-botserver) ![Docker Pulls](https://img.shields.io/docker/pulls/lpicanco/botserver.svg) <br/> *Provided by [@lpicanco](https://github.com/lpicanco/docker-botserver)* |
| Building & Quality | [![Build Status](https://travis-ci.com/GeneralBots/BotServer.svg?branch=master)](https://travis-ci.com/GeneralBots/BotServer) [![Coverage Status](https://coveralls.io/repos/github/GeneralBots/BotServer/badge.svg)](https://coveralls.io/github/GeneralBots/BotServer) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) |
| Packaging | [![forthebadge](https://badge.fury.io/js/botserver.svg)](https://badge.fury.io) [![ZipFile](https://camo.githubusercontent.com/0150c0f148d50fe9750ebc5d313581da699a8c50/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7a69702d646f776e6c6f61642d626c75652e737667)](https://github.com/GeneralBots/BotServer/releases/latest) [![Dependencies](https://david-dm.org/GeneralBots/botserver.svg)](https://david-dm.org) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) |
| Samples | [VBA](https://github.com/GeneralBots/BotServer/tree/master/packages/default.gbdialog) or [![TypeScript](https://badges.frapsoft.com/typescript/code/typescript.svg?v=101)](https://github.com/GeneralBots/AzureADPasswordReset.gbapp)
| [Docker Image](https://github.com/lpicanco/docker-botserver) | ![Docker Automated build](https://img.shields.io/docker/automated/lpicanco/botserver.svg) ![Docker Build Status](https://img.shields.io/docker/build/lpicanco/botserver.svg) ![MicroBadger Size](https://img.shields.io/microbadger/image-size/lpicanco/botserver.svg) ![MicroBadger Layers](https://img.shields.io/microbadger/layers/lpicanco/botserver.svg) ![Docker Pulls](https://img.shields.io/docker/pulls/lpicanco/botserver.svg) <br/> *Provided by [@lpicanco](https://github.com/lpicanco/docker-botserver)* |
# General Bots
General Bots
------------------
![General Bot Logo](https://github.com/GeneralBots/BotServer/blob/main/logo.png?raw=true))
![General Bot Logo](https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/logo.png)
General Bot is a strongly typed LLM conversational platform 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.
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.
## What is a Bot Server?
@ -44,115 +28,28 @@ advanced fashion writing custom code in editors like Visual Studio Code, Atom or
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). LLM and BASIC can be mixed used to build custom dialogs so Bot can be extended just like VBA for Excel.
editor). BASIC can be used to build custom dialogs so Bot can be extended just like VBA for Excel (currently in alpha).
## Getting Started
### Prerequisites
Before you embark on your General Bots journey, ensure you have the following tools installed:
- **Node.js (version 20 or later)**: General Bots leverages the latest features of Node.js to provide a robust and efficient runtime environment. Download it from [nodejs.org](https://nodejs.org/en/download/).
- **Git (latest stable version)**: Essential for version control and collaborating on bot projects. Get it from [git-scm.com](https://git-scm.com/downloads).
### Quick Start Guide
Follow these steps to get your General Bots server up and running:
1. Clone the repository:
```bash
git clone https://github.com/GeneralBots/BotServer
```
This command creates a local copy of the General Bots server repository on your machine.
2. Navigate to the project directory:
```bash
cd BotServer
```
This changes your current directory to the newly cloned BotServer folder.
3. Install dependencies and start the server:
```bash
npm install
npm run start
```
The `npm install` command installs all necessary dependencies for the project. `npm run start` builds your bot server locally and serves it through a development server.
### Accessing Your Bot
Once the server is running, you can access your bot at `http://localhost:4242/`. This local server allows you to interact with your bot and test its functionality in real-time. If you want to publish
without password, define [ADMIN_OPEN_PUBLISH](https://github.com/GeneralBots/BotBook/master/docs/chapter-07-gbot-reference#enviroment-variables-reference) as true in BotServer .env file.
To publish bot packages and initiate a conversation with the bot, use the command:
```
/publish
```
This command prepares your bot packages for use and allows you to start interacting with your bot immediately.
## Development Workflow
### 1. Project Structure
The General Bots server follows a modular architecture designed for flexibility and scalability. Here's an overview of the main directories:
```
BotServer/
├── packages/
│ ├── core.gbapp/ # Core bot functionality
│ ├── kb.gbapp/ # Knowledge base packages
├── src / # Main entry point
└── package.json # Project configuration
```
This structure allows for easy navigation and management of different aspects of your bot project.
### 2. Creating Custom Packages
One of the strengths of General Bots is its extensibility. You can create custom packages to enhance your bot's capabilities:
- **.gbkb (Knowledge Base packages)**: Store and manage your bot's knowledge and responses.
- **.gbtheme (Theme packages)**: Customize the visual appearance of your bot interface.
- **.gbapp (Application packages)**: Add new features and functionalities to your bot.
Each package type has its own structure and purpose, which we'll explore in depth in their respective chapters.
![General Bot Reference Architecture](https://raw.githubusercontent.com/GeneralBots/BotBook/master/images/general-bots-reference-architecture.png)
## Samples
Several samples, including a Bot for AD Password Reset, are avaiable on the [repository list](https://github.com/GeneralBots).
### Using complete General Bots Conversational Data Analytics
![](https://user-images.githubusercontent.com/14840374/178154826-8188029e-b4f4-48aa-bc0d-126307ce5121.png)
```
TALK "General Bots Labs presents FISCAL DATA SHOW BY BASIC"
TALK "Gift Contributions to Reduce the Public Debt API (https://fiscaldata.treasury.gov/datasets/gift-contributions-reduce-debt-held-by-public/gift-contributions-to-reduce-the-public-debt)"
result = GET "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v2/accounting/od/gift_contributions?page[size]=500"
data = result.data
data = SELECT YEAR(record_date) as Yr, SUM(CAST(contribution_amt AS NUMBER)) AS Amount FROM data GROUP BY YEAR(record_date)
TALK "Demonstration of Gift Contributions with AS IMAGE keyword"
SET THEME dark
png = data as IMAGE
SEND FILE png
DELAY 5
TALK " Demonstration of Gift Contributions CHART keyword"
img = CHART "bar", data
SEND FILE img
```
## Guide
[Read the General Bots BotBook Guide](https://docs.pragmatismo.com.br)
[Read the General Bots BotBook Guide](https://github.com/GeneralBots/BotBook/tree/master/book).
# Videos
7 AI General Bots LLM Templates for Goodness
[https://www.youtube.com/watch?v=KJgvUPXi3Fw](https://www.youtube.com/watch?v=KJgvUPXi3Fw)
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.
[![General Bot Video](https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/docs/images/video-01-thumb.jpg)](https://www.youtube.com/watch?v=AfKTwljoMOs)
See how easy is to use 'hear' and 'talk' to build Microsoft BOT Framework v4 logic with plain BASIC * published on December 3rd, 2018.
[![See how easy is to use 'hear' and 'talk' to build Microsoft BOT Framework v4 logic with plain BASIC](https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/docs/images/video-02-thumb.jpg)](https://www.youtube.com/watch?v=yX1sF9n9628)
# Contributing
@ -161,14 +58,14 @@ See our [Contribution Guidelines](https://github.com/pragmatismo-io/BotServer/bl
# Reporting Security Issues
Security issues and bugs should be reported privately, via email, to the pragmatismo.com.br Security
team at [security@pragmatismo.com.br](mailto:security@pragmatismo.com.br). You should
Security issues and bugs should be reported privately, via email, to the Pragmatismo.io Security
team at [security@pragmatismo.io](mailto:security@pragmatismo.io). 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.
# License & Warranty
General Bot Copyright (c) pragmatismo.com.br. All rights reserved.
General Bot Copyright (c) Pragmatismo.io. All rights reserved.
Licensed under the AGPL-3.0.
According to our dual licensing model, this program can be used either
@ -184,12 +81,12 @@ 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 Bot" is a registered trademark of pragmatismo.com.br.
"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.
<a href="https://stackoverflow.com/questions/ask?tags=generalbots">:speech_balloon: Ask a question</a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://github.com/GeneralBots/BotBook">:book: Read the Docs</a>
Team pictures made with [contrib.rocks](https://contrib.rocks).
General Bots Code Name is [Guaribas](https://en.wikipedia.org/wiki/Guaribas), the name of a city in Brazil, state of Piaui.
[Roberto Mangabeira Unger](http://www.robertounger.com/en/): "No one should have to do work that can be done by a machine".

6
ROADMAP.md Normal file
View file

@ -0,0 +1,6 @@
# Roadmap
| Title | Priority | Release | Status |
|-------------------------------|------------------------------------------------------------------------------------------------------------|---------|--------|
| Isolation of .gbapp per .gbot | Today .gbapp loaded is shared across all bot instances and must be associated to one or more individually. | Medium | 2019Q4 |
| Python based .gbapps | Write conversational login in Python | Low | - |

7
SAMPLES.md Normal file
View file

@ -0,0 +1,7 @@
# General Bots Server Samples
| Sample | Description |
|--------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| [IntranetBotQuickStart-gbai](https://github.com/pragmatismo-io/IntranetBotQuickStart.gbai) | Free modules from General Bots Intranet based bot. |
| [AzureADPasswordReset-gbapp](https://github.com/pragmatismo-io/AzureADPasswordReset.gbapp) | Custom General Bot App (gbapp) for resetting an user password in Azure Active Directory, Office 365, Dynamics 365 or any app published through Azure AD. |
| [ProjectOnline.gbkb](https://github.com/pragmatismo-io/ProjectOnline.gbkb) | The .gbkb file demonstring a Knowledge Base for Pragmatismo.io KBot for Microsoft Project. |

View file

@ -1,61 +0,0 @@
# General Bots Security Policy
## Overview
Request your free IT security evaluation
• Reduce the risk of IT problems
• Plan for problems and deal with them when they happen
• Keep working if something does go wrong
• Protect company, client and employee data
• Keep valuable company information, such as plans and designs, secret
• Meet our legal obligations under the General Data Protection Regulation and other laws
• Meet our professional obligations towards our clients and customers
This IT security policy helps us:
• Rodrigo Rodriguez is the director with overall responsibility for IT security strategy.
• Microsoft is the IT partner organisation we use to help with our planning and support.
• Microsoft is the data protection officer to advise on data protection laws and best practices
Review process
We will review this policy yearly.
In the meantime, if you have any questions, suggestions
or feedback, please contact security@pragmatismo.com.br
We will only classify information which is necessary for the completion of our duties. We will also limit
access to personal data to only those that need it for processing. We classify information into different
categories so that we can ensure that it is protected properly and that we allocate security resources
appropriately:
• Unclassified. This is information that can be made public without any implications for the company,
such as information that is already in the public domain.
• Employee confidential. This includes information such as medical records, pay and so on.
• Company confidential. Such as contracts, source code, business plans, passwords for critical IT
systems, client contact records, accounts etc.
• Client confidential. This includes personally identifiable information such as name or address,
passwords to client systems, client business plans, new product information, market sensitive
information etc.
Employees joining and leaving
We will provide training to new staff and support for existing staff to implement this policy. This includes:
• An initial introduction to IT security, covering the risks, basic security measures, company policies
and where to get help
• Each employee will complete the National Archives Responsible for Information training course
(approximately 75 minutes)
• Training on how to use company systems and security software properly
• On request, a security health check on their computer, tablet or phone
When people leave a project or leave the company, we will promptly revoke their access privileges to
The company will ensure the data protection office is given all appropriate resources to carry out their
tasks and maintain their expert knowledge.
The Data Protection Officer reports directly to the highest level of management and must not carry out
any other tasks that could result in a conflict of interest.
## Reporting a Vulnerability
You can expect to get an update on a reported vulnerability in a day or two.
security@pragmatismo.com.br

View file

@ -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

View file

@ -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"
}
]
}

Binary file not shown.

Binary file not shown.

65
boot.js Normal file
View file

@ -0,0 +1,65 @@
#!/usr/bin/env node
const Fs = require('fs');
const Path = require('path');
const { exec } = require('child_process');
var pjson = require('./package.json');
// Displays version of Node JS being used at runtime and others attributes.
console.log(`[GB Runtime] BotServer = v${pjson.version}`);
console.log(`[GB Runtime] BotLib = v${pjson.dependencies.botlib}`);
console.log(`[GB Runtime] BotBuilder (MS) = v${pjson.dependencies.botbuilder}`);
console.log(`[GB Runtime] NodeJS = ${process.version}`);
console.log(`[GB Runtime] platform = ${process.platform}`);
console.log(`[GB Runtime] architecture = ${process.arch}`);
console.log(`[GB Runtime] argv = ${process.argv}`);
console.log(`[GB Runtime] debugPort = ${process.debugPort}`);
var now = () => {
return (new Date()).toISOString().replace(/T/, ' ').replace(/\..+/, '') + ' UTC';
}
try {
var run = () => {
console.log(`[GB Runtime] Initializing General Bots Server...`);
const GBServer = require("./dist/src/app").GBServer
console.log(`[GB Runtime] ${now()} - Running '${GBServer.name}' on '${__dirname}' directory`);
process.env.PWD = __dirname;
GBServer.run();
}
var processDist = () => {
if (!Fs.existsSync('dist')) {
console.log(`${now()} - Compiling...`);
exec(Path.join(__dirname, 'node_modules/.bin/tsc'), (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
run();
});
}
else {
run();
}
};
// Installing modules if it has not been done yet.
if (!Fs.existsSync('node_modules')) {
console.log(`${now()} - Installing modules for the first time, please wait...`);
exec('npm install', (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
processDist();
});
}
else {
processDist();
}
} catch (e) {
console.log(e);
}

View file

@ -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);
}

View file

@ -115,7 +115,7 @@ IF EXIST "%DEPLOYMENT_TARGET%\deploy\default.gbui\package.json" (
popd
)
:: 4. Install TypeScript
:: 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%"

View file

@ -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."

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

After

Width:  |  Height:  |  Size: 280 KiB

View file

@ -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"
}
]

View file

@ -3,13 +3,13 @@
ECHO General Bots Command Line
IF EXIST node_modules goto COMPILE
ECHO Installing Packages for the first time use (it may take several minutes)...
ECHO Installing Packages for the first time use...
CALL npm install --silent
:COMPILE
IF EXIST dist goto ALLSET
ECHO Compiling...
npm run build
CALL node_modules\.bin\tsc
:ALLSET
npm run start
node boot.js

View file

@ -1,2 +0,0 @@
echo Starting General Bots...
npm run start

11
greenkeeper.json Normal file
View file

@ -0,0 +1,11 @@
{
"groups": {
"default": {
"packages": [
"package.json",
"packages/default.gbtheme/package.json",
"packages/default.gbui/package.json"
]
}
}
}

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

64572
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,8 @@
{
"name": "botserver",
"version": "5.0.0",
"version": "2.0.153",
"description": "General Bot Community Edition open-core server.",
"main": "./boot.mjs",
"type": "module",
"main": "./boot.js",
"bugs": "https://github.com/pragmatismo-io/BotServer/issues",
"homepage": "https://github.com/pragmatismo-io/BotServer/#readme",
"contributors": [
@ -11,36 +10,29 @@
"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>"
"Dário Vieira <dario.junior3@gmail.com>"
],
"opencv4nodejs": {
"disableAutoBuild": "1"
},
"engines": {
"node": "=22.9.0"
"node": "=14.10.1"
},
"license": "AGPL-3.0",
"preferGlobal": true,
"private": false,
"bin": {
"gbot": "./boot.mjs"
"gbot": "./boot.js"
},
"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",
"tslint": "tslint --fix ./src/*.ts ./packages/**/*.ts -t verbose -e ./packages/default.gbui/**/* -e ./packages/**/*.gbdialog/**/*",
"build": "npm install && npm run build-server && npm run build-gbui && npm run build-docs",
"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",
"start": "node ./boot.js",
"reverse-proxy": "node_modules/.bin/ngrok http 4242",
"watch:build": "tsc --watch",
"posttypedoc": "shx cp .nojekyll docs/reference/.nojekyll",
@ -55,226 +47,100 @@
"semantic-release": "semantic-release",
"commit": "git-cz"
},
"jest": {
"workerIdleMemoryLimit": "4096MB",
"transform": {
".+\\.tsx?$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json"
]
},
"dependencies": {
"@azure/arm-appservice": "15.0.0",
"@azure/arm-cognitiveservices": "7.5.0",
"@azure/arm-resources": "5.2.0",
"@azure/arm-search": "3.2.0",
"@azure/arm-sql": "10.0.0",
"@azure/arm-subscriptions": "5.1.0",
"@azure/cognitiveservices-computervision": "8.2.0",
"@azure/keyvault-keys": "4.8.0",
"@azure/ms-rest-js": "2.7.0",
"@azure/msal-node": "2.13.1",
"@azure/openai": "2.0.0-beta.1",
"@azure/search-documents": "12.1.0",
"@azure/storage-blob": "12.24.0",
"@google-cloud/pubsub": "4.7.0",
"@google-cloud/translate": "8.5.0",
"@hubspot/api-client": "11.2.0",
"@koa/cors": "5.0.0",
"@langchain/anthropic": "^0.3.7",
"@langchain/community": "0.2.31",
"@langchain/core": "^0.3.17",
"@langchain/openai": "0.2.8",
"@microsoft/microsoft-graph-client": "3.0.7",
"@nlpjs/basic": "4.27.0",
"@nosferatu500/textract": "3.1.3",
"@push-rpc/core": "1.9.0",
"@push-rpc/http": "1.9.0",
"@push-rpc/openapi": "1.9.0",
"@push-rpc/websocket": "1.9.0",
"@semantic-release/changelog": "6.0.3",
"@semantic-release/exec": "6.0.3",
"@semantic-release/git": "10.0.1",
"@sendgrid/mail": "8.1.3",
"@sequelize/core": "7.0.0-alpha.37",
"@sequelize/postgres": "^7.0.0-alpha.43",
"@types/validator": "13.12.1",
"adm-zip": "0.5.16",
"ai2html": "^0.121.1",
"alasql": "4.5.1",
"@azure/ms-rest-js": "2.5.1",
"@google-cloud/pubsub": "^2.13.0",
"@google-cloud/translate": "^6.2.6",
"@microsoft/microsoft-graph-client": "2.2.1",
"@semantic-release/changelog": "5.0.1",
"@semantic-release/exec": "5.0.0",
"@semantic-release/git": "9.0.0",
"@sendgrid/mail": "^7.4.4",
"@types/validator": "13.1.4",
"adal-node": "0.2.2",
"adm-zip": "^0.5.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": "^5.1.1",
"billboard.js": "3.13.0",
"azure-arm-cognitiveservices": "3.0.0",
"azure-arm-resource": "7.4.0",
"azure-arm-search": "1.3.0-preview",
"azure-arm-sql": "5.7.0",
"azure-arm-website": "5.7.0",
"azure-search-client": "3.1.5",
"bluebird": "3.7.2",
"body-parser": "1.20.2",
"botbuilder": "4.23.0",
"botbuilder-adapter-facebook": "1.0.12",
"botbuilder-ai": "4.23.0",
"botbuilder-dialogs": "4.23.0",
"botframework-connector": "4.23.0",
"botlib": "5.0.0",
"c3-chart-maker": "0.2.8",
"cd": "0.3.3",
"chalk-animation": "2.0.3",
"chatgpt": "5.2.5",
"chrome-remote-interface": "0.33.2",
"cli-progress": "3.12.0",
"body-parser": "1.19.0",
"botbuilder": "4.11.0",
"botbuilder-adapter-facebook": "1.0.11",
"botbuilder-ai": "4.11.0",
"botbuilder-dialogs": "4.11.0",
"botframework-connector": "4.11.0",
"botlib": "1.9.4",
"cli-spinner": "0.2.10",
"core-js": "3.38.1",
"cors": "2.8.5",
"csv-database": "0.9.2",
"data-forge": "1.10.2",
"date-diff": "1.0.2",
"docximager": "0.0.4",
"docxtemplater": "3.50.0",
"core-js": "3.14.0",
"date-diff": "^0.2.2",
"dotenv-extended": "2.9.0",
"electron": "32.0.1",
"exceljs": "4.4.0",
"express": "4.19.2",
"exceljs": "4.2.1",
"express": "4.17.1",
"express-remove-route": "1.0.0",
"facebook-nodejs-business-sdk": "^20.0.2",
"ffmpeg-static": "5.2.0",
"formidable": "^3.5.1",
"get-image-colors": "4.0.1",
"glob": "^11.0.0",
"google-libphonenumber": "3.2.38",
"googleapis": "143.0.0",
"hnswlib-node": "3.0.0",
"html-to-md": "0.8.6",
"http-proxy": "1.18.1",
"ibm-watson": "9.1.0",
"icojs": "^0.19.4",
"instagram-private-api": "1.46.1",
"iso-639-1": "3.1.3",
"isomorphic-fetch": "3.0.0",
"jimp": "1.6.0",
"js-md5": "0.8.3",
"json-schema-to-zod": "2.4.0",
"jsqr": "^1.4.0",
"just-indent": "0.0.1",
"keyv": "5.0.1",
"koa": "2.15.3",
"koa-body": "6.0.1",
"koa-ratelimit": "5.1.0",
"koa-router": "12.0.1",
"langchain": "0.2.17",
"language-tags": "1.0.9",
"line-replace": "2.0.1",
"livekit-server-sdk": "^2.12.0",
"lodash": "4.17.21",
"luxon": "3.5.0",
"mammoth": "1.8.0",
"mariadb": "3.3.1",
"mime-types": "2.1.35",
"minio": "^8.0.4",
"moment": "2.30.1",
"ms-rest-azure": "3.0.2",
"mysql": "^2.18.1",
"ffmpeg-static": "4.3.0",
"google-libphonenumber": "3.2.21",
"googleapis": "75.0.0",
"ibm-watson": "6.1.1",
"js-beautify": "1.13.13",
"luxon": "^2.0.2",
"marked": "2.0.7",
"momentjs": "^2.0.0",
"ms-rest-azure": "3.0.0",
"nexmo": "2.9.1",
"ngrok": "5.0.0-beta.2",
"node-cron": "3.0.3",
"node-html-parser": "6.1.13",
"node-nlp": "4.27.0",
"node-tesseract-ocr": "2.2.1",
"nodemailer": "6.10.1",
"nodemon": "^3.1.7",
"npm": "10.8.3",
"open": "10.1.0",
"open-docxtemplater-image-module": "1.0.3",
"openai": "4.57.0",
"pdf-extraction": "1.0.2",
"pdf-parse": "1.1.1",
"pdf-to-png-converter": "3.3.0",
"pdfjs-dist": "4.6.82",
"pg": "^8.13.1",
"phone": "3.1.50",
"pizzip": "3.1.7",
"pptxtemplater": "1.0.5",
"pragmatismo-io-framework": "1.1.1",
"prism-media": "1.3.5",
"public-ip": "7.0.1",
"punycode": "2.3.1",
"puppeteer": "23.2.2",
"puppeteer-extra": "3.3.6",
"puppeteer-extra-plugin-minmax": "1.1.2",
"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",
"node-cron": "3.0.0",
"npm": "7.21.0",
"opn": "6.0.0",
"pdf-extraction": "^1.0.2",
"phone": "2.4.21",
"pragmatismo-io-framework": "1.0.20",
"prism-media": "1.3.1",
"public-ip": "4.0.4",
"readline": "1.3.0",
"reflect-metadata": "0.2.2",
"rimraf": "6.0.1",
"reflect-metadata": "0.1.13",
"request-promise": "4.2.5",
"request-promise-native": "1.0.8",
"rimraf": "3.0.2",
"safe-buffer": "5.2.1",
"scanf": "1.2.0",
"sequelize": "6.37.3",
"sequelize-cli": "6.6.2",
"sequelize-typescript": "2.1.6",
"simple-git": "3.26.0",
"speakingurl": "14.0.1",
"sqlite3": "5.1.7",
"ssr-for-bots": "1.0.1-c",
"scanf": "1.1.2",
"sequelize": "5.21.5",
"sequelize-typescript": "1.1.0",
"simple-git": "2.39.1",
"speakingurl": "^14.0.1",
"sppull": "2.7.0",
"strict-password-generator": "1.1.2",
"stripe": "^18.0.0",
"super-strong-password-generator": "2.0.2",
"super-strong-password-generator-es": "2.0.2",
"svg2img": "^1.0.0-beta.2",
"swagger-client": "3.29.2",
"swagger-ui-dist": "5.17.14",
"tabulator-tables": "6.2.5",
"tedious": "18.6.1",
"swagger-client": "2.1.18",
"tedious": "9.2.1",
"textract": "2.5.0",
"twilio": "5.2.3",
"twitter-api-v2": "1.17.2",
"typeorm": "0.3.20",
"typescript": "5.5.4",
"url-join": "5.0.0",
"vhost": "3.0.2",
"vm2": "3.9.19",
"vm2-process": "2.1.5",
"typescript": "4.1.2",
"url-join": "4.0.1",
"vbscript-to-typescript": "1.0.8",
"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.26.1-alpha.1",
"winston": "3.14.2",
"ws": "8.18.0",
"yaml": "2.5.0",
"yarn": "1.22.22",
"zod-to-json-schema": "3.23.2"
"washyourmouthoutwithsoap": "1.0.2"
},
"devDependencies": {
"@types/lodash": "^4.17.20",
"@types/node": "^24.1.0",
"@types/node-fetch": "^2.6.12",
"@types/qrcode": "1.5.5",
"@types/url-join": "4.0.3",
"@typescript-eslint/eslint-plugin": "8.4.0",
"@typescript-eslint/parser": "8.4.0",
"ban-sensitive-files": "1.10.5",
"commitizen": "4.3.0",
"@types/url-join": "4.0.0",
"@types/winston": "2.4.4",
"ban-sensitive-files": "1.9.15",
"commitizen": "4.2.4",
"cz-conventional-changelog": "3.3.0",
"dependency-check": "4.1.0",
"git-issues": "1.3.1",
"license-checker": "25.0.1",
"ngrok": "4.0.1",
"nsp": "3.2.1",
"prettier-standard": "16.4.1",
"semantic-release": "24.1.0",
"simple-commit-message": "4.1.3",
"semantic-release": "17.4.3",
"simple-commit-message": "4.1.2",
"travis-deploy-once": "5.0.11",
"tslint": "6.1.3",
"tsx": "^4.19.1",
"vitest": "2.0.5"
"ts-node": "10.0.0",
"tslint": "6.1.2",
"tslint-microsoft-contrib": "^6.2.0",
"typedoc": "0.20.36"
},
"eslintConfig": {
"env": {
@ -324,9 +190,6 @@
"release": {
"tagFormat": "${version}",
"debug": true,
"branches": [
"main"
],
"verifyConditions": [
"@semantic-release/github"
],

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -17,11 +19,11 @@
| 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 |
| 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. |
| "General Bots" 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. |
@ -34,23 +36,20 @@
'use strict';
import crypto from 'crypto';
import urlJoin from 'url-join';
const crypto = require('crypto');
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
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 { GBMinInstance, IGBDialog, GBLog, IGBPackage } from 'botlib';
import urlJoin = require('url-join');
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
import { GBImporter } from '../../core.gbapp/services/GBImporterService';
import { Messages } from '../strings';
import { GBAdminService } from '../services/GBAdminService';
import { CollectionUtil } from 'pragmatismo-io-framework';
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 {
/**
* Dialogs for administration tasks.
*/
export class AdminDialog extends IGBDialog {
public static isIntentYes(locale, utterance) {
return utterance.toLowerCase().match(Messages[locale].affirmative_sentences);
}
@ -59,7 +58,15 @@ class AdminDialog extends IGBDialog {
return utterance.toLowerCase().match(Messages[locale].negative_sentences);
}
/**
* Setup dialogs flows and define services call.
*
* @param bot The bot adapter.
* @param min The minimal bot instance data.
*/
public static setup(min: GBMinInstance) {
// Setup services.
const importer = new GBImporter(min.core);
const deployer = new GBDeployer(min.core, importer);
@ -68,26 +75,24 @@ class AdminDialog extends IGBDialog {
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 {
}
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)) {
if (step.context.activity['originalText'] === process.env.ADMIN_PASS) {
// TODO: Per bot: min.instance.adminPass
await min.conversationalService.sendText(min, step, Messages[locale].welcome);
return await step.endDialog(true);
@ -102,26 +107,24 @@ class AdminDialog extends IGBDialog {
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 {
}
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'];
const sensitive = step.result;
if (await GBUtil.comparePassword( sensitive, min.instance.adminPass)) {
if (sensitive === min.instance.adminPass) {
await min.conversationalService.sendText(min, step, Messages[locale].welcome);
return await min.conversationalService.prompt(min, step, Messages[locale].which_task);
@ -132,8 +135,8 @@ class AdminDialog extends IGBDialog {
}
},
async step => {
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
const locale: string = step.context.activity.locale;
// tslint:disable-next-line:no-unsafe-any
const text: string = step.context.activity['originalText'];
const cmdName = text.split(' ')[0];
@ -143,6 +146,36 @@ class AdminDialog extends IGBDialog {
try {
if (text === 'quit') {
return await step.replaceDialog('/');
} else if (cmdName === 'deployPackage' || cmdName === 'dp') {
await GBAdminService.deployPackageCommand(min, text, deployer);
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'redeployPackage' || cmdName === 'rp') {
await min.conversationalService.sendText(min, step, 'The package is being *unloaded*...');
await GBAdminService.undeployPackageCommand(text, min);
await min.conversationalService.sendText(min, step, 'Now, *deploying* package...');
await GBAdminService.deployPackageCommand(min, text, deployer);
await min.conversationalService.sendText(
min,
step,
'Package deployed. Just need to rebuild the index... Doing it right now.'
);
await GBAdminService.rebuildIndexPackageCommand(min, deployer);
await min.conversationalService.sendText(min, step, 'Finished importing of that .gbkb package. Thanks.');
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'undeployPackage' || cmdName === 'up') {
await min.conversationalService.sendText(min, step, 'The package is being *undeployed*...');
await GBAdminService.undeployPackageCommand(text, min);
await min.conversationalService.sendText(min, step, 'Package *undeployed*.');
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'rebuildIndex' || cmdName === 'ri' || cmdName === 'Ri') {
await GBAdminService.rebuildIndexPackageCommand(min, deployer);
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'syncBotServer') {
await GBAdminService.syncBotServerCommand(min, deployer);
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'setupSecurity') {
return await step.beginDialog('/setupSecurity');
} else {
@ -165,15 +198,14 @@ class AdminDialog extends IGBDialog {
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 {
}
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');
@ -183,23 +215,17 @@ class AdminDialog extends IGBDialog {
}
},
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(';') : [];
// If the user says yes, starts publishing.
if (AdminDialog.isIntentYes(locale, step.result)) {
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;
}
}
for (let index = 0; index < min.appPackages.length; index++) {
const element = min.appPackages[index];
await element.onExchangeData(min, 'install', null);
// TODO: Filter just to the .gbapp being installed.
}
} else {
await min.conversationalService.sendText(min, step, Messages[locale].publish_canceled);
@ -208,38 +234,20 @@ class AdminDialog extends IGBDialog {
])
);
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 {
}
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') {
if (step.activeDialog.state.options.confirm || process.env.ADMIN_OPEN_PUBLISH === "true") {
return await step.next('sim');
} else {
const locale = step.context.activity.locale;
@ -247,9 +255,10 @@ class AdminDialog extends IGBDialog {
}
},
async step => {
min = GBServer.globals.minInstances.find(p => p.botId === min.botId);
const locale = step.context.activity.locale;
// If the user says yes, starts publishing.
if (AdminDialog.isIntentYes(locale, step.result)) {
let from = step.context.activity.from.id;
@ -257,7 +266,7 @@ class AdminDialog extends IGBDialog {
if (step.activeDialog.state.options.firstTime) {
canPublish = true;
} else {
canPublish = AdminDialog.canPublish(min, from) || process.env.ADMIN_OPEN_PUBLISH === 'true';
canPublish = AdminDialog.canPublish(min, from) || process.env.ADMIN_OPEN_PUBLISH === "true";
}
if (!canPublish) {
@ -270,7 +279,6 @@ class AdminDialog extends IGBDialog {
}
},
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);
@ -289,70 +297,44 @@ class AdminDialog extends IGBDialog {
const packages = [];
let skipError = false;
if (!filename || filename === '') {
if (filename === null || 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}.gbtheme`);
packages.push(`${botId}.gbdialog`);
packages.push(`${botId}.gbot`);
skipError = true;
} else {
await min.conversationalService.sendText(min, step, `Starting publishing for ${filename}...`);
packages.push(filename);
}
await CollectionUtil.asyncForEach(packages, async packageName => {
let cmd1;
try {
let cmd1;
if (packageName.indexOf('.') !== -1) {
cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${process.env.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);
}
await GBAdminService.deployPackageCommand(min, cmd1, deployer);
await min.conversationalService.sendText(min, step, `Finished publishing ${packageName}.`);
} catch (error) {
GBLog.error(error);
if (!skipError) {
await min.conversationalService.sendText(min, step, `ERROR: ${error}`);
if (
packageName.toLowerCase() === 'gbdialog' ||
packageName.toLowerCase() === 'gbdrive' ||
packageName.toLowerCase() === 'gbdata' ||
packageName.toLowerCase() === 'gbkb' ||
packageName.toLowerCase() === 'gbot' ||
packageName.toLowerCase() === 'gbtheme'
) {
packageName = `${min.botId}.${packageName}`;
return await step.replaceDialog('/ask', { isReturning: true });
}
}
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.`);
await min.conversationalService.sendText(min, step, Messages[locale].publish_success);
if (!step.activeDialog.state.options.confirm) {
return await step.replaceDialog('/ask', { isReturning: true });
} else {
@ -363,11 +345,17 @@ class AdminDialog extends IGBDialog {
);
}
/**
* Check if the specified phone can receive a message by running
* the /broadcast command with specific phone numbers.
* @param phone Phone number to check (eg.: +5521900002233)
*/
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);
const canPublish =
min.core.getParam(min.instance, 'Can Publish', null);
if (canPublish) {
list = list.concat(canPublish.split(';'));
}
@ -376,9 +364,7 @@ class AdminDialog extends IGBDialog {
if (!result && min.instance.params) {
const params = JSON.parse(min.instance.params);
if (params) {
return list.includes(params['Can Publish']);
}
return list.includes(params['Can Publish']);
}
return result;
}
@ -388,72 +374,56 @@ class AdminDialog extends IGBDialog {
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 {
}
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);
}
async step => {
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'];
step.activeDialog.state.authenticatorTenant = step.result;
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'];
step.activeDialog.state.authenticatorAuthorityHostUrl = step.result;
const tokenName = step.activeDialog.state.tokenName;
min.instance.authenticatorTenant =
step.activeDialog.state.authenticatorTenant;
min.instance.authenticatorAuthorityHostUrl =
step.activeDialog.state.authenticatorAuthorityHostUrl;
if (!tokenName) {
min.instance.authenticatorAuthorityHostUrl = step.activeDialog.state.authenticatorAuthorityHostUrl;
min.instance.authenticatorTenant = step.activeDialog.state.authenticatorTenant;
await min.adminService.updateSecurityInfo(
min.instance.instanceId,
step.activeDialog.state.authenticatorTenant,
step.activeDialog.state.authenticatorAuthorityHostUrl
);
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);
min.adminService.setValue(min.instance.instanceId, '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`;
const redirectUri = urlJoin(
min.instance.botEndpoint,
min.instance.botId,
'/token'
);
const url = `https://login.microsoftonline.com/${step.activeDialog.state.authenticatorTenant
}/oauth2/authorize?client_id=${min.instance.marketplaceId
}&response_type=code&redirect_uri=${redirectUri
}&scope=https://graph.microsoft.com/.default&state=${state}&response_mode=query`;
await min.conversationalService.sendText(min, step, Messages[locale].consent(url));
@ -463,5 +433,3 @@ class AdminDialog extends IGBDialog {
);
}
}
export { AdminDialog };

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -36,10 +38,8 @@
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
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';
import { AdminDialog } from './dialogs/AdminDialog';
import { GuaribasAdmin } from './models/AdminModel';
/**
* The package for admin.gbapp.
@ -47,27 +47,28 @@ import { GBLogEx } from '../core.gbapp/services/GBLogEx.js';
export class GBAdminPackage implements IGBPackage {
public sysPackages: IGBPackage[];
public async getDialogs (min: GBMinInstance) {
GBLogEx.verbose(min,`getDialogs called.`);
public async getDialogs(min: GBMinInstance) {
GBLog.verbose(`getDialogs called.`);
}
public async unloadPackage (core: IGBCoreService): Promise<void> {
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 unloadBot(min: GBMinInstance): Promise<void> {
GBLog.verbose(`unloadBot called.`);
}
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
GBLogEx.verbose(min, `onNewSession called.`);
public async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
GBLog.verbose(`onNewSession called.`);
}
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
GBLogEx.verbose(min,`onExchangeData called.`);
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
GBLog.verbose(`onExchangeData called.`);
}
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
public async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
core.sequelize.addModels([GuaribasAdmin]);
}
public async loadBot (min: GBMinInstance): Promise<void> {
public async loadBot(min: GBMinInstance): Promise<void> {
AdminDialog.setup(min);
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -34,27 +36,35 @@
'use strict';
import { Column, CreatedAt, DataType, Model, Table, UpdatedAt } from 'sequelize-typescript';
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
public instanceId: number;
@Column
public key: string;
@Column(DataType.STRING(4000))
declare value: string;
public value: string;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -35,26 +37,19 @@
'use strict';
import { AuthenticationContext, TokenResponse } from 'adal-node';
import { GBError, GBLog, GBMinInstance, IGBAdminService, IGBCoreService, IGBDeployer, IGBInstance } from 'botlib';
import { FindOptions } from 'sequelize/types';
import urlJoin from 'url-join';
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService.js';
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 msRestAzure from 'ms-rest-azure';
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';
import { GBLog, GBMinInstance, IGBAdminService, IGBCoreService, IGBDeployer, IGBInstance } from 'botlib';
import urlJoin = require('url-join');
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
import { GuaribasInstance } from '../../core.gbapp/models/GBModel';
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
import { GBImporter } from '../../core.gbapp/services/GBImporterService';
import { GBSharePointService } from '../../sharepoint.gblib/services/SharePointService';
import { GuaribasAdmin } from '../models/AdminModel';
const Path = require('path');
const msRestAzure = require('ms-rest-azure');
const PasswordGenerator = require('strict-password-generator').default;
const crypto = require("crypto");
/**
* Services for server administration.
@ -72,19 +67,21 @@ export class GBAdminService implements IGBAdminService {
}
public static generateUuid(): string {
return crypto.randomUUID();
return msRestAzure.generateUuid();
}
public static async getNodeVersion() {
public static getNodeVersion() {
const packageJson = urlJoin(process.cwd(), 'package.json');
const pkg = JSON.parse(await fs.readFile(packageJson, 'utf8'));
return pkg.engines.node.replace('=', '');
// tslint:disable-next-line: non-literal-require
const pjson = require(packageJson);
return pjson.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;
return credentials.tokenCache._entries[0].accessToken;
}
public static async getADALCredentialsFromUsername(username: string, password: string) {
@ -92,52 +89,68 @@ export class GBAdminService implements IGBAdminService {
}
public static getMobileCode() {
return this.getNumberIdentifier(6);
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: false,
lowerCaseAlpha: false,
number: true,
specialCharacter: false,
minimumLength: 6,
maximumLength: 6
};
return passwordGenerator.generatePassword(options);
}
public static getRndPassword(): string {
let password = caseSensitive_Numbs_SpecialCharacters_PW(15);
password = password.replace(/[\@\[\=\:\;\?\"\'\#]/gi, '*');
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: true,
lowerCaseAlpha: true,
number: true,
specialCharacter: true,
minimumLength: 14,
maximumLength: 14
};
let password = passwordGenerator.generatePassword(options);
password = password.replace(/[\@\[\=\:\;\?\"\'\#]/gi, '1');
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 password;
}
public static getRndReadableIdentifier() {
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: false,
lowerCaseAlpha: true,
number: false,
specialCharacter: false,
minimumLength: 14,
maximumLength: 14
};
return removeRepeatedChars(password, 1);
return passwordGenerator.generatePassword(options);
}
public static getRndReadableIdentifier(): string {
return lowercase_PW(14);
}
public static getNumberIdentifier() {
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: false,
lowerCaseAlpha: false,
number: true,
specialCharacter: false,
minimumLength: 14,
maximumLength: 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();
return passwordGenerator.generatePassword(options);
}
/**
* @see https://stackoverflow.com/a/52171480
*/
public static getHash(str: string, seed = 0) {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed;
public static getHash(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);
@ -148,40 +161,48 @@ export class GBAdminService implements IGBAdminService {
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
}
public static async undeployPackageCommand(text: string, min: GBMinInstance) {
public static async undeployPackageCommand(text: any, 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);
const localFolder = Path.join('work', `${min.instance.botId}.gbai`, Path.basename(packageName));
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
) {
public static async deployPackageCommand(min: GBMinInstance, 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);
if (!this.isSharePointPath(packageName)) {
const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
if (additionalPath === undefined) {
throw new Error('ADDITIONAL_DEPLOY_PATH is not set and deployPackage was called.');
}
await deployer.deployPackage(min, urlJoin(additionalPath, packageName));
} else {
const siteName = text.split(' ')[1];
const folderName = text.split(' ')[2];
await deployer['deployPackage2'](min, user, localFolder, true);
const s = new GBSharePointService();
const localFolder = Path.join('work', `${min.instance.botId}.gbai`, Path.basename(folderName));
// .gbot packages are handled using storage API, so no download
// of local resources is required.
await deployer['downloadFolder'](min,
Path.join('work', `${min.instance.botId}.gbai`),
Path.basename(folderName));
await deployer.deployPackage(min, localFolder);
}
}
public static async rebuildIndexPackageCommand(min: GBMinInstance, deployer: GBDeployer) {
const service = await AzureDeployerService.createInstance(deployer);
const searchIndex = min.instance.searchIndex
? min.instance.searchIndex
: GBServer.globals.minBoot.instance.searchIndex;
await deployer.rebuildIndex(min.instance, service.getKBSearchSchema(searchIndex));
public static async rebuildIndexPackageCommand(min: GBMinInstance, deployer: IGBDeployer) {
await deployer.rebuildIndex(
min.instance,
new AzureDeployerService(deployer).getKBSearchSchema(min.instance.searchIndex)
);
}
public static async syncBotServerCommand(min: GBMinInstance, deployer: GBDeployer) {
@ -191,8 +212,8 @@ export class GBAdminService implements IGBAdminService {
}
public async setValue(instanceId: number, key: string, value: string) {
const options = <FindOptions>{ where: {} };
options.where = { key: key, instanceId: instanceId };
const options = { where: {} };
options.where = { key: key };
let admin = await GuaribasAdmin.findOne(options);
if (admin === null) {
admin = new GuaribasAdmin();
@ -208,7 +229,7 @@ export class GBAdminService implements IGBAdminService {
authenticatorTenant: string,
authenticatorAuthorityHostUrl: string
): Promise<IGBInstance> {
const options = <FindOptions>{ where: {} };
const options = { where: {} };
options.where = { instanceId: instanceId };
const item = await GuaribasInstance.findOne(options);
item.authenticatorTenant = authenticatorTenant;
@ -218,120 +239,61 @@ export class GBAdminService implements IGBAdminService {
}
public async getValue(instanceId: number, key: string): Promise<string> {
const options = <FindOptions>{ where: {} };
const options = { 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}).`);
public async acquireElevatedToken(instanceId: number): Promise<string> {
// TODO: Use boot bot as base for authentication.
let expiresOnV;
try {
expiresOnV = await this.getValue(instanceId, `${tokenName}expiresOn`);
} catch (error) {
throw new Error(`/setupSecurity is required before running /publish.`);
}
const botId = GBConfigService.get('BOT_ID');
instanceId = (await this.core.loadInstanceByBotId(botId)).instanceId;
return new Promise<string>(async (resolve, reject) => {
const instance = await this.core.loadInstanceById(instanceId);
const expiresOn = new Date(expiresOnV);
const expiresOn = new Date(await this.getValue(instanceId, 'expiresOn'));
if (expiresOn.getTime() > new Date().getTime()) {
const accessToken = await this.getValue(instanceId, `${tokenName}accessToken`);
const accessToken = await this.getValue(instanceId, 'accessToken');
resolve(accessToken);
} else {
if (tokenName && !root) {
const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`);
const authorizationUrl = urlJoin(
instance.authenticatorAuthorityHostUrl,
instance.authenticatorTenant,
'/oauth2/authorize'
);
let url = urlJoin(host, tenant, 'oauth/token');
let buff = new Buffer(`${clientId}:${clientSecret}`);
const base64 = buff.toString('base64');
const refreshToken = await this.getValue(instanceId, 'refreshToken');
const resource = 'https://graph.microsoft.com';
const authenticationContext = new AuthenticationContext(authorizationUrl);
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) {
authenticationContext.acquireTokenWithRefreshToken(
refreshToken,
instance.marketplaceId,
instance.marketplacePassword,
resource,
async (err, res) => {
if (err !== null) {
reject(err);
} else {
const token = res as TokenResponse;
try {
await this.setValue(instanceId, 'accessToken', token.accessToken);
await this.setValue(instanceId, 'refreshToken', token.refreshToken);
await this.setValue(instanceId, 'expiresOn', token.expiresOn.toString());
resolve(token.accessToken);
} catch (error) {
reject(err);
} else {
const token = res as TokenResponse;
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> {}
public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise<void> { }
}

View file

@ -1,9 +1,9 @@
export const Messages = {
'en-US': {
authenticate: 'Please, authenticate:',
welcome: 'Welcome to pragmatismo.com.br GeneralBots Administration.',
welcome: 'Welcome to Pragmatismo.io GeneralBots Administration.',
which_task: 'Which task do you wanna run now?',
working: command => `I'm working on ${command}...`,
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.`,
@ -12,7 +12,7 @@ export const Messages = {
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}).`,
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): ',
@ -26,9 +26,9 @@ export const Messages = {
},
'pt-BR': {
authenticate: 'Please, authenticate:',
welcome: 'Welcome to pragmatismo.com.br GeneralBots Administration.',
welcome: 'Welcome to Pragmatismo.io GeneralBots Administration.',
which_task: 'Which task do you wanna run now?',
working: command => `I'm working on ${command}...`,
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.`,
@ -37,7 +37,7 @@ export const Messages = {
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}).`,
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): ',

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -36,33 +38,35 @@
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
import { Sequelize } from 'sequelize-typescript';
import { GuaribasConversation, GuaribasConversationMessage } from './models/index.js';
import { GuaribasConversation, GuaribasConversationMessage } from './models';
/**
* .gblib Package handler.
*/
export class GBAnalyticsPackage implements IGBPackage {
public sysPackages: IGBPackage[];
public async getDialogs (min: GBMinInstance) {
public async getDialogs(min: GBMinInstance) {
GBLog.verbose(`getDialogs called.`);
}
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
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> {
public async unloadPackage(core: IGBCoreService): Promise<void> {
GBLog.verbose(`unloadPackage called.`);
}
public async loadBot (min: GBMinInstance): Promise<void> {
public async loadBot(min: GBMinInstance): Promise<void> {
GBLog.verbose(`loadBot called.`);
}
public async unloadBot (min: GBMinInstance): Promise<void> {
public async unloadBot(min: GBMinInstance): Promise<void> {
GBLog.verbose(`unloadBot called.`);
}
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
public async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
GBLog.verbose(`onNewSession called.`);
}
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
GBLog.verbose(`onExchangeData called.`);
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -52,61 +54,58 @@ import {
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';
import { GuaribasChannel, GuaribasInstance } from '../../core.gbapp/models/GBModel';
import { GuaribasSubject } from '../../kb.gbapp/models';
import { GuaribasUser } from '../../security.gbapp/models';
/**
* A conversation that groups many messages.
*/
@Table
export class GuaribasConversation extends Model<GuaribasConversation> {
@PrimaryKey
@AutoIncrement
@Column(DataType.INTEGER)
declare conversationId: number;
@Column
public conversationId: number;
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
declare instanceId: number;
@Column
public instanceId: number;
@ForeignKey(() => GuaribasSubject)
@Column(DataType.INTEGER)
declare startSubjectId: number;
@Column
public startSubjectId: number;
@BelongsTo(() => GuaribasSubject)
declare startSubject: GuaribasSubject;
public startSubject: GuaribasSubject;
@ForeignKey(() => GuaribasChannel)
@Column(DataType.INTEGER)
declare channelId: string;
@Column
public channelId: string;
@Column(DataType.DATE)
declare rateDate: Date;
@Column public rateDate: Date;
@Column(DataType.FLOAT)
declare rate: number;
@Column
public rate: number;
@Column(DataType.STRING(512))
declare feedback: string;
@Column
public feedback: string;
@Column
@CreatedAt
@Column(DataType.DATE)
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@UpdatedAt
declare updatedAt: Date;
@Column(DataType.STRING(255))
declare text: string;
@Column public text: string;
@ForeignKey(() => GuaribasUser)
@Column(DataType.INTEGER)
declare startedByUserId: number;
@Column
public startedByUserId: number;
@BelongsTo(() => GuaribasUser)
declare startedBy: GuaribasUser;
public startedBy: GuaribasUser;
}
/**
@ -114,43 +113,44 @@ export class GuaribasConversation extends Model<GuaribasConversation> {
*/
@Table
export class GuaribasConversationMessage extends Model<GuaribasConversationMessage> {
@PrimaryKey
@AutoIncrement
@Column(DataType.INTEGER)
declare conversationMessageId: number;
@Column
public conversationMessageId: number;
@ForeignKey(() => GuaribasSubject)
@Column(DataType.INTEGER)
declare subjectId: number;
@Column
public subjectId: number;
@Column(DataType.TEXT)
declare content: string;
public content: string;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
//tslint:disable-next-line:no-use-before-declare
@ForeignKey(() => GuaribasConversation)
@Column(DataType.INTEGER)
declare conversationId: number;
@Column
public conversationId: number;
//tslint:disable-next-line:no-use-before-declare
@BelongsTo(() => GuaribasConversation)
declare conversation: GuaribasConversation;
public conversation: GuaribasConversation;
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
declare instanceId: number;
@Column
public instanceId: number;
@ForeignKey(() => GuaribasUser)
@Column(DataType.INTEGER)
declare userId: number;
@Column
public userId: number;
@BelongsTo(() => GuaribasUser)
declare user: GuaribasUser;
public user: GuaribasUser;
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -33,16 +35,18 @@
*/
import { AzureText } from 'pragmatismo-io-framework';
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';
import { GBServer } from '../../../src/app';
import { GuaribasUser } from '../../security.gbapp/models';
import { GuaribasConversation, GuaribasConversationMessage } from '../models';
/**
* Base services for Bot Analytics.
*/
export class AnalyticsService {
public async createConversation (user: GuaribasUser): Promise<GuaribasConversation> {
public async createConversation(
user: GuaribasUser
): Promise<GuaribasConversation> {
const conversation = new GuaribasConversation();
conversation.startedBy = user;
conversation.startedByUserId = user.userId;
@ -51,24 +55,21 @@ export class AnalyticsService {
return await conversation.save();
}
public async updateConversationSuggestion (
instanceId: number,
conversationId: string,
feedback: string,
locale: string
): Promise<number> {
public async updateConversationSuggestion(instanceId: number,
conversationId: string, feedback: string, locale: string): Promise<number> {
const minBoot = GBServer.globals.minBoot as any;
const rate = await AzureText.getSentiment(
minBoot.instance.textAnalyticsKey ? minBoot.instance.textAnalyticsKey : minBoot.instance.textAnalyticsKey,
minBoot.instance.textAnalyticsEndpoint
? minBoot.instance.textAnalyticsEndpoint
: minBoot.instance.textAnalyticsEndpoint,
minBoot.instance.textAnalyticsKey ? minBoot.instance.textAnalyticsKey :
minBoot.instance.textAnalyticsKey,
minBoot.instance.textAnalyticsEndpoint ? minBoot.instance.textAnalyticsEndpoint :
minBoot.instance.textAnalyticsEndpoint,
locale,
feedback
);
const options = <FindOptions>{ where: {} };
options.where = { conversationId: conversationId, instanceId: instanceId };
const options = { where: { } };
options.where = { conversationId: conversationId, instanceId: instanceId };
const item = await GuaribasConversation.findOne(options);
item.feedback = feedback;
@ -77,20 +78,21 @@ export class AnalyticsService {
await item.save();
return rate;
}
public async createMessage (
public async createMessage(
instanceId: number,
conversationId: number,
conversation: GuaribasConversation,
userId: number,
content: string
): Promise<GuaribasConversationMessage> {
const message = GuaribasConversationMessage.build();
message.content = typeof content === 'object' ? JSON.stringify(content) : content;
message.content = content;
message.instanceId = instanceId;
message.userId = userId;
message.conversationId = conversationId;
message.conversationId = conversation.conversationId;
return await message.save();
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -35,22 +37,19 @@
'use strict';
import { GBLog, IGBInstallationDeployer, IGBInstance } from 'botlib';
import fs from 'fs/promises';
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService.js';
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService.js';
import scanf from 'scanf';
import { AzureDeployerService } from '../services/AzureDeployerService.js';
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
import { GBUtil } from '../../../src/util.js';
import * as fs from 'fs';
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService';
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService';
const scanf = require('scanf');
/**
* Handles command-line dialog for getting info for Boot Bot.
*/
export class StartDialog {
public static async createBaseInstance (deployer, freeTier) {
public static async createBaseInstance(installationDeployer: IGBInstallationDeployer) {
// No .env so asks for cloud credentials to start a new farm.
if (!await GBUtil.exists(`.env`)) {
if (!fs.existsSync(`.env`)) {
process.stdout.write(
'A empty enviroment is detected. To start automatic deploy, please enter some information:\n'
);
@ -74,16 +73,13 @@ export class StartDialog {
// Connects to the cloud and retrieves subscriptions.
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
const list = await installationDeployer.getSubscriptions(credentials);
let subscriptionId: string;
while (subscriptionId === undefined) {
const list = await (new AzureDeployerService()).getSubscriptions(credentials);
subscriptionId = this.retrieveSubscriptionId(list);
}
const installationDeployer = await AzureDeployerService.createInstanceWithADALCredentials(
deployer, freeTier, subscriptionId, credentials);
let location: string;
while (location === undefined) {
location = this.retrieveLocation();
@ -100,7 +96,6 @@ export class StartDialog {
}
// Prepares the first instance on bot farm.
const instance = <IGBInstance>{};
instance.botId = botId;
@ -111,12 +106,12 @@ export class StartDialog {
instance.cloudLocation = location;
instance.marketplaceId = appId;
instance.marketplacePassword = appPassword;
instance.adminPass = await GBUtil.hashPassword(GBAdminService.getRndPassword());
instance.adminPass = GBAdminService.getRndPassword();
return { instance, credentials, subscriptionId , installationDeployer};
return { instance, credentials, subscriptionId };
}
private static retrieveUsername () {
private static retrieveUsername() {
let value = GBConfigService.get('CLOUD_USERNAME');
if (value === undefined) {
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_USERNAME:`);
@ -126,7 +121,7 @@ export class StartDialog {
return value;
}
private static retrievePassword () {
private static retrievePassword() {
let password = GBConfigService.get('CLOUD_PASSWORD');
if (password === undefined) {
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_PASSWORD:`);
@ -136,7 +131,7 @@ export class StartDialog {
return password;
}
private static retrieveBotId () {
private static retrieveBotId() {
let botId = GBConfigService.get('BOT_ID');
if (botId === undefined) {
process.stdout.write(
@ -151,11 +146,12 @@ cannot start or end with or contain consecutive dashes and having 4 to 42 charac
return botId;
}
/**
*
*
* Update Manifest in Azure: "signInAudience": "AzureADandPersonalMicrosoftAccount" and "accessTokenAcceptedVersion": 2.
*/
private static retrieveAppId () {
private static retrieveAppId() {
let appId = GBConfigService.get('MARKETPLACE_ID');
if (appId === undefined) {
process.stdout.write(
@ -171,7 +167,7 @@ generate manually an App ID and App Secret.\n`
return appId;
}
private static retrieveAppPassword () {
private static retrieveAppPassword() {
let appPassword = GBConfigService.get('MARKETPLACE_SECRET');
if (appPassword === undefined) {
process.stdout.write('Generated Password (MARKETPLACE_SECRET):');
@ -181,16 +177,12 @@ generate manually an App ID and App Secret.\n`
return appPassword;
}
private static retrieveSubscriptionId (list) {
private static retrieveSubscriptionId(list) {
let subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
if (subscriptionId){
return subscriptionId;
}
const map = {};
let index = 1;
list.forEach(element => {
GBLogEx.info(0, `${index}: ${element.displayName} (${element.subscriptionId})`);
GBLog.info(`${index}: ${element.displayName} (${element.subscriptionId})`);
map[index++] = element;
});
let subscriptionIndex;
@ -203,7 +195,7 @@ generate manually an App ID and App Secret.\n`
return subscriptionId;
}
private static retrieveLocation () {
private static retrieveLocation() {
let location = GBConfigService.get('CLOUD_LOCATION');
if (location === undefined) {
process.stdout.write('CLOUD_LOCATION (eg. westus):');

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -41,26 +43,27 @@ import { Sequelize } from 'sequelize-typescript';
* Package for Azure Deployer.
*/
export class GBAzureDeployerPackage implements IGBPackage {
public sysPackages: IGBPackage[];
public async getDialogs (min: GBMinInstance) {
public sysPackages: IGBPackage[];
public async getDialogs(min: GBMinInstance) {
GBLog.verbose(`getDialogs called.`);
}
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
public async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
GBLog.verbose(`loadPackage called.`);
}
public async unloadPackage (core: IGBCoreService): Promise<void> {
public async unloadPackage(core: IGBCoreService): Promise<void> {
GBLog.verbose(`unloadPackage called.`);
}
public async loadBot (min: GBMinInstance): Promise<void> {
public async loadBot(min: GBMinInstance): Promise<void> {
GBLog.verbose(`loadBot called.`);
}
public async unloadBot (min: GBMinInstance): Promise<void> {
public async unloadBot(min: GBMinInstance): Promise<void> {
GBLog.verbose(`unloadBot called.`);
}
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
public async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
GBLog.verbose(`onNewSession called.`);
}
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
GBLog.verbose(`onExchangeData called.`);
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -34,30 +36,33 @@
'use strict';
import urlJoin from 'url-join';
import { HttpMethods, ServiceClient, TokenCredentials, WebResource } from '@azure/ms-rest-js';
import { CognitiveServicesManagementClient } from '@azure/arm-cognitiveservices';
import { ResourceManagementClient } from '@azure/arm-resources';
import { SubscriptionClient } from '@azure/arm-subscriptions';
import { SearchManagementClient } from '@azure/arm-search';
import { Server, SqlManagementClient } from '@azure/arm-sql';
import { WebSiteManagementClient } from '@azure/arm-appservice';
import { AppServicePlan, Site, SiteLogsConfig, SiteSourceControl } from '@azure/arm-appservice';
import { HttpHeaders, HttpMethods, ServiceClient, WebResource } from '@azure/ms-rest-js';
import { CognitiveServicesManagementClient } from 'azure-arm-cognitiveservices';
import { ResourceManagementClient, SubscriptionClient } from 'azure-arm-resource';
import { SearchManagementClient } from 'azure-arm-search';
import { SqlManagementClient } from 'azure-arm-sql';
import { WebSiteManagementClient } from 'azure-arm-website';
//tslint:disable-next-line:no-submodule-imports
import { AppServicePlan, Site, SiteConfigResource, SiteLogsConfig, SiteSourceControl } from 'azure-arm-website/lib/models';
import { GBLog, IGBInstallationDeployer, IGBInstance, IGBDeployer, IGBCoreService } from 'botlib';
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService.js';
import { GBCorePackage } from '../../../packages/core.gbapp/index.js';
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService.js';
import { GBDeployer } from '../../../packages/core.gbapp/services/GBDeployer.js';
import { Account } from '@azure/arm-cognitiveservices';
import MicrosoftGraph from '@microsoft/microsoft-graph-client';
import { Spinner } from 'cli-spinner';
import * as publicIp from 'public-ip';
import { AccessToken, TokenCredential } from '@azure/core-auth';
import { GBUtil } from '../../../src/util.js';
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService';
import { GBCorePackage } from '../../../packages/core.gbapp';
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService';
import { GBDeployer } from '../../../packages/core.gbapp/services/GBDeployer';
const MicrosoftGraph = require("@microsoft/microsoft-graph-client");
const WebSiteResponseTimeout = 900;
const Spinner = require('cli-spinner').Spinner;
// tslint:disable-next-line: no-submodule-imports
import * as simplegit from 'simple-git/promise';
const git = simplegit();
// tslint:disable-next-line:no-submodule-imports
import { CognitiveServicesAccount } from 'azure-arm-cognitiveservices/lib/models';
import urlJoin = require('url-join');
const iconUrl = 'https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png';
const publicIp = require('public-ip');
const WebSiteResponseTimeout = 900;
/**
* Deployer for Microsoft cloud.
*/
@ -65,13 +70,13 @@ export class AzureDeployerService implements IGBInstallationDeployer {
public apiVersion = '2017-12-01';
public defaultEndPoint = 'http://localhost:4242';
public instance: IGBInstance;
public cloud: ResourceManagementClient;
public resourceClient: ResourceManagementClient.ResourceManagementClient;
public webSiteClient: WebSiteManagementClient;
public storageClient: SqlManagementClient;
public cognitiveClient: CognitiveServicesManagementClient;
public searchClient: SearchManagementClient;
public provider = 'Microsoft.BotService';
public subscriptionClient: SubscriptionClient;
public subscriptionClient: SubscriptionClient.SubscriptionClient;
public accessToken: string;
public location: string;
public subscriptionId: string;
@ -80,39 +85,29 @@ export class AzureDeployerService implements IGBInstallationDeployer {
public core: IGBCoreService;
private freeTier: boolean;
constructor(deployer: IGBDeployer, freeTier: boolean = true) {
this.deployer = deployer;
this.freeTier = freeTier;
}
public async runSearch(instance: IGBInstance) {
await this.deployer.rebuildIndex(instance, this.getKBSearchSchema(instance.searchIndex));
}
public static async createInstance(deployer: GBDeployer): Promise<AzureDeployerService> {
public static async createInstance(deployer: GBDeployer, freeTier: boolean = true): Promise<AzureDeployerService> {
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
return await this.createInstanceWithCredentials(deployer, freeTier, subscriptionId, username, password);
}
public static async createInstanceWithADALCredentials(deployer: GBDeployer, freeTier: boolean = true,
subscriptionId: string, credentials): Promise<AzureDeployerService> {
const service = new AzureDeployerService();
const service = new AzureDeployerService(deployer);
service.core = deployer.core;
service.deployer = deployer;
service.freeTier = freeTier;
const token = credentials['tokenCache']._entries[0];
await service.initServices(token.accessToken, token.expiresOn, subscriptionId);
service.initServices(credentials, subscriptionId);
return service;
}
public static async createInstanceWithCredentials(deployer: GBDeployer, freeTier: boolean = true,
subscriptionId: string, username: string, password: string): Promise<AzureDeployerService> {
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
return await this.createInstanceWithADALCredentials(deployer, freeTier, subscriptionId, credentials);
}
private static createRequestObject(url: string, accessToken: string, verb: HttpMethods, body: string) {
const req = new WebResource();
req.method = verb;
@ -126,12 +121,12 @@ export class AzureDeployerService implements IGBInstallationDeployer {
}
public async getSubscriptions(credentials) {
const subscriptionClient = new SubscriptionClient(credentials);
const subscriptionClient = new SubscriptionClient.default(credentials);
return subscriptionClient.subscriptions.list();
}
public getKBSearchSchema(indexName: any) {
public getKBSearchSchema(indexName) {
return {
name: indexName,
fields: [
@ -242,20 +237,23 @@ export class AzureDeployerService implements IGBInstallationDeployer {
};
}
public async botExists(botId: string) {
public async botExists(botId) {
const baseUrl = `https://management.azure.com/`;
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
const httpClient = new ServiceClient();
const query = `providers/${this.provider}/checkNameAvailability/Action?api-version=${this.apiVersion}`;
const query = `providers/${this.provider
}/checkNameAvailability/Action?api-version=${this.apiVersion}`;
const url = urlJoin(baseUrl, query);
const body = {
name: botId,
type: 'botServices'
type: "botServices"
};
const req = AzureDeployerService.createRequestObject(url, accessToken, 'POST', JSON.stringify(body));
@ -264,12 +262,7 @@ export class AzureDeployerService implements IGBInstallationDeployer {
return !res.parsedBody.valid;
}
public async updateBotProxy(botId: string, group: string, endpoint: string) {
if (!await this.botExists(botId)) {
GBLog.error(`Bot ${botId} does not exist on cloud.`);
return;
}
public async updateBotProxy(botId, group, endpoint) {
const baseUrl = `https://management.azure.com/`;
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
@ -284,7 +277,8 @@ export class AzureDeployerService implements IGBInstallationDeployer {
}
};
const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`;
const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider
}/botServices/${botId}?api-version=${this.apiVersion}`;
const url = urlJoin(baseUrl, query);
const req = AzureDeployerService.createRequestObject(url, accessToken, 'PATCH', JSON.stringify(parameters));
const res = await httpClient.sendRequest(req);
@ -292,10 +286,11 @@ export class AzureDeployerService implements IGBInstallationDeployer {
if (!JSON.parse(res.bodyAsText).id) {
throw res.bodyAsText;
}
GBLogEx.info(0, `Bot proxy updated at: ${endpoint}.`);
GBLog.info(`Bot proxy updated at: ${endpoint}.`);
}
public async updateBot(botId: string, group: string, name: string, description: string, endpoint: string) {
public async updateBot(botId: string, group: string, name: string,
description: string, endpoint: string) {
const baseUrl = `https://management.azure.com/`;
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
@ -313,7 +308,8 @@ export class AzureDeployerService implements IGBInstallationDeployer {
}
};
const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`;
const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider
}/botServices/${botId}?api-version=${this.apiVersion}`;
const url = urlJoin(baseUrl, query);
const req = AzureDeployerService.createRequestObject(url, accessToken, 'PATCH', JSON.stringify(parameters));
const res = await httpClient.sendRequest(req);
@ -321,10 +317,10 @@ export class AzureDeployerService implements IGBInstallationDeployer {
if (!JSON.parse(res.bodyAsText).id) {
throw res.bodyAsText;
}
GBLogEx.info(0, `Bot updated at: ${endpoint}.`);
GBLog.info(`Bot updated at: ${endpoint}.`);
}
public async deleteBot(botId: string, group: string) {
public async deleteBot(botId: string, group) {
const baseUrl = `https://management.azure.com/`;
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
@ -333,91 +329,66 @@ export class AzureDeployerService implements IGBInstallationDeployer {
const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
const httpClient = new ServiceClient();
const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`;
const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider
}/botServices/${botId}?api-version=${this.apiVersion}`;
const url = urlJoin(baseUrl, query);
const req = AzureDeployerService.createRequestObject(url, accessToken, 'DELETE', undefined);
const res = await httpClient.sendRequest(req);
if (res.bodyAsText !== '') {
if (res.bodyAsText !== "") {
throw res.bodyAsText;
}
GBLogEx.info(0, `Bot ${botId} was deleted from the provider.`);
GBLog.info(`Bot ${botId} was deleted from the provider.`);
}
public async openStorageFirewall(groupName: string, serverName: string) {
public async openStorageFirewall(groupName, serverName) {
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
const ip = await publicIp.publicIpv4();
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
const storageClient = new SqlManagementClient(credentials, subscriptionId);
const ip = await publicIp.v4();
let params = {
startIpAddress: ip,
endIpAddress: ip
};
await this.storageClient.firewallRules.createOrUpdate(groupName, serverName, 'gb', params);
await storageClient.firewallRules.createOrUpdate(groupName, serverName, 'gb', params);
}
public async deployFarm(
proxyAddress: string,
instance: IGBInstance,
credentials: any,
credentials,
subscriptionId: string
): Promise<IGBInstance> {
return await this.deployFarm2(proxyAddress,
instance,
credentials,
subscriptionId);
}
public async deployFarm2(
proxyAddress: string,
instance: IGBInstance,
credentials: any,
subscriptionId: string
) {
const culture = 'en-us';
const token = credentials['tokenCache']._entries[0];
await this.initServices(token.accessToken, token.expiresOn, subscriptionId);
this.initServices(credentials, subscriptionId);
const spinner = new Spinner('%s');
spinner.start();
spinner.setSpinnerString('|/-\\');
let keys: any;
const name = instance.botId;
GBLogEx.info(0, `Enabling resource providers...`);
await this.enableResourceProviders('Microsoft.CognitiveServices');
await this.enableResourceProviders('Microsoft.BotService');
await this.enableResourceProviders('Microsoft.Search');
await this.enableResourceProviders('Microsoft.Web');
await this.enableResourceProviders('Microsoft.Sql');
GBLogEx.info(0, `Deploying Deploy Group (It may take a few minutes)...`);
GBLog.info(`Deploying Deploy Group (It may take a few minutes)...`);
await this.createDeployGroup(name, instance.cloudLocation);
let serverFarm;
let serverName;
GBLog.info(`Deploying Bot Server...`);
const serverFarm = await this.createHostingPlan(name, `${name}-server-plan`, instance.cloudLocation);
const serverName = `${name}-server`;
await this.createServer(serverFarm.id, name, serverName, instance.cloudLocation);
if (process.env.DEPLOY_WEB) {
GBLogEx.info(0, `Deploying Bot Server...`);
serverFarm = await this.createHostingPlan(name, `${name}-server-plan`, instance.cloudLocation);
serverName = `${name}-server`;
await this.createServer(serverFarm.id, name, serverName, instance.cloudLocation);
}
GBLogEx.info(0, `Deploying Bot Storage...`);
GBLog.info(`Deploying Bot Storage...`);
const administratorLogin = `sa${GBAdminService.getRndReadableIdentifier()}`;
const administratorPassword = GBAdminService.getRndPassword();
const storageServer = `${name.toLowerCase()}-storage-server`;
const storageName = `${name}-storage`;
await this.createStorageServer(
name,
storageServer,
administratorLogin,
administratorPassword,
storageServer,
instance.cloudLocation
await this.createStorageServer(name, storageServer, administratorLogin,
administratorPassword, storageServer, instance.cloudLocation
);
await this.createStorage(name, storageServer, storageName, instance.cloudLocation);
instance.storageUsername = administratorLogin;
@ -426,75 +397,64 @@ export class AzureDeployerService implements IGBInstallationDeployer {
instance.storageDialect = 'mssql';
instance.storageServer = `${storageServer}.database.windows.net`;
// TODO: Enable in .env
// GBLogEx.info(min, `Deploying Search...`);
// const searchName = `${name}-search`.toLowerCase();
// await this.createSearch(name, searchName, instance.cloudLocation);
// const searchKeys = await this.searchClient.adminKeys.get(name, searchName);
// instance.searchHost = `${searchName}.search.windows.net`;
// instance.searchIndex = 'azuresql-index';
// instance.searchIndexer = 'azuresql-indexer';
// instance.searchKey = searchKeys.primaryKey;
GBLog.info(`Deploying Search...`);
const searchName = `${name}-search`.toLowerCase();
await this.createSearch(name, searchName, instance.cloudLocation);
const searchKeys = await this.searchClient.adminKeys.get(name, searchName);
instance.searchHost = `${searchName}.search.windows.net`;
instance.searchIndex = 'azuresql-index';
instance.searchIndexer = 'azuresql-indexer';
instance.searchKey = searchKeys.primaryKey;
// GBLogEx.info(min, `Deploying Speech...`);
// const speech = await this.createSpeech(name, `${name}speech`, instance.cloudLocation);
// keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
// instance.speechEndpoint = speech.properties.endpoint;
// instance.speechKey = keys.key1;
GBLog.info(`Deploying Speech...`);
const speech = await this.createSpeech(name, `${name}-speech`, instance.cloudLocation);
keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
instance.speechEndpoint = speech.endpoint;
instance.speechKey = keys.key1;
// GBLogEx.info(min, `Deploying Text Analytics...`);
// const textAnalytics = await this.createTextAnalytics(name, `${name}-textanalytics`, instance.cloudLocation);
// instance.textAnalyticsEndpoint = textAnalytics.properties.endpoint.replace(`/text/analytics/v2.0`, '');
GBLog.info(`Deploying Text Analytics...`);
const textAnalytics = await this.createTextAnalytics(name, `${name}-textanalytics`, instance.cloudLocation);
keys = await this.cognitiveClient.accounts.listKeys(name, textAnalytics.name);
instance.textAnalyticsEndpoint = textAnalytics.endpoint.replace(`/text/analytics/v2.0`, '');
instance.textAnalyticsKey = keys.key1;
GBLogEx.info(0, `Deploying SpellChecker...`);
GBLog.info(`Deploying SpellChecker...`);
const spellChecker = await this.createSpellChecker(name, `${name}-spellchecker`);
instance.spellcheckerEndpoint = spellChecker.properties.endpoint;
keys = await this.cognitiveClient.accounts.listKeys(name, spellChecker.name);
instance.spellcheckerKey = keys.key1;
instance.spellcheckerEndpoint = spellChecker.endpoint;
// GBLogEx.info(min, `Deploying NLP...`);
// const nlp = await this.createNLP(name, `${name}-nlp`, instance.cloudLocation);
// const nlpa = await this.createNLPAuthoring(name, `${name}-nlpa`, instance.cloudLocation);
// instance.nlpEndpoint = nlp.properties.endpoint;
GBLog.info(`Deploying NLP...`);
const nlp = await this.createNLP(name, `${name}-nlp`, instance.cloudLocation);
const nlpa = await this.createNLPAuthoring(name, `${name}-nlpa`, instance.cloudLocation);
keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name);
let authoringKeys = await this.cognitiveClient.accounts.listKeys(name, nlpa.name);
instance.nlpAuthoringKey = authoringKeys.key1;
const nlpAppId = await this.createNLPService(name, name, instance.cloudLocation, culture, instance.nlpAuthoringKey);
instance.nlpEndpoint = nlp.endpoint;
instance.nlpKey = keys.key1;
instance.nlpAppId = nlpAppId;
GBLogEx.info(0, `Deploying Bot...`);
instance.botEndpoint = 'TODO: remove this column.';
GBLog.info(`Deploying Bot...`);
instance.botEndpoint = this.defaultEndPoint;
instance = await this.internalDeployBot(
instance,
this.accessToken,
name,
name,
name,
'General BootBot',
`${proxyAddress}/api/messages/${name}`,
'global',
instance.nlpAppId,
instance.nlpKey,
instance.marketplaceId,
instance.marketplacePassword,
instance, this.accessToken, name, name, name, 'General BootBot',
`${proxyAddress}/api/messages/${name}`, 'global',
instance.nlpAppId, instance.nlpKey, instance.marketplaceId, instance.marketplacePassword,
instance.cloudSubscriptionId
);
GBLogEx.info(0, `Waiting one minute to finish NLP service and keys creation...`);
await GBUtil.sleep(60000);
// keys = await this.cognitiveClient.accounts.listKeys(name, textAnalytics.name);
// instance.textAnalyticsKey = keys.key1;
keys = await this.cognitiveClient.accounts.listKeys(name, spellChecker.name);
instance.spellcheckerKey = keys.key1;
// let authoringKeys = await this.cognitiveClient.accounts.listKeys(name, nlpa.name);
// keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name);
// instance.nlpKey = keys.key1;
GBLog.info('Updating server environment variables...');
await this.updateWebisteConfig(name, serverName, serverFarm.id, instance);
// instance.nlpAuthoringKey = authoringKeys.key1;
// const nlpAppId = await this.createNLPService(name, name, instance.cloudLocation, culture, instance.nlpAuthoringKey);
// instance.nlpAppId = nlpAppId;
if (process.env.DEPLOY_WEB) {
GBLogEx.info(0, 'Updating server environment variables...');
await this.updateWebisteConfig(name, serverName, serverFarm.id, instance);
}
spinner.stop();
GBLog.info('Opening your browser with default.gbui...');
const opn = require('opn');
opn(`http://localhost:4242`);
return instance;
}
@ -518,12 +478,12 @@ export class AzureDeployerService implements IGBInstallationDeployer {
instance.nlpAuthoringKey = authoringKey;
instance.marketplaceId = appId;
instance.marketplacePassword = appPassword;
instance.adminPass = await GBUtil.hashPassword(GBAdminService.getRndPassword());
instance.adminPass = GBAdminService.getRndPassword();
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
// tslint:disable-next-line:no-http-string
const url = `https://${instance.botId}.azurewebsites.net`;
return await this.deployFarm(url, instance, credentials, subscriptionId);
this.deployFarm(url, instance, credentials, subscriptionId);
}
/**
@ -531,17 +491,17 @@ export class AzureDeployerService implements IGBInstallationDeployer {
*/
public async internalDeployBot(
instance,
accessToken: string,
botId: string,
name: string,
accessToken,
botId,
name,
group,
description: string,
description,
endpoint,
location,
nlpAppId,
nlpKey: string,
appId: string,
appPassword: string,
nlpKey,
appId,
appPassword,
subscriptionId
): Promise<IGBInstance> {
return new Promise(async (resolve, reject) => {
@ -567,12 +527,15 @@ export class AzureDeployerService implements IGBInstallationDeployer {
luisAppIds: [nlpAppId],
luisKey: nlpKey,
msaAppId: appId,
msaAppPassword: appPassword
msaAppPassword: appPassword,
enabledChannels: ['webchat', "skype"],//, "facebook"],
configuredChannels: ['webchat', "skype"]//, "facebook"]
}
};
const httpClient = new ServiceClient();
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`;
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider
}/botServices/${botId}?api-version=${this.apiVersion}`;
let url = urlJoin(baseUrl, query);
let req = AzureDeployerService.createRequestObject(url, accessToken, 'PUT', JSON.stringify(parameters));
const res = await httpClient.sendRequest(req);
@ -581,87 +544,50 @@ export class AzureDeployerService implements IGBInstallationDeployer {
return;
}
await GBUtil.sleep(30000);
// MSFT has changed without warnings.
try {
//tslint:disable-next-line:max-line-length.
query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/Microsoft.BotService/botServices/${botId}/channels/WebChatChannel/listChannelWithKeys?api-version=${this.apiVersion}`;
//tslint:disable-next-line:max-line-length
query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/Microsoft.BotService/botServices/${botId}/channels/WebChatChannel/listChannelWithKeys?api-version=${this.apiVersion
}`;
url = urlJoin(baseUrl, query);
req = AzureDeployerService.createRequestObject(url, accessToken, 'POST', JSON.stringify(parameters));
const resChannel = await httpClient.sendRequest(req);
const key = JSON.parse(resChannel.bodyAsText).properties.properties.sites[0].key;
instance.webchatKey = key;
instance.whatsappBotKey = key;
resolve(instance);
} catch (error) {
reject(error);
}
});
}
public async syncBotServerRepository(group: string, name: string) {
public async syncBotServerRepository(group, name) {
await this.webSiteClient.webApps.syncRepository(group, name);
}
public async initServices(accessToken: string, expiresOnTimestamp, subscriptionId: string) {
this.accessToken = accessToken;
class AccessToken2 implements AccessToken {
public expiresOnTimestamp: number;
public token: string;
}
class StaticAccessToken implements TokenCredential {
public getToken(): Promise<AccessToken> {
return new Promise<AccessToken>(async (resolve, reject) => {
const t = new AccessToken2();
t.token = accessToken;
t.expiresOnTimestamp = expiresOnTimestamp;
resolve(t);
});
}
}
const token = new StaticAccessToken();
this.cloud = new ResourceManagementClient(token, subscriptionId);
this.webSiteClient = new WebSiteManagementClient(token, subscriptionId);
this.storageClient = new SqlManagementClient(token, subscriptionId);
this.cognitiveClient = new CognitiveServicesManagementClient(token, subscriptionId);
this.searchClient = new SearchManagementClient(token, subscriptionId);
public initServices(credentials: any, subscriptionId: string) {
this.resourceClient = new ResourceManagementClient.default(credentials, subscriptionId);
this.webSiteClient = new WebSiteManagementClient(credentials, subscriptionId);
this.storageClient = new SqlManagementClient(credentials, subscriptionId);
this.cognitiveClient = new CognitiveServicesManagementClient(credentials, subscriptionId);
this.searchClient = new SearchManagementClient(credentials, subscriptionId);
this.accessToken = credentials.tokenCache._entries[0].accessToken;
}
private async createStorageServer(
group: string,
name: string,
administratorLogin: string,
administratorPassword: string,
serverName: string,
location: string
) {
private async createStorageServer(group, name, administratorLogin, administratorPassword, serverName, location) {
const params = {
location: location,
administratorLogin: administratorLogin,
administratorLoginPassword: administratorPassword,
fullyQualifiedDomainName: serverName,
requestOptions: { timeout: 60 * 1000 * 5 }
fullyQualifiedDomainName: serverName
};
let database: Server;
try {
database = await this.storageClient.servers.beginCreateOrUpdateAndWait(group, name, params);
} catch (error) {
// Try again (MSFT issues).
GBLogEx.info(0, 'Storage (server) creation failed. Retrying...');
database = await this.storageClient.servers.beginCreateOrUpdateAndWait(group, name, params);
}
const database = await this.storageClient.servers.createOrUpdate(group, name, params);
// AllowAllWindowsAzureIps must be created that way, so the Azure Search can
// AllowAllWindowsAzureIps must be created that way, so the Azure Search can
// access SQL Database to index its contents.
const paramsFirewall = {
@ -674,19 +600,25 @@ export class AzureDeployerService implements IGBInstallationDeployer {
}
public async createApplication(token: string, name: string) {
return new Promise<string>((resolve, reject) => {
let client = MicrosoftGraph.Client.init({
authProvider: done => {
done(null, token);
}
});
let app:any = {
displayName: name,
signInAudience: "AzureADandPersonalMicrosoftAccount",
const app = {
displayName: name
};
const res = await client.api(`/applications`).post(app);
return res;
client.api(`/applications`).post(app, (err, res) => {
if (err) {
reject(err)
}
else {
resolve(res);
}
});
});
}
public async createApplicationSecret(token: string, appId: string) {
@ -698,21 +630,22 @@ export class AzureDeployerService implements IGBInstallationDeployer {
});
const body = {
passwordCredential: {
displayName: 'General Bots Generated'
displayName: "General Bots Generated"
}
};
client.api(`/applications/${appId}/addPassword`).post(body, (err, res) => {
if (err) {
reject(err);
} else {
reject(err)
}
else {
resolve(res.secretText);
}
});
});
}
private async registerProviders(subscriptionId: string, baseUrl: string, accessToken: string) {
private async registerProviders(subscriptionId, baseUrl, accessToken) {
const query = `subscriptions/${subscriptionId}/providers/${this.provider}/register?api-version=2018-02-01`;
const requestUrl = urlJoin(baseUrl, query);
@ -743,12 +676,13 @@ export class AzureDeployerService implements IGBInstallationDeployer {
let app = null;
if (apps.bodyAsText && apps.bodyAsText !== '[]') {
const result = JSON.parse(apps.bodyAsText);
const result = JSON.parse(apps.bodyAsText)
if (result.error) {
if (result.error.code !== '401') {
if (result.error.code !== "401") {
throw new Error(result.error);
}
} else {
}
else {
app = result.filter(x => x.name === name)[0];
}
}
@ -782,7 +716,14 @@ export class AzureDeployerService implements IGBInstallationDeployer {
return await httpClient.sendRequest(req);
}
public async refreshEntityList(location: string, nlpAppId: string, clEntityId: string, nlpKey: string, data: any) {
public async refreshEntityList(
location: string,
nlpAppId: string,
clEntityId: string,
nlpKey: string,
data: any,
) {
const req = new WebResource();
req.method = 'PUT';
req.url = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/apps/${nlpAppId}/versions/0.1/closedlists/${clEntityId}`;
@ -795,7 +736,12 @@ export class AzureDeployerService implements IGBInstallationDeployer {
return await httpClient.sendRequest(req);
}
public async trainNLP(location: string, nlpAppId: string, nlpAuthoringKey: string) {
public async trainNLP(
location: string,
nlpAppId: string,
nlpAuthoringKey: string,
) {
const req = new WebResource();
req.method = 'POST';
req.url = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/apps/${nlpAppId}/versions/0.1/train`;
@ -807,12 +753,16 @@ export class AzureDeployerService implements IGBInstallationDeployer {
return await httpClient.sendRequest(req);
}
public async publishNLP(location: string, nlpAppId: string, nlpAuthoringKey: string) {
public async publishNLP(
location: string,
nlpAppId: string,
nlpAuthoringKey: string,
) {
const body = {
versionId: '0.1',
versionId: "0.1",
isStaging: false,
directVersionPublish: false
};
}
const req = new WebResource();
req.method = 'POST';
req.url = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/apps/${nlpAppId}/publish`;
@ -825,40 +775,32 @@ export class AzureDeployerService implements IGBInstallationDeployer {
return await httpClient.sendRequest(req);
}
private async createSearch(group: string, name: string, location: string) {
private async createSearch(group, name, location) {
const params = {
sku: {
name: this.freeTier ? 'free' : 'standard'
name:
this.freeTier ? 'free' : 'standard'
},
location: location
};
return await this.searchClient.services.beginCreateOrUpdateAndWait(group, name, params as any);
return await this.searchClient.services.createOrUpdate(group, name, params);
}
private async createStorage(group: string, serverName: string, name: string, location: string) {
private async createStorage(group, serverName, name, location) {
const params = {
sku: { name: 'Basic' },
sku: { name: this.freeTier ? 'Free' : 'Basic' },
createMode: 'Default',
location: location
};
let database;
try {
database = await this.storageClient.databases.beginCreateOrUpdateAndWait(group, serverName, name, params);
} catch (error) {
// Try again (MSFT issues).
GBLogEx.info(0, 'Storage (database) creation failed. Retrying...');
database = await this.storageClient.databases.beginCreateOrUpdateAndWait(group, serverName, name, params);
}
return database;
return await this.storageClient.databases.createOrUpdate(group, serverName, name, params);
}
private async createCognitiveServices(group: string, name: string, location: string, kind: string): Promise<Account> {
private async createCognitiveServices(group, name, location, kind): Promise<CognitiveServicesAccount> {
const params = {
sku: {
name: name
name: ""
},
createMode: 'Default',
location: location,
@ -866,7 +808,7 @@ export class AzureDeployerService implements IGBInstallationDeployer {
properties: {}
};
if (kind === 'LUIS.Authoring' || kind === 'LUIS') {
if (kind === 'LUIS.Authoring') {
params.sku.name = this.freeTier ? 'F0' : 'S0';
} else if (kind === 'TextAnalytics') {
params.sku.name = this.freeTier ? 'F0' : 'S0';
@ -874,47 +816,38 @@ export class AzureDeployerService implements IGBInstallationDeployer {
params.sku.name = this.freeTier ? 'S0' : 'S1';
} else if (kind === 'CognitiveServices') {
params.sku.name = 'S0';
} else if (kind === 'SpeechServices') {
params.sku.name = this.freeTier ? 'F0' : 'S0';
}
return await this.cognitiveClient.accounts.beginCreateAndWait(group, name, params);
return await this.cognitiveClient.accounts.create(group, name, params);
}
private async createSpeech(group: string, name: string, location: string): Promise<Account> {
private async createSpeech(group, name, location): Promise<CognitiveServicesAccount> {
return await this.createCognitiveServices(group, name, location, 'SpeechServices');
}
private async createNLP(group: string, name: string, location: string): Promise<Account> {
private async createNLP(group, name, location): Promise<CognitiveServicesAccount> {
return await this.createCognitiveServices(group, name, location, 'LUIS');
}
private async createNLPAuthoring(group: string, name: string, location: string): Promise<Account> {
private async createNLPAuthoring(group, name, location): Promise<CognitiveServicesAccount> {
return await this.createCognitiveServices(group, name, location, 'LUIS.Authoring');
}
private async createSpellChecker(group: string, name: string): Promise<Account> {
private async createSpellChecker(group, name): Promise<CognitiveServicesAccount> {
return await this.createCognitiveServices(group, name, 'westus', 'CognitiveServices');
}
private async createTextAnalytics(group: string, name: string, location: string): Promise<Account> {
private async createTextAnalytics(group, name, location): Promise<CognitiveServicesAccount> {
return await this.createCognitiveServices(group, name, location, 'TextAnalytics');
}
private async createDeployGroup(name: string, location: string) {
private async createDeployGroup(name, location) {
const params = { location: location };
return await this.cloud.resourceGroups.createOrUpdate(name, params);
return await this.resourceClient.resourceGroups.createOrUpdate(name, params);
}
private async enableResourceProviders(name: string) {
const ret = await this.cloud.providers.get(name);
if (ret.registrationState === 'NotRegistered') {
await this.cloud.providers.register(name);
}
}
private async createHostingPlan(group: string, name: string, location: string): Promise<AppServicePlan> {
private async createHostingPlan(group, name, location): Promise<AppServicePlan> {
const params = {
serverFarmWithRichSkuName: name,
location: location,
@ -925,23 +858,25 @@ export class AzureDeployerService implements IGBInstallationDeployer {
}
};
return await this.webSiteClient.appServicePlans.beginCreateOrUpdateAndWait(group, name, params);
return await this.webSiteClient.appServicePlans.createOrUpdate(group, name, params);
}
private async createServer(farmId: string, group: string, name: string, location: string) {
private async createServer(farmId, group, name, location) {
let tryed = false;
const create = async () => {
const parameters: Site = {
location: location,
serverFarmId: farmId,
siteConfig: {
nodeVersion: await GBAdminService.getNodeVersion(),
nodeVersion: GBAdminService.getNodeVersion(),
detailedErrorLoggingEnabled: true,
requestTracingEnabled: true
}
};
const server = await this.webSiteClient.webApps.beginCreateOrUpdateAndWait(group, name, parameters);
const server = await this.webSiteClient.webApps.createOrUpdate(group, name, parameters);
const siteLogsConfig: SiteLogsConfig = {
applicationLogs: {
@ -958,7 +893,7 @@ export class AzureDeployerService implements IGBInstallationDeployer {
deploymentRollbackEnabled: false
};
await this.webSiteClient.webApps.beginCreateOrUpdateSourceControlAndWait(group, name, souceControlConfig);
await this.webSiteClient.webApps.createOrUpdateSourceControl(group, name, souceControlConfig);
return server;
};
@ -967,28 +902,32 @@ export class AzureDeployerService implements IGBInstallationDeployer {
} catch (e) {
if (!tryed) {
tryed = true;
GBLogEx.info(0, 'Retrying Deploying Bot Server...');
GBLog.info('Retrying Deploying Bot Server...');
try {
return await create();
} catch (error) {
GBLogEx.info(0, 'Server creation failed at all on MSAzure, stopping...');
GBLog.info('Server creation failed at all on MSAzure, stopping...');
throw error;
}
}
}
}
private async updateWebisteConfig(group: string, name: string, serverFarmId: string, instance: IGBInstance) {
private async updateWebisteConfig(group, name, serverFarmId, instance: IGBInstance) {
const parameters: Site = {
location: instance.cloudLocation,
serverFarmId: serverFarmId,
siteConfig: {
appSettings: [
{ name: 'WEBSITES_CONTAINER_START_TIME_LIMIT', value: `${WebSiteResponseTimeout}` },
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: await GBAdminService.getNodeVersion() },
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: GBAdminService.getNodeVersion() },
{ name: 'ADDITIONAL_DEPLOY_PATH', value: `` },
{ name: 'ADMIN_PASS', value: `${instance.adminPass}` },
{ name: 'BOT_ID', value: `${instance.botId}` },
{ name: 'CLOUD_SUBSCRIPTIONID', value: `${instance.cloudSubscriptionId}` },
{ name: 'CLOUD_LOCATION', value: `${instance.cloudLocation}` },
{ name: 'CLOUD_GROUP', value: `${instance.botId}` },
{ name: 'CLOUD_USERNAME', value: `${instance.cloudUsername}` },
{ name: 'CLOUD_PASSWORD', value: `${instance.cloudPassword}` },
{ name: 'MARKETPLACE_ID', value: `${instance.marketplaceId}` },
@ -998,11 +937,12 @@ export class AzureDeployerService implements IGBInstallationDeployer {
{ name: 'STORAGE_NAME', value: `${instance.storageName}` },
{ name: 'STORAGE_USERNAME', value: `${instance.storageUsername}` },
{ name: 'STORAGE_PASSWORD', value: `${instance.storagePassword}` },
{ name: 'STORAGE_SYNC', value: `true` }
]
{ name: 'STORAGE_SYNC', value: `true` }]
}
};
return await this.webSiteClient.webApps.beginCreateOrUpdateAndWait(group, name, parameters);
return await this.webSiteClient.webApps.createOrUpdate(group, name, parameters);
}
}

View file

@ -1,6 +1,6 @@
export const Messages = {
'en-US': {
about_suggestions: 'Suggestions are welcomed and improve my quality...'
about_suggestions: 'Suggestions are welcomed and improve my quality...'
},
'pt-BR': {
about_suggestions: 'Sugestões melhoram muito minha qualidade...'

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -35,62 +37,16 @@
'use strict';
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
import { GuaribasSchedule } from '../core.gbapp/models/GBModel.js';
import { GuaribasSchedule } from '../core.gbapp/models/GBModel';
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 CurrentEngineName = "guaribas-1.0.0";
public async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
core.sequelize.addModels([GuaribasSchedule]);
}
@ -111,14 +67,6 @@ export class GBBasicPackage implements IGBPackage {
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 = {};
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -47,29 +49,30 @@ import {
UpdatedAt
} from 'sequelize-typescript';
import { GuaribasInstance } from '../../core.gbapp/models/GBModel.js';
import { GuaribasInstance } from '../../core.gbapp/models/GBModel';
@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;
@Column
public name: string;
@Column
public schedule: string;
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
instanceId: number;
@Column
public instanceId: number;
@BelongsTo(() => GuaribasInstance)
instance: GuaribasInstance;
public instance: GuaribasInstance;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
}

View file

@ -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();
}
}

View file

@ -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';
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' };
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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';
import { DialogKeywords } from './DialogKeywords.js';
import { CollectionUtil } from 'pragmatismo-io-framework';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
import urlJoin from 'url-join';
import { GBServer } from '../../../src/app.js';
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
import { 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 CollectionUtil.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 };
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -31,13 +33,12 @@
'use strict';
import { GBLog, GBMinInstance, GBService } from 'botlib';
import { GBServer } from '../../../src/app.js';
import { GBServer } from '../../../src/app';
import { CollectionUtil } from 'pragmatismo-io-framework';
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
import { GuaribasSchedule } from '../../core.gbapp/models/GBModel.js';
import { GBVMService } from '../../basic.gblib/services/GBVMService';
import { GuaribasSchedule } from '../../core.gbapp/models/GBModel';
import cron from 'node-cron';
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
const cron = require('node-cron');
/**
* @fileoverview Schedule Services.
@ -47,36 +48,36 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
* Basic services for BASIC manipulation.
*/
export class ScheduleServices extends GBService {
public async deleteScheduleIfAny(min: GBMinInstance, name: string) {
let i = 1;
while (i <= 10) {
const task = min['scheduleMap'] ? min['scheduleMap'][name + i] : null;
if (task) {
task.destroy();
const task = min["scheduleMap"] ? min["scheduleMap"][name] : null;
if (task) {
task.destroy();
delete min["scheduleMap"][name];
}
const count = await GuaribasSchedule.destroy({
where: {
instanceId: min.instance.instanceId,
name: name
}
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++;
if (count > 0) {
GBLog.info(`BASIC: Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`);
}
}
/**
* Finds and update user agent information to a next available person.
*/
public async createOrUpdateSchedule(min: GBMinInstance, schedule: string, name: string): Promise<GuaribasSchedule> {
public async createOrUpdateSchedule(
min: GBMinInstance,
schedule: string,
name: string
): Promise<GuaribasSchedule> {
let record = await GuaribasSchedule.findOne({
where: {
instanceId: min.instance.instanceId,
@ -85,7 +86,7 @@ export class ScheduleServices extends GBService {
});
if (record === null) {
record = await GuaribasSchedule.create(<GuaribasSchedule>{
record = await GuaribasSchedule.create({
instanceId: min.instance.instanceId,
name: name,
schedule: schedule
@ -100,72 +101,58 @@ export class ScheduleServices extends GBService {
return record;
}
/**
* Load all cached schedule from BASIC SET SCHEDULE keyword.
*/
public async scheduleAll() {
* Load all cached schedule from BASIC SET SCHEDULE keyword.
*/
public async loadSchedules(min: GBMinInstance) {
GBLog.info(`Loading instances from storage...`);
let schedules;
try {
schedules = await GuaribasSchedule.findAll();
let i = 0;
let lastName = '';
await CollectionUtil.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) {
const options = { where: { instanceId: min.instance.instanceId } };
schedules = await GuaribasSchedule.findAll(options);
if (process.env.ENDPOINT_UPDATE === 'true') {
await CollectionUtil.asyncForEach(schedules, async item => {
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}...`);
GBLog.info(`Scheduling ${item.name} on ${min.botId}...`);
try {
const options = {
scheduled: true,
timezone: 'America/Sao_Paulo'
};
const task = min['scheduleMap'][item.name];
const task = min["scheduleMap"][item.name];
if (task) {
task.stop();
min['scheduleMap'][item.name] = null;
min["scheduleMap"][item.name] = null;
}
min['scheduleMap'][item.name] = cron.schedule(
min["scheduleMap"][item.name] = cron.schedule(
item.schedule,
function () {
const finalData = async () => {
let script = item.name.split(';')[0];
let script = item.name;
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);
await GBVMService.callVM(script, min, null, null);
};
(async () => {
await finalData();
})();
},
options
}, options
);
} catch (error) {
GBLogEx.error(min, `Running .gbdialog word ${item.name} : ${error}...`);
}
GBLog.info(`Running .gbdialog word ${item.name} on:${item.schedule}...`);
} catch (error) { }
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,103 @@
/*****************************************************************************\
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) Pragmatismo.io. 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.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. |
| |
\*****************************************************************************/
/**
* @fileoverview General Bots server core.
*/
'use strict';
import { GBLog } from 'botlib';
import * as ts from 'typescript';
/**
* Wrapper for a TypeScript compiler.
*/
export class TSCompiler {
private static shouldIgnoreError(diagnostic) {
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
if (message.indexOf('Cannot find name') >= 0
|| message.indexOf('Cannot find module') >= 0
|| message.indexOf('implicitly has an') >= 0
|| message.indexOf('Cannot invoke an') >= 0
|| message.indexOf('Cannot use imports, exports, or module') >= 0
) {
return true;
}
return false;
}
public compile(
fileNames: string[],
options: ts.CompilerOptions = {
noStrictGenericChecks: true,
noImplicitUseStrict: true,
noEmitOnError: false,
noImplicitAny: true,
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.None,
moduleResolution: ts.ModuleResolutionKind.Classic,
noEmitHelpers: true,
maxNodeModuleJsDepth: 0,
esModuleInterop: false
}
) {
const program = ts.createProgram(fileNames, options);
const emitResult = program.emit();
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
allDiagnostics.forEach(diagnostic => {
if (!TSCompiler.shouldIgnoreError(diagnostic)) {
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
if (diagnostic.file !== undefined) {
if (
diagnostic.file.fileName.indexOf('readable-stream') == -1 &&
diagnostic.file.fileName.indexOf('request-promise') == -1
) {
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
GBLog.error(`BASIC error: ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
}
} else {
GBLog.error(`BASIC error: ${message}`);
}
}
});
return emitResult;
}
}

View file

@ -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';
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;
}
}
}

View file

@ -0,0 +1,157 @@
// Source: https://github.com/uweg/vbscript-to-typescript
"use strict";
exports.__esModule = true;
var fs_1 = require("fs");
var path = require("path");
function convertFile(file) {
var extension = path.extname(file);
var withoutExtension = file.substr(0, file.length - extension.length);
var targetFile = withoutExtension + ".ts";
var baseName = path.basename(file, extension);
var content = fs_1.readFileSync(file, 'utf8');
var result = convert(content, baseName);
console.log("Writing to \"" + targetFile + "\"...");
fs_1.writeFileSync(targetFile, result);
}
exports.convertFile = convertFile;
function convert(input, name) {
var result = convertImports(input, name);
return result;
}
exports.convert = convert;
function convertImports(input, name) {
var items = [];
var result = input.replace(/<!-- #include file="(.*?\/)?(.*?).asp" -->/gi, function (input, group1, group2) {
var path = group1 || './';
var file = "" + path + group2;
items.push({ name: group2, path: file });
return "<%\n" + group2 + "();\n%>";
});
result = convertCode(result);
result = convertExpressions(result);
result = convertStrings(result);
result = "\nexport function " + name + "() {\n" + result + "\n}";
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
var item = items_1[_i];
result = "import {" + item.name + "} from \"" + item.path + "\"\n" + result;
}
return result;
}
exports.convertImports = convertImports;
function convertCode(input) {
var result = input.replace(/<%([^=][\s\S]*?)%>/gi, function (input, group1) {
var code = group1;
code = convertComments(code);
code = convertIfStatements(code);
code = convertSwitchStatements(code);
code = convertFunctions(code);
code = convertForStatements(code);
code = convertLoops(code);
code = convertPRec(code);
code = convertPLan(code);
return "<%" + code + "%>";
});
return result;
}
exports.convertCode = convertCode;
function convertExpressions(input) {
var result = input.replace(/<%=([\s\S]*?)%>/gi, function (input, group1) {
var content = convertPRec(group1);
content = convertPLan(content);
return "${" + content + "}";
});
return result;
}
exports.convertExpressions = convertExpressions;
function convertStrings(input) {
var result = input.replace(/%>([\s\S]+?)<%/gi, "\nResponse.Write(`$1`);\n");
// Entire document is a string
if (result.indexOf("<%") === -1) {
result = "Response.Write(`" + result + "`);";
}
// Start of the document is a string
var firstIndex = result.indexOf("<%");
if (firstIndex > 0) {
result = "Response.Write(`" + result.substr(0, firstIndex) + "`);\n" + result.substring(firstIndex + 2);
}
result = result.replace(/%>$/, "");
// End of the document is a string
var lastIndex = result.lastIndexOf("%>");
if (lastIndex > -1 && lastIndex < result.length - 2) {
result = result.substr(0, lastIndex) + "\nResponse.Write(`" + result.substr(lastIndex + 3) + "`);";
}
result = result.replace(/^<%/, "");
return result;
}
exports.convertStrings = convertStrings;
function convertComments(input) {
var result = '';
var splitted = input.split(/(".*")/gim);
for (var _i = 0, splitted_1 = splitted; _i < splitted_1.length; _i++) {
var part = splitted_1[_i];
if (part.indexOf("\"") === 0) {
result += part;
}
else {
result += part.replace(/'/gi, "//");
}
}
return result;
}
exports.convertComments = convertComments;
function convertIfStatements(input) {
var result = input.replace(/if +(.*?) +then/gi, function (input, group1) {
var condition = convertConditions(group1);
return "\nif (" + condition + ") {\n";
});
result = result.replace(/end if/gi, "\n}\n");
result = result.replace(/else(?!{)/gi, "\n}\nelse {\n");
return result;
}
exports.convertIfStatements = convertIfStatements;
function convertSwitchStatements(input) {
var result = input.replace(/select case +(.*)/gi, "\nswitch ($1) {\n");
result = result.replace(/end select/gi, "\n}\n");
return result;
}
exports.convertSwitchStatements = convertSwitchStatements;
function convertFunctions(input) {
var result = input.replace(/function +(.*)\((.*)\)/gi, "\n$1 = ($2) => {\n");
result = result.replace(/end function/gi, "\n}\n");
return result;
}
exports.convertFunctions = convertFunctions;
function convertForStatements(input) {
var result = input.replace(/for +(.*to.*)/gi, "\nfor ($1) {\n");
result = result.replace(/^ *next *$/gim, "}\n");
return result;
}
exports.convertForStatements = convertForStatements;
function convertConditions(input) {
var result = input.replace(/ +and +/gi, " && ");
result = result.replace(/ +or +/gi, " || ");
result = result.replace(/ +<> +/gi, " !== ");
result = result.replace(/ += +/gi, " === ");
return result;
}
exports.convertConditions = convertConditions;
function convertLoops(input) {
var result = input.replace(/do while +(.*)/gi, function (input, group1) {
var condition = convertConditions(group1);
return "\nwhile (" + condition + ") {\n";
});
result = result.replace(/^ *loop *$/gim, "}\n");
return result;
}
exports.convertLoops = convertLoops;
function convertPRec(input) {
var result = input.replace(/(p_rec\("\S+?"\))/gi, "$1.Value");
return result;
}
exports.convertPRec = convertPRec;
function convertPLan(input) {
var result = input.replace(/(l_\S+?)\(p_lan\)/gi, "$1[p_lan]");
return result;
}
exports.convertPLan = convertPLan;

View file

@ -1,310 +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';
import { CollectionUtil } from 'pragmatismo-io-framework';
import { GBServer } from '../../../../src/app.js';
import { DebuggerService } from '../DebuggerService.js';
import finalStream from 'final-stream';
import { GBLogEx } from '../../../core.gbapp/services/GBLogEx.js';
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 CollectionUtil.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 CollectionUtil.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
};
};

View file

@ -1,67 +0,0 @@
import { VMScript, NodeVM } from 'vm2';
import crypto1 from 'crypto';
import net1 from 'net';
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`);

View file

@ -1,10 +1,9 @@
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:'
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
},
'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:'
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
}
};

View file

@ -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");
});

View file

@ -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"
}});
});

View file

@ -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'
}
});
});

View file

@ -6,7 +6,7 @@
"title": "Default General Bot",
"description": "Default General Bot",
"whoAmIVideo": "TODO.mp4",
"author": "pragmatismo.com.br",
"author": "pragmatismo.io",
"license": "AGPL",
"engineName": "guaribas-1.0.0"
}

View file

@ -2,6 +2,7 @@
"enabledAdmin": "true",
"searchScore": ".45",
"nlpScore": ".80",
"nlpVsSearch": ".4",
"state":"active",
"autoPackageSync": "gbdialog, gbot, gbtheme"
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -36,17 +38,14 @@
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
import { Sequelize } from 'sequelize-typescript';
import { ConsoleDirectLine } from './services/ConsoleDirectLine';
/**
* Package for GoogleChat.gblib
* Package for console.glib.
*/
export class GBHubSpotPackage implements IGBPackage {
export class GBConsolePackage implements IGBPackage {
public sysPackages: IGBPackage[];
public async loadBot(min: GBMinInstance): Promise<void> {
GBLog.verbose(`loadBot called.`);
}
public channel: ConsoleDirectLine;
public async getDialogs(min: GBMinInstance) {
GBLog.verbose(`getDialogs called.`);
}
@ -65,4 +64,7 @@ export class GBHubSpotPackage implements IGBPackage {
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
GBLog.verbose(`onExchangeData called.`);
}
public async loadBot(min: GBMinInstance): Promise<void> {
this.channel = new ConsoleDirectLine(min.instance.webchatKey);
}
}

View file

@ -0,0 +1,176 @@
const Swagger = require('swagger-client');
const rp = require('request-promise');
import { GBLog, GBService } from 'botlib';
/**
* Bot simulator in terminal window.
*/
export class ConsoleDirectLine extends GBService {
public pollInterval: number = 1000;
public directLineSecret: string = '';
public directLineClientName: string = 'DirectLineClient';
public directLineSpecUrl: string = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json';
constructor(directLineSecret: string) {
super();
this.directLineSecret = directLineSecret;
// tslint:disable-next-line:no-unsafe-any
const directLineClient = rp(this.directLineSpecUrl)
.then((spec: string) => {
// tslint:disable-next-line:no-unsafe-any
return new Swagger({
spec: JSON.parse(spec.trim()),
usePromise: true
});
})
.then(client => {
// tslint:disable-next-line:no-unsafe-any
client.clientAuthorizations.add(
'AuthorizationBotConnector',
// tslint:disable-next-line:no-unsafe-any
new Swagger.ApiKeyAuthorization('Authorization', `Bearer ${directLineSecret}`, 'header')
);
return client;
})
.catch(err => {
GBLog.error(`Error initializing DirectLine client ${err}`);
});
const _this_ = this;
// tslint:disable-next-line:no-unsafe-any
directLineClient.then(client => {
// tslint:disable-next-line:no-unsafe-any
client.Conversations.Conversations_StartConversation()
.then(response => {
// tslint:disable-next-line:no-unsafe-any
return response.obj.conversationId;
})
.then(conversationId => {
_this_.sendMessagesFromConsole(client, conversationId);
_this_.pollMessages(client, conversationId);
})
.catch(err => {
GBLog.error(`Error starting conversation ${err}`);
});
});
}
public sendMessagesFromConsole(client, conversationId) {
const _this_ = this;
process.stdin.resume();
const stdin = process.stdin;
process.stdout.write('Command> ');
stdin.addListener('data', e => {
// tslint:disable-next-line:no-unsafe-any
const input: string = e.toString().trim();
if (input !== undefined) {
// exit
if (input.toLowerCase() === 'exit') {
return process.exit();
}
// tslint:disable-next-line:no-unsafe-any
client.Conversations.Conversations_PostActivity({
conversationId: conversationId,
activity: {
textFormat: 'plain',
text: input,
type: 'message',
from: {
id: _this_.directLineClientName,
name: _this_.directLineClientName
}
}
}).catch(err => {
GBLog.error(`Error sending message: ${err}`);
});
process.stdout.write('Command> ');
}
});
}
public pollMessages(client, conversationId) {
const _this_ = this;
GBLog.info(`Starting polling message for conversationId: ${conversationId}`);
let watermark;
setInterval(() => {
// tslint:disable-next-line:no-unsafe-any
client.Conversations.Conversations_GetActivities({ conversationId: conversationId, watermark: watermark })
.then(response => {
// tslint:disable-next-line:no-unsafe-any
watermark = response.obj.watermark;
// tslint:disable-next-line:no-unsafe-any
return response.obj.activities;
})
.then(_this_.printMessages, _this_.directLineClientName);
// tslint:disable-next-line:align
}, this.pollInterval);
}
// tslint:disable:no-unsafe-any
public printMessages(activities, directLineClientName) {
if (activities && activities.length) {
// ignore own messages
activities = activities.filter(m => {
return m.from.id !== directLineClientName;
});
if (activities.length) {
// print other messages
activities.forEach(activity => {
GBLog.info(activity.text);
// tslint:disable-next-line:align
}, this);
process.stdout.write('Command> ');
}
}
}
// tslint:enable:no-unsafe-any
// tslint:disable:no-unsafe-any
public printMessage(activity) {
if (activity.text) {
GBLog.info(activity.text);
}
if (activity.attachments) {
activity.attachments.forEach(attachment => {
switch (attachment.contentType) {
case 'application/vnd.microsoft.card.hero':
this.renderHeroCard(attachment);
break;
case 'image/png':
GBLog.info(`Opening the requested image ${attachment.contentUrl}`);
open(attachment.contentUrl);
break;
default:
GBLog.info(`Unknown contentType: ${attachment.contentType}`);
break;
}
});
}
}
// tslint:enable:no-unsafe-any
// tslint:disable:no-unsafe-any
public renderHeroCard(attachment) {
const width = 70;
const contentLine = content => {
return `${' '.repeat((width - content.length) / 2)}content${' '.repeat((width - content.length) / 2)}`;
};
GBLog.info(`/${'*'.repeat(width + 1)}`);
GBLog.info(`*${contentLine(attachment.content.title)}*`);
GBLog.info(`*${' '.repeat(width)}*`);
GBLog.info(`*${contentLine(attachment.content.text)}*`);
GBLog.info(`${'*'.repeat(width + 1)}/`);
}
// tslint:enable:no-unsafe-any
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -37,10 +39,10 @@
import { BotAdapter } from 'botbuilder';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
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 { Messages } from '../strings';
import { SecService } from '../../security.gbapp/services/SecService';
import { GBServer } from '../../../src/app';
import { GBConversationalService } from '../services/GBConversationalService';
/**
* Dialog for the bot explains about itself.
*/
@ -51,13 +53,14 @@ export class BroadcastDialog extends IGBDialog {
* @param bot The bot adapter.
* @param min The minimal bot instance data.
*/
public static setup (bot: BotAdapter, min: GBMinInstance) {
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 {
}
else{
return await step.next(step.options);
}
},

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -37,10 +39,10 @@
import { BotAdapter } from 'botbuilder';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
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 { Messages } from '../strings';
import { SecService } from '../../security.gbapp/services/SecService';
import { GBServer } from '../../../src/app';
import { GBConversationalService } from '../services/GBConversationalService';
import { CollectionUtil } from 'pragmatismo-io-framework';
/**
* Dialog for the bot explains about itself.
@ -52,62 +54,63 @@ export class LanguageDialog extends IGBDialog {
* @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 CollectionUtil.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 });
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 user = await min.userProfile.get(step.context, {});
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 CollectionUtil.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();
user.systemUser = await sec.updateUserLocale(user.systemUser.userId, translatorLocale);
await min.userProfile.set(step.context, user);
await min.conversationalService.sendText(min, step,
Messages[locale].language_chosen);
await step.replaceDialog('/ask', { firstTime: true });
}
]));
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -37,10 +39,10 @@
import { BotAdapter } from 'botbuilder';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
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';
import { GBServer } from '../../../src/app';
import { SecService } from '../../security.gbapp/services/SecService';
import { GBConversationalService } from '../services/GBConversationalService';
import { Messages } from '../strings';
/**
* Dialog for the bot explains about itself.
*/
@ -51,33 +53,32 @@ export class SwitchBotDialog extends IGBDialog {
* @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();
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();
}
]));
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -36,11 +38,10 @@
import { BotAdapter } from 'botbuilder';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
import { GBServer } from '../../../src/app.js';
import { Messages } from '../strings.js';
import { GBLogEx } from '../services/GBLogEx.js';
import { GBConfigService } from '../services/GBConfigService.js';
import { GBLog, GBMinInstance, IGBDialog } from 'botlib';
import { GBServer } from '../../../src/app';
import { GBConversationalService } from '../services/GBConversationalService';
import { Messages } from '../strings';
/**
* Dialog for Welcoming people.
@ -52,58 +53,57 @@ export class WelcomeDialog extends IGBDialog {
* @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);
}
public static setup(bot: BotAdapter, min: GBMinInstance) {
const locale = step.context.activity.locale;
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 (
// 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
if (GBServer.globals.entryPointDialog !== null &&
min.instance.botId === process.env.BOT_ID &&
step.context.activity.channelId === 'webchat') {
return step.replaceDialog(GBServer.globals.entryPointDialog);
}
const user = await min.userProfile.get(step.context, {});
const locale = step.context.activity.locale;
if (!user.once && step.context.activity.channelId === 'webchat'
&& min.core.getParam<boolean>(min.instance, 'HelloGoodX', true) === "true") {
user.once = true;
await min.userProfile.set(step.context, user);
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 min.conversationalService.sendText(min, step, Messages[locale].hi(msg));
await step.replaceDialog('/ask', { firstTime: true });
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 });
}
if (
step.context.activity !== undefined &&
step.context.activity.type === 'message' &&
step.context.activity.text !== ''
) {
GBLog.info(`/answer being called from WelcomeDialog.`);
await step.replaceDialog('/answer', { query: step.context.activity.text });
}
return await step.next();
}
])
);
return await step.next();
}
]));
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -37,8 +39,8 @@
import { BotAdapter } from 'botbuilder';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
import { GBConversationalService } from '../services/GBConversationalService.js';
import { Messages } from '../strings.js';
import { GBConversationalService } from '../services/GBConversationalService';
import { Messages } from '../strings';
/**
* Dialog for the bot explains about itself.
*/
@ -49,34 +51,33 @@ export class WhoAmIDialog extends IGBDialog {
* @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();
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();
}
]));
}
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -36,12 +38,12 @@
import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
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';
import { BroadcastDialog } from './dialogs/BroadcastDialog';
import { LanguageDialog } from './dialogs/LanguageDialog';
import { SwitchBotDialog } from './dialogs/SwitchBot';
import { WelcomeDialog } from './dialogs/WelcomeDialog';
import { WhoAmIDialog } from './dialogs/WhoAmIDialog';
import { GuaribasChannel, GuaribasException, GuaribasInstance, GuaribasPackage } from './models/GBModel';
/**
* Package for core.gbapp.
@ -50,27 +52,27 @@ 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 loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
core.sequelize.addModels([GuaribasInstance, GuaribasPackage, GuaribasChannel, GuaribasException]);
}
public async getDialogs (min: GBMinInstance) {
public async getDialogs(min: GBMinInstance) {
GBLog.verbose(`getDialogs called.`);
}
public async unloadPackage (core: IGBCoreService): Promise<void> {
public async unloadPackage(core: IGBCoreService): Promise<void> {
GBLog.verbose(`unloadPackage called.`);
}
public async unloadBot (min: GBMinInstance): Promise<void> {
public async unloadBot(min: GBMinInstance): Promise<void> {
GBLog.verbose(`unloadBot called.`);
}
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
public async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
GBLog.verbose(`onNewSession called.`);
}
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
GBLog.verbose(`onExchangeData called.`);
}
public async loadBot (min: GBMinInstance): Promise<void> {
public async loadBot(min: GBMinInstance): Promise<void> {
WelcomeDialog.setup(min.bot, min);
WhoAmIDialog.setup(min.bot, min);
SwitchBotDialog.setup(min.bot, min);

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -45,4 +47,4 @@ import {
Table,
UpdatedAt
} from 'sequelize-typescript';
import { GuaribasInstance } from './GBModel.js';
import { GuaribasInstance } from './GBModel';

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -53,216 +55,221 @@ import { IGBInstance } from 'botlib';
* Base instance data for a bot.
*/
@Table
export class GuaribasInstance extends Model<GuaribasInstance> implements IGBInstance {
export class GuaribasInstance extends Model<GuaribasInstance>
implements IGBInstance {
@PrimaryKey
@AutoIncrement
@Column(DataType.INTEGER)
declare instanceId: number;
@Column
public instanceId: number;
@Column(DataType.STRING(255))
declare botEndpoint: string;
@Column
public botEndpoint: string;
@Column(DataType.STRING(255))
declare whoAmIVideo: string;
@Column
public whoAmIVideo: string;
@Column(DataType.STRING(255))
declare botId: string;
@Column
public botId: string;
@Column(DataType.STRING(255))
declare title: string;
@Column
public title: string;
@Column({ type: DataType.STRING(16) })
declare activationCode: string;
public activationCode: string;
@Column(DataType.STRING(255))
declare description: string;
@Column
public description: string;
@Column({ type: DataType.STRING(16) })
declare state: string;
public state: string;
declare version: string;
@Column
declare public version: string;
@Column(DataType.STRING(64))
declare botKey: string;
@Column
public enabledAdmin: boolean;
@Column(DataType.STRING(255))
declare enabledAdmin: boolean;
@Column
public engineName: string;
@Column(DataType.STRING(255))
declare engineName: string;
@Column
public marketplaceId: string;
@Column(DataType.STRING(255))
declare marketplaceId: string;
@Column
public textAnalyticsKey: string;
@Column(DataType.STRING(255))
declare textAnalyticsKey: string;
@Column(DataType.STRING(255))
declare textAnalyticsEndpoint: string;
@Column
public textAnalyticsEndpoint: string;
@Column({ type: DataType.STRING(64) })
declare translatorKey: string;
public translatorKey: string;
@Column
@Column({ type: DataType.STRING(128) })
declare translatorEndpoint: string;
public translatorEndpoint: string;
@Column(DataType.STRING(255))
declare marketplacePassword: string;
@Column
public marketplacePassword: string;
@Column(DataType.STRING(255))
declare webchatKey: string;
@Column
public webchatKey: string;
@Column(DataType.STRING(255))
declare authenticatorTenant: string;
@Column
public authenticatorTenant: string;
@Column(DataType.STRING(255))
declare authenticatorAuthorityHostUrl: string;
@Column
public authenticatorAuthorityHostUrl: string;
@Column(DataType.STRING(255))
declare cloudSubscriptionId: string;
@Column
public cloudSubscriptionId: string;
@Column(DataType.STRING(255))
declare cloudUsername: string;
@Column
public cloudUsername: string;
@Column(DataType.STRING(255))
declare cloudPassword: string;
@Column
public cloudPassword: string;
@Column(DataType.STRING(255))
declare cloudLocation: string;
@Column
public cloudLocation: string;
@Column(DataType.STRING(255))
declare googleBotKey: string;
@Column
public googleBotKey: string;
@Column(DataType.STRING(255))
declare googleChatApiKey: string;
@Column
public googleChatApiKey: string;
@Column(DataType.STRING(255))
declare googleChatSubscriptionName: string;
@Column
public googleChatSubscriptionName: string;
@Column(DataType.STRING(255))
declare googleClientEmail: string;
@Column
public googleClientEmail: string;
@Column({ type: DataType.STRING(4000) })
declare googlePrivateKey: string;
@Column(DataType.STRING(255))
declare googleProjectId: string;
public googlePrivateKey: string;
@Column
public googleProjectId: string;
@Column({ type: DataType.STRING(255) })
facebookWorkplaceVerifyToken: string;
@Column({ type: DataType.STRING(255) })
declare facebookWorkplaceVerifyToken: string;
@Column({ type: DataType.STRING(255) })
declare facebookWorkplaceAppSecret: string;
facebookWorkplaceAppSecret: string;
@Column({ type: DataType.STRING(512) })
declare facebookWorkplaceAccessToken: string;
facebookWorkplaceAccessToken: string;
@Column
public whatsappBotKey: string;
@Column(DataType.STRING(255))
declare whatsappBotKey: string;
@Column
public whatsappServiceKey: string;
@Column(DataType.STRING(255))
declare whatsappServiceKey: string;
@Column
public whatsappServiceNumber: string;
@Column(DataType.STRING(255))
declare whatsappServiceNumber: string;
@Column
public whatsappServiceUrl: string;
@Column(DataType.STRING(255))
declare whatsappServiceUrl: string;
@Column
public smsKey: string;
@Column(DataType.STRING(255))
declare smsKey: string;
@Column
public smsSecret: string;
@Column(DataType.STRING(255))
declare smsSecret: string;
@Column
public smsServiceNumber: string;
@Column(DataType.STRING(255))
declare smsServiceNumber: string;
@Column
public speechKey: string;
@Column(DataType.STRING(255))
declare speechKey: string;
@Column
public speechEndpoint: string;
@Column(DataType.STRING(255))
declare speechEndpoint: string;
@Column
public spellcheckerKey: string;
@Column(DataType.STRING(255))
declare spellcheckerKey: string;
@Column
public spellcheckerEndpoint: string;
@Column(DataType.STRING(255))
declare spellcheckerEndpoint: string;
@Column
public theme: string;
@Column(DataType.STRING(255))
declare theme: string;
@Column
public ui: string;
@Column(DataType.STRING(255))
declare ui: string;
@Column
public kb: string;
@Column(DataType.STRING(255))
declare kb: string;
@Column
public nlpAppId: string;
@Column(DataType.STRING(255))
declare nlpAppId: string;
@Column(DataType.STRING(255))
declare nlpKey: string;
@Column
public nlpKey: string;
@Column
@Column({ type: DataType.STRING(512) })
declare nlpEndpoint: string;
public nlpEndpoint: string;
@Column(DataType.STRING(255))
declare nlpAuthoringKey: string;
@Column
public nlpAuthoringKey: string;
@Column(DataType.STRING(255))
declare deploymentPaths: string;
@Column
public deploymentPaths: string;
@Column(DataType.STRING(255))
declare searchHost: string;
@Column
public searchHost: string;
@Column(DataType.STRING(255))
declare searchKey: string;
@Column
public searchKey: string;
@Column(DataType.STRING(255))
declare searchIndex: string;
@Column
public searchIndex: string;
@Column(DataType.STRING(255))
declare searchIndexer: string;
@Column
public searchIndexer: string;
@Column(DataType.STRING(255))
declare storageUsername: string;
@Column
public storageUsername: string;
@Column(DataType.STRING(255))
declare storagePassword: string;
@Column
public storagePassword: string;
@Column(DataType.STRING(255))
declare storageName: string;
@Column
public storageName: string;
@Column(DataType.STRING(255))
declare storageServer: string;
@Column
public storageServer: string;
@Column(DataType.STRING(255))
declare storageDialect: string;
@Column
public storageDialect: string;
@Column(DataType.STRING(255))
declare storagePath: string;
@Column
public storagePath: string;
@Column(DataType.STRING(255))
declare adminPass: string;
@Column
public adminPass: string;
@Column(DataType.FLOAT)
declare searchScore: number;
public nlpVsSearch: number; // TODO: Remove field.
@Column(DataType.FLOAT)
declare nlpScore: number;
public searchScore: number;
@Column(DataType.DATE)
@Column(DataType.FLOAT)
public nlpScore: number;
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
@Column(DataType.STRING(4000))
declare params: string;
public params: string;
}
/**
@ -272,29 +279,29 @@ export class GuaribasInstance extends Model<GuaribasInstance> implements IGBInst
export class GuaribasPackage extends Model<GuaribasPackage> {
@PrimaryKey
@AutoIncrement
@Column(DataType.INTEGER)
declare packageId: number;
@Column
public packageId: number;
@Column(DataType.STRING(255))
declare packageName: string;
@Column
public packageName: string;
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
declare instanceId: number;
@Column
public instanceId: number;
@BelongsTo(() => GuaribasInstance)
declare instance: GuaribasInstance;
public instance: GuaribasInstance;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
@Column({ type: DataType.STRING(512) })
declare custom: string;
public custom: string;
}
/**
@ -304,19 +311,19 @@ export class GuaribasPackage extends Model<GuaribasPackage> {
export class GuaribasChannel extends Model<GuaribasChannel> {
@PrimaryKey
@AutoIncrement
@Column(DataType.INTEGER)
declare channelId: number;
@Column
public channelId: number;
@Column(DataType.STRING(255))
declare title: string;
@Column
public title: string;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
}
/**
@ -324,77 +331,76 @@ export class GuaribasChannel extends Model<GuaribasChannel> {
*/
@Table
//tslint:disable-next-line:max-classes-per-file
export class GuaribasLog extends Model<GuaribasLog> {
export class GuaribasException extends Model<GuaribasException> {
@PrimaryKey
@AutoIncrement
@Column(DataType.INTEGER)
declare logId: number;
@Column
public exceptionId: number;
@Column(DataType.STRING(1024))
declare message: string;
@Column
public message: string;
@Column(DataType.STRING(1))
declare kind: string;
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
declare instanceId: number;
@Column
public instanceId: number;
@BelongsTo(() => GuaribasInstance)
declare instance: GuaribasInstance;
public instance: GuaribasInstance;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
}
@Table
//tslint:disable-next-line:max-classes-per-file
export class GuaribasApplications extends Model<GuaribasApplications> {
@Column(DataType.STRING(255))
declare name: string;
@Column
public name: string;
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
declare instanceId: number;
@Column
public instanceId: number;
@BelongsTo(() => GuaribasInstance)
declare instance: GuaribasInstance;
public instance: GuaribasInstance;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public 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;
@Column
public name: string;
@Column
public schedule: string;
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
declare instanceId: number;
@Column
public instanceId: number;
@BelongsTo(() => GuaribasInstance)
declare instance: GuaribasInstance;
public instance: GuaribasInstance;
@Column(DataType.DATE)
@Column
@CreatedAt
declare createdAt: Date;
declare public createdAt: Date;
@Column(DataType.DATE)
@Column
@UpdatedAt
declare updatedAt: Date;
declare public updatedAt: Date;
}

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -31,8 +33,6 @@
'use strict';
import { GBLog } from 'botlib';
import * as en from 'dotenv-extended';
import path from 'path';
/**
* @fileoverview General Bots server core.
@ -58,7 +58,7 @@ export class GBConfigService {
public static init(): any {
try {
en.load({
require('dotenv-extended').load({
encoding: 'utf8',
silent: true,
path: '.env',
@ -77,38 +77,19 @@ export class GBConfigService {
}
}
public static get(key: string) {
public static get(key: string): string | undefined {
let value = GBConfigService.tryGet(key);
if (!value) {
if (value === undefined) {
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':
case 'BOT_ID':
value = undefined;
break;
case 'STORAGE_LIBRARY':
value = path.join(process.env.PWD, 'templates');
break;
case 'BOT_ID':
value = 'default';
case 'CLOUD_PASSWORD':
value = undefined;
break;
case 'CLOUD_SUBSCRIPTIONID':
value = undefined;
@ -119,18 +100,14 @@ export class GBConfigService {
case 'MARKETPLACE_ID':
value = undefined;
break;
case 'LOG_ON_STORAGE':
value = false;
break;
case 'MARKETPLACE_SECRET':
value = undefined;
break;
case 'STORAGE_DIALECT':
value = 'sqlite';
value = undefined;
break;
case 'STORAGE_FILE':
value = './data.db';
case 'STORAGE_STORAGE':
value = './guaribas.sqlite';
break;
case 'GBKB_AUTO_DEPLOY':
value = false;
@ -177,18 +154,6 @@ export class GBConfigService {
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;

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ _ _ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/ \ /`\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| |*| |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -34,40 +36,30 @@
'use strict';
import { GBLog, GBMinInstance, IGBCoreService, IGBInstallationDeployer, IGBInstance, IGBPackage } from 'botlib';
import fs from 'fs/promises';
import { GBLog, IGBCoreService, IGBInstallationDeployer, IGBInstance, IGBPackage } from 'botlib';
import * as fs from 'fs';
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 { StartDialog } from '../../azuredeployer.gbapp/dialogs/StartDialog.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 { GBAzureDeployerPackage } from '../../azuredeployer.gbapp/index.js';
import { GBSharePointPackage } from '../../sharepoint.gblib/index.js';
import { GBServer } from '../../../src/app';
import { GBAdminPackage } from '../../admin.gbapp/index';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { GBAnalyticsPackage } from '../../analytics.gblib';
import { StartDialog } from '../../azuredeployer.gbapp/dialogs/StartDialog';
import { GBCorePackage } from '../../core.gbapp';
import { GBCustomerSatisfactionPackage } from '../../customer-satisfaction.gbapp';
import { GBKBPackage } from '../../kb.gbapp';
import { GBSecurityPackage } from '../../security.gbapp';
import { GBWhatsappPackage } from '../../whatsapp.gblib/index';
import { GuaribasInstance } from '../models/GBModel';
import { GBConfigService } from './GBConfigService';
import { GBAzureDeployerPackage } from '../../azuredeployer.gbapp';
import { GBSharePointPackage } from '../../sharepoint.gblib';
import { CollectionUtil } from 'pragmatismo-io-framework';
import { GBBasicPackage } from '../../basic.gblib/index.js';
import { GBGoogleChatPackage } from '../../google-chat.gblib/index.js';
import { GBHubSpotPackage } from '../../hubspot.gblib/index.js';
import open from 'open';
import ngrok from 'ngrok';
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';
import { GBBasicPackage } from '../../basic.gblib';
import { GBGoogleChatPackage } from '../../google-chat.gblib';
const opn = require('opn');
const cron = require('node-cron');
/**
* GBCoreService contains main logic for handling storage services related
@ -108,7 +100,7 @@ export class GBCoreService implements IGBCoreService {
private dialect: string;
/**
*
*
*/
constructor() {
this.adminService = new GBAdminService(this);
@ -122,87 +114,72 @@ export class GBCoreService implements IGBCoreService {
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') {
if (this.dialect === 'mssql') {
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';
}
storage = GBConfigService.get('STORAGE_STORAGE');
} else {
throw new Error(`Unknown dialect: ${this.dialect}.`);
}
const logging: boolean | Function =
GBConfigService.get('STORAGE_LOGGING') === 'true'
? (str: string): void => {
GBLogEx.info(0, str);
GBLog.info(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 acquire = parseInt(GBConfigService.get('STORAGE_ACQUIRE_TIMEOUT'));
const sequelizeOptions: SequelizeOptions = {
define: {
freezeTableName: true,
timestamps: false,
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' ? {
dialectOptions: {
options: {
trustServerCertificate: true,
encrypt: encrypt,
},
} : {},
pool: {
max: 5,
min: 0,
idle: 10000,
evict: 10000,
acquire: acquire,
encrypt: encrypt
}
},
pool: {
max: 32,
min: 8,
idle: 40000,
evict: 40000,
acquire: acquire
}
};
this.sequelize = new Sequelize(database, username, password, sequelizeOptions);
// Specifies custom setup for MSFT...
if (this.dialect === 'mssql') {
this.queryGenerator = this.sequelize.getQueryInterface().QueryGenerator;
// tslint:disable:no-unsafe-any
this.createTableQuery = this.queryGenerator.createTableQuery;
this.queryGenerator.createTableQuery = (tableName, attributes, options) =>
this.createTableQueryOverride(tableName, attributes, options);
this.changeColumnQuery = this.queryGenerator.changeColumnQuery;
this.queryGenerator.changeColumnQuery = (tableName, attributes) =>
this.changeColumnQueryOverride(tableName, attributes);
// tslint:enable:no-unsafe-any
}
}
/**
@ -213,7 +190,7 @@ export class GBCoreService implements IGBCoreService {
try {
await this.sequelize.authenticate();
} catch (error) {
GBLogEx.info(0, 'Opening storage firewall on infrastructure...');
GBLog.info('Opening storage firewall on infrastructure...');
// tslint:disable:no-unsafe-any
if (error.parent.code === 'ELOGIN') {
await this.openStorageFrontier(installationDeployer);
@ -224,50 +201,30 @@ export class GBCoreService implements IGBCoreService {
}
}
/**
* Syncronizes structure between model and tables in storage.
*/
* 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...');
GBLog.info('Syncing database...');
return await this.sequelize.sync({
alter: alter,
force: false // Keep it false due to data loss danger.
force: false // Keep it false this due to data loss danger.
});
} else {
const msg = `Database synchronization is disabled.`;
GBLogEx.info(0, msg);
GBLog.info(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 CollectionUtil.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) {
if (process.env.LOAD_ONLY !== undefined) {
const bots = process.env.LOAD_ONLY.split(`;`);
const and = [];
await CollectionUtil.asyncForEach(bots, async e => {
@ -277,15 +234,12 @@ export class GBCoreService implements IGBCoreService {
const options = {
where: {
[Op.or]: and
},
order: [['instanceId', 'ASC']]
}
};
return await GuaribasInstance.findAll(options as any);
return await GuaribasInstance.findAll(options);
} else {
const options = { where: { state: 'active' } ,
order: [['instanceId', 'ASC']]};
return await GuaribasInstance.findAll(options as any);
const options = { where: { state: 'active' } };
return await GuaribasInstance.findAll(options);
}
}
@ -316,16 +270,18 @@ export class GBCoreService implements IGBCoreService {
}
/**
* Writes .env required to start the full server. Used during
* first startup, when user is asked some questions to create the
* 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=
ADMIN_PASS=${instance.adminPass}
BOT_ID=${instance.botId}
CLOUD_SUBSCRIPTIONID=${instance.cloudSubscriptionId}
CLOUD_LOCATION=${instance.cloudLocation}
CLOUD_GROUP=${instance.botId}
CLOUD_USERNAME=${instance.cloudUsername}
CLOUD_PASSWORD=${instance.cloudPassword}
MARKETPLACE_ID=${instance.marketplaceId}
@ -336,27 +292,26 @@ 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);
fs.writeFileSync('.env', env);
}
/**
/**
* Certifies that network servers will reach back the development machine
* when calling back from web services. This ensures that reverse proxy is
* established.
*/
public async ensureProxy(port): Promise<string> {
try {
if (
(await GBUtil.exists('node_modules/ngrok/bin/ngrok.exe')) ||
(await GBUtil.exists('node_modules/.bin/ngrok'))
) {
return await ngrok.connect({ port: port });
if (fs.existsSync('node_modules/ngrok/bin/ngrok.exe') || fs.existsSync('node_modules/ngrok/bin/ngrok')) {
const ngrok = require('ngrok');
return await ngrok.connect({ port: port }, 10);
} else {
GBLog.warn('ngrok executable not found. Check installation or node_modules folder.');
GBLog.warn('ngrok executable not found (only tested on Windows). Check installation or node_modules folder.');
return 'https://localhost';
}
@ -385,7 +340,7 @@ ENDPOINT_UPDATE=true
}
/**
* Defines the entry point dialog to be called whenever a user
* Defines the entry point dialog to be called whenever a user
* starts talking to the bot.
*/
public setEntryPointDialog(dialogName: string) {
@ -425,31 +380,12 @@ ENDPOINT_UPDATE=true
}
try {
instance.params = JSON.stringify(JSON.parse(instance.params));
} catch (error) {
} catch (err) {
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 CollectionUtil.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.
*/
@ -458,23 +394,22 @@ ENDPOINT_UPDATE=true
installationDeployer: IGBInstallationDeployer,
proxyAddress: string
) {
GBLogEx.info(0, `Loading instances from storage...`);
GBLog.info(`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 CollectionUtil.asyncForEach(instances, async instance => {
GBLogEx.info(instance.instanceId, `Updating bot endpoint for ${instance.botId}...`);
GBLog.info(`Updating bot endpoint for ${instance.botId}...`);
try {
await installationDeployer.updateBotProxy(
instance.botId,
group,
GBConfigService.get('CLOUD_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')}.`);
GBLog.warn(`Bot ${instance.botId} not found on resource group ${GBConfigService.get('CLOUD_GROUP')}.`);
} else {
throw new Error(`Error updating bot proxy, details: ${error}.`);
}
@ -494,10 +429,7 @@ ENDPOINT_UPDATE=true
Try setting STORAGE_SYNC to true in .env file. Error: ${error.message}.`
);
} else {
GBLogEx.info(
0,
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
);
GBLog.info(`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}.`);
@ -509,7 +441,7 @@ ENDPOINT_UPDATE=true
}
/**
* Loads all system packages from 'packages' folder.
* 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
@ -529,12 +461,10 @@ ENDPOINT_UPDATE=true
GBAzureDeployerPackage,
GBSharePointPackage,
GBGoogleChatPackage,
GBBasicPackage,
GBHubSpotPackage,
SaaSPackage
GBBasicPackage
],
async e => {
GBLogEx.info(0, `Loading sys package: ${e.name}...`);
GBLog.info(`Loading sys package: ${e.name}...`);
const p = Object.create(e.prototype) as IGBPackage;
sysPackages.push(p);
@ -547,45 +477,34 @@ ENDPOINT_UPDATE=true
}
/**
* Verifies that an complex global password has been specified
* Verifies that an complex global password has been specified
* before starting the server.
*/
public ensureAdminIsSecured() { }
public ensureAdminIsSecured() {
const password = GBConfigService.get('ADMIN_PASS');
if (!GBAdminService.StrongRegex.test(password)) {
throw new Error(
'Please, define a really strong password in ADMIN_PASS environment variable before running the server.'
);
}
}
/**
* Creates the first bot instance (boot instance) used to "boot" the server.
* At least one bot is required to perform conversational administrative tasks.
* So a base main bot is always deployed and will act as root bot for
* configuration tree with three levels: .env > root bot > all other bots.
*/
public async createBootInstance(
core: GBCoreService,
installationDeployer: IGBInstallationDeployer,
proxyAddress: string
) {
return await this.createBootInstanceEx(
core,
installationDeployer,
proxyAddress,
null,
GBConfigService.get('FREE_TIER')
);
}
/**
* Creates the first bot instance (boot instance) used to "boot" the server.
* At least one bot is required to perform conversational administrative tasks.
* So a base main bot is always deployed and will act as root bot for
* configuration tree with three levels: .env > root bot > all other bots.
*/
public async createBootInstanceEx(
core: GBCoreService,
installationDeployer: IGBInstallationDeployer,
proxyAddress: string,
deployer,
freeTier
) {
GBLogEx.info(0, `Deploying cognitive infrastructure (on the cloud / on premises)...`);
GBLog.info(`Deploying cognitive infrastructure (on the cloud / on premises)...`);
try {
const { instance, credentials, subscriptionId, installationDeployer } = await StartDialog.createBaseInstance(
deployer,
freeTier
);
const { instance, credentials, subscriptionId } = await StartDialog.createBaseInstance(installationDeployer);
installationDeployer['core'] = this;
const changedInstance = await installationDeployer['deployFarm2'](
const changedInstance = await installationDeployer.deployFarm(
proxyAddress,
instance,
credentials,
@ -593,12 +512,12 @@ ENDPOINT_UPDATE=true
);
await this.writeEnv(changedInstance);
GBConfigService.init();
GBLogEx.info(0, `File .env written. Preparing storage and search for the first time...`);
GBLog.info(`File .env written. Preparing storage and search for the first time...`);
await this.openStorageFrontier(installationDeployer);
await this.initStorage();
return [changedInstance, installationDeployer];
return changedInstance;
} catch (error) {
GBLog.warn(
`There is an error being thrown, so please cleanup any infrastructure objects
@ -613,7 +532,7 @@ ENDPOINT_UPDATE=true
*/
public openBrowserInDevelopment() {
if (process.env.NODE_ENV === 'development') {
open('http://localhost:4242');
opn('http://localhost:4242');
}
}
@ -696,270 +615,45 @@ ENDPOINT_UPDATE=true
* 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 group = GBConfigService.get('CLOUD_GROUP');
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.
* and loaded into the work folder from /publish 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 {
public getParam<T>(instance: IGBInstance, name: string, defaultValue?: T): 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);
const params = JSON.parse(instance.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 (typeof defaultValue === 'boolean') {
return new Boolean(value ? value.toLowerCase() === 'true' : defaultValue);
}
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') {
if (typeof defaultValue === 'string') {
return value ? value : defaultValue;
}
if (value && typeof defaultValue === 'number') {
return new Number(value ? value : defaultValue ? defaultValue : 0).valueOf();
if (typeof defaultValue === 'number') {
return new Number(value ? value : defaultValue ? defaultValue : 0);
}
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 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 CollectionUtil.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 });
if (instance['dataValues'] && !value) {
value = instance['dataValues'][name];
if (value === null) {
const minBoot = GBServer.globals.minBoot as any;
if (minBoot.instance && minBoot.instance.datavalues) {
value = minBoot.instance.datavalues[name];
}
}
}
return instance;
return value;
}
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);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,13 @@
/*****************************************************************************\
| ® |
| |
| |
| |
| |
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) pragmatismo.com.br. All rights reserved. |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
@ -21,7 +23,7 @@
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of pragmatismo.com.br. |
| "General Bots" 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. |
@ -35,13 +37,11 @@
'use strict';
import { GBMinInstance, IGBCoreService, IGBInstance } from 'botlib';
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';
import fs = require('fs');
import urlJoin = require('url-join');
import { GBServer } from '../../../src/app';
import { GuaribasInstance } from '../models/GBModel';
import { GBConfigService } from './GBConfigService';
/**
* Handles the importing of packages.
@ -49,28 +49,16 @@ import { GBUtil } from '../../../src/util.js';
export class GBImporter {
public core: IGBCoreService;
constructor (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;
}
public async importIfNotExistsBotPackage(botId: string,
packageName: string, localPath: string, additionalInstance: IGBInstance = null) {
const settingsJson = JSON.parse(fs.readFileSync(urlJoin(localPath, 'settings.json'), 'utf8'));
if (botId === undefined) {
botId = settingsJson.botId;
}
let instance: IGBInstance;
if (botId === undefined) {
botId = GBConfigService.get('BOT_ID');
@ -78,7 +66,7 @@ export class GBImporter {
if (!instance) {
instance = <IGBInstance>{};
instance.state = 'active';
instance.adminPass = await GBUtil.hashPassword( GBConfigService.get('ADMIN_PASS'));
instance.adminPass = GBConfigService.get('ADMIN_PASS');
instance.botId = GBConfigService.get('BOT_ID');
instance.cloudSubscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
instance.cloudLocation = GBConfigService.get('CLOUD_LOCATION');
@ -96,7 +84,7 @@ export class GBImporter {
instance = await this.core.loadInstanceByBotId(botId);
}
if (instance != undefined && !instance.botId) {
if (instance != undefined && instance.botId === null) {
console.log(`Null BotId after load instance with botId: ${botId}.`);
} else {
instance = additionalInstance;
@ -105,23 +93,23 @@ export class GBImporter {
return await this.createOrUpdateInstanceInternal(instance, botId, localPath, settingsJson);
}
public async createBotInstance (botId: string) {
const fullSettingsJson = <GuaribasInstance>{ };
fullSettingsJson['botId'] = botId;
public async createBotInstance(botId: string) {
const fullSettingsJson = { ...GBServer.globals.bootInstance };
fullSettingsJson.botId = botId;
return await GuaribasInstance.create(fullSettingsJson);
}
private async createOrUpdateInstanceInternal (
private async createOrUpdateInstanceInternal(
instance: IGBInstance,
botId: string,
localPath: string,
settingsJson: any
) {
const fullSettingsJson = { ...GBServer.globals.bootInstance, ...settingsJson,
description:"General Bot", title:botId
};
const packageJson = JSON.parse(fs.readFileSync(urlJoin(localPath, 'package.json'), 'utf8'));
const servicesJson = JSON.parse(fs.readFileSync(urlJoin(localPath, 'services.json'), 'utf8'));
const fullSettingsJson = { ...GBServer.globals.bootInstance, ...packageJson, ...settingsJson, ...servicesJson };
if (botId !== undefined) {
fullSettingsJson.botId = botId;

View file

@ -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';
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
});
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,371 +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';
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();
}
});
await page.setExtraHTTPHeaders({
'ngrok-skip-browser-warning': '1'
});
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();
}
}
}
}

View file

@ -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);
};

Some files were not shown because too many files have changed in this diff Show more