build(deps): bump webpack from 5.75.0 to 5.76.0 in /packages/default.gbui #366
|
|
@ -1,2 +1,2 @@
|
|||
[config]
|
||||
command = deploy.cmd
|
||||
command = bash ./deploy.sh
|
||||
5
.env
|
|
@ -1,5 +0,0 @@
|
|||
ADMIN_PASS=
|
||||
ADDITIONAL_DEPLOY_PATH=
|
||||
DATABASE_DIALECT=sqlite
|
||||
DATABASE_OBJECT_PREFIX=env1-
|
||||
DATABASE_SYNC=false
|
||||
3
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
* text=auto
|
||||
*.js eol=lf
|
||||
*.ts eol=lf
|
||||
35
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal 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
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: Custom issue template
|
||||
about: Describe this issue template's purpose here.
|
||||
|
||||
---
|
||||
|
||||
|
||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal 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
|
|
@ -0,0 +1,2 @@
|
|||
**Description**
|
||||
A clear and concise description of what the requirement is.
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Please check if your PR fulfills the following specifications:
|
||||
|
||||
- [ ] Tests for the changes have been added
|
||||
- [ ] Tests for the changes have been done
|
||||
- [ ] Docs have been added/updated
|
||||
|
||||
### References
|
||||
|
|
|
|||
31
.gitignore
vendored
|
|
@ -1,7 +1,30 @@
|
|||
node_modules
|
||||
/deploy/default.gbui/build
|
||||
/.coveralls.yml
|
||||
/.env
|
||||
/.npmrc
|
||||
/.nyc_output
|
||||
/coverage
|
||||
/dist
|
||||
/guaribas.sqlite
|
||||
/docs
|
||||
/guaribas.log
|
||||
/guaribas.sqlite
|
||||
/node_modules
|
||||
/packages/default.gbui/build
|
||||
/packages/default.gbui/.env
|
||||
/packages/default.gbui/node_modules
|
||||
/packages/default.gbui/package-lock.json
|
||||
/packages/default.gbui/yarn-lock.json
|
||||
/work
|
||||
/docs
|
||||
*.vbs.compiled
|
||||
*.vbs.js
|
||||
*.vbs.ts
|
||||
.env
|
||||
*.env
|
||||
.vscode/launch.json
|
||||
.wwebjs_auth
|
||||
GB.log
|
||||
gb.log
|
||||
GB.log.json
|
||||
yarn-error.log
|
||||
package-lock.json
|
||||
yarn-lock.json
|
||||
packages/saas.gbapp.zip
|
||||
|
|
|
|||
9
.hintrc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": [
|
||||
"development"
|
||||
],
|
||||
"hints": {
|
||||
"typescript-config/strict": "off",
|
||||
"typescript-config/consistent-casing": "off"
|
||||
}
|
||||
}
|
||||
15
.npmignore
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# This file must be a copy of .gitignore except for the WILLSHIP commented lines below.
|
||||
/.coveralls.yml
|
||||
/.env
|
||||
/.npmrc
|
||||
# WILLSHIP /.nyc_output
|
||||
/coverage
|
||||
# WILLSHIP /dist
|
||||
/guaribas.log
|
||||
/guaribas.sqlite
|
||||
/node_modules
|
||||
# WILLSHIP /packages/default.gbui/build
|
||||
/packages/default.gbui/.env
|
||||
/packages/default.gbui/node_modules
|
||||
/tmp
|
||||
/work
|
||||
8
.prettierrc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120,
|
||||
"arrowParens": "avoid",
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
||||
33
.travis.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
dist: focal
|
||||
language: node_js
|
||||
node_js:
|
||||
- 19.7.0
|
||||
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
before_script:
|
||||
- npm run build
|
||||
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
- /^greenkeeper/.*$/
|
||||
except:
|
||||
- /^v\d+\.\d+\.\d+$/
|
||||
|
||||
after_success:
|
||||
- npm install -g travis-deploy-once
|
||||
- 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: main
|
||||
19
.vscode/launch.json
vendored
|
|
@ -4,15 +4,24 @@
|
|||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"sourceMaps": true,
|
||||
"name": "Debug Program",
|
||||
"program": "${workspaceRoot}/dist/src/app.js",
|
||||
"program": "${workspaceRoot}/boot.mjs",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
"NODE_ENV": "development",
|
||||
"NODE_NO_WARNINGS":"1"
|
||||
},
|
||||
"args":["--no-deprecation"],
|
||||
"skipFiles": ["node_modules/**/*.js"],
|
||||
"outFiles": ["${workspaceRoot}/dist/*.js"],
|
||||
"args": [
|
||||
"--no-deprecation",
|
||||
"--loader ts-node/esm",
|
||||
"--require ${workspaceRoot}/suppress-node-warnings.cjs",
|
||||
],
|
||||
"skipFiles": [
|
||||
"node_modules/**/*.js"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/dist/**/*.js"],
|
||||
"stopOnEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
|
|
|
|||
3
.vscode/settings.json
vendored
|
|
@ -1,4 +1,3 @@
|
|||
{
|
||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
14
.vscode/tasks.json
vendored
|
|
@ -1,6 +1,20 @@
|
|||
{
|
||||
// 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",
|
||||
|
|
|
|||
2492
CHANGELOG.md
Normal file
48
CODE_OF_CONDUCT-pt-br.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# 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/
|
||||
49
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## 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 person’s 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.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using standard(no idiomatic expressions), welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
* Writing general pieces of code so it can be widely used.
|
||||
|
||||
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)
|
||||
* 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
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
|
||||
|
|
@ -22,13 +22,11 @@ When logging a bug, please be sure to include the following:
|
|||
|
||||
We also accept suggestions in the issue tracker.
|
||||
|
||||
|
||||
In general, things we find useful when reviewing suggestions are:
|
||||
* A description of the problem you're trying to solve
|
||||
* An overview of the suggested solution
|
||||
* Examples of how the suggestion would work in various places
|
||||
|
||||
|
||||
# Instructions for Contributing Code
|
||||
|
||||
## Contributing bug fixes
|
||||
|
|
@ -54,6 +52,33 @@ Your pull request should:
|
|||
* Have clear commit messages
|
||||
* e.g. "Refactor feature", "Fix issue", "Add tests for issue"
|
||||
|
||||
## Running (and adding) the Tests
|
||||
## You need to be able to run your system
|
||||
|
||||
from: http://catern.com/run.html
|
||||
|
||||
When developing a system, it is important to be able to run the system in its entirety.
|
||||
"Run the unit tests" doesn't count. The complexity of your system is in the interactions between the units.
|
||||
|
||||
"Run an individual service against mocks" doesn't count. A mock will rarely behave identically to the real dependency, and the behavior of the individual service will be unrealistic. You need to run the actual system.
|
||||
|
||||
"Run an individual service in a shared stateful development environment running all the other services" doesn't count. A shared development environment will be unreliable as it diverges more and more from the real system.
|
||||
|
||||
"Run most services in a mostly-isolated development environment, calling out to a few hard-to-run external services" doesn't count. Those few external services on the edge of the mostly-isolated development environment are often the most crucial ones; without the ability to run modified versions of them, your development process is crippled. Furthermore, being dependent on external services greatly complicates where and how you can run the system; it's much harder to, for example, run tests with the system on every commit if that will access external services.
|
||||
|
||||
"Run all the services that make up the system in an isolated development environment" counts; it's the bare minimum requirement. Bonus points if this can be done completely on localhost, without using an off-host cluster deployment system.
|
||||
|
||||
Without the ability to actually run the entire system in this way while developing, many evil practices will tend to become common.
|
||||
|
||||
Testing is harder and far less representative, and therefore many issues can only be found when changes are deployed to production.
|
||||
In turn, production deployment will cause issues more often, and so deployment will be more slow and less frequent.
|
||||
Deploying the system to new environments is more difficult, since the developers aren't able to actually run the system. Existing practices in production will be cargo-culted and copied around indefinitely, even when they are unnecessary or actively harmful.
|
||||
Exploratory usage of the system is very difficult, so it will be harder to consider using the system for purposes outside what it was originally developed for, and new use cases will become rare.
|
||||
Downstream clients who depend on the system will also suffer all these issues, since without the ability to run the upstream system in development, they can't run their own entire system, which is a superset of the upstream system.
|
||||
Running the entire system during development is the first step to preventing these issues. Further steps include writing automated tests for the system (which can be run repeatedly during development), and using, as much as possible, the same code to run the system in development and in production.
|
||||
Developers of large or legacy systems that cannot already be run in their entirety during development often believe that it is impractical to run the entire system during development. They'll talk about the many dependencies of their system, how it requires careful configuration of a large number of hosts, or how it's too complex to get reliable behavior.
|
||||
|
||||
In my experience, they're always wrong. These systems can be run locally during development with a relatively small investment of effort. Typically, these systems are just ultimately not as complicated as people think they are; once the system's dependencies are actually known and understood rather than being cargo-culted or assumed, running the system, and all its dependencies, is straightforward.
|
||||
|
||||
Being able to run your entire system during development is just about the most basic requirement for a software project. It's not, on its own, sufficient for your development practices to be high quality; but if you can't do this, then you're not even in the running.
|
||||
|
||||
|
||||
*Coming soon*
|
||||
|
|
|
|||
148
DATABASE-CHANGES.md
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
|
||||
# 2.0.0
|
||||
|
||||
``` SQL
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
agentSystemId nvarchar(16) NULL,
|
||||
agentMode nvarchar(16) NULL,
|
||||
agentContacted datetime NULL
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [phone]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [internalAddress]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasUser] DROP COLUMN [currentBotId]
|
||||
GO
|
||||
|
||||
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [authenticatorClientId]
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [authenticatorClientSecret]
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
locale nvarchar(5) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
translatorKey nvarchar(64) NULL
|
||||
translatorEndpoint nvarchar(64) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
activationCode nvarchar(16) NULL
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
params nvarchar(4000) NULL
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
state nvarchar(16) NULL
|
||||
GO
|
||||
UPDATE dbo.GuaribasInstance SET state= 'active'
|
||||
|
||||
# 2.0.3
|
||||
|
||||
``` SQL
|
||||
|
||||
ALTER TABLE dbo.GuaribasPackage ADD
|
||||
params custom(512) NULL
|
||||
GO
|
||||
|
||||
```
|
||||
|
||||
|
||||
# 2.0.56
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
hearOnDialog nvarchar(64) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasConversation ADD
|
||||
instanceId int,
|
||||
feedback nvarchar(512) NULL
|
||||
GO
|
||||
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [translatorendpoint]
|
||||
GO
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
translatorEndpoint nvarchar(128) NULL
|
||||
GO
|
||||
|
||||
|
||||
# 2.0.108
|
||||
|
||||
ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [agentSystemId]
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
agentSystemId nvarchar(255) NULL,
|
||||
GO
|
||||
|
||||
# 2.0.115
|
||||
|
||||
ALTER TABLE dbo.GuaribasQuestion ADD
|
||||
skipIndex bit NULL
|
||||
GO
|
||||
|
||||
# 2.0.116 >
|
||||
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
googleBotKey nvarchar(255) NULL,
|
||||
googleChatApiKey nvarchar(255) NULL,
|
||||
googleChatSubscriptionName nvarchar(255) NULL,
|
||||
googleClientEmail nvarchar(255) NULL,
|
||||
googlePrivateKey nvarchar(4000) NULL,
|
||||
googleProjectId nvarchar(255) NULL
|
||||
GO
|
||||
|
||||
# 2.0.119
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD
|
||||
facebookWorkplaceVerifyToken nvarchar(255) NULL,
|
||||
facebookWorkplaceAppSecret nvarchar(255) NULL,
|
||||
facebookWorkplaceAccessToken nvarchar(512) NULL
|
||||
GO
|
||||
|
||||
|
||||
# 2.0.140
|
||||
|
||||
/****** Object: Table [dbo].[GuaribasSchedule] Script Date: 25/08/2021 03:53:15 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[GuaribasSchedule]
|
||||
[id] [int] IDENTITY(1,1) NOT NULL,
|
||||
[name] [nvarchar](255) NULL,
|
||||
[schedule] [nvarchar](255) NULL,
|
||||
[instanceId] [int] NULL,
|
||||
[createdAt] [datetimeoffset](7) NULL,
|
||||
[updatedAt] [datetimeoffset](7) NULL
|
||||
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasInstance ADD botKey nvarchar(64) NULL;
|
||||
|
||||
# 2.3.9
|
||||
|
||||
GO
|
||||
|
||||
ALTER TABLE dbo.GuaribasUser ADD
|
||||
params nvarchar(4000) NULL
|
||||
GO
|
||||
8
FEATURES.md
Normal 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 |
|
||||
7
LOCALIZATION.md
Normal 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.
|
||||
|
||||
216
README.md
|
|
@ -1,159 +1,121 @@
|
|||
General Bots Community Edition Preview
|
||||
====================================
|
||||
<a href="https://github.com/generalbots/botserver/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=generalbots/botserver" />
|
||||
</a>
|
||||
|
||||
Welcome to General Bots!
|
||||
-------
|
||||
|
||||
General Bots is a packaged based chat bot server focused in convention
|
||||
over configuration and codeless aproaches, which brings software packages
|
||||
and application server concepts to help parallel bot development.
|
||||
| Area | Status |
|
||||
|------------------------------|----------------------------------------------------------------------------------------------------|
|
||||
| Releases | [](https://www.npmjs.com/package/botserver/) [](https://www.npmjs.com/package/botlib/) [](https://github.com/semantic-release/semantic-release)|
|
||||
| Community | [](https://stackoverflow.com/questions/tagged/generalbots) [](https://badges.frapsoft.com) [](http://makeapullrequest.com) [](https://github.com/GeneralBots/BotServer/blob/master/LICENSE.txt)|
|
||||
| Management | [](https://gitHub.com/GeneralBots/BotServer/graphs/commit-activity) |
|
||||
| Security | [](https://snyk.io/test/github/GeneralBots/BotServer) |
|
||||
| Building & Quality | [](https://app.travis-ci.com/github/GeneralBots/BotServer) [](https://coveralls.io/github/GeneralBots/BotServer) [](https://github.com/prettier/prettier) |
|
||||
| Packaging | [](https://badge.fury.io) [](https://github.com/GeneralBots/BotServer/releases/latest) [](https://david-dm.org) [](http://commitizen.github.io/cz-cli/) |
|
||||
| Samples | [VBA](https://github.com/GeneralBots/BotServer/tree/master/packages/default.gbdialog) or [](https://github.com/GeneralBots/AzureADPasswordReset.gbapp)
|
||||
| [Docker Image](https://github.com/lpicanco/docker-botserver) |      <br/> *Provided by [@lpicanco](https://github.com/lpicanco/docker-botserver)* |
|
||||
|
||||
Also, everyone can create bots copying and pasting some files and using their
|
||||
favorite tools like Excel (or any .tsv editor) or Photoshop (or any .png
|
||||
editor).
|
||||
General Bots
|
||||
------------------
|
||||
|
||||
### What is Bot Server?
|
||||

|
||||
|
||||
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?
|
||||
|
||||
Bot Server accelerates the process of developing a bot. It provisions all code
|
||||
base, resources and deployment to the cloud, and gives you templates you can
|
||||
choose from when you create a bot. Uses a database and tables as backend and
|
||||
allow you to further modify your bot package directly downloading it in a ZIP
|
||||
file and editing it and uploading it back to the server (deploying process).
|
||||
Besides providing a framework to develop bot packages in a more advanced
|
||||
editor like Visual Studio Code, Atom or Brackets.
|
||||
choose from whenever you need a new bot. The server has a database and service
|
||||
backend allowing you to further modify your bot package directly by downloading
|
||||
a zip file, editing and uploading it back to the server (deploying process) with
|
||||
no code. The Bot Server also provides a framework to develop bot packages in a more
|
||||
advanced fashion writing custom code in editors like Visual Studio Code, Atom or Brackets.
|
||||
|
||||
### The same build process for everyone
|
||||
Everyone can create bots by just copying and pasting some files and using their
|
||||
favorite tools from Office (or any text editor) or Photoshop (or any image
|
||||
editor). BASIC can be used to build custom dialogs so Bot can be extended just like VBA for Excel (currently in alpha).
|
||||
|
||||
GeneralBots aims to delivery bots in azure in a very easy and fast fashion. Use
|
||||
Office tools like Word or Excel to edit your Bot - using code (JavaScript or TypeScript) just to empower custom requirements.
|
||||

|
||||
|
||||
How To
|
||||
------
|
||||
## Samples
|
||||
|
||||
Several samples, including a Bot for AD Password Reset, are avaiable on the [repository list](https://github.com/GeneralBots).
|
||||
|
||||
### Updating the Bot Knoledge Base (.gbkb folder)
|
||||
### Using complete General Bots Conversational Data Analytics
|
||||
|
||||

|
||||
|
||||
The subjects.json file contains all information related to the subject tree and can be used to build the menu carrousel as well give a set of words to be used as subject catcher in the conversation. A hierarchy can be specified.
|
||||
```
|
||||
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)
|
||||
|
||||
### Creating a new Theme folder (.gbtheme folder)
|
||||
TALK "Demonstration of Gift Contributions with AS IMAGE keyword"
|
||||
SET THEME dark
|
||||
png = data as IMAGE
|
||||
SEND FILE png
|
||||
|
||||
A theme is composed of some CSS files and images. That set of files can change
|
||||
everything in the General Bots UI. Use them extensively before going to change
|
||||
the UI application itself (HTML & JS).
|
||||
DELAY 5
|
||||
TALK " Demonstration of Gift Contributions CHART keyword"
|
||||
img = CHART "bar", data
|
||||
SEND FILE img
|
||||
```
|
||||
|
||||
Package Types
|
||||
-------------
|
||||
## Guide
|
||||
|
||||
### .gbai
|
||||
[Read the General Bots BotBook Guide](https://github.com/GeneralBots/BotBook/tree/master/book).
|
||||
|
||||
Embraces all packages types (content, logic & conversation) into a pluggable bot
|
||||
directory.
|
||||
# Videos
|
||||
|
||||
### .gbapp
|
||||
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.
|
||||
|
||||
The artificial intelligence extensions in form of pluggable apps. Dialogs,
|
||||
Services and all model related to data. A set of interactions, use cases,
|
||||
integrations in form of conversationals dialogs.
|
||||
The .gbapp adds the General Bots base library (botlib) for building Node.js TypeScript Apps packages.
|
||||
[](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.
|
||||
|
||||
Four components builds up a General Bots App:
|
||||
[](https://www.youtube.com/watch?v=yX1sF9n9628)
|
||||
|
||||
|
||||
# Contributing
|
||||
|
||||
* dialogs
|
||||
* models
|
||||
* services
|
||||
* tests
|
||||
This project welcomes contributions and suggestions.
|
||||
See our [Contribution Guidelines](https://github.com/pragmatismo-io/BotServer/blob/master/CONTRIBUTING.md) for more details.
|
||||
|
||||
#### Dialogs
|
||||
# Reporting Security Issues
|
||||
|
||||
All code contained in a dialog builds the flow to custom conversations in
|
||||
built-in and additional packages .
|
||||
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
|
||||
|
||||
#### Models
|
||||
|
||||
Models builds the foundation of data relationships in form of entities.
|
||||
|
||||
|
||||
#### Services
|
||||
|
||||
Services are a façade for bot back-end logic and other custom processing.
|
||||
|
||||
|
||||
#### Tests
|
||||
|
||||
Tests try to automate code execution validation before crashing in production.
|
||||
|
||||
|
||||
### .gbot
|
||||
|
||||
An expression of an artificial inteligence entity. A .gbot file defines
|
||||
all bots dependencies related to services and other resources.
|
||||
|
||||
### .gbtheme
|
||||
|
||||
A theme of a bot at a given time. CSS files & images that can compose all UI
|
||||
presentation and using it a branding can be done.
|
||||
|
||||
### .gbkb
|
||||
|
||||
A set of subjects that bot knows.
|
||||
|
||||
|
||||
### .gblib
|
||||
|
||||
Shared code that can be used across bot apps.
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
### GeneralBots admin commands
|
||||
|
||||
General Bots can be controlled by the same chat window people talk to, so
|
||||
here is a list of admin commands related to deploying .gb* files.
|
||||
|
||||
| Command | Description |
|
||||
|-----------------|-----------------------------------------------------------------------------------------------------------------|
|
||||
| deployPackage | Deploy a KB package. Usage **deployPackage** [package-name]. Then, you need to run rebuildIndex. |
|
||||
| undeployPackage | Undeploy a KB. Usage **undeployPackage** [package-name]. |
|
||||
| redeployPackage | Undeploy and then deploys the KB. Usage **redeployPackage** [package-name]. Then, you need to run rebuildIndex. |
|
||||
| rebuildIndex | Rebuild Azure Search indexes, must be run after **deployPackage** or **redeployPackage**. |
|
||||
|
||||
### Credits & Inspiration
|
||||
|
||||
* Rodrigo Rodriguez (me@rodrigorodriguez.com) - Coding, Docs & Architecture.
|
||||
* David Lerner (david.lerner@hotmail.com) - UI, UX & Theming
|
||||
* Eduardo Romeiro (eromeirosp@outlook.com) - Content & UX
|
||||
|
||||
|
||||
Powered by Microsoft [BOT Framework](https://dev.botframework.com/) and [Azure](http://www.azure.com).
|
||||
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
|
||||
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 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> <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".
|
||||
|
||||
|
||||
## License & Warranty
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
|||
6
ROADMAP.md
Normal 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
|
|
@ -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. |
|
||||
62
SECURITY.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# 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.
|
||||
• Dário Vieira has day-to-day operational responsibility for implementing this policy.
|
||||
• 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.io
|
||||
|
||||
|
||||
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.io
|
||||
79
WARNINGS.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# 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
|
||||
|
||||
BIN
blank.docx
Normal file
BIN
blank.xlsx
Normal file
63
boot.mjs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import Fs from 'fs';
|
||||
import Path from 'path';
|
||||
import { exec } from 'child_process';
|
||||
import pjson from './package.json' assert { type: 'json' };
|
||||
|
||||
// Displays version of Node JS being used at runtime and others attributes.
|
||||
|
||||
console.log(``);
|
||||
console.log(``);
|
||||
console.log(` █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® `);
|
||||
console.log(`██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ `);
|
||||
console.log(`██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ `);
|
||||
console.log(`██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ `);
|
||||
console.log(` █████ █████ █ ███ █████ ██ ██ ██ ██ ██████ ████ █████ █ ███ 3.0`);
|
||||
process.stdout.write(` botserver@${pjson.version}, botlib@${pjson.dependencies.botlib}, botbuilder@${pjson.dependencies.botbuilder}, node@${process.version.replace('v', '')}, ${process.platform} ${process.arch} `);
|
||||
|
||||
var now = () => {
|
||||
return new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '') + ' UTC';
|
||||
};
|
||||
var __dirname = process.env.PWD || process.cwd();
|
||||
try {
|
||||
var run = () => {
|
||||
import('./dist/src/app.js').then((gb)=> {
|
||||
console.log(`\n`);
|
||||
gb.GBServer.run()
|
||||
});
|
||||
};
|
||||
var processDist = () => {
|
||||
if (!Fs.existsSync('dist')) {
|
||||
console.log(`\n`);
|
||||
console.log(`Generall Bots: 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(`\n`);
|
||||
console.log(`Generall Bots: 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);
|
||||
}
|
||||
18
deploy.cmd
|
|
@ -59,7 +59,7 @@ IF DEFINED KUDU_SELECT_NODE_VERSION_CMD (
|
|||
SET /p NODE_EXE=<"%DEPLOYMENT_TEMP%\__nodeVersion.tmp"
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
)
|
||||
|
||||
|
||||
IF EXIST "%DEPLOYMENT_TEMP%\__npmVersion.tmp" (
|
||||
SET /p NPM_JS_PATH=<"%DEPLOYMENT_TEMP%\__npmVersion.tmp"
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
|
|
@ -96,7 +96,7 @@ call :SelectNodeVersion
|
|||
:: 3. Install npm packages
|
||||
IF EXIST "%DEPLOYMENT_TARGET%\package.json" (
|
||||
pushd "%DEPLOYMENT_TARGET%"
|
||||
echo GUARIBASDEPLOYER ------------------ Installing packages for server.
|
||||
echo [General Bots Deployer] Installing packages for server...
|
||||
call :ExecuteCmd !NPM_CMD! install --production
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
popd
|
||||
|
|
@ -104,20 +104,24 @@ IF EXIST "%DEPLOYMENT_TARGET%\package.json" (
|
|||
|
||||
:: 3.1 Install npm packages on UI
|
||||
IF EXIST "%DEPLOYMENT_TARGET%\deploy\default.gbui\package.json" (
|
||||
call :ExecuteCmd !NPM_CMD! config set scripts-prepend-node-path true
|
||||
pushd "%DEPLOYMENT_TARGET%\deploy\default.gbui"
|
||||
echo GUARIBASDEPLOYER ------------------ Installing packages for default.gbui.
|
||||
echo [General Bots Deployer] Installing packages for default.gbui...
|
||||
call :ExecuteCmd !NPM_CMD! install
|
||||
echo GUARIBASDEPLOYER ------------------ Building default.gbui.
|
||||
echo [General Bots Deployer] Building default.gbui...
|
||||
call :ExecuteCmd !NPM_CMD! run build
|
||||
IF !ERRORLEVEL! NEQ 0 goto error
|
||||
RMDIR /s /q "%DEPLOYMENT_TARGET%\deploy\default.gbui\node_modules"
|
||||
popd
|
||||
)
|
||||
|
||||
|
||||
:: 4. Install typescript
|
||||
echo GUARIBASDEPLOYER ------------------ Transpiling...
|
||||
:: 4. Install TypeScript
|
||||
echo [General Bots Deployer] Transpiling...
|
||||
call :ExecuteCmd node %DEPLOYMENT_TARGET%\node_modules\typescript\bin\tsc -v
|
||||
call :ExecuteCmd node %DEPLOYMENT_TARGET%\node_modules\typescript\bin\tsc -p "%DEPLOYMENT_TARGET%"
|
||||
|
||||
echo [General Bots Deployer] Deployment Finished.
|
||||
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
goto end
|
||||
|
||||
|
|
|
|||
96
deploy.sh
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#!/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."
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
import { AzureSearch } from "pragmatismo-io-framework1";
|
||||
import { Prompts, Session, UniversalBot } from 'botbuilder';
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { IGBDialog } from "botlib";
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
||||
import { GBImporter } from '../../core.gbapp/services/GBImporter';
|
||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
||||
|
||||
const UrlJoin = require("url-join");
|
||||
export class AdminDialog extends IGBDialog {
|
||||
|
||||
static setup(bot: UniversalBot, min: GBMinInstance) {
|
||||
|
||||
let importer = new GBImporter(min.core);
|
||||
let deployer = new GBDeployer(min.core, importer);
|
||||
|
||||
bot
|
||||
.dialog("/admin", [
|
||||
(session: Session, args) => {
|
||||
Prompts.text(session, "Please, authenticate:");
|
||||
if (args == undefined || args.firstRun) {
|
||||
}
|
||||
},
|
||||
(session: Session, results) => {
|
||||
var text = results.response;
|
||||
if (
|
||||
!session.privateConversationData.authenticated ||
|
||||
text === GBConfigService.get("ADMIN_PASS")
|
||||
) {
|
||||
session.privateConversationData.authenticated = true;
|
||||
session.send(
|
||||
"Welcome to Pragmatismo.io GeneralBots Administration."
|
||||
);
|
||||
Prompts.text(session, "Which task do you wanna run now?");
|
||||
} else {
|
||||
session.endDialog();
|
||||
}
|
||||
},
|
||||
function(session: Session, results) {
|
||||
var text = results.response;
|
||||
if (text === "quit") {
|
||||
session.privateConversationData.authenticated = false;
|
||||
session.replaceDialog("/");
|
||||
} else if (text === "sync") {
|
||||
min.core.syncDatabaseStructure(() => {});
|
||||
session.send("Sync started...");
|
||||
session.replaceDialog("/admin", {
|
||||
firstRun: false
|
||||
});
|
||||
} else if (text.split(" ")[0] === "rebuildIndex") {
|
||||
AdminDialog.rebuildIndexCommand(min, session, () =>
|
||||
session.replaceDialog("/admin", {
|
||||
firstRun: false
|
||||
})
|
||||
);
|
||||
} else if (text.split(" ")[0] === "deployPackage") {
|
||||
AdminDialog.deployPackageCommand(text, session, deployer, min, () =>
|
||||
session.replaceDialog("/admin", {
|
||||
firstRun: false
|
||||
})
|
||||
);
|
||||
} else if (text.split(" ")[0] === "redeployPackage") {
|
||||
AdminDialog.undeployPackageCommand(text, min,session, () => {
|
||||
AdminDialog.deployPackageCommand(text, session, deployer, min, () => {
|
||||
session.send("Redeploy done.");
|
||||
session.replaceDialog("/admin", {
|
||||
firstRun: false
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (text.split(" ")[0] === "undeployPackage") {
|
||||
AdminDialog.undeployPackageCommand(text, min, session, () =>
|
||||
session.replaceDialog("/admin", {
|
||||
firstRun: false
|
||||
})
|
||||
);
|
||||
} else if (text.split(" ")[0] === "applyPackage") {
|
||||
session.send("Applying in progress...");
|
||||
min.core.loadInstance(text.split(" ")[1], (item, err) => {
|
||||
session.send("Applying done...");
|
||||
session.replaceDialog("/");
|
||||
});
|
||||
session.replaceDialog("/admin", {
|
||||
firstRun: false
|
||||
});
|
||||
}
|
||||
}
|
||||
])
|
||||
.triggerAction({
|
||||
matches: /^(admin)/i
|
||||
});
|
||||
}
|
||||
|
||||
static undeployPackageCommand(text: any, min: GBMinInstance, session: Session, cb) {
|
||||
let packageName = text.split(" ")[1];
|
||||
let importer = new GBImporter(min.core);
|
||||
let deployer = new GBDeployer(min.core, importer);
|
||||
session.send(`Undeploying package ${packageName}...`);
|
||||
deployer.undeployPackageFromLocalPath(
|
||||
min.instance,
|
||||
UrlJoin("deploy", packageName),
|
||||
(data, err) => {
|
||||
session.send(`Package ${packageName} undeployed...`);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
static deployPackageCommand(
|
||||
text: string,
|
||||
session: Session,
|
||||
deployer: GBDeployer,
|
||||
min: GBMinInstance,
|
||||
cb
|
||||
) {
|
||||
let packageName = text.split(" ")[1];
|
||||
session.send(`Deploying package ${packageName}... (It may take a few seconds)`);
|
||||
deployer.deployPackageFromLocalPath(
|
||||
UrlJoin("deploy", packageName),
|
||||
(data, err) => {
|
||||
session.send(`Package ${packageName} deployed... Please run rebuildIndex command.`);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
static rebuildIndexCommand(min: GBMinInstance, session: Session, cb) {
|
||||
let search = new AzureSearch(
|
||||
min.instance.searchKey,
|
||||
min.instance.searchHost,
|
||||
min.instance.searchIndex,
|
||||
min.instance.searchIndexer
|
||||
);
|
||||
session.send("Rebuilding index...");
|
||||
search.rebuildIndex((data, err) => {
|
||||
session.send("Index rebuilt.");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import { IGBDialog } from "botlib";
|
||||
import { Prompts, UniversalBot, Session, ListStyle } from "botbuilder";
|
||||
import UrlJoin from "url-join";
|
||||
import { GBMinInstance } from "botlib";
|
||||
var fs = require("fs");
|
||||
var request = require("request");
|
||||
var mkdirp = require("mkdirp");
|
||||
var builder = require("botbuilder");
|
||||
const logger = require('../base/winston');
|
||||
|
||||
export class AskDialog extends IGBDialog {
|
||||
static setup(bot: UniversalBot, min: GBMinInstance) {
|
||||
bot.dialog("/attachFile", [
|
||||
function(session, args, next) {
|
||||
logger.debug("/attachFile/F1: Start");
|
||||
if (session.privateConversationData.JWToken === undefined) {
|
||||
logger.error("/attachFile/F1: Undefined JWToken");
|
||||
session.endConversation(
|
||||
"Unable to store your attachments. Sorry for the inconvenience, please try again."
|
||||
);
|
||||
} else {
|
||||
if (session.privateConversationData.userRequest.text.length === 0) {
|
||||
if (
|
||||
session.privateConversationData.userRequest.attachments.length ===
|
||||
1
|
||||
) {
|
||||
var txt =
|
||||
"I received your attachment. Please let me know how should I handle it.";
|
||||
} else {
|
||||
var txt =
|
||||
"I received your attachments. Please let me know how should I handle them.";
|
||||
}
|
||||
var msg = new builder.Message(session)
|
||||
.textFormat("markdown")
|
||||
.text(txt);
|
||||
builder.Prompts.text(session, msg);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
function(session, args, next) {
|
||||
logger.debug("/attachFile/F2: Start");
|
||||
if (!(args.response === null) && !(args.response === undefined)) {
|
||||
session.privateConversationData.userRequest.text = args.response;
|
||||
}
|
||||
|
||||
var mkdirName =
|
||||
"work"
|
||||
|
||||
mkdirp(mkdirName, function(err) {
|
||||
if (err) {
|
||||
logger.error(
|
||||
"/attachFile/F2: unable to create folder. Error-> " + err
|
||||
);
|
||||
session.endConversation(
|
||||
"Unable to store your attachments. Sorry for the inconvenience, please try again."
|
||||
);
|
||||
} else {
|
||||
if (!mkdirName.endsWith("/")) {
|
||||
mkdirName = mkdirName + "/";
|
||||
}
|
||||
session.privateConversationData.attachmentsToWrite =
|
||||
session.privateConversationData.userRequest.attachments.length -
|
||||
1;
|
||||
writeFileRequest(session, mkdirName);
|
||||
}
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
function writeFileRequest(session, mkdirName) {
|
||||
var options = {
|
||||
url:
|
||||
session.privateConversationData.userRequest.attachments[
|
||||
session.privateConversationData.attachmentsToWrite
|
||||
].contentUrl,
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-type":
|
||||
session.privateConversationData.userRequest.attachments[
|
||||
session.privateConversationData.attachmentsToWrite
|
||||
].contentType
|
||||
}
|
||||
};
|
||||
// if (
|
||||
// session.message.address.channelId === "skype" ||
|
||||
// session.message.address.channelId === "msteams"
|
||||
// ) {
|
||||
// options.headers.Authorization =
|
||||
// "Bearer " + session.privateConversationData.JWToken;
|
||||
// }
|
||||
|
||||
request(options, function(err, response, body) {
|
||||
if (err) {
|
||||
logger.error(err);
|
||||
} else {
|
||||
logger.trace(response.statusCode);
|
||||
|
||||
var fileName =
|
||||
session.privateConversationData.userRequest.attachments[
|
||||
session.privateConversationData.attachmentsToWrite
|
||||
].name;
|
||||
if (fs.existsSync(mkdirName + fileName)) {
|
||||
var fileType = fileName.substr(fileName.lastIndexOf(".")); //e.g. '.pdf'
|
||||
var fileSubName = fileName.substr(
|
||||
0,
|
||||
fileName.length - fileType.length
|
||||
); //'name' if original fileName is 'name.pdf'
|
||||
var j = 1;
|
||||
while (
|
||||
fs.existsSync(mkdirName + fileSubName + "(" + j + ")" + fileType)
|
||||
) {
|
||||
j += 1;
|
||||
}
|
||||
fileName = fileSubName + "(" + j + ")" + fileType;
|
||||
}
|
||||
session.privateConversationData.userRequest.attachments[
|
||||
session.privateConversationData.attachmentsToWrite
|
||||
] = {
|
||||
name: fileName,
|
||||
contentUrl: mkdirName,
|
||||
contentType:
|
||||
session.privateConversationData.userRequest.attachments[
|
||||
session.privateConversationData.attachmentsToWrite
|
||||
].contentType
|
||||
};
|
||||
fs.writeFile(
|
||||
mkdirName + fileName,
|
||||
body,
|
||||
{ encoding: "binary" },
|
||||
function(err) {
|
||||
//{encoding: 'binary' , flag: 'wx'}
|
||||
if (err) {
|
||||
logger.error(
|
||||
"/attachFile/F2: unable to save file. Error-> " + err
|
||||
);
|
||||
session.endConversation(
|
||||
"Unable to store your attachments. Sorry for the inconvenience, please try again."
|
||||
);
|
||||
} else {
|
||||
session.privateConversationData.attachmentsToWrite -= 1;
|
||||
if (session.privateConversationData.attachmentsToWrite < 0) {
|
||||
session.beginDialog("/textRequest");
|
||||
} else {
|
||||
writeFileRequest(session, mkdirName);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import {
|
||||
Sequelize,
|
||||
DataTypes,
|
||||
DataTypeUUIDv4,
|
||||
DataTypeDate,
|
||||
DataTypeDecimal
|
||||
} from "sequelize";
|
||||
import {
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
HasMany,
|
||||
BelongsTo,
|
||||
BelongsToMany,
|
||||
Length,
|
||||
ForeignKey,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
DataType,
|
||||
IsUUID,
|
||||
PrimaryKey,
|
||||
AutoIncrement
|
||||
} from "sequelize-typescript";
|
||||
import { IGBInstance } from "botlib";
|
||||
|
||||
|
||||
@Table
|
||||
export class GuaribasInstance extends Model<GuaribasInstance> implements IGBInstance {
|
||||
|
||||
@Column
|
||||
whoAmIVideo: string;
|
||||
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
instanceId: number;
|
||||
|
||||
@Column botId: string;
|
||||
|
||||
@Column title: string;
|
||||
|
||||
@Column description: string;
|
||||
|
||||
@Column version: string;
|
||||
|
||||
@Column enabledAdmin: boolean;
|
||||
|
||||
/* Services section on bot.json */
|
||||
|
||||
@Column engineName: string;
|
||||
|
||||
@Column marketplaceId: string;
|
||||
|
||||
@Column textAnalyticsKey: string;
|
||||
|
||||
@Column marketplacePassword: string;
|
||||
|
||||
@Column webchatKey: string;
|
||||
|
||||
@Column theme: string;
|
||||
|
||||
@Column ui: string;
|
||||
|
||||
@Column kb: string;
|
||||
|
||||
@Column
|
||||
@Column({ type: DataType.STRING(512) })
|
||||
nlpServerUrl: string;
|
||||
|
||||
@Column searchHost: string;
|
||||
|
||||
@Column searchKey: string;
|
||||
|
||||
@Column searchIndex: string;
|
||||
|
||||
@Column searchIndexer: string;
|
||||
|
||||
/* Settings section of bot.json */
|
||||
|
||||
@Column({
|
||||
type: DataType.FLOAT
|
||||
})
|
||||
nlpVsSearch: number;
|
||||
|
||||
@Column({
|
||||
type: DataType.FLOAT
|
||||
})
|
||||
searchScore: number;
|
||||
|
||||
@Column({
|
||||
type: DataType.FLOAT
|
||||
})
|
||||
nlpScore: number;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
creationDate: Date;
|
||||
|
||||
@Column
|
||||
@UpdatedAt
|
||||
updatedOn: Date;
|
||||
}
|
||||
|
||||
@Table
|
||||
export class GuaribasPackage extends Model<GuaribasPackage> {
|
||||
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
packageId: number;
|
||||
|
||||
@Column
|
||||
packageName: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number;
|
||||
}
|
||||
|
||||
@Table
|
||||
export class GuaribasChannel extends Model<GuaribasChannel> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
channelId: number;
|
||||
|
||||
@Column title: string;
|
||||
}
|
||||
|
||||
@Table
|
||||
export class GuaribasException extends Model<GuaribasException> {
|
||||
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
exceptionId: number;
|
||||
|
||||
@Column message: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
creationDate: Date;
|
||||
}
|
||||
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
const UrlJoin = require("url-join");
|
||||
const gBuilder = require("botbuilder");
|
||||
const logger = require("../../../src/logger");
|
||||
|
||||
import { GBConfigService } from "./GBConfigService";
|
||||
import { GBCoreService } from "./GBCoreService";
|
||||
|
||||
import { Session, Message, LuisRecognizer } from "botbuilder";
|
||||
|
||||
import { GBService, GBServiceCallback, IGBConversationalService} from "botlib";
|
||||
import { GBError } from "botlib";
|
||||
import { GBERROR_TYPE } from "botlib";
|
||||
import { GBMinInstance } from "botlib";
|
||||
|
||||
|
||||
export class GBConversationalService implements IGBConversationalService{
|
||||
|
||||
coreService: GBCoreService;
|
||||
|
||||
constructor(coreService: GBCoreService) {
|
||||
this.coreService = coreService;
|
||||
}
|
||||
|
||||
sendEvent(session: Session, name: string, value: any) {
|
||||
var msg = new gBuilder.Message();
|
||||
msg.data.type = "event";
|
||||
msg.data.name = name;
|
||||
msg.data.value = value;
|
||||
session.send(msg);
|
||||
}
|
||||
|
||||
runNLP(
|
||||
session: Session,
|
||||
min: GBMinInstance,
|
||||
text: string,
|
||||
cb: GBServiceCallback<any>
|
||||
) {
|
||||
LuisRecognizer.recognize(
|
||||
text,
|
||||
min.instance.nlpServerUrl,
|
||||
(err, intents, entities) => {
|
||||
if (err) {
|
||||
cb(null, new GBError(err, GBERROR_TYPE.nlpGeneralError));
|
||||
return;
|
||||
}
|
||||
|
||||
if (intents && intents.length > 0) {
|
||||
var intent = intents[0].intent;
|
||||
var entity =
|
||||
entities && entities.length > 0
|
||||
? entities[0].entity.toUpperCase()
|
||||
: null;
|
||||
logger.trace(
|
||||
"luis: intent: [" + intent + "] entity: [" + entity + "]"
|
||||
);
|
||||
|
||||
// PACKAGE: Send to packages.
|
||||
|
||||
if (intent === "Student.CheckAttendance") {
|
||||
session.replaceDialog("/belagua-check-attendance", {entities: entities});
|
||||
}
|
||||
else if(intent === 'User.Authenticate'){
|
||||
session.replaceDialog("/belagua-user-login", {entities: entities});
|
||||
}
|
||||
else if (intent === "PerguntarSobreTermo") {
|
||||
session.send(
|
||||
"Vou mostrar um menu para ajudar você a formular sua pergunta..."
|
||||
);
|
||||
session.replaceDialog("/menu");
|
||||
} else if (intent === "ShowSubjectMenu") {
|
||||
session.replaceDialog("/menu");
|
||||
} else {
|
||||
session.sendTyping();
|
||||
session.send("Desculpe-me, não encontrei nada a respeito...");
|
||||
}
|
||||
|
||||
cb({ intent, entities }, null);
|
||||
} else {
|
||||
session.sendTyping();
|
||||
session.send("Lamento, não achei nada a respeito...");
|
||||
cb(null, null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
const Path = require("path");
|
||||
const Fs = require("fs");
|
||||
const _ = require("lodash");
|
||||
const Parse = require("csv-parse");
|
||||
const Async = require("async");
|
||||
const UrlJoin = require("url-join");
|
||||
const Walk = require("fs-walk");
|
||||
const logger = require("../../../src/logger");
|
||||
|
||||
import { Sequelize } from "sequelize-typescript";
|
||||
import { Promise } from "bluebird";
|
||||
import { GBConfigService } from "./GBConfigService";
|
||||
import { DataTypeUUIDv1 } from "sequelize";
|
||||
import { UniversalBot } from "botbuilder";
|
||||
import { GBServiceCallback, IGBInstance, IGBCoreService } from 'botlib';
|
||||
import { GuaribasInstance } from "../models/GBModel";
|
||||
|
||||
/**
|
||||
* Core service layer.
|
||||
*/
|
||||
export class GBCoreService implements IGBCoreService {
|
||||
|
||||
public sequelize: Sequelize;
|
||||
|
||||
/** Dialect used. Tested: mssql and sqlite. */
|
||||
|
||||
dialect: string;
|
||||
|
||||
constructor() {
|
||||
this.dialect = GBConfigService.get("DATABASE_DIALECT");
|
||||
}
|
||||
|
||||
/** Get config and connect to storage. */
|
||||
initDatabase(cb) {
|
||||
|
||||
let host = "";
|
||||
let database = "";
|
||||
let username = "";
|
||||
let password = "";
|
||||
let storage = "";
|
||||
|
||||
if (this.dialect === "mssql") {
|
||||
host = GBConfigService.get("DATABASE_HOST");
|
||||
database = GBConfigService.get("DATABASE_NAME");
|
||||
username = GBConfigService.get("DATABASE_USERNAME");
|
||||
password = GBConfigService.get("DATABASE_PASSWORD");
|
||||
} else if (this.dialect === "sqlite") {
|
||||
storage = GBConfigService.get("DATABASE_STORAGE");
|
||||
}
|
||||
|
||||
this.sequelize = new Sequelize({
|
||||
host: host,
|
||||
database: database,
|
||||
username: username,
|
||||
password: password,
|
||||
logging: false,
|
||||
operatorsAliases: false,
|
||||
dialect: this.dialect,
|
||||
storage: storage,
|
||||
|
||||
dialectOptions: {
|
||||
encrypt: true
|
||||
},
|
||||
pool: {
|
||||
max: 32,
|
||||
min: 8,
|
||||
idle: 40000,
|
||||
evict: 40000,
|
||||
acquire: 40000
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// TODO: Packages add model.
|
||||
|
||||
if (GBConfigService.get("DATABASE_SYNC") === "true") {
|
||||
this.syncDatabaseStructure(cb);
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
/** Calls ORM to sync storage. */
|
||||
syncDatabaseStructure(cb) {
|
||||
logger.trace("Syncing database...");
|
||||
this.sequelize.sync().then(value => {
|
||||
logger.trace("Database synced.");
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads all items to start several listeners.
|
||||
* @param cb Instances loaded or error info.
|
||||
*/
|
||||
loadInstances(cb: GBServiceCallback<IGBInstance[]>) {
|
||||
GuaribasInstance.findAll({})
|
||||
.then((items: IGBInstance[]) => {
|
||||
if (!items) items = [];
|
||||
|
||||
if (items.length == 0) {
|
||||
cb([], null);
|
||||
} else {
|
||||
cb(items, null);
|
||||
}
|
||||
})
|
||||
.catch(reason => {
|
||||
if (reason.message.indexOf("no such table: GuaribasInstance") != -1) {
|
||||
cb([], null);
|
||||
} else {
|
||||
cb(null, reason);
|
||||
logger.trace(`GuaribasServiceError: ${reason}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads just one Bot instance.
|
||||
*/
|
||||
loadInstance(botId: string, cb: GBServiceCallback<IGBInstance>) {
|
||||
let options = { where: {} };
|
||||
|
||||
if (botId != "[default]") {
|
||||
options.where = { botId: botId };
|
||||
}
|
||||
|
||||
GuaribasInstance.findOne(options)
|
||||
.then((instance: IGBInstance) => {
|
||||
if (instance) {
|
||||
cb(instance, null);
|
||||
} else {
|
||||
cb(null, null);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
cb(null, err);
|
||||
logger.trace(`GuaribasServiceError: ${err}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
const logger = require("../../../src/logger");
|
||||
const Path = require("path");
|
||||
const Fs = require("fs");
|
||||
const FsExtra = require("fs-extra");
|
||||
const _ = require("lodash");
|
||||
const Async = require("async");
|
||||
const UrlJoin = require("url-join");
|
||||
const Walk = require("fs-walk");
|
||||
const WaitUntil = require("wait-until");
|
||||
|
||||
import { KBService } from './../../kb.gbapp/services/KBService';
|
||||
import { GBImporter } from "./GBImporter";
|
||||
import { GBCoreService } from "./GBCoreService";
|
||||
import { GBServiceCallback, IGBCoreService, IGBInstance } from "botlib";
|
||||
import { Sequelize } from "sequelize-typescript";
|
||||
import { Promise } from "bluebird";
|
||||
import { GBConfigService } from "./GBConfigService";
|
||||
import { DataTypeUUIDv1 } from "sequelize";
|
||||
import { GBError, GBERROR_TYPE } from "botlib";
|
||||
import { UniversalBot } from "botbuilder";
|
||||
import { GBConversationalService } from "./GBConversationalService";
|
||||
import { GuaribasPackage } from '../models/GBModel';
|
||||
|
||||
/** Deployer service for bots, themes, ai and more. */
|
||||
export class GBDeployer {
|
||||
|
||||
core: IGBCoreService;
|
||||
|
||||
importer: GBImporter;
|
||||
|
||||
workDir: string = "./work";
|
||||
|
||||
constructor(core: IGBCoreService, importer: GBImporter) {
|
||||
this.core = core;
|
||||
this.importer = importer;
|
||||
}
|
||||
|
||||
/** Deploys a bot to the storage. */
|
||||
deployBot(localPath: string, cb: GBServiceCallback<any>) {
|
||||
let packageType = Path.extname(localPath);
|
||||
let packageName = Path.basename(localPath);
|
||||
|
||||
this.importer.importIfNotExistsBotPackage(
|
||||
packageName,
|
||||
localPath,
|
||||
(data, err) => {
|
||||
if (err) {
|
||||
logger.trace(err);
|
||||
} else {
|
||||
cb(data, null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
deployPackageToStorage(
|
||||
instanceId: number,
|
||||
packageName: string,
|
||||
cb: GBServiceCallback<GuaribasPackage>
|
||||
) {
|
||||
GuaribasPackage.create({
|
||||
packageName: packageName,
|
||||
instanceId: instanceId
|
||||
}).then((item: GuaribasPackage) => {
|
||||
cb(item, null);
|
||||
});
|
||||
}
|
||||
|
||||
deployTheme(localPath: string, cb: GBServiceCallback<any>) {
|
||||
// DISABLED: Until completed, "/ui/public".
|
||||
// FsExtra.copy(localPath, this.workDir + packageName)
|
||||
// .then(() => {
|
||||
// cb(null, null);
|
||||
// })
|
||||
// .catch(err => {
|
||||
// var gberr = GBError.create(
|
||||
// `GuaribasBusinessError: Error copying package: ${localPath}.`
|
||||
// );
|
||||
// cb(null, gberr);
|
||||
// });
|
||||
}
|
||||
|
||||
deployPackageFromLocalPath(localPath: string, cb: GBServiceCallback<any>) {
|
||||
let packageType = Path.extname(localPath);
|
||||
|
||||
switch (packageType) {
|
||||
case ".gbot":
|
||||
this.deployBot(localPath, cb);
|
||||
break;
|
||||
|
||||
case ".gbtheme":
|
||||
this.deployTheme(localPath, cb);
|
||||
break;
|
||||
|
||||
// PACKAGE: Put in package logic.
|
||||
case ".gbkb":
|
||||
let service = new KBService();
|
||||
service.deployKb(this.core, this, localPath, cb);
|
||||
break;
|
||||
|
||||
case ".gbui":
|
||||
break;
|
||||
|
||||
default:
|
||||
var err = GBError.create(
|
||||
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
||||
);
|
||||
cb(null, err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
undeployPackageFromLocalPath(
|
||||
instance: IGBInstance,
|
||||
localPath: string,
|
||||
cb: GBServiceCallback<any>
|
||||
) {
|
||||
let packageType = Path.extname(localPath);
|
||||
let packageName = Path.basename(localPath);
|
||||
|
||||
this.getPackageByName(instance.instanceId, packageName, (p, err) => {
|
||||
switch (packageType) {
|
||||
case ".gbot":
|
||||
// TODO: this.undeployBot(packageName, localPath, cb);
|
||||
break;
|
||||
|
||||
case ".gbtheme":
|
||||
// TODO: this.undeployTheme(packageName, localPath, cb);
|
||||
break;
|
||||
|
||||
case ".gbkb":
|
||||
let service = new KBService();
|
||||
service.undeployKbFromStorage(instance, p.packageId, cb);
|
||||
break;
|
||||
|
||||
case ".gbui":
|
||||
break;
|
||||
|
||||
default:
|
||||
var err = GBError.create(
|
||||
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
||||
);
|
||||
cb(null, err);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getPackageByName(
|
||||
instanceId: number,
|
||||
packageName: string,
|
||||
cb: GBServiceCallback<GuaribasPackage>
|
||||
) {
|
||||
|
||||
var where = { packageName: packageName, instanceId: instanceId };
|
||||
|
||||
GuaribasPackage.findOne({
|
||||
where: where
|
||||
})
|
||||
.then((value: GuaribasPackage) => {
|
||||
cb(value, null);
|
||||
})
|
||||
.error(reason => {
|
||||
cb(null, reason);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Hot deploy processing.
|
||||
*
|
||||
*/
|
||||
scanBootPackage(cb: GBServiceCallback<boolean>) {
|
||||
|
||||
const deployFolder = "deploy";
|
||||
let bootPackage = GBConfigService.get("BOOT_PACKAGE");
|
||||
|
||||
if (bootPackage === "none") {
|
||||
cb(true, null);
|
||||
} else {
|
||||
this.deployPackageFromLocalPath(
|
||||
UrlJoin(deployFolder, bootPackage),
|
||||
(data, err) => {
|
||||
logger.trace(`Boot package deployed: ${bootPackage}`);
|
||||
if (err) logger.trace(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
const _ = require("lodash");
|
||||
const Parse = require("csv-parse");
|
||||
const Async = require("async");
|
||||
const UrlJoin = require("url-join");
|
||||
const Walk = require("fs-walk");
|
||||
const logger = require("../../../src/logger");
|
||||
|
||||
import { KBService } from './../../kb.gbapp/services/KBService';
|
||||
import { Sequelize } from "sequelize-typescript";
|
||||
import { Promise } from "bluebird";
|
||||
import Fs = require("fs");
|
||||
import Path = require("path");
|
||||
import { DataTypeUUIDv1 } from "sequelize";
|
||||
import { GBConfigService } from "./GBConfigService";
|
||||
import { GBCoreService } from "./GBCoreService";
|
||||
import { GBServiceCallback, IGBCoreService, IGBInstance } from "botlib";
|
||||
import { SecService } from "../../security.gblib/services/SecService";
|
||||
import { GuaribasInstance } from "../models/GBModel";
|
||||
|
||||
export class GBImporter {
|
||||
core: IGBCoreService;
|
||||
|
||||
constructor(core: IGBCoreService) {
|
||||
this.core = core;
|
||||
}
|
||||
importIfNotExistsBotPackage(
|
||||
packageName: string,
|
||||
localPath: string,
|
||||
cb: GBServiceCallback<IGBInstance>
|
||||
) {
|
||||
let _this = this;
|
||||
|
||||
let packageJson = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
||||
);
|
||||
|
||||
let botId = packageJson.botId;
|
||||
|
||||
this.core.loadInstance(botId, (instance, err) => {
|
||||
if (instance) {
|
||||
cb(instance, null);
|
||||
} else {
|
||||
this.createInstanceInternal(packageName, localPath, packageJson, cb);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private createInstanceInternal(
|
||||
packageName: string,
|
||||
localPath: string,
|
||||
packageJson: any,
|
||||
cb: GBServiceCallback<IGBInstance>
|
||||
) {
|
||||
const settings = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "settings.json"), "utf8")
|
||||
);
|
||||
const servicesJson = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "services.json"), "utf8")
|
||||
);
|
||||
|
||||
packageJson = Object.assign(packageJson, settings, servicesJson);
|
||||
|
||||
GuaribasInstance.create(packageJson).then((instance: IGBInstance) => {
|
||||
|
||||
// PACKAGE: security.json loading
|
||||
let service = new SecService();
|
||||
service.importSecurityFile(localPath, instance);
|
||||
|
||||
cb(instance, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,400 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
const gBuilder = require("botbuilder");
|
||||
const UrlJoin = require("url-join");
|
||||
const Path = require("path");
|
||||
const Fs = require("fs");
|
||||
const Url = require("url");
|
||||
const logger = require("../../../src/logger");
|
||||
const WaitUntil = require("wait-until");
|
||||
const Walk = require("fs-walk");
|
||||
const express = require("express");
|
||||
|
||||
import { UniversalBot } from "botbuilder";
|
||||
import { Session, MemoryBotStorage, Message } from "botbuilder";
|
||||
import { GBCoreService } from "./GBCoreService";
|
||||
import { GBConversationalService } from "./GBConversationalService";
|
||||
import { GBConfigService } from "./GBConfigService";
|
||||
import * as request from "request-promise-native";
|
||||
import { GBMinInstance, IGBCoreService, IGBInstance, IGBPackage, GBError } from "botlib";
|
||||
import { GBServiceCallback } from "botlib";
|
||||
import { GBAnalyticsPackage } from "../../analytics.gblib";
|
||||
import { GBCorePackage } from "../../core.gbapp";
|
||||
import { GBKBPackage } from '../../kb.gbapp';
|
||||
import { GBDeployer } from './GBDeployer';
|
||||
import { GBSecurityPackage } from '../../security.gblib';
|
||||
import { GBAdminPackage } from './../../admin.gbapp/index';
|
||||
import { GBCustomerSatisfactionPackage } from "../../customer-satisfaction.gbapp";
|
||||
|
||||
/** Minimal service layer for a bot. */
|
||||
|
||||
export class GBMinService {
|
||||
|
||||
core: GBCoreService;
|
||||
conversationalService: GBConversationalService;
|
||||
deployer: GBDeployer;
|
||||
|
||||
deployFolder = "deploy";
|
||||
corePackage = "core.gbai";
|
||||
|
||||
/**
|
||||
* Static iniatialization of minimal instance.
|
||||
*
|
||||
* @param core Basic database services to identify instance, for example.
|
||||
* @param cb Returns the loaded instance.
|
||||
*/
|
||||
constructor(
|
||||
core: GBCoreService,
|
||||
conversationalService: GBConversationalService,
|
||||
deployer: GBDeployer
|
||||
) {
|
||||
this.core = core;
|
||||
this.conversationalService = conversationalService;
|
||||
this.deployer = deployer;
|
||||
}
|
||||
|
||||
/** Constructs a new minimal instance for each bot. */
|
||||
|
||||
buildMin(cb: GBServiceCallback<GBMinInstance>, server: any, appPackages: Array<IGBPackage>) {
|
||||
|
||||
var _this = this;
|
||||
|
||||
// Serves default UI on root address '/'.
|
||||
|
||||
let uiPackage = "default.gbui";
|
||||
server.use(
|
||||
"/",
|
||||
express.static(UrlJoin(this.deployFolder, uiPackage, "build"))
|
||||
);
|
||||
|
||||
// Loads all bot instances from storage.
|
||||
|
||||
_this.core.loadInstances((instances: IGBInstance[], err) => {
|
||||
|
||||
// Gets the authorization key for each instance from Bot Service.
|
||||
|
||||
instances.forEach(instance => {
|
||||
let options = {
|
||||
url:
|
||||
"https://directline.botframework.com/v3/directline/tokens/generate",
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${instance.webchatKey}`
|
||||
}
|
||||
};
|
||||
request(options).then((response: string) => {
|
||||
|
||||
// Serves the bot information object via http so clients can get
|
||||
// instance information stored on server.
|
||||
|
||||
let responseObject = JSON.parse(response);
|
||||
server.get("/instances/:botId", (req, res) => {
|
||||
|
||||
// Returns the instance object to clients requesting bot info.
|
||||
|
||||
let botId = req.params.botId;
|
||||
_this.core.loadInstance(
|
||||
botId,
|
||||
(instance: IGBInstance, err) => {
|
||||
if (instance) {
|
||||
res.send(
|
||||
JSON.stringify({
|
||||
instanceId: instance.instanceId,
|
||||
botId: botId,
|
||||
theme: instance.theme,
|
||||
secret: instance.webchatKey, // TODO: Use token.
|
||||
conversationId: responseObject.conversationId
|
||||
})
|
||||
);
|
||||
} else {
|
||||
let error = `Instance not found: ${botId}.`;
|
||||
res.send(error);
|
||||
logger.error(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// The minimal bot is built here.
|
||||
|
||||
let min = new GBMinInstance();
|
||||
min.botId = instance.botId;
|
||||
min.core = _this.core;
|
||||
min.conversationalService = _this.conversationalService;
|
||||
|
||||
let connector = new gBuilder.ChatConnector({
|
||||
appId: instance.marketplaceId,
|
||||
appPassword: instance.marketplacePassword
|
||||
});
|
||||
|
||||
// Serves individual URL for each bot conversational interface...
|
||||
|
||||
let url = `/api/messages/${instance.botId}`;
|
||||
logger.trace(
|
||||
`GeneralBots(${instance.engineName}) listening on: ${url}.`
|
||||
);
|
||||
server.post(url, connector.listen());
|
||||
|
||||
// Serves individual URL for each bot user interface.
|
||||
|
||||
let uiUrl = `/${instance.botId}`;
|
||||
server.use(
|
||||
uiUrl,
|
||||
express.static(UrlJoin(this.deployFolder, uiPackage, "build"))
|
||||
);
|
||||
logger.trace(`Bot UI ${uiPackage} acessible at: ${uiUrl}.`);
|
||||
|
||||
|
||||
// Prepares bot service.
|
||||
|
||||
let inMemoryStorage = new MemoryBotStorage();
|
||||
min.bot = new gBuilder.UniversalBot(connector, {
|
||||
storage: inMemoryStorage
|
||||
});
|
||||
|
||||
// Call the loadBot event.
|
||||
|
||||
appPackages.forEach(e => e.loadBot(min));
|
||||
|
||||
// Setups handlers.
|
||||
|
||||
min.bot.use({
|
||||
|
||||
botbuilder: (session, next) => {
|
||||
if (!session.privateConversationData.loaded) {
|
||||
setTimeout(
|
||||
() =>
|
||||
`Sending loading instance to client ${min.instance.ui}.`,
|
||||
min.conversationalService.sendEvent(
|
||||
session,
|
||||
"loadInstance",
|
||||
min.instance // TODO: Send a new thiner object.
|
||||
),
|
||||
500
|
||||
);
|
||||
session.privateConversationData.loaded = true;
|
||||
appPackages.forEach(e => {
|
||||
e.onNewSession(min, session)
|
||||
});
|
||||
// PACKAGE: min.subjects = [];
|
||||
}
|
||||
next();
|
||||
},
|
||||
receive: function (event: any, next) {
|
||||
logger.trace(
|
||||
`Event RCV: (Type: ${event.type}, Name: ${event.name}, Value: ${
|
||||
event.value
|
||||
}).`
|
||||
);
|
||||
|
||||
// PACKAGE: Provide loop here.
|
||||
|
||||
if (
|
||||
event.type === "conversationUpdate" &&
|
||||
event.membersAdded.length > 0 &&
|
||||
event.membersAdded[0].name != "You"
|
||||
) {
|
||||
|
||||
min.bot.beginDialog(event.address, "/");
|
||||
} else if (event.name === "whoAmI") {
|
||||
min.bot.beginDialog(event.address, "/whoAmI");
|
||||
} else if (event.name === "showSubjects") {
|
||||
min.bot.beginDialog(event.address, "/menu");
|
||||
} else if (event.name === "giveFeedback") {
|
||||
min.bot.beginDialog(event.address, "/feedback", {
|
||||
fromMenu: true
|
||||
});
|
||||
} else if (event.name === "showFAQ") {
|
||||
min.bot.beginDialog(event.address, "/faq");
|
||||
} else if (event.name === "ask") {
|
||||
min.bot.beginDialog(event.address, "/answer", {
|
||||
query: event.data,
|
||||
fromFaq: true
|
||||
});
|
||||
} else if (event.name === "quality") {
|
||||
min.bot.beginDialog(event.address, "/quality", {
|
||||
score: event.data
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
},
|
||||
send: function (event, next) {
|
||||
this.core.createMessage(
|
||||
this.min.conversation,
|
||||
this.min.conversation.startedBy,
|
||||
event.source,
|
||||
(data, err) => {
|
||||
logger.trace(event.source);
|
||||
}
|
||||
);
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
let generalPackages = [GBAdminPackage, GBAnalyticsPackage, GBCorePackage, GBSecurityPackage, GBKBPackage, GBCustomerSatisfactionPackage];
|
||||
|
||||
generalPackages.forEach(e => {
|
||||
logger.trace(`Loading package: ${e.name}...`);
|
||||
let p = Object.create(e.prototype) as IGBPackage;
|
||||
p.loadBot(min)
|
||||
});
|
||||
|
||||
// Specialized load for each min instance.
|
||||
|
||||
cb(min, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** Performs package deployment in all .gbai or default. */
|
||||
public deployPackages(core: IGBCoreService, server: any, appPackages: Array<IGBPackage>, sysPackages: Array<IGBPackage>) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
var _this = this;
|
||||
let botsToProcess = 0, botsProcessed = 0;
|
||||
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
||||
let paths = [this.deployFolder];
|
||||
if (additionalPath) {
|
||||
paths = paths.concat(additionalPath.toLowerCase().split(";"));
|
||||
}
|
||||
let botPackages = new Array<string>();
|
||||
let generalPackages = new Array<string>();
|
||||
|
||||
function doIt(path) {
|
||||
const isDirectory = source => Fs.lstatSync(source).isDirectory()
|
||||
const getDirectories = source =>
|
||||
Fs.readdirSync(source).map(name => Path.join(source, name)).filter(isDirectory)
|
||||
|
||||
let dirs = getDirectories(path);
|
||||
dirs.forEach(element => {
|
||||
if (element.endsWith('.gbot')) {
|
||||
botPackages.push(element);
|
||||
}
|
||||
else {
|
||||
generalPackages.push(element);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
logger.trace(`Starting looking for generalPackages...`);
|
||||
paths.forEach(e => {
|
||||
logger.trace(`Looking in: ${e}...`);
|
||||
doIt(e)
|
||||
});
|
||||
|
||||
/** Deploys all .gbot files first. */
|
||||
|
||||
botPackages.forEach(e => {
|
||||
logger.trace(`Deploying bot: ${e}...`);
|
||||
this.deployer.deployBot(e, (data, err) => {
|
||||
botsProcessed++;
|
||||
});
|
||||
});
|
||||
|
||||
/** Then all remaining generalPackages are loaded. */
|
||||
|
||||
generalPackages.forEach(filename => {
|
||||
|
||||
let filenameOnly = Path.basename(filename);
|
||||
logger.trace(`Deploying package: ${filename}...`);
|
||||
|
||||
/** Handles apps for general bots - .gbapp must stay out of deploy folder. */
|
||||
|
||||
if (Path.extname(filename) === ".gbapp" || Path.extname(filename) === ".gblib") {
|
||||
|
||||
// Skips .gbapp inside deploy folder.
|
||||
if (!filename.startsWith('deploy')) {
|
||||
import(filename).then(m => {
|
||||
|
||||
let p = new m.Package();
|
||||
p.loadPackage(core);
|
||||
appPackages.push(p);
|
||||
logger.trace(`App (.gbapp) deployed: ${filenameOnly}.`);
|
||||
});
|
||||
}
|
||||
|
||||
/** Themes for bots. */
|
||||
|
||||
} else if (Path.extname(filename) === ".gbtheme") {
|
||||
server.use("/themes/" + filenameOnly, express.static(filename));
|
||||
logger.trace(`Theme (.gbtheme) assets acessible at: ${"/themes/" + filenameOnly}.`);
|
||||
|
||||
|
||||
/** Knowledge base for bots. */
|
||||
|
||||
} else if (Path.extname(filename) === ".gbkb") {
|
||||
server.use(
|
||||
"/kb/" + filenameOnly + "/subjects",
|
||||
express.static(UrlJoin(filename, "subjects"))
|
||||
);
|
||||
logger.trace(`KB (.gbkb) assets acessible at: ${"/kb/" + filenameOnly}.`);
|
||||
}
|
||||
|
||||
else if (Path.extname(filename) === ".gbui" || filename.endsWith(".git")) {
|
||||
// Already Handled
|
||||
}
|
||||
|
||||
/** Unknown package format. */
|
||||
|
||||
else {
|
||||
let err = new Error(`Package type not handled: ${filename}.`);
|
||||
reject(err);
|
||||
}
|
||||
botsProcessed++;
|
||||
});
|
||||
|
||||
WaitUntil()
|
||||
.interval(100)
|
||||
.times(50)
|
||||
.condition(function (cb) {
|
||||
logger.trace(`Waiting for package deployment...`);
|
||||
cb(botsProcessed == (generalPackages.length + botPackages.length));
|
||||
})
|
||||
.done(function (result) {
|
||||
logger.trace(`Package deployment done.`);
|
||||
resolve();
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import { UniversalBot, Session, Prompts, ListStyle } from "botbuilder";
|
||||
import UrlJoin from "url-join";
|
||||
import { CSService } from '../services/CSService';
|
||||
import { AzureText } from "pragmatismo-io-framework1";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { IGBDialog } from "botlib";
|
||||
|
||||
export class FeedbackDialog extends IGBDialog {
|
||||
|
||||
static setup(bot: UniversalBot, min: GBMinInstance) {
|
||||
|
||||
const service = new CSService();
|
||||
|
||||
bot.dialog("/feedbackNumber", [
|
||||
function(session, args) {
|
||||
session.sendTyping();
|
||||
let msgs = [
|
||||
"O que achou do meu atendimento, de 1 a 5?",
|
||||
"Qual a nota do meu atendimento?",
|
||||
"Como define meu atendimento numa escala de 1 a 5?"
|
||||
];
|
||||
Prompts.choice(session, msgs, "1|2|3|4|5", {
|
||||
listStyle: ListStyle.button
|
||||
});
|
||||
},
|
||||
function(session, results) {
|
||||
let rate = results.response.entity;
|
||||
service.updateConversationRate(session.userData.conversation, rate, item => {
|
||||
let msgs = ["Obrigado!", "Obrigado por responder."];
|
||||
session.send(msgs);
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
bot.dialog("/feedback", [
|
||||
function(session, args) {
|
||||
if (args && args.fromMenu) {
|
||||
let msgs = [
|
||||
"Sugestões melhoram muito minha qualidade...",
|
||||
"Obrigado pela sua iniciativa de sugestão."
|
||||
];
|
||||
session.send(msgs);
|
||||
}
|
||||
session.sendTyping();
|
||||
let msgs = [
|
||||
"O que achou do meu atendimento?",
|
||||
"Como foi meu atendimento?",
|
||||
"Gostaria de dizer algo sobre meu atendimento?"
|
||||
];
|
||||
Prompts.text(session, msgs);
|
||||
},
|
||||
function(session, results) {
|
||||
AzureText.getSentiment(
|
||||
min.instance.textAnalyticsKey,
|
||||
results.response,
|
||||
(err, rate) => {
|
||||
if (!err && rate > 0) {
|
||||
session.send("Bom saber que você gostou. Conte comigo.");
|
||||
} else {
|
||||
session.send(
|
||||
"Vamos registrar sua questão, obrigado pela sinceridade."
|
||||
);
|
||||
}
|
||||
session.replaceDialog('/ask', {isReturning: true});
|
||||
}
|
||||
);
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
package-lock=false
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"name": "default.gbui",
|
||||
"version": "0.0.9",
|
||||
"private": true,
|
||||
"homepage": ".",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome": "^1.1.3",
|
||||
"@fortawesome/fontawesome-free-solid": "^5.0.6",
|
||||
"@fortawesome/react-fontawesome": "0.1.0-3",
|
||||
"botframework-webchat": "^0.11.4",
|
||||
"deep-extend": "0.5.0",
|
||||
"fetch": "1.1.0",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-player": "1.2.1",
|
||||
"react-powerbi": "^0.1.7",
|
||||
"react-scripts": "^1.1.1",
|
||||
"react-transition-group": "^2.3.0-beta.0",
|
||||
"url-join": "^4.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
import React from "react";
|
||||
import GBMarkdownPlayer from "./players/GBMarkdownPlayer.js";
|
||||
import GBImagePlayer from "./players/GBImagePlayer.js";
|
||||
import GBVideoPlayer from "./players/GBVideoPlayer.js";
|
||||
import GBBulletPlayer from "./players/GBBulletPlayer.js";
|
||||
import SidebarMenu from "./components/SidebarMenu.js";
|
||||
import GBCss from "./components/GBCss.js";
|
||||
import { DirectLine } from "botframework-directlinejs";
|
||||
import { ConnectionStatus } from "botframework-directlinejs";
|
||||
import { Chat } from "botframework-webchat";
|
||||
import GBPowerBIPlayer from "./players/GBPowerBIPlayer.js";
|
||||
|
||||
class GBUIApp extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
botConnection: null,
|
||||
instance: null,
|
||||
token: null
|
||||
};
|
||||
}
|
||||
|
||||
send(command) {
|
||||
window.botConnection
|
||||
.postActivity({
|
||||
type: "event",
|
||||
name: command,
|
||||
locale: "en-us",
|
||||
textFormat: "plain",
|
||||
timestamp: new Date().toISOString(),
|
||||
from: { id: "webUser", name: "You" }
|
||||
})
|
||||
.subscribe(console.log("EVENT SENT TO Guaribas."));
|
||||
}
|
||||
getUser() {
|
||||
return { id: "webUser@gb", name: "You" };
|
||||
}
|
||||
|
||||
postEvent(name, value) {
|
||||
window.botConnection.postActivity({
|
||||
type: "event",
|
||||
value: value,
|
||||
from: this.getUser(),
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
postMessage(value) {
|
||||
window.botConnection.postActivity({
|
||||
type: "message",
|
||||
text: value,
|
||||
from: this.getUser()
|
||||
});
|
||||
}
|
||||
|
||||
configureChat() {
|
||||
var botId = window.location.href.split("/")[3];
|
||||
|
||||
if (!botId) {
|
||||
botId = "[default]";
|
||||
}
|
||||
|
||||
fetch("/instances/" + botId)
|
||||
.then(res => res.json())
|
||||
.then(
|
||||
result => {
|
||||
this.setupBotConnection(result.secret);
|
||||
},
|
||||
error => {
|
||||
this.setState({
|
||||
isLoaded: false,
|
||||
err: error
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
setupBotConnection(secret) {
|
||||
let _this = this;
|
||||
window["botchatDebug"] = true;
|
||||
|
||||
const botConnection = new DirectLine({
|
||||
secret: secret
|
||||
});
|
||||
|
||||
botConnection.connectionStatus$.subscribe(connectionStatus => {
|
||||
if (connectionStatus === ConnectionStatus.Online) {
|
||||
botConnection.postActivity({
|
||||
type: "event",
|
||||
value: "startGB",
|
||||
from: this.getUser(),
|
||||
name: "startGB"
|
||||
});
|
||||
|
||||
_this.setState({ botConnection: botConnection });
|
||||
}
|
||||
});
|
||||
|
||||
window.botConnection = botConnection;
|
||||
this.postEvent("startGB", true);
|
||||
|
||||
botConnection.activity$
|
||||
.filter(
|
||||
activity =>
|
||||
activity.type === "event" && activity.name === "loadInstance"
|
||||
)
|
||||
.subscribe(activity => {
|
||||
_this.setState({ instance: activity.value });
|
||||
});
|
||||
|
||||
botConnection.activity$
|
||||
.filter(activity => activity.type === "event" && activity.name === "stop")
|
||||
.subscribe(activity => {
|
||||
if (_this.player) {
|
||||
_this.player.stop();
|
||||
}
|
||||
});
|
||||
|
||||
botConnection.activity$
|
||||
.filter(activity => activity.type === "event" && activity.name === "play")
|
||||
.subscribe(activity => {
|
||||
_this.setState({ playerType: activity.value.playerType });
|
||||
_this.player.play(activity.value.data);
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.configureChat();
|
||||
}
|
||||
|
||||
render() {
|
||||
let chat = <div />;
|
||||
|
||||
let playerComponent = "";
|
||||
|
||||
if (this.state.playerType) {
|
||||
switch (this.state.playerType) {
|
||||
case "markdown":
|
||||
playerComponent = (
|
||||
<GBMarkdownPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "bullet":
|
||||
playerComponent = (
|
||||
<GBBulletPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "video":
|
||||
playerComponent = (
|
||||
<GBVideoPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "image":
|
||||
playerComponent = (
|
||||
<GBImagePlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "pbi":
|
||||
playerComponent = (
|
||||
<GBPowerBIPlayer
|
||||
app={this}
|
||||
ref={player => {
|
||||
this.player = player;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
"GBERROR: Unknow player type specified on message from server."
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let sideBar = (
|
||||
<div className="sidebar">
|
||||
<SidebarMenu chat={this.chat} instance={this.state.instance} />
|
||||
</div>
|
||||
);
|
||||
|
||||
if (this.state.botConnection) {
|
||||
chat = (
|
||||
<Chat
|
||||
ref={chat => {
|
||||
this.chat = chat;
|
||||
}}
|
||||
botConnection={this.state.botConnection}
|
||||
user={this.getUser()}
|
||||
bot={{ id: "bot@gb", name: "Bot" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.state.instance) {
|
||||
sideBar = "";
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<GBCss instance={this.state.instance} />
|
||||
{sideBar}
|
||||
<div className="player">{playerComponent}</div>
|
||||
{chat}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default GBUIApp;
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
import React, { Component } from "react";
|
||||
import { Report } from "react-powerbi";
|
||||
import * as pbi from "powerbi-client";
|
||||
|
||||
class GBPowerBIPlayer extends Component {
|
||||
send(value) {
|
||||
setTimeout(() => {
|
||||
window.botConnection
|
||||
.postActivity({
|
||||
type: "event",
|
||||
name: "quality",
|
||||
data: value,
|
||||
locale: "en-us",
|
||||
textFormat: "plain",
|
||||
timestamp: new Date().toISOString(),
|
||||
from: { id: "webUser", name: "You" }
|
||||
})
|
||||
.subscribe(console.log("success"));
|
||||
}, 400);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
embedUrl: "",
|
||||
accessToken: "",
|
||||
filters: null
|
||||
};
|
||||
}
|
||||
|
||||
play(data) {
|
||||
var jobId = 1;
|
||||
|
||||
const basicFilter = {
|
||||
$schema: "http://powerbi.com/product/schema#basic",
|
||||
target: {
|
||||
table: "PauiniJob",
|
||||
column: "jobId"
|
||||
},
|
||||
operator: "Equals",
|
||||
values: [jobId],
|
||||
filterType: pbi.models.FilterType.BasicFilter
|
||||
};
|
||||
|
||||
this.setState({
|
||||
embedUrl: data.embedUrl,
|
||||
accessToken: data.accessToken,
|
||||
filters: [basicFilter]
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.setState({
|
||||
embedUrl: "",
|
||||
accessToken: "",
|
||||
filters: null
|
||||
});
|
||||
}
|
||||
|
||||
clickYes() {
|
||||
this.send(1);
|
||||
}
|
||||
|
||||
clickNo() {
|
||||
this.send(0);
|
||||
}
|
||||
|
||||
render() {
|
||||
var quality = (
|
||||
<div className="gb-markdown-player-quality">
|
||||
<span ref={i => (this.quality = i)}>O relatório atende?</span>
|
||||
|
||||
<button
|
||||
className="gb-quality-button-yes"
|
||||
onClick={() => this.clickYes()}
|
||||
ref={i => (this.Yes = i)}
|
||||
>
|
||||
Sim
|
||||
</button>
|
||||
|
|
||||
<button
|
||||
className="gb-quality-button-no"
|
||||
onClick={() => this.clickNo()}
|
||||
ref={i => (this.No = i)}
|
||||
>
|
||||
Não
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (this.state.content === "") {
|
||||
quality = "";
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={i => (this.playerText = i)} className="media-player">
|
||||
<div className="media-player-container">
|
||||
<div className="media-player-scroll">
|
||||
<Report
|
||||
embedUrl={this.state.embedUrl}
|
||||
accessToken={this.state.accessToken}
|
||||
filterPaneEnabled={true}
|
||||
filters={this.state.filters}
|
||||
navContentPaneEnabled={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{quality}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default GBPowerBIPlayer;
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import { Prompts, UniversalBot, Session, ListStyle } from "botbuilder";
|
||||
import { IGBDialog } from "botlib";
|
||||
import { AzureText } from "pragmatismo-io-framework1";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { KBService } from './../services/KBService';
|
||||
|
||||
const logger = require("../../../src/logger");
|
||||
|
||||
export class AskDialog extends IGBDialog {
|
||||
static setup(bot: UniversalBot, min: GBMinInstance) {
|
||||
|
||||
const service = new KBService();
|
||||
|
||||
bot.dialog("/answer", [
|
||||
(session, args) => {
|
||||
let text = "";
|
||||
|
||||
if (args && args.query) {
|
||||
text = args.query;
|
||||
} else if (args && args.fromFaq) {
|
||||
let msgs = [
|
||||
`Ótima escolha, procurando resposta para sua questão...`,
|
||||
`Pesquisando sobre o termo...`,
|
||||
`Aguarde, por favor, enquanto acho sua resposta...`
|
||||
];
|
||||
session.sendTyping();
|
||||
session.send(msgs);
|
||||
}
|
||||
|
||||
if (text === "") {
|
||||
session.replaceDialog("/ask");
|
||||
} else if (AzureText.isIntentNo(text)) {
|
||||
session.replaceDialog("/feedback");
|
||||
} else if (AzureText.isIntentYes(text)) {
|
||||
session.replaceDialog("/menu");
|
||||
} else {
|
||||
AzureText.getSpelledText(
|
||||
"1f1653cd23e941ce869af73bdf9ef272",
|
||||
text,
|
||||
(data, err) => {
|
||||
if (data != text) {
|
||||
logger.trace("Spelled Text: " + data);
|
||||
text = data;
|
||||
}
|
||||
|
||||
session.userData.lastQuestion = data;
|
||||
|
||||
service.ask(
|
||||
min.instance,
|
||||
text,
|
||||
min.instance.searchScore,
|
||||
session.userData.subjects,
|
||||
resultsA => {
|
||||
min.conversationalService.sendEvent(session, "stop", null);
|
||||
|
||||
if (resultsA && resultsA.answer) {
|
||||
session.userData.isAsking = false;
|
||||
service.sendAnswer(min.conversationalService,
|
||||
session,
|
||||
resultsA.answer
|
||||
);
|
||||
session.userData.lastQuestionId = resultsA.questionId;
|
||||
|
||||
session.replaceDialog("/ask", { isReturning: true });
|
||||
} else {
|
||||
//if (min.isAsking) {
|
||||
// Second time with no filter.
|
||||
|
||||
service.ask(
|
||||
min.instance,
|
||||
text,
|
||||
min.instance.searchScore,
|
||||
null,
|
||||
resultsB => {
|
||||
if (resultsB && resultsB.answer) {
|
||||
session.userData.isAsking = false;
|
||||
|
||||
if (session.userData.subjects.length > 0) {
|
||||
let subjectText = `${KBService.getSubjectItemsSeparatedBySpaces(
|
||||
session.userData.subjects
|
||||
)}`;
|
||||
|
||||
let msgs = [
|
||||
`Respondendo nao apenas sobre ${subjectText}... `,
|
||||
`Respondendo de modo mais abrangente...`,
|
||||
`Vou te responder de modo mais abrangente... Não apenas sobre ${subjectText}`
|
||||
];
|
||||
session.send(msgs);
|
||||
}
|
||||
session.userData.isAsking = false;
|
||||
service.sendAnswer(min.conversationalService,
|
||||
session,
|
||||
resultsB.answer
|
||||
);
|
||||
session.replaceDialog("/ask", { isReturning: true });
|
||||
|
||||
session.userData.lastQuestionId = resultsB.questionId;
|
||||
} else {
|
||||
|
||||
min.conversationalService.runNLP(
|
||||
session,
|
||||
min,
|
||||
text,
|
||||
(data, error) => {
|
||||
|
||||
if (!data)
|
||||
{
|
||||
let msgs = [
|
||||
"Desculpe-me, não encontrei nada a respeito.",
|
||||
"Lamento... Não encontrei nada sobre isso. Vamos tentar novamente?",
|
||||
"Desculpe-me, não achei nada parecido. Poderia tentar escrever de outra forma?"
|
||||
];
|
||||
|
||||
session.send(msgs);
|
||||
session.replaceDialog("/ask", { isReturning: true });
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
bot
|
||||
.dialog("/ask", [
|
||||
(session, args) => {
|
||||
session.userData.isAsking = true;
|
||||
|
||||
let text = [
|
||||
`Pergunte-me sobre qualquer assunto ou digite **menu** para conhecer uma lista de opções.`,
|
||||
`Pode perguntar sobre qualquer assunto... Ou digita **menu** para conhecer uma lista de opções.`,
|
||||
`Faça qualquer pergunta ou também posso te mostrar o **menu** de assuntos sempre que precisar...`
|
||||
];
|
||||
|
||||
if (session.userData.subjects.length > 0) {
|
||||
text = [
|
||||
`Faça sua pergunta...`,
|
||||
`Pode perguntar sobre o assunto em questão... `,
|
||||
`Qual a pergunta?`
|
||||
];
|
||||
}
|
||||
|
||||
if (args && args.isReturning) {
|
||||
text = [
|
||||
"Sobre o que mais posso ajudar?",
|
||||
"Então, posso ajudar em algo a mais?",
|
||||
"Deseja fazer outra pergunta?"
|
||||
];
|
||||
}
|
||||
|
||||
Prompts.text(session, text);
|
||||
},
|
||||
(session, results) => {
|
||||
session.replaceDialog("/answer", { query: results.response });
|
||||
}
|
||||
])
|
||||
.triggerAction({
|
||||
matches: /^(procurar|bing|google|perguntar)/i
|
||||
});
|
||||
bot.beginDialogAction("ask", "/ask");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import { Length } from "sequelize-typescript";
|
||||
import {
|
||||
UniversalBot,
|
||||
Session,
|
||||
Message,
|
||||
AttachmentLayout,
|
||||
CardAction,
|
||||
HeroCard,
|
||||
CardImage
|
||||
} from "botbuilder";
|
||||
import UrlJoin from "url-join";
|
||||
import { IGBDialog } from "botlib";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { AzureText } from "pragmatismo-io-framework1";
|
||||
import { GuaribasSubject } from '../models';
|
||||
import { KBService } from "../services/KBService";
|
||||
|
||||
const UrlJoin = require("url-join");
|
||||
const WaitUntil = require("wait-until");
|
||||
|
||||
export class MenuDialog extends IGBDialog {
|
||||
|
||||
static setup(bot: UniversalBot, min: GBMinInstance) {
|
||||
|
||||
var service = new KBService();
|
||||
|
||||
bot
|
||||
.dialog("/menu", [
|
||||
(session, args) => {
|
||||
var rootSubjectId = null;
|
||||
var botId = min.instance.botId;
|
||||
|
||||
var msg = session.message;
|
||||
if (msg.attachments && msg.attachments.length > 0) {
|
||||
var attachment = msg.attachments[0];
|
||||
}
|
||||
|
||||
if (args && args.data) {
|
||||
var subject = JSON.parse(args.data); // ?
|
||||
|
||||
if (subject.to) {
|
||||
let dialog = subject.to.split(":")[1];
|
||||
session.replaceDialog("/" + dialog);
|
||||
session.endDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
session.userData.subjects.push(subject);
|
||||
rootSubjectId = subject.subjectId;
|
||||
|
||||
if (session.userData.subjects.length > 0) {
|
||||
|
||||
service.getFaqBySubjectArray(
|
||||
"menu",
|
||||
session.userData.subjects,
|
||||
(data, err) => {
|
||||
min.conversationalService.sendEvent(session, "play", {
|
||||
playerType: "bullet",
|
||||
data: data.slice(0, 6)
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
session.userData.subjects = [];
|
||||
session.sendTyping();
|
||||
WaitUntil()
|
||||
.interval(2000)
|
||||
.times(1)
|
||||
.condition(function(cb) {
|
||||
return false;
|
||||
})
|
||||
.done(function(result) {
|
||||
let msgs = [
|
||||
"Aqui estão algumas categorias de assuntos...",
|
||||
"Selecionando o assunto você pode me ajudar a encontrar a resposta certa...",
|
||||
"Você pode selecionar algum dos assuntos abaixo e perguntar algo..."
|
||||
];
|
||||
session.send(msgs);
|
||||
});
|
||||
|
||||
session.userData.isAsking = false;
|
||||
}
|
||||
|
||||
service.getSubjectItems(
|
||||
min.instance.instanceId,
|
||||
rootSubjectId,
|
||||
data => {
|
||||
var msg = new Message(session);
|
||||
msg.attachmentLayout(AttachmentLayout.carousel);
|
||||
var attachments = [];
|
||||
|
||||
data.forEach(function(item: GuaribasSubject) {
|
||||
var subject = item;
|
||||
var button = CardAction.dialogAction(
|
||||
session,
|
||||
"menuAction",
|
||||
JSON.stringify({
|
||||
title: subject.title,
|
||||
subjectId: subject.subjectId,
|
||||
to: subject.to
|
||||
}),
|
||||
"Selecionar"
|
||||
);
|
||||
var card = new HeroCard(session)
|
||||
.title(subject.title)
|
||||
.text(subject.description)
|
||||
.images([
|
||||
CardImage.create(
|
||||
session,
|
||||
UrlJoin(
|
||||
"/kb",
|
||||
min.instance.kb,
|
||||
"subjects",
|
||||
"subject.png" // TODO: subject.internalId + ".png" or fallback to subject.png
|
||||
)
|
||||
)
|
||||
]) // Using public dir of ui.
|
||||
.buttons([button]);
|
||||
attachments.push(card);
|
||||
});
|
||||
|
||||
if (attachments.length == 0) {
|
||||
if (session.userData.subjects && session.userData.subjects.length > 0) {
|
||||
session.send(
|
||||
`Vamos pesquisar sobre ${KBService.getFormattedSubjectItems(
|
||||
session.userData.subjects
|
||||
)}?`
|
||||
);
|
||||
}
|
||||
|
||||
session.replaceDialog("/ask", {});
|
||||
} else {
|
||||
msg.attachments(attachments);
|
||||
session.send(msg);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
session.userData.isAsking = true;
|
||||
},
|
||||
function(session, results) {
|
||||
var text = results.response;
|
||||
if (AzureText.isIntentNo(text)) {
|
||||
session.replaceDialog("/feedback");
|
||||
} else {
|
||||
session.replaceDialog("/ask");
|
||||
}
|
||||
}
|
||||
])
|
||||
.triggerAction({
|
||||
matches: /^(menu)/i
|
||||
});
|
||||
|
||||
bot.beginDialogAction("menuAction", "/menu");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,640 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
const logger = require("../../../src/logger");
|
||||
const Path = require("path");
|
||||
const Fs = require("fs");
|
||||
const Parse = require("csv-parse");
|
||||
const Async = require("async");
|
||||
const UrlJoin = require("url-join");
|
||||
const Walk = require("fs-walk");
|
||||
const WaitUntil = require("wait-until");
|
||||
const marked = require("marked");
|
||||
|
||||
import { GuaribasQuestion, GuaribasAnswer, GuaribasSubject }from "../models";
|
||||
import { GBServiceCallback, IGBCoreService, IGBConversationalService, IGBInstance } from "botlib";
|
||||
import { AzureSearch } from "pragmatismo-io-framework1";
|
||||
import { GBCoreService } from 'deploy/core.gbapp/services/GBCoreService';
|
||||
import { GBDeployer } from "../../core.gbapp/services/GBDeployer";
|
||||
import { GBConversationalService } from "../../core.gbapp/services/GBConversationalService";
|
||||
import { Session } from "botbuilder";
|
||||
import { GuaribasPackage } from "../../core.gbapp/models/GBModel";
|
||||
|
||||
export class KBService {
|
||||
|
||||
getAnswerById(
|
||||
instanceId: number,
|
||||
answerId: number,
|
||||
cb: GBServiceCallback<GuaribasAnswer>
|
||||
) {
|
||||
GuaribasAnswer.findAll({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
answerId: answerId
|
||||
}
|
||||
}).then((item: GuaribasAnswer[]) => {
|
||||
cb(item[0], null);
|
||||
});
|
||||
}
|
||||
|
||||
getAnswerByText(
|
||||
instanceId: number,
|
||||
text: string,
|
||||
cb: GBServiceCallback<any>
|
||||
) {
|
||||
GuaribasQuestion.findOne({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
content: text
|
||||
}
|
||||
}).then((question: GuaribasQuestion) => {
|
||||
GuaribasAnswer.findOne({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
answerId: question.answerId
|
||||
}
|
||||
}).then((answer: GuaribasAnswer) => {
|
||||
cb({ question: question, answer: answer }, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
addAnswer(obj: GuaribasAnswer, cb: GBServiceCallback<GuaribasAnswer>) {
|
||||
GuaribasAnswer.create(obj).then(item => {
|
||||
if (cb) {
|
||||
cb(item, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ask(
|
||||
instance: IGBInstance,
|
||||
what: string,
|
||||
searchScore: number,
|
||||
subjects: GuaribasSubject[],
|
||||
cb: GBServiceCallback<any>
|
||||
) {
|
||||
if (instance.searchKey === "") {
|
||||
cb(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Builds search query.
|
||||
|
||||
what = what.replace("?", " ");
|
||||
what = what.replace("!", " ");
|
||||
what = what.replace(".", " ");
|
||||
what = what.replace("/", " ");
|
||||
what = what.replace("\\", " ");
|
||||
|
||||
if (subjects) {
|
||||
what = `${what} ${KBService.getSubjectItemsSeparatedBySpaces(
|
||||
subjects
|
||||
)}`;
|
||||
}
|
||||
|
||||
// TODO: Filter by instance. what = `${what}&$filter=instanceId eq ${instanceId}`;
|
||||
|
||||
// Performs search.
|
||||
|
||||
var _this = this;
|
||||
|
||||
if (instance.searchKey) {
|
||||
let service = new AzureSearch(
|
||||
instance.searchKey,
|
||||
instance.searchHost,
|
||||
instance.searchIndex,
|
||||
instance.searchIndexer
|
||||
);
|
||||
|
||||
service.search(what, (err: any, results: any) => {
|
||||
if (results && results.length > 0) {
|
||||
// Ponders over configuration.
|
||||
|
||||
if (results[0]["@search.score"] >= searchScore) {
|
||||
_this.getAnswerById(
|
||||
instance.instanceId,
|
||||
results[0].answerId,
|
||||
(answer, err) => {
|
||||
cb({ answer: answer, questionId: results[0].questionId }, null);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
cb(null, null);
|
||||
}
|
||||
} else {
|
||||
cb(null, null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.getAnswerByText(instance.instanceId, what, (data, err) => {
|
||||
cb({ answer: data.answer, questionId: data.question.questionId }, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
createGuaribasKbIndex(cb, name) {
|
||||
let _this = this;
|
||||
let schema = {
|
||||
name: name,
|
||||
fields: [
|
||||
{
|
||||
name: "questionId",
|
||||
type: "Edm.String",
|
||||
searchable: false,
|
||||
filterable: false,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: true
|
||||
},
|
||||
{
|
||||
name: "subject1",
|
||||
type: "Edm.String",
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: "subject2",
|
||||
type: "Edm.String",
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: "subject3",
|
||||
type: "Edm.String",
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: "subject4",
|
||||
type: "Edm.String",
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: "content",
|
||||
type: "Edm.String",
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: "answerId",
|
||||
type: "Edm.Int32",
|
||||
searchable: false,
|
||||
filterable: false,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: "instanceId",
|
||||
type: "Edm.Int32",
|
||||
searchable: false,
|
||||
filterable: true,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: "packageId",
|
||||
type: "Edm.Int32",
|
||||
searchable: false,
|
||||
filterable: true,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
}
|
||||
],
|
||||
scoringProfiles: [],
|
||||
defaultScoringProfile: null,
|
||||
corsOptions: null
|
||||
};
|
||||
|
||||
// TODO: Migrate to Azure Search.
|
||||
// this.client.createIndex(schema, function(err, schemaReturned) {
|
||||
|
||||
// let schemaIndexer = {
|
||||
// name: _this.searchIndexer,
|
||||
// description: 'gb',
|
||||
// dataSourceName: 'gb', // TODO: Create it too dynamically from .env.
|
||||
// targetIndexName: _this.searchIndex,
|
||||
// parameters: {
|
||||
// 'maxFailedItems' : 10,
|
||||
// 'maxFailedItemsPerBatch' : 5,
|
||||
// 'base64EncodeKeys': false,
|
||||
// 'batchSize': 500
|
||||
// }};
|
||||
|
||||
// // create/update an indexer
|
||||
// _this.client.createIndexer(schemaIndexer, function(err, schemaIndexerReturned){
|
||||
// cb(schemaIndexerReturned, err);
|
||||
// });
|
||||
|
||||
// });
|
||||
}
|
||||
|
||||
static getFormattedSubjectItems(subjects: GuaribasSubject[]) {
|
||||
if (!subjects) return "";
|
||||
let out = [];
|
||||
subjects.forEach(subject => {
|
||||
out.push(subject.title);
|
||||
});
|
||||
return out.join(", ");
|
||||
}
|
||||
|
||||
static getSubjectItemsSeparatedBySpaces(subjects: GuaribasSubject[]) {
|
||||
let out = [];
|
||||
subjects.forEach(subject => {
|
||||
out.push(subject.title);
|
||||
});
|
||||
return out.join(" ");
|
||||
}
|
||||
|
||||
getSubjectItems(
|
||||
instanceId: number,
|
||||
parentId: number,
|
||||
cb: GBServiceCallback<GuaribasSubject[]>
|
||||
) {
|
||||
var where = { parentSubjectId: parentId, instanceId: instanceId };
|
||||
GuaribasSubject.findAll({
|
||||
where: where
|
||||
})
|
||||
.then((values: GuaribasSubject[]) => {
|
||||
cb(values, null);
|
||||
})
|
||||
.error(reason => {
|
||||
cb(null, reason);
|
||||
});
|
||||
}
|
||||
|
||||
getFaqBySubjectArray(from: string, subjects: any, cb) {
|
||||
let where = {
|
||||
from: from
|
||||
};
|
||||
|
||||
if (subjects) {
|
||||
if (subjects[0]) {
|
||||
where["subject1"] = subjects[0].title;
|
||||
}
|
||||
|
||||
if (subjects[1]) {
|
||||
where["subject2"] = subjects[1].title;
|
||||
}
|
||||
|
||||
if (subjects[2]) {
|
||||
where["subject3"] = subjects[2].title;
|
||||
}
|
||||
|
||||
if (subjects[3]) {
|
||||
where["subject4"] = subjects[3].title;
|
||||
}
|
||||
}
|
||||
GuaribasQuestion.findAll({
|
||||
where: where
|
||||
})
|
||||
.then((items: GuaribasQuestion[]) => {
|
||||
if (!items) items = [];
|
||||
if (items.length == 0) {
|
||||
cb([], null);
|
||||
} else {
|
||||
cb(items, null);
|
||||
}
|
||||
})
|
||||
.catch(reason => {
|
||||
if (reason.message.indexOf("no such table: IGBInstance") != -1) {
|
||||
cb([], null);
|
||||
} else {
|
||||
cb(null, reason);
|
||||
logger.trace(`GuaribasServiceError: ${reason}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
importKbTabularFile(
|
||||
basedir: string,
|
||||
filename: string,
|
||||
instanceId: number,
|
||||
packageId: number,
|
||||
cb
|
||||
) {
|
||||
var filePath = UrlJoin(basedir, filename);
|
||||
|
||||
var parser = Parse(
|
||||
{
|
||||
delimiter: "\t"
|
||||
},
|
||||
function (err, data) {
|
||||
Async.eachSeries(data, function (line, callback) {
|
||||
callback();
|
||||
let subjectsText = line[0];
|
||||
var from = line[1];
|
||||
var to = line[2];
|
||||
var question = line[3];
|
||||
var answer = line[4];
|
||||
|
||||
// Skip the first line.
|
||||
|
||||
if (!(subjectsText === "subjects" && from == "from")) {
|
||||
let format = ".txt";
|
||||
|
||||
// Extract answer from external media if any.
|
||||
|
||||
if (answer.indexOf(".md") > -1) {
|
||||
let mediaFilename = UrlJoin(basedir, "..", "articles", answer);
|
||||
if (Fs.existsSync(mediaFilename)) {
|
||||
answer = Fs.readFileSync(mediaFilename, "utf8");
|
||||
format = ".md";
|
||||
} else {
|
||||
logger.trace("[GBImporter] File not found: ", mediaFilename);
|
||||
answer =
|
||||
"Por favor, contate a administração para rever esta pergunta.";
|
||||
}
|
||||
}
|
||||
|
||||
let subjectArray = subjectsText.split(".");
|
||||
let subject1: string,
|
||||
subject2: string,
|
||||
subject3: string,
|
||||
subject4: string;
|
||||
|
||||
var indexer = 0;
|
||||
subjectArray.forEach(element => {
|
||||
if (indexer == 0) {
|
||||
subject1 = subjectArray[indexer].substring(0, 63);
|
||||
} else if (indexer == 1) {
|
||||
subject2 = subjectArray[indexer].substring(0, 63);
|
||||
} else if (indexer == 2) {
|
||||
subject3 = subjectArray[indexer].substring(0, 63);
|
||||
} else if (indexer == 3) {
|
||||
subject4 = subjectArray[indexer].substring(0, 63);
|
||||
}
|
||||
indexer++;
|
||||
});
|
||||
|
||||
GuaribasAnswer.create({
|
||||
instanceId: instanceId,
|
||||
content: answer,
|
||||
format: format,
|
||||
packageId: packageId
|
||||
}).then(function (answer: GuaribasAnswer) {
|
||||
GuaribasQuestion.create({
|
||||
from: from,
|
||||
to: to,
|
||||
subject1: subject1,
|
||||
subject2: subject2,
|
||||
subject3: subject3,
|
||||
subject4: subject4,
|
||||
content: question,
|
||||
instanceId: instanceId,
|
||||
answerId: answer.answerId,
|
||||
packageId: packageId
|
||||
});
|
||||
});
|
||||
} else {
|
||||
logger.warn("[GBImporter] Missing header in file: ", filename);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
Fs.createReadStream(filePath, {
|
||||
encoding: "UCS-2"
|
||||
}).pipe(parser);
|
||||
}
|
||||
|
||||
sendAnswer(conversationalService: IGBConversationalService, session: Session, answer: GuaribasAnswer) {
|
||||
|
||||
if (answer.content.endsWith('.mp4')) {
|
||||
conversationalService.sendEvent(session, "play", {
|
||||
playerType: "video",
|
||||
data: answer.content
|
||||
});
|
||||
}else if (answer.content.length > 140) {
|
||||
let msgs = [
|
||||
"Vou te responder na tela para melhor visualização...",
|
||||
"A resposta está na tela...",
|
||||
"Veja a resposta na tela..."
|
||||
];
|
||||
session.send(msgs);
|
||||
var html = answer.content;
|
||||
if (answer.format === ".md") {
|
||||
marked.setOptions({
|
||||
renderer: new marked.Renderer(),
|
||||
gfm: true,
|
||||
tables: true,
|
||||
breaks: false,
|
||||
pedantic: false,
|
||||
sanitize: false,
|
||||
smartLists: true,
|
||||
smartypants: false,
|
||||
xhtml: false
|
||||
});
|
||||
html = marked(answer.content);
|
||||
}
|
||||
conversationalService.sendEvent(session, "play", { playerType: "markdown", data: html });
|
||||
} else {
|
||||
session.send(answer.content);
|
||||
conversationalService.sendEvent(session, "stop", null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
importKbPackage(
|
||||
localPath: string,
|
||||
packageStorage: GuaribasPackage,
|
||||
instance: IGBInstance
|
||||
) {
|
||||
this.importSubjectFile(
|
||||
packageStorage.packageId,
|
||||
UrlJoin(localPath, "subjects.json"),
|
||||
instance
|
||||
);
|
||||
let _this = this;
|
||||
setTimeout(() => {
|
||||
_this.importKbTabularDirectory(
|
||||
localPath,
|
||||
instance,
|
||||
packageStorage.packageId
|
||||
);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
importKbTabularDirectory(
|
||||
localPath: string,
|
||||
instance: IGBInstance,
|
||||
packageId: number
|
||||
) {
|
||||
let _this = this;
|
||||
Walk.files(
|
||||
UrlJoin(localPath, "tabular"),
|
||||
(basedir, filename, stat, next) => {
|
||||
if (filename.endsWith(".tsv")) {
|
||||
_this.importKbTabularFile(
|
||||
basedir,
|
||||
filename,
|
||||
instance.instanceId,
|
||||
packageId,
|
||||
(data, err) => {
|
||||
if (err) {
|
||||
logger.trace(err);
|
||||
} else {
|
||||
logger.trace("Import KB done.");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
function (err) {
|
||||
if (err) logger.trace(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
importSubjectFile(
|
||||
packageId: number,
|
||||
filename: string,
|
||||
instance: IGBInstance
|
||||
) {
|
||||
var subjects = JSON.parse(Fs.readFileSync(filename, "utf8"));
|
||||
|
||||
function doIt(subjects: GuaribasSubject[], parentSubjectId: number) {
|
||||
Async.eachSeries(subjects, (item, callback) => {
|
||||
let mediaFilename = item.id + ".png";
|
||||
GuaribasSubject.create({
|
||||
internalId: item.id,
|
||||
parentSubjectId: parentSubjectId,
|
||||
instanceId: instance.instanceId,
|
||||
from: item.from,
|
||||
to: item.to,
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
packageId: packageId
|
||||
}).then((value: any) => {
|
||||
if (item.children) {
|
||||
doIt(item.children, value.subjectId);
|
||||
}
|
||||
});
|
||||
callback();
|
||||
});
|
||||
}
|
||||
doIt(subjects.children, null);
|
||||
}
|
||||
|
||||
|
||||
undeployKbFromStorage(
|
||||
instance: IGBInstance,
|
||||
packageId: number,
|
||||
cb: GBServiceCallback<any>
|
||||
) {
|
||||
GuaribasQuestion.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
}).then(value => {
|
||||
GuaribasAnswer.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
}).then(value => {
|
||||
GuaribasSubject.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
}).then(value => {
|
||||
GuaribasPackage.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
}).then(value => {
|
||||
var search = new AzureSearch(
|
||||
instance.searchKey,
|
||||
instance.searchHost,
|
||||
instance.searchIndex,
|
||||
instance.searchIndexer
|
||||
);
|
||||
logger.trace("rebuildIndex called.");
|
||||
search.rebuildIndex(() => {
|
||||
logger.trace("rebuildIndex done.");
|
||||
cb(null, null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploys a knowledge base to the storage using the .gbkb format.
|
||||
*
|
||||
* @param localPath Path to the .gbkb folder.
|
||||
* @param cb Package instance or error info.
|
||||
*/
|
||||
deployKb(core: IGBCoreService, deployer: GBDeployer, localPath: string, cb: GBServiceCallback<any>) {
|
||||
let packageType = Path.extname(localPath);
|
||||
let packageName = Path.basename(localPath);
|
||||
logger.trace("[GBDeployer] Opening package: ", packageName);
|
||||
let packageObject = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
||||
);
|
||||
|
||||
core.loadInstance(packageObject.botId, (instance, err) => {
|
||||
deployer.deployPackageToStorage(
|
||||
instance.instanceId,
|
||||
packageName,
|
||||
(p, err) => {
|
||||
this.importKbPackage(localPath, p, instance);
|
||||
setTimeout(() => {
|
||||
cb(null, null);
|
||||
}, 8000);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
1248
directline-3.0.json
Normal file
1
docs/_config.yml
Normal file
|
|
@ -0,0 +1 @@
|
|||
theme: jekyll-theme-minimal
|
||||
BIN
docs/images/general-bots-block-architecture.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
docs/images/general-bots-composing-subjects-json-and-excel.gif
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 78 KiB |
BIN
docs/images/general-bots-stack.png
Normal file
|
After Width: | Height: | Size: 261 KiB |
BIN
docs/images/generalbots-logo-squared.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
docs/images/generalbots-open-core-starting-from-scratch.gif
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/images/video-01-thumb.jpg
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
docs/images/video-02-thumb.jpg
Normal file
|
After Width: | Height: | Size: 163 KiB |
2660
docs/reference/assets/css/main.css
Normal file
BIN
docs/reference/assets/images/icons.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
docs/reference/assets/images/icons@2x.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/reference/assets/images/widgets.png
Normal file
|
After Width: | Height: | Size: 480 B |
BIN
docs/reference/assets/images/widgets@2x.png
Normal file
|
After Width: | Height: | Size: 855 B |
248
docs/reference/assets/js/main.js
Normal file
1
docs/reference/assets/js/search.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
window.searchData = {"kinds":{"128":"Class","512":"Constructor","1024":"Property","2048":"Method"},"rows":[{"id":0,"kind":128,"name":"RootData","url":"classes/rootdata.html","classes":"tsd-kind-class"},{"id":1,"kind":512,"name":"constructor","url":"classes/rootdata.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class","parent":"RootData"},{"id":2,"kind":1024,"name":"publicAddress","url":"classes/rootdata.html#publicaddress","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":3,"kind":1024,"name":"server","url":"classes/rootdata.html#server","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":4,"kind":1024,"name":"sysPackages","url":"classes/rootdata.html#syspackages","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":5,"kind":1024,"name":"appPackages","url":"classes/rootdata.html#apppackages","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":6,"kind":1024,"name":"minService","url":"classes/rootdata.html#minservice","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":7,"kind":1024,"name":"bootInstance","url":"classes/rootdata.html#bootinstance","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":8,"kind":1024,"name":"minInstances","url":"classes/rootdata.html#mininstances","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":9,"kind":1024,"name":"minBoot","url":"classes/rootdata.html#minboot","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":10,"kind":1024,"name":"wwwroot","url":"classes/rootdata.html#wwwroot","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":11,"kind":1024,"name":"entryPointDialog","url":"classes/rootdata.html#entrypointdialog","classes":"tsd-kind-property tsd-parent-kind-class","parent":"RootData"},{"id":12,"kind":128,"name":"GBServer","url":"classes/gbserver.html","classes":"tsd-kind-class"},{"id":13,"kind":1024,"name":"globals","url":"classes/gbserver.html#globals","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-static","parent":"GBServer"},{"id":14,"kind":2048,"name":"run","url":"classes/gbserver.html#run","classes":"tsd-kind-method tsd-parent-kind-class tsd-is-static","parent":"GBServer"},{"id":15,"kind":512,"name":"constructor","url":"classes/gbserver.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class","parent":"GBServer"}],"index":{"version":"2.3.9","fields":["name","parent"],"fieldVectors":[["name/0",[0,3.075]],["parent/0",[]],["name/1",[1,19.169]],["parent/1",[0,0.291]],["name/2",[2,24.277]],["parent/2",[0,0.291]],["name/3",[3,24.277]],["parent/3",[0,0.291]],["name/4",[4,24.277]],["parent/4",[0,0.291]],["name/5",[5,24.277]],["parent/5",[0,0.291]],["name/6",[6,24.277]],["parent/6",[0,0.291]],["name/7",[7,24.277]],["parent/7",[0,0.291]],["name/8",[8,24.277]],["parent/8",[0,0.291]],["name/9",[9,24.277]],["parent/9",[0,0.291]],["name/10",[10,24.277]],["parent/10",[0,0.291]],["name/11",[11,24.277]],["parent/11",[0,0.291]],["name/12",[12,13.291]],["parent/12",[]],["name/13",[13,24.277]],["parent/13",[12,1.256]],["name/14",[14,24.277]],["parent/14",[12,1.256]],["name/15",[1,19.169]],["parent/15",[12,1.256]]],"invertedIndex":[["apppackages",{"_index":5,"name":{"5":{}},"parent":{}}],["bootinstance",{"_index":7,"name":{"7":{}},"parent":{}}],["constructor",{"_index":1,"name":{"1":{},"15":{}},"parent":{}}],["entrypointdialog",{"_index":11,"name":{"11":{}},"parent":{}}],["gbserver",{"_index":12,"name":{"12":{}},"parent":{"13":{},"14":{},"15":{}}}],["globals",{"_index":13,"name":{"13":{}},"parent":{}}],["minboot",{"_index":9,"name":{"9":{}},"parent":{}}],["mininstances",{"_index":8,"name":{"8":{}},"parent":{}}],["minservice",{"_index":6,"name":{"6":{}},"parent":{}}],["publicaddress",{"_index":2,"name":{"2":{}},"parent":{}}],["rootdata",{"_index":0,"name":{"0":{}},"parent":{"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{},"10":{},"11":{}}}],["run",{"_index":14,"name":{"14":{}},"parent":{}}],["server",{"_index":3,"name":{"3":{}},"parent":{}}],["syspackages",{"_index":4,"name":{"4":{}},"parent":{}}],["wwwroot",{"_index":10,"name":{"10":{}},"parent":{}}]],"pipeline":[]}}
|
||||
213
docs/reference/index.html
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
<!doctype html>
|
||||
<html class="default no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>General Bots Open Core</title>
|
||||
<meta name="description" content="Documentation for General Bots Open Core">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="assets/css/main.css">
|
||||
<script async src="assets/js/search.js" id="search-script"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="tsd-page-toolbar">
|
||||
<div class="container">
|
||||
<div class="table-wrap">
|
||||
<div class="table-cell" id="tsd-search" data-index="assets/js/search.json" data-base=".">
|
||||
<div class="field">
|
||||
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
|
||||
<input id="tsd-search-field" type="text" />
|
||||
</div>
|
||||
<ul class="results">
|
||||
<li class="state loading">Preparing search index...</li>
|
||||
<li class="state failure">The search index is not available</li>
|
||||
</ul>
|
||||
<a href="index.html" class="title">General Bots Open Core</a>
|
||||
</div>
|
||||
<div class="table-cell" id="tsd-widgets">
|
||||
<div id="tsd-filter">
|
||||
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
|
||||
<div class="tsd-filter-group">
|
||||
<div class="tsd-select" id="tsd-filter-visibility">
|
||||
<span class="tsd-select-label">All</span>
|
||||
<ul class="tsd-select-list">
|
||||
<li data-value="public">Public</li>
|
||||
<li data-value="protected">Public/Protected</li>
|
||||
<li data-value="private" class="selected">All</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="checkbox" id="tsd-filter-inherited" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
|
||||
<input type="checkbox" id="tsd-filter-externals" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-externals">Externals</label>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tsd-page-title">
|
||||
<div class="container">
|
||||
<h1>General Bots Open Core</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="container container-main">
|
||||
<div class="row">
|
||||
<div class="col-8 col-content">
|
||||
<div class="tsd-panel tsd-typography">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Area</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td>Releases</td>
|
||||
<td><a href="https://www.npmjs.com/package/botserver/"><img src="https://img.shields.io/npm/dt/botserver.svg?logo=npm&label=botserver" alt="General Bots"></a> <a href="https://www.npmjs.com/package/botlib/"><img src="https://img.shields.io/npm/dt/botlib.svg?logo=npm&label=botlib" alt=".gbapp lib"></a> <a href="https://github.com/semantic-release/semantic-release"><img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg" alt="semantic-release"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Community</td>
|
||||
<td><a href="https://stackoverflow.com/questions/tagged/generalbots"><img src="https://img.shields.io/stackexchange/stackoverflow/t/generalbots.svg" alt="StackExchange"></a> <a href="https://badges.frapsoft.com"><img src="https://badges.frapsoft.com/os/v2/open-source.svg" alt="Open-source"></a> <a href="http://makeapullrequest.com"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs Welcome"></a> <a href="https://github.com/GeneralBots/BotServer/blob/master/LICENSE.txt"><img src="https://img.shields.io/badge/license-AGPL-blue.svg" alt="License"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Management</td>
|
||||
<td><a href="https://gitHub.com/GeneralBots/BotServer/graphs/commit-activity"><img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg" alt="Maintenance"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td><a href="https://snyk.io/test/github/GeneralBots/BotServer"><img src="https://snyk.io/test/github/GeneralBots/BotServer/badge.svg" alt="Known Vulnerabilities"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Building & Quality</td>
|
||||
<td><a href="https://travis-ci.com/GeneralBots/BotServer"><img src="https://travis-ci.com/GeneralBots/BotServer.svg?branch=master" alt="Build Status"></a> <a href="https://coveralls.io/github/GeneralBots/BotServer"><img src="https://coveralls.io/repos/github/GeneralBots/BotServer/badge.svg" alt="Coverage Status"></a> <a href="https://github.com/prettier/prettier"><img src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square" alt="code style: prettier"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Packaging</td>
|
||||
<td><a href="https://badge.fury.io"><img src="https://badge.fury.io/js/botserver.svg" alt="forthebadge"></a> <a href="https://github.com/GeneralBots/BotServer/releases/latest"><img src="https://camo.githubusercontent.com/0150c0f148d50fe9750ebc5d313581da699a8c50/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7a69702d646f776e6c6f61642d626c75652e737667" alt="ZipFile"></a> <a href="https://david-dm.org"><img src="https://david-dm.org/GeneralBots/botserver.svg" alt="Dependencies"></a> <a href="http://commitizen.github.io/cz-cli/"><img src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg" alt="Commitizen friendly"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Samples</td>
|
||||
<td><a href="https://github.com/GeneralBots/BotServer/tree/master/packages/default.gbdialog">VBA</a> or <a href="https://github.com/GeneralBots/AzureADPasswordReset.gbapp"><img src="https://badges.frapsoft.com/typescript/code/typescript.svg?v=101" alt="TypeScript"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/lpicanco/docker-botserver">Docker Image</a></td>
|
||||
<td><img src="https://img.shields.io/docker/automated/lpicanco/botserver.svg" alt="Docker Automated build"> <img src="https://img.shields.io/docker/build/lpicanco/botserver.svg" alt="Docker Build Status"> <img src="https://img.shields.io/microbadger/image-size/lpicanco/botserver.svg" alt="MicroBadger Size"> <img src="https://img.shields.io/microbadger/layers/lpicanco/botserver.svg" alt="MicroBadger Layers"> <img src="https://img.shields.io/docker/pulls/lpicanco/botserver.svg" alt="Docker Pulls"> <br/> <em>Provided by <a href="https://github.com/lpicanco/docker-botserver">@lpicanco</a></em></td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<a href="#general-bots" id="general-bots" style="color: inherit; text-decoration: none;">
|
||||
<h2>General Bots</h2>
|
||||
</a>
|
||||
<p><img src="https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/logo.png" alt="General Bot Logo"></p>
|
||||
<p>General Bot is a strongly typed package based chat bot server focused in convention over configuration and code-less approaches, which brings software packages and application server concepts to help parallel bot development.</p>
|
||||
<a href="#what-is-a-bot-server" id="what-is-a-bot-server" style="color: inherit; text-decoration: none;">
|
||||
<h2>What is a Bot Server?</h2>
|
||||
</a>
|
||||
<p>Bot Server accelerates the process of developing a bot. It provisions all code
|
||||
base, resources and deployment to the cloud, and gives you templates you can
|
||||
choose from whenever you need a new bot. The server has a database and service
|
||||
backend allowing you to further modify your bot package directly by downloading
|
||||
a zip file, editing and uploading it back to the server (deploying process) with
|
||||
no code. The Bot Server also provides a framework to develop bot packages in a more
|
||||
advanced fashion writing custom code in editors like Visual Studio Code, Atom or Brackets.</p>
|
||||
<p>Everyone can create bots by just copying and pasting some files and using their
|
||||
favorite tools from Office (or any text editor) or Photoshop (or any image
|
||||
editor). BASIC can be used to build custom dialogs so Bot can be extended just like VBA for Excel (currently in alpha).</p>
|
||||
<p><img src="https://raw.githubusercontent.com/GeneralBots/BotBook/master/images/general-bots-reference-architecture.png" alt="General Bot Reference Architecture"></p>
|
||||
<a href="#samples" id="samples" style="color: inherit; text-decoration: none;">
|
||||
<h2>Samples</h2>
|
||||
</a>
|
||||
<p>Several samples, including a Bot for AD Password Reset, are avaiable on the <a href="https://github.com/GeneralBots">repository list</a>.</p>
|
||||
<a href="#guide" id="guide" style="color: inherit; text-decoration: none;">
|
||||
<h2>Guide</h2>
|
||||
</a>
|
||||
<p><a href="https://github.com/GeneralBots/BotBook/tree/master/book">Read the General Bots BotBook Guide</a>.</p>
|
||||
<a href="#videos" id="videos" style="color: inherit; text-decoration: none;">
|
||||
<h1>Videos</h1>
|
||||
</a>
|
||||
<p>Now with the General Bots server you can press F5 on Visual Studio to get a bot factory on your environment* published on November 10th, 2018.</p>
|
||||
<p><a href="https://www.youtube.com/watch?v=AfKTwljoMOs"><img src="https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/docs/images/video-01-thumb.jpg" alt="General Bot Video"></a></p>
|
||||
<p>See how easy is to use 'hear' and 'talk' to build Microsoft BOT Framework v4 logic with plain BASIC * published on December 3rd, 2018.</p>
|
||||
<p><a href="https://www.youtube.com/watch?v=yX1sF9n9628"><img src="https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/docs/images/video-02-thumb.jpg" alt="See how easy is to use 'hear' and 'talk' to build Microsoft BOT Framework v4 logic with plain BASIC"></a></p>
|
||||
<a href="#contributing" id="contributing" style="color: inherit; text-decoration: none;">
|
||||
<h1>Contributing</h1>
|
||||
</a>
|
||||
<p>This project welcomes contributions and suggestions.
|
||||
See our <a href="https://github.com/pragmatismo-io/BotServer/blob/master/CONTRIBUTING.md">Contribution Guidelines</a> for more details.</p>
|
||||
<a href="#reporting-security-issues" id="reporting-security-issues" style="color: inherit; text-decoration: none;">
|
||||
<h1>Reporting Security Issues</h1>
|
||||
</a>
|
||||
<p>Security issues and bugs should be reported privately, via email, to the Pragmatismo.io Security
|
||||
team at <a href="mailto:security@pragmatismo.io">security@pragmatismo.io</a>. You should
|
||||
receive a response within 24 hours. If for some reason you do not, please follow up via
|
||||
email to ensure we received your original message. </p>
|
||||
<a href="#license-amp-warranty" id="license-amp-warranty" style="color: inherit; text-decoration: none;">
|
||||
<h1>License & Warranty</h1>
|
||||
</a>
|
||||
<p>General Bot Copyright (c) Pragmatismo.io. All rights reserved.
|
||||
Licensed under the AGPL-3.0. </p>
|
||||
<p>According to our dual licensing model, this program can be used either
|
||||
under the terms of the GNU Affero General Public License, version 3,
|
||||
or under a proprietary license. </p>
|
||||
<p>The texts of the GNU Affero General Public License with an additional
|
||||
permission and of our proprietary license can be found at and
|
||||
in the LICENSE file you have received along with this program.</p>
|
||||
<p>This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.</p>
|
||||
<p>"General Bot" is a registered trademark of Pragmatismo.io.
|
||||
The licensing of the program under the AGPLv3 does not imply a
|
||||
trademark license. Therefore any rights, title and interest in
|
||||
our trademarks remain entirely with us.</p>
|
||||
<p><a href="https://stackoverflow.com/questions/ask?tags=generalbots">:speech_balloon: Ask a question</a> <a href="https://github.com/GeneralBots/BotBook">:book: Read the Docs</a></p>
|
||||
<p>General Bots Code Name is <a href="https://en.wikipedia.org/wiki/Guaribas">Guaribas</a>, the name of a city in Brazil, state of Piaui.
|
||||
<a href="http://www.robertounger.com/en/">Roberto Mangabeira Unger</a>: "No one should have to do work that can be done by a machine".</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
|
||||
<nav class="tsd-navigation primary">
|
||||
<ul>
|
||||
<li class=" ">
|
||||
<a href="modules.html">Exports</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="tsd-navigation secondary menu-sticky">
|
||||
<ul class="before-current">
|
||||
<li class=" tsd-kind-class">
|
||||
<a href="classes/gbserver.html" class="tsd-kind-icon">GBServer</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-class">
|
||||
<a href="classes/rootdata.html" class="tsd-kind-icon">Root<wbr>Data</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="with-border-bottom">
|
||||
<div class="container">
|
||||
<h2>Legend</h2>
|
||||
<div class="tsd-legend-group">
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-class"><span class="tsd-kind-icon">Property</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<div class="container tsd-generator">
|
||||
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
|
||||
</div>
|
||||
<div class="overlay"></div>
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
382
extensions.json
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
15
gbot.cmd
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
@ECHO off
|
||||
|
||||
ECHO General Bots Command Line
|
||||
|
||||
IF EXIST node_modules goto COMPILE
|
||||
ECHO Installing Packages for the first time use (it may take several minutes)...
|
||||
CALL npm install --silent
|
||||
|
||||
:COMPILE
|
||||
IF EXIST dist goto ALLSET
|
||||
ECHO Compiling...
|
||||
npm run build
|
||||
|
||||
:ALLSET
|
||||
npm run start
|
||||
2
gbot.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
echo Starting General Bots...
|
||||
npm run start
|
||||
11
greenkeeper.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"groups": {
|
||||
"default": {
|
||||
"packages": [
|
||||
"package.json",
|
||||
"packages/default.gbtheme/package.json",
|
||||
"packages/default.gbui/package.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
logo.png
Normal file
|
After Width: | Height: | Size: 8 KiB |
333
package.json
|
|
@ -1,51 +1,300 @@
|
|||
{
|
||||
"name": "botserver",
|
||||
"version": "0.0.11",
|
||||
"description": "General Bots Community Edition open-core server.",
|
||||
"author": "me@rodrigorodriguez.com",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./src/app.ts",
|
||||
"homepage": "http://pragmatismo.io",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"start": "node ./dist/src/app.js",
|
||||
"startIde": "npm-run-all clean --parallel watch:build watch:server --print-label",
|
||||
"watch:build": "tsc --watch",
|
||||
"watch:server": "nodemon './dist/index.js' --watch './dist'",
|
||||
"test": "mocha -r ts-node/register src/**/*.test.ts",
|
||||
"build-docs": "typedoc --options typedoc.json src/"
|
||||
},
|
||||
"version": "2.4.42",
|
||||
"type": "module",
|
||||
"description": "General Bot Community Edition open-core server.",
|
||||
"main": "./boot.mjs",
|
||||
"bugs": "https://github.com/pragmatismo-io/BotServer/issues",
|
||||
"homepage": "https://github.com/pragmatismo-io/BotServer/#readme",
|
||||
"contributors": [
|
||||
"Rodrigo Rodriguez <me@rodrigorodriguez.com>",
|
||||
"João Ferreira <joao.parana@gmail.com>",
|
||||
"Jorge Ramos <jramos@pobox.com>",
|
||||
"PH <ph.an@outlook.com>",
|
||||
"Dário Vieira <dario.junior3@gmail.com>",
|
||||
"Alan Perdomo <alanperdomo@hotmail.com>"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8.9.4"
|
||||
"node": "=19.7.0"
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"preferGlobal": true,
|
||||
"private": false,
|
||||
"bin": {
|
||||
"gbot": "./boot.cjs"
|
||||
},
|
||||
"readme": "README.md",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GeneralBots/BotServer.git"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf node_modules/ dist/ docs/reference",
|
||||
"tslint": "tslint --fix ./src/*.ts ./packages/**/*.ts -t verbose",
|
||||
"build": "npm install && npm run build-server && npm run build-gbui",
|
||||
"build-server": "tsc",
|
||||
"build-gbui": "cd packages/default.gbui && echo SKIP_PREFLIGHT_CHECK=true >.env && npm install && npm run build",
|
||||
"build-docs": "typedoc --options typedoc.json src/",
|
||||
"test": "node test.js",
|
||||
"start": "NODE_NO_WARNINGS=1 node ./boot.mjs --loader ts-node/esm --require ./suppress-node-warnings.cjs",
|
||||
"reverse-proxy": "node_modules/.bin/ngrok http 4242",
|
||||
"watch:build": "tsc --watch",
|
||||
"posttypedoc": "shx cp .nojekyll docs/reference/.nojekyll",
|
||||
"ban": "ban",
|
||||
"issues": "git-issues",
|
||||
"license": "license-checker --production --onlyunknown --csv",
|
||||
"pretty": "prettier-standard 'src/*.ts' 'packages/**/*.ts'",
|
||||
"secure": "nsp check",
|
||||
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";",
|
||||
"unused-deps": "dependency-check --unused --no-dev ./package.json",
|
||||
"travis-deploy-once": "travis-deploy-once --pro",
|
||||
"semantic-release": "semantic-release",
|
||||
"commit": "git-cz"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "^1.5.2",
|
||||
"botbuilder": "^3.14.0",
|
||||
"chokidar": "^2.0.2",
|
||||
"csv-parse": "^2.2.0",
|
||||
"dotenv-extended": "^1.0.4",
|
||||
"express": "^4.16.2",
|
||||
"fs-walk": "0.0.1",
|
||||
"marked": "^0.3.12",
|
||||
"reflect-metadata": "^0.1.12",
|
||||
"request-promise-native": "^1.0.5",
|
||||
"sequelize": "^4.37.6",
|
||||
"sequelize-typescript": "^0.6.3",
|
||||
"sqlite3": "^3.1.13",
|
||||
"tedious": "^2.1.1",
|
||||
"url-join": "^4.0.0",
|
||||
"wait-until": "0.0.2",
|
||||
"winston": "^2.4.0"
|
||||
"@azure/arm-appservice": "13.0.3",
|
||||
"@azure/arm-cognitiveservices": "7.3.1",
|
||||
"@azure/arm-resources": "5.1.0",
|
||||
"@azure/arm-search": "3.0.1",
|
||||
"@azure/arm-sql": "9.0.1",
|
||||
"@azure/arm-subscriptions": "5.1.0",
|
||||
"@azure/cognitiveservices-computervision": "8.2.0",
|
||||
"@azure/keyvault-keys": "4.6.0",
|
||||
"@azure/ms-rest-js": "2.6.2",
|
||||
"@azure/msal-node": "1.14.3",
|
||||
"@azure/search-documents": "11.3.1",
|
||||
"@google-cloud/pubsub": "3.2.1",
|
||||
"@google-cloud/translate": "7.0.4",
|
||||
"@hubspot/api-client": "7.1.2",
|
||||
"@koa/cors": "4.0.0",
|
||||
"@microsoft/microsoft-graph-client": "3.0.4",
|
||||
"@nlpjs/basic": "4.26.1",
|
||||
"@nosferatu500/textract": "3.1.2",
|
||||
"@push-rpc/core": "1.1.5",
|
||||
"@push-rpc/http": "1.1.5",
|
||||
"@push-rpc/websocket": "1.1.5",
|
||||
"@semantic-release/changelog": "5.0.1",
|
||||
"@semantic-release/exec": "5.0.0",
|
||||
"@semantic-release/git": "9.0.0",
|
||||
"@sendgrid/mail": "7.7.0",
|
||||
"@types/node": "18.11.9",
|
||||
"@types/validator": "13.7.10",
|
||||
"adm-zip": "0.5.9",
|
||||
"alasql": "2.1.6",
|
||||
"any-shell-escape": "0.1.1",
|
||||
"arraybuffer-to-buffer": "0.0.7",
|
||||
"async-mutex": "0.4.0",
|
||||
"async-promises": "0.2.3",
|
||||
"basic-auth": "2.0.1",
|
||||
"billboard.js": "3.6.3",
|
||||
"bluebird": "3.7.2",
|
||||
"body-parser": "1.20.1",
|
||||
"botbuilder": "4.18.0",
|
||||
"botbuilder-adapter-facebook": "1.0.12",
|
||||
"botbuilder-ai": "4.18.0",
|
||||
"botbuilder-dialogs": "4.18.0",
|
||||
"botframework-connector": "4.18.0",
|
||||
"botlib": "3.0.11",
|
||||
"c3-chart-maker": "0.2.8",
|
||||
"cd": "0.3.3",
|
||||
"chatgpt": "2.4.2",
|
||||
"chrome-remote-interface": "0.31.3",
|
||||
"cli-progress": "3.11.2",
|
||||
"cli-spinner": "0.2.10",
|
||||
"core-js": "3.26.1",
|
||||
"data-forge": "1.9.6",
|
||||
"date-diff": "1.0.2",
|
||||
"docximager": "0.0.4",
|
||||
"docxtemplater": "3.9.7",
|
||||
"dotenv-extended": "2.9.0",
|
||||
"dynamics-web-api": "1.7.6",
|
||||
"exceljs": "4.3.0",
|
||||
"express": "4.18.2",
|
||||
"express-remove-route": "1.0.0",
|
||||
"ffmpeg-static": "5.1.0",
|
||||
"google-libphonenumber": "3.2.31",
|
||||
"googleapis": "109.0.1",
|
||||
"ibm-watson": "7.1.2",
|
||||
"join-images-updated": "1.1.4",
|
||||
"keyv": "4.5.2",
|
||||
"koa": "2.13.4",
|
||||
"koa-body": "6.0.1",
|
||||
"koa-router": "12.0.0",
|
||||
"line-replace": "2.0.1",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.1.0",
|
||||
"mammoth": "1.5.1",
|
||||
"mime-types": "2.1.35",
|
||||
"moment": "1.3.0",
|
||||
"ms-rest-azure": "3.0.0",
|
||||
"nexmo": "2.9.1",
|
||||
"ngrok": "4.3.3",
|
||||
"node-cron": "3.0.2",
|
||||
"node-html-parser": "6.1.5",
|
||||
"node-nlp": "4.26.1",
|
||||
"node-tesseract-ocr": "2.2.1",
|
||||
"npm": "9.6.1",
|
||||
"open": "8.4.0",
|
||||
"open-docxtemplater-image-module": "1.0.3",
|
||||
"openai": "3.3.0",
|
||||
"pdf-extraction": "1.0.2",
|
||||
"pdf-to-png-converter": "3.1.0",
|
||||
"pdfkit": "0.13.0",
|
||||
"phone": "3.1.30",
|
||||
"pizzip": "3.1.3",
|
||||
"pptxtemplater": "1.0.5",
|
||||
"pragmatismo-io-framework": "1.1.1",
|
||||
"prism-media": "1.3.4",
|
||||
"public-ip": "6.0.1",
|
||||
"punycode": "2.1.1",
|
||||
"puppeteer": "19.8.0",
|
||||
"puppeteer-extra": "3.3.4",
|
||||
"puppeteer-extra-plugin-minmax": "1.1.2",
|
||||
"puppeteer-extra-plugin-stealth": "2.11.1",
|
||||
"qr-scanner": "1.4.2",
|
||||
"qrcode": "1.5.1",
|
||||
"qrcode-terminal": "0.12.0",
|
||||
"readline": "1.3.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"safe-buffer": "5.2.1",
|
||||
"scanf": "1.1.2",
|
||||
"sequelize": "6.28.2",
|
||||
"sequelize-cli": "6.6.0",
|
||||
"sequelize-typescript": "2.1.5",
|
||||
"sharp": "0.31.3",
|
||||
"simple-git": "3.16.0",
|
||||
"speakingurl": "14.0.1",
|
||||
"ssr-for-bots": "1.0.1-c",
|
||||
"strict-password-generator": "1.1.2",
|
||||
"swagger-client": "3.18.5",
|
||||
"tabulator-tables": "5.4.2",
|
||||
"tedious": "15.1.2",
|
||||
"textract": "2.5.0",
|
||||
"twitter-api-v2": "1.12.9",
|
||||
"typescript": "4.9.5",
|
||||
"url-join": "5.0.0",
|
||||
"vbscript-to-typescript": "1.0.8",
|
||||
"vhost": "3.0.2",
|
||||
"vm2": "3.9.11",
|
||||
"vm2-process": "2.1.1",
|
||||
"walk-promise": "0.2.0",
|
||||
"washyourmouthoutwithsoap": "1.0.2",
|
||||
"whatsapp-web.js": "git://github.com/pedroslopez/whatsapp-web.js/commit/abac063b779570729476cf42e29dc694e5345ca6",
|
||||
"winston": "3.8.2",
|
||||
"winston-logs-display": "1.0.0",
|
||||
"ws": "8.12.1",
|
||||
"yarn": "1.22.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/azure": "^0.9.19",
|
||||
"@types/chai": "4.0.4",
|
||||
"@types/mocha": "2.2.43",
|
||||
"chai": "^4.1.2",
|
||||
"mocha": "^3.5.3",
|
||||
"mocha-typescript": "^1.1.12",
|
||||
"ts-node": "3.3.0",
|
||||
"typedoc": "^0.10.0",
|
||||
"typescript": "2.7.2"
|
||||
"@types/qrcode": "1.5.0",
|
||||
"@types/url-join": "4.0.1",
|
||||
"ban-sensitive-files": "1.9.18",
|
||||
"commitizen": "4.2.2",
|
||||
"cz-conventional-changelog": "3.3.0",
|
||||
"dependency-check": "4.1.0",
|
||||
"git-issues": "1.0.0",
|
||||
"license-checker": "25.0.1",
|
||||
"prettier-standard": "15.0.1",
|
||||
"semantic-release": "17.2.4",
|
||||
"simple-commit-message": "4.0.13",
|
||||
"super-strong-password-generator": "2.0.2",
|
||||
"super-strong-password-generator-es": "2.0.2",
|
||||
"travis-deploy-once": "5.0.11",
|
||||
"ts-node": "10.9.1",
|
||||
"tslint": "6.1.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"mocha": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
},
|
||||
"rules": {
|
||||
"indent": "off",
|
||||
"linebreak-style": [
|
||||
"warn",
|
||||
"unix"
|
||||
],
|
||||
"no-unused-vars": [
|
||||
"warn"
|
||||
],
|
||||
"no-undef": [
|
||||
"warn"
|
||||
],
|
||||
"no-console": [
|
||||
"warn"
|
||||
],
|
||||
"no-case-declarations": [
|
||||
"warn"
|
||||
],
|
||||
"no-extra-semi": [
|
||||
"warn"
|
||||
],
|
||||
"no-unreachable": [
|
||||
"warn"
|
||||
],
|
||||
"no-redeclare": [
|
||||
"warn"
|
||||
],
|
||||
"no-useless-escape": [
|
||||
"warn"
|
||||
],
|
||||
"no-constant-condition": [
|
||||
"warn"
|
||||
]
|
||||
}
|
||||
},
|
||||
"release": {
|
||||
"tagFormat": "${version}",
|
||||
"debug": true,
|
||||
"branches": [
|
||||
"main"
|
||||
],
|
||||
"verifyConditions": [
|
||||
"@semantic-release/github"
|
||||
],
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/changelog"
|
||||
],
|
||||
"prepare": [
|
||||
"@semantic-release/npm",
|
||||
{
|
||||
"path": "@semantic-release/exec",
|
||||
"cmd": "git status"
|
||||
},
|
||||
"@semantic-release/changelog",
|
||||
{
|
||||
"path": "@semantic-release/git",
|
||||
"assets": [
|
||||
"package.json",
|
||||
"CHANGELOG.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"publish": [
|
||||
"@semantic-release/npm",
|
||||
"@semantic-release/github"
|
||||
],
|
||||
"analyzeCommits": "simple-commit-message"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
},
|
||||
"pre-git": {
|
||||
"commit-msg": "simple",
|
||||
"pre-commit": [],
|
||||
"pre-push": [],
|
||||
"post-commit": [],
|
||||
"post-checkout": [],
|
||||
"post-merge": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
434
packages/admin.gbapp/dialogs/AdminDialog.ts
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 crypto from 'crypto';
|
||||
import urlJoin from 'url-join';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBLog, 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 { CollectionUtil } from 'pragmatismo-io-framework';
|
||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||
|
||||
/**
|
||||
* Dialogs for administration tasks.
|
||||
*/
|
||||
export class AdminDialog extends IGBDialog {
|
||||
public static isIntentYes(locale, utterance) {
|
||||
return utterance.toLowerCase().match(Messages[locale].affirmative_sentences);
|
||||
}
|
||||
|
||||
public static isIntentNo(locale, utterance) {
|
||||
return utterance.toLowerCase().match(Messages[locale].negative_sentences);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
AdminDialog.setupSecurityDialogs(min);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/admin-auth', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].authenticate;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, prompt);
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const sensitive = step.context.activity['originalText'];
|
||||
|
||||
if (sensitive === min.instance.adminPass) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].welcome);
|
||||
|
||||
return await step.endDialog(true);
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].wrong_password);
|
||||
return await step.replaceDialog('/admin-auth');
|
||||
}
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/admin', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].authenticate;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, prompt);
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const sensitive = step.context.activity['originalText'];
|
||||
|
||||
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);
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].wrong_password);
|
||||
|
||||
return await step.endDialog();
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
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];
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].working(cmdName));
|
||||
let unknownCommand = false;
|
||||
|
||||
try {
|
||||
if (text === 'quit') {
|
||||
return await step.replaceDialog('/');
|
||||
} else if (cmdName === 'setupSecurity') {
|
||||
return await step.beginDialog('/setupSecurity');
|
||||
} else {
|
||||
unknownCommand = true;
|
||||
}
|
||||
|
||||
if (unknownCommand) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].unknown_command);
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].finished_working);
|
||||
}
|
||||
} catch (error) {
|
||||
await min.conversationalService.sendText(min, step, error.message ? error.message : error);
|
||||
}
|
||||
await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/install', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
step.activeDialog.state.options.args = (step.options as any).args;
|
||||
if (step.activeDialog.state.options.confirm) {
|
||||
return await step.next('sim');
|
||||
} else {
|
||||
const locale = step.context.activity.locale;
|
||||
return await min.conversationalService.prompt(min, step, Messages[locale].publish_type_yes);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
// If the user says yes, starts publishing.
|
||||
|
||||
if (AdminDialog.isIntentYes(locale, step.result)) {
|
||||
const list = min.core.getParam(min.instance, '.gbapp List', null);
|
||||
const items = list ? list.split(';') : [];
|
||||
|
||||
step.activeDialog.state.options.args;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
for (let j = 0; j < min.appPackages.length; j++) {
|
||||
if (items[i] === min.appPackages[j]['name']) {
|
||||
const element = min.appPackages[i];
|
||||
await element.onExchangeData(min, 'install', null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].publish_canceled);
|
||||
}
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/logs', [
|
||||
async step => {
|
||||
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 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 => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
|
||||
async step => {
|
||||
step.activeDialog.state.options.confirm = true; // Feature removed.
|
||||
if (step.activeDialog.state.options.confirm || process.env.ADMIN_OPEN_PUBLISH === 'true') {
|
||||
return await step.next('sim');
|
||||
} else {
|
||||
const locale = step.context.activity.locale;
|
||||
return await min.conversationalService.prompt(min, step, Messages[locale].publish_type_yes);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
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;
|
||||
|
||||
let canPublish: Boolean;
|
||||
if (step.activeDialog.state.options.firstTime) {
|
||||
canPublish = true;
|
||||
} else {
|
||||
canPublish = AdminDialog.canPublish(min, from) || process.env.ADMIN_OPEN_PUBLISH === 'true';
|
||||
}
|
||||
|
||||
if (!canPublish) {
|
||||
await step.beginDialog('/admin-auth');
|
||||
} else {
|
||||
await step.next(true);
|
||||
}
|
||||
} else {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].publish_canceled);
|
||||
}
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
if (!step.result) {
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].publish_must_be_admin);
|
||||
|
||||
return step.endDialog();
|
||||
}
|
||||
|
||||
const botId = min.instance.botId;
|
||||
|
||||
await min.conversationalService.sendText(min, step, Messages[locale].working('Publishing'));
|
||||
|
||||
step.activeDialog.state.options.args = (step.options as any).args;
|
||||
const filename = step.activeDialog.state.options.args
|
||||
? step.activeDialog.state.options.args.split(' ')[0]
|
||||
: null;
|
||||
|
||||
const packages = [];
|
||||
let skipError = false;
|
||||
if (filename === null || filename === '') {
|
||||
await min.conversationalService.sendText(min, step, `Starting publishing for ${botId} packages...`);
|
||||
packages.push(`${botId}.gbkb`);
|
||||
packages.push(`${botId}.gbtheme`);
|
||||
packages.push(`${botId}.gbdialog`);
|
||||
packages.push(`${botId}.gbot`);
|
||||
skipError = true;
|
||||
} else {
|
||||
packages.push(filename);
|
||||
}
|
||||
|
||||
|
||||
await CollectionUtil.asyncForEach(packages, async packageName => {
|
||||
let cmd1;
|
||||
|
||||
if (
|
||||
packageName.toLowerCase() === 'gbdialog' ||
|
||||
packageName.toLowerCase() === 'gbkb' ||
|
||||
packageName.toLowerCase() === 'gbot' ||
|
||||
packageName.toLowerCase() === 'gbtheme'
|
||||
) {
|
||||
packageName = `${min.botId}.${packageName}`;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
let sec = new SecService();
|
||||
const member = step.context.activity.from;
|
||||
const user = await sec.ensureUser(
|
||||
min.instance.instanceId,
|
||||
member.id,
|
||||
member.name,
|
||||
'',
|
||||
'web',
|
||||
member.name,
|
||||
null
|
||||
);
|
||||
|
||||
await GBAdminService.deployPackageCommand(min, user, cmd1, deployer);
|
||||
|
||||
});
|
||||
await min.conversationalService.sendText(min, step, `Training is finished.`);
|
||||
|
||||
if (!step.activeDialog.state.options.confirm) {
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
} else {
|
||||
return await step.endDialog();
|
||||
}
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (canPublish) {
|
||||
list = list.concat(canPublish.split(';'));
|
||||
}
|
||||
|
||||
let result = list.includes(phone);
|
||||
|
||||
if (!result && min.instance.params) {
|
||||
const params = JSON.parse(min.instance.params);
|
||||
if (params) {
|
||||
return list.includes(params['Can Publish']);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static setupSecurityDialogs(min: GBMinInstance) {
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog('/setupSecurity', [
|
||||
async step => {
|
||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
||||
return await step.beginDialog('/auth');
|
||||
} else {
|
||||
return await step.next(step.options);
|
||||
}
|
||||
},
|
||||
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].enter_authenticator_tenant;
|
||||
|
||||
return await min.conversationalService.prompt(min, step, prompt);
|
||||
},
|
||||
async step => {
|
||||
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 => {
|
||||
step.activeDialog.state.authenticatorAuthorityHostUrl = step.result;
|
||||
|
||||
min.instance.authenticatorTenant = step.activeDialog.state.authenticatorTenant;
|
||||
min.instance.authenticatorAuthorityHostUrl = step.activeDialog.state.authenticatorAuthorityHostUrl;
|
||||
|
||||
await min.adminService.updateSecurityInfo(
|
||||
min.instance.instanceId,
|
||||
step.activeDialog.state.authenticatorTenant,
|
||||
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, 'AntiCSRFAttackState', state);
|
||||
|
||||
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));
|
||||
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
75
packages/admin.gbapp/index.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 { 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';
|
||||
|
||||
|
||||
/**
|
||||
* The package for admin.gbapp.
|
||||
*/
|
||||
export class GBAdminPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
|
||||
public async getDialogs (min: GBMinInstance) {
|
||||
GBLogEx.verbose(min,`getDialogs called.`);
|
||||
}
|
||||
public async unloadPackage (core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async unloadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLogEx.verbose(min,`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLogEx.verbose(min, `onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
|
||||
GBLogEx.verbose(min,`onExchangeData called.`);
|
||||
}
|
||||
|
||||
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
core.sequelize.addModels([GuaribasAdmin]);
|
||||
}
|
||||
|
||||
public async loadBot (min: GBMinInstance): Promise<void> {
|
||||
AdminDialog.setup(min);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
| 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. |
|
||||
| |
|
||||
|
|
@ -30,31 +30,33 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
const UrlJoin = require("url-join");
|
||||
'use strict';
|
||||
|
||||
import { Column, CreatedAt, DataType, Model, Table, UpdatedAt } from 'sequelize-typescript';
|
||||
|
||||
/**
|
||||
* General settings store.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasAdmin extends Model<GuaribasAdmin> {
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib";
|
||||
import { Session } from 'botbuilder';
|
||||
import { Sequelize } from "sequelize-typescript";
|
||||
@Column(DataType.STRING(255))
|
||||
declare key: string;
|
||||
|
||||
export class GBAnalyticsPackage implements IGBPackage {
|
||||
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
|
||||
}
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
loadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
onNewSession(min: GBMinInstance, session: Session): void {
|
||||
|
||||
}
|
||||
@Column(DataType.STRING(4000))
|
||||
declare value: string;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
286
packages/admin.gbapp/services/GBAdminService.ts
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
|
||||
|
||||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 { 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';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||
|
||||
/**
|
||||
* Services for server administration.
|
||||
*/
|
||||
export class GBAdminService implements IGBAdminService {
|
||||
public static GB_PROMPT: string = 'GeneralBots: ';
|
||||
public static masterBotInstanceId = 0;
|
||||
|
||||
public static StrongRegex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})');
|
||||
|
||||
public core: IGBCoreService;
|
||||
|
||||
constructor(core: IGBCoreService) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public static generateUuid(): string {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
public static getNodeVersion() {
|
||||
const packageJson = urlJoin(process.cwd(), 'package.json');
|
||||
const pkg = JSON.parse(Fs.readFileSync(packageJson, 'utf8'));
|
||||
return pkg.engines.node.replace('=', '');
|
||||
}
|
||||
|
||||
public static async getADALTokenFromUsername(username: string, password: string) {
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
|
||||
|
||||
return (credentials as any).tokenCache._entries[0].accessToken;
|
||||
}
|
||||
|
||||
public static async getADALCredentialsFromUsername(username: string, password: string) {
|
||||
|
||||
return await msRestAzure.loginWithUsernamePassword(username, password);
|
||||
}
|
||||
|
||||
public static getMobileCode() {
|
||||
|
||||
return this.getNumberIdentifier(6);
|
||||
}
|
||||
|
||||
public static getRndPassword(): string {
|
||||
let password = caseSensitive_Numbs_SpecialCharacters_PW(15);
|
||||
password = password.replace(/[\@\[\=\:\;\?\"\'\#]/gi, '*');
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
public static getRndReadableIdentifier(): string {
|
||||
|
||||
return lowercase_PW(14);
|
||||
}
|
||||
|
||||
public static getNumberIdentifier(digits: number = 14): string {
|
||||
|
||||
if (digits <= 0) {
|
||||
throw new Error('Number of digits should be greater than 0.');
|
||||
}
|
||||
|
||||
const min = 10 ** (digits - 1);
|
||||
const max = 10 ** digits - 1;
|
||||
const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
return randomNumber.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://stackoverflow.com/a/52171480
|
||||
*/
|
||||
public static getHash(str: string, seed = 0) {
|
||||
let h1 = 0xdeadbeef ^ seed,
|
||||
h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||
}
|
||||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||
}
|
||||
|
||||
public static async undeployPackageCommand(text: string, min: GBMinInstance) {
|
||||
|
||||
const packageName = text.split(' ')[1];
|
||||
const importer = new GBImporter(min.core);
|
||||
const deployer = new GBDeployer(min.core, importer);
|
||||
const path = DialogKeywords.getGBAIPath(min.botId, null, packageName);
|
||||
const localFolder = Path.join('work', path);
|
||||
await deployer.undeployPackageFromLocalPath(min.instance, localFolder);
|
||||
}
|
||||
|
||||
public static isSharePointPath(path: string) {
|
||||
return path.indexOf('sharepoint.com') !== -1;
|
||||
}
|
||||
public static async deployPackageCommand(min: GBMinInstance, user: GuaribasUser, text: string, deployer: IGBDeployer) {
|
||||
const packageName = text.split(' ')[1];
|
||||
|
||||
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['deployPackage2'](min, user, urlJoin(additionalPath, packageName));
|
||||
} else {
|
||||
const folderName = text.split(' ')[2];
|
||||
const packageType = Path.extname(folderName).substr(1);
|
||||
const gbaiPath = DialogKeywords.getGBAIPath(min.instance.botId, packageType, null);
|
||||
const localFolder = Path.join('work', gbaiPath);
|
||||
|
||||
// .gbot packages are handled using storage API, so no download
|
||||
// of local resources is required.
|
||||
const gbai = DialogKeywords.getGBAIPath(min.instance.botId);
|
||||
await deployer['downloadFolder'](min,
|
||||
Path.join('work', `${gbai}`),
|
||||
Path.basename(localFolder));
|
||||
await deployer['deployPackage2'](min, user, localFolder);
|
||||
}
|
||||
}
|
||||
public static async rebuildIndexPackageCommand(min: GBMinInstance, deployer: GBDeployer) {
|
||||
const service = await AzureDeployerService.createInstance(deployer);
|
||||
await deployer.rebuildIndex(
|
||||
min.instance,
|
||||
service.getKBSearchSchema(min.instance.searchIndex)
|
||||
);
|
||||
}
|
||||
|
||||
public static async syncBotServerCommand(min: GBMinInstance, deployer: GBDeployer) {
|
||||
const serverName = `${min.instance.botId}-server`;
|
||||
const service = await AzureDeployerService.createInstance(deployer);
|
||||
service.syncBotServerRepository(min.instance.botId, serverName);
|
||||
}
|
||||
|
||||
public async setValue(instanceId: number, key: string, value: string) {
|
||||
const options = <FindOptions>{ where: {} };
|
||||
options.where = { key: key, instanceId: instanceId };
|
||||
let admin = await GuaribasAdmin.findOne(options);
|
||||
if (admin === null) {
|
||||
admin = new GuaribasAdmin();
|
||||
admin.key = key;
|
||||
}
|
||||
admin.value = value;
|
||||
admin.instanceId = instanceId;
|
||||
await admin.save();
|
||||
}
|
||||
|
||||
public async updateSecurityInfo(
|
||||
instanceId: number,
|
||||
authenticatorTenant: string,
|
||||
authenticatorAuthorityHostUrl: string
|
||||
): Promise<IGBInstance> {
|
||||
const options = <FindOptions>{ where: {} };
|
||||
options.where = { instanceId: instanceId };
|
||||
const item = await GuaribasInstance.findOne(options);
|
||||
item.authenticatorTenant = authenticatorTenant;
|
||||
item.authenticatorAuthorityHostUrl = authenticatorAuthorityHostUrl;
|
||||
|
||||
return item.save();
|
||||
}
|
||||
|
||||
public async getValue(instanceId: number, key: string): Promise<string> {
|
||||
const options = <FindOptions>{ where: {} };
|
||||
options.where = { key: key, instanceId: instanceId };
|
||||
const obj = await GuaribasAdmin.findOne(options);
|
||||
return obj.value;
|
||||
}
|
||||
|
||||
public async acquireElevatedToken(instanceId: number, root: boolean = false): Promise<string> {
|
||||
|
||||
if (root) {
|
||||
const minBoot = GBServer.globals.minBoot;
|
||||
instanceId = minBoot.instance.instanceId;
|
||||
}
|
||||
GBLog.info(`Acquiring token for instanceId: ${instanceId} (root: ${root}).`);
|
||||
|
||||
let expiresOnV;
|
||||
try {
|
||||
expiresOnV = await this.getValue(instanceId, 'expiresOn');
|
||||
} catch (error) {
|
||||
throw new Error(`/setupSecurity is required before running /publish.`);
|
||||
}
|
||||
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
const instance = await this.core.loadInstanceById(instanceId);
|
||||
|
||||
const expiresOn = new Date(expiresOnV);
|
||||
if (expiresOn.getTime() > new Date().getTime()) {
|
||||
const accessToken = await this.getValue(instanceId, 'accessToken');
|
||||
resolve(accessToken);
|
||||
} else {
|
||||
const authorizationUrl = urlJoin(
|
||||
instance.authenticatorAuthorityHostUrl,
|
||||
instance.authenticatorTenant,
|
||||
'/oauth2/authorize'
|
||||
);
|
||||
|
||||
const refreshToken = await this.getValue(instanceId, 'refreshToken');
|
||||
const resource = 'https://graph.microsoft.com';
|
||||
const authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise<void> { }
|
||||
}
|
||||
52
packages/admin.gbapp/strings.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
export const Messages = {
|
||||
'en-US': {
|
||||
authenticate: 'Please, authenticate:',
|
||||
welcome: 'Welcome to Pragmatismo.io GeneralBots Administration.',
|
||||
which_task: 'Which task do you wanna run now?',
|
||||
working: command => `I'm working on ${command}...`,
|
||||
finished_working: 'Done.',
|
||||
unknown_command: text =>
|
||||
`Well, but ${text} is not a administrative General Bots command, I will try to search for it.`,
|
||||
hi: text => `Hello, ${text}.`,
|
||||
undeployPackage: text => `Undeploying package ${text}...`,
|
||||
deployPackage: text => `Deploying package ${text}...`,
|
||||
redeployPackage: text => `Redeploying package ${text}...`,
|
||||
packageUndeployed: text => `√ Package ${text} undeployed...`,
|
||||
consent: url => `Please, consent access to this app at: [Microsoft Online](${url}).`,
|
||||
wrong_password: 'Sorry, wrong password. Please, try again.',
|
||||
enter_authenticator_tenant: 'Enter the Authenticator Tenant (eg.: domain.onmicrosoft.com):',
|
||||
enter_authenticator_authority_host_url: 'Enter the Authority Host URL (eg.: https://login.microsoftonline.com): ',
|
||||
enter_authenticator_client_id: `Enter the Client Id GUID: Get from
|
||||
[this url](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview)`,
|
||||
enter_authenticator_client_secret: 'Enter the Client Secret:',
|
||||
publish_must_be_admin: 'Seu telefone precisa estar com privilégios administrativos para realizar publicação.',
|
||||
publish_success: 'Publicação realizada.',
|
||||
publish_type_yes: 'Por favor, digite *Sim* para continuar com a publicação.',
|
||||
publish_canceled: 'Publicação cancelada.'
|
||||
},
|
||||
'pt-BR': {
|
||||
authenticate: 'Please, authenticate:',
|
||||
welcome: 'Welcome to Pragmatismo.io GeneralBots Administration.',
|
||||
which_task: 'Which task do you wanna run now?',
|
||||
working: command => `I'm working on ${command}...`,
|
||||
finished_working: 'Done.',
|
||||
unknown_command: text =>
|
||||
`Well, but ${text} is not a administrative General Bots command, I will try to search for it.`,
|
||||
hi: text => `Hello, ${text}.`,
|
||||
undeployPackage: text => `Undeploying package ${text}...`,
|
||||
deployPackage: text => `Deploying package ${text}...`,
|
||||
redeployPackage: text => `Redeploying package ${text}...`,
|
||||
packageUndeployed: text => `Package ${text} undeployed...`,
|
||||
consent: url => `Please, consent access to this app at: [Microsoft Online](${url}).`,
|
||||
wrong_password: 'Sorry, wrong password. Please, try again.',
|
||||
enter_authenticator_tenant: 'Enter the Authenticator Tenant (eg.: domain.onmicrosoft.com):',
|
||||
enter_authenticator_authority_host_url: 'Enter the Authority Host URL (eg.: https://login.microsoftonline.com): ',
|
||||
enter_authenticator_client_id: `Enter the Client Id GUID: Get from
|
||||
[this url](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview)`,
|
||||
enter_authenticator_client_secret: 'Enter the Client Secret:',
|
||||
publish_must_be_admin: 'Seu telefone precisa estar com privilégios administrativos para realizar publicação.',
|
||||
publish_success: 'Publicação realizada.',
|
||||
publish_type_yes: 'Por favor, digite *Sim* para continuar com a publicação.',
|
||||
publish_canceled: 'Publicação cancelada.'
|
||||
}
|
||||
};
|
||||
70
packages/analytics.gblib/index.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { GuaribasConversation, GuaribasConversationMessage } from './models/index.js';
|
||||
|
||||
/**
|
||||
* .gblib Package handler.
|
||||
*/
|
||||
export class GBAnalyticsPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
public async getDialogs (min: GBMinInstance) {
|
||||
GBLog.verbose(`getDialogs called.`);
|
||||
}
|
||||
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
GBLog.verbose(`loadPackage called.`);
|
||||
core.sequelize.addModels([GuaribasConversation, GuaribasConversationMessage]);
|
||||
}
|
||||
public async unloadPackage (core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async loadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`loadBot called.`);
|
||||
}
|
||||
public async unloadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLog.verbose(`onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
|
||||
GBLog.verbose(`onExchangeData called.`);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
| 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. |
|
||||
| |
|
||||
|
|
@ -30,117 +30,125 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
Sequelize,
|
||||
DataTypes,
|
||||
DataTypeUUIDv4,
|
||||
DataTypeDate,
|
||||
DataTypeDecimal
|
||||
} from "sequelize";
|
||||
import {
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
HasMany,
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
BelongsToMany,
|
||||
Length,
|
||||
ForeignKey,
|
||||
Column,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
HasMany,
|
||||
IsUUID,
|
||||
Length,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
AutoIncrement
|
||||
} from "sequelize-typescript";
|
||||
import { GuaribasSubject } from "../../kb.gbapp/models";
|
||||
import { GuaribasUser } from "../../security.gblib/models";
|
||||
import { GuaribasChannel, GuaribasInstance } from "../../core.gbapp/models/GBModel";
|
||||
Sequelize,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasChannel, GuaribasInstance } from '../../core.gbapp/models/GBModel.js';
|
||||
import { GuaribasSubject } from '../../kb.gbapp/models/index.js';
|
||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||
|
||||
/**
|
||||
* A conversation that groups many messages.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasConversation extends Model<GuaribasConversation> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
conversationId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare conversationId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasSubject)
|
||||
@Column
|
||||
startSubjectId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare startSubjectId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasSubject)
|
||||
startSubject: GuaribasSubject;
|
||||
declare startSubject: GuaribasSubject;
|
||||
|
||||
@ForeignKey(() => GuaribasChannel)
|
||||
@Column
|
||||
channelId: string;
|
||||
@Column(DataType.INTEGER)
|
||||
declare channelId: string;
|
||||
|
||||
@Column rateDate: Date;
|
||||
@Column(DataType.DATE)
|
||||
declare rateDate: Date;
|
||||
|
||||
@Column({
|
||||
type: DataType.FLOAT
|
||||
})
|
||||
@Column
|
||||
rate: number;
|
||||
@Column(DataType.FLOAT)
|
||||
declare rate: number;
|
||||
|
||||
@Column(DataType.STRING(512))
|
||||
declare feedback: string;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
creationDate: Date;
|
||||
@Column(DataType.DATE)
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column text: string;
|
||||
|
||||
@HasMany(() => GuaribasConversationMessage)
|
||||
conversationMessage: GuaribasConversationMessage[];
|
||||
@Column(DataType.STRING(255))
|
||||
declare text: string;
|
||||
|
||||
@ForeignKey(() => GuaribasUser)
|
||||
@Column
|
||||
startedByUserId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare startedByUserId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasUser)
|
||||
startedBy: GuaribasUser;
|
||||
declare startedBy: GuaribasUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single message in a conversation.
|
||||
*/
|
||||
@Table
|
||||
export class GuaribasConversationMessage extends Model<GuaribasConversationMessage> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
conversationMessageId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare conversationMessageId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasSubject)
|
||||
@Column
|
||||
subjectId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare subjectId: number;
|
||||
|
||||
@Column({ type: DataType.TEXT })
|
||||
content: string;
|
||||
@Column(DataType.TEXT)
|
||||
declare content: string;
|
||||
|
||||
@Column
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
creationDate: Date;
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
updatedOn: Date;
|
||||
declare updatedAt: Date;
|
||||
|
||||
//tslint:disable-next-line:no-use-before-declare
|
||||
@ForeignKey(() => GuaribasConversation)
|
||||
@Column
|
||||
conversationId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare conversationId: number;
|
||||
|
||||
//tslint:disable-next-line:no-use-before-declare
|
||||
@BelongsTo(() => GuaribasConversation)
|
||||
conversation: GuaribasConversation;
|
||||
declare conversation: GuaribasConversation;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare instanceId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasUser)
|
||||
@Column
|
||||
userId: number;
|
||||
@Column(DataType.INTEGER)
|
||||
declare userId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasUser)
|
||||
user: GuaribasUser;
|
||||
declare user: GuaribasUser;
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
| 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. |
|
||||
| |
|
||||
|
|
@ -30,74 +30,70 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
const Path = require("path");
|
||||
const Fs = require("fs");
|
||||
const _ = require("lodash");
|
||||
const Parse = require("csv-parse");
|
||||
const Async = require("async");
|
||||
const UrlJoin = require("url-join");
|
||||
const Walk = require("fs-walk");
|
||||
const logger = require("../../../src/logger");
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
import { GBServiceCallback, GBService, IGBInstance } from "botlib";
|
||||
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from "../models";
|
||||
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';
|
||||
|
||||
export class SecService extends GBService {
|
||||
/**
|
||||
* Base services for Bot Analytics.
|
||||
*/
|
||||
export class AnalyticsService {
|
||||
public async createConversation (user: GuaribasUser): Promise<GuaribasConversation> {
|
||||
const conversation = new GuaribasConversation();
|
||||
conversation.startedBy = user;
|
||||
conversation.startedByUserId = user.userId;
|
||||
conversation.instanceId = user.instanceId;
|
||||
|
||||
importSecurityFile(localPath: string, instance: IGBInstance) {
|
||||
var security = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "security.json"), "utf8")
|
||||
);
|
||||
security.groups.forEach(group => {
|
||||
let groupDb = GuaribasGroup.build({
|
||||
instanceId: instance.instanceId,
|
||||
displayName: group.displayName
|
||||
});
|
||||
groupDb.save().then(groupDb => {
|
||||
group.users.forEach(user => {
|
||||
let userDb = GuaribasUser.build({
|
||||
instanceId: instance.instanceId,
|
||||
groupId: groupDb.groupId,
|
||||
userName: user.userName
|
||||
});
|
||||
userDb.save().then(userDb => {
|
||||
let userGroup = GuaribasUserGroup.build();
|
||||
userGroup.groupId = groupDb.groupId;
|
||||
userGroup.userId = userDb.userId;
|
||||
userGroup.save();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return await conversation.save();
|
||||
}
|
||||
|
||||
ensureUser(
|
||||
public async updateConversationSuggestion (
|
||||
instanceId: number,
|
||||
userSystemId: string,
|
||||
userName: string,
|
||||
address: string,
|
||||
channelName: string,
|
||||
displayName: string,
|
||||
cb: GBServiceCallback<GuaribasUser>
|
||||
) {
|
||||
GuaribasUser.findOne({
|
||||
attributes: ["instanceId", "internalAddress"],
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
userSystemId: userSystemId
|
||||
}
|
||||
}).then(user => {
|
||||
if (!user) {
|
||||
user = GuaribasUser.build();
|
||||
}
|
||||
user.userSystemId = userSystemId;
|
||||
user.userName = userName;
|
||||
user.displayName = displayName;
|
||||
user.internalAddress = address;
|
||||
user.email = userName;
|
||||
user.defaultChannel = channelName;
|
||||
user.save();
|
||||
cb(user, null);
|
||||
});
|
||||
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,
|
||||
locale,
|
||||
feedback
|
||||
);
|
||||
|
||||
const options = <FindOptions>{ where: {} };
|
||||
options.where = { conversationId: conversationId, instanceId: instanceId };
|
||||
const item = await GuaribasConversation.findOne(options);
|
||||
|
||||
item.feedback = feedback;
|
||||
item.rate = rate;
|
||||
item.rateDate = new Date();
|
||||
await item.save();
|
||||
|
||||
return rate;
|
||||
}
|
||||
}
|
||||
|
||||
public async createMessage (
|
||||
instanceId: number,
|
||||
conversationId: number,
|
||||
userId: number,
|
||||
content: string
|
||||
): Promise<GuaribasConversationMessage> {
|
||||
|
||||
const message = GuaribasConversationMessage.build();
|
||||
message.content = typeof content === 'object' ? JSON.stringify(content) : content;
|
||||
message.instanceId = instanceId;
|
||||
message.userId = userId;
|
||||
message.conversationId = conversationId;
|
||||
|
||||
return await message.save();
|
||||
}
|
||||
}
|
||||
214
packages/azuredeployer.gbapp/dialogs/StartDialog.ts
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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, IGBInstallationDeployer, IGBInstance } from 'botlib';
|
||||
import * as Fs from 'fs';
|
||||
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';
|
||||
|
||||
/**
|
||||
* Handles command-line dialog for getting info for Boot Bot.
|
||||
*/
|
||||
export class StartDialog {
|
||||
public static async createBaseInstance (deployer, freeTier) {
|
||||
// No .env so asks for cloud credentials to start a new farm.
|
||||
|
||||
if (!Fs.existsSync(`.env`)) {
|
||||
process.stdout.write(
|
||||
'A empty enviroment is detected. To start automatic deploy, please enter some information:\n'
|
||||
);
|
||||
}
|
||||
|
||||
let botId: string;
|
||||
while (botId === undefined) {
|
||||
botId = this.retrieveBotId();
|
||||
}
|
||||
|
||||
let username: string;
|
||||
while (username === undefined) {
|
||||
username = this.retrieveUsername();
|
||||
}
|
||||
|
||||
let password: string;
|
||||
while (password === undefined) {
|
||||
password = this.retrievePassword();
|
||||
}
|
||||
|
||||
// Connects to the cloud and retrieves subscriptions.
|
||||
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
let appId: string;
|
||||
while (appId === undefined) {
|
||||
appId = this.retrieveAppId();
|
||||
}
|
||||
|
||||
let appPassword: string;
|
||||
while (appPassword === undefined) {
|
||||
appPassword = this.retrieveAppPassword();
|
||||
}
|
||||
|
||||
// Prepares the first instance on bot farm.
|
||||
const instance = <IGBInstance>{};
|
||||
|
||||
instance.botId = botId;
|
||||
instance.state = 'active';
|
||||
instance.cloudUsername = username;
|
||||
instance.cloudPassword = password;
|
||||
instance.cloudSubscriptionId = subscriptionId;
|
||||
instance.cloudLocation = location;
|
||||
instance.marketplaceId = appId;
|
||||
instance.marketplacePassword = appPassword;
|
||||
instance.adminPass = GBAdminService.getRndPassword();
|
||||
|
||||
return { instance, credentials, subscriptionId , installationDeployer};
|
||||
}
|
||||
|
||||
private static retrieveUsername () {
|
||||
let value = GBConfigService.get('CLOUD_USERNAME');
|
||||
if (value === undefined) {
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_USERNAME:`);
|
||||
value = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static retrievePassword () {
|
||||
let password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
if (password === undefined) {
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_PASSWORD:`);
|
||||
password = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
private static retrieveBotId () {
|
||||
let botId = GBConfigService.get('BOT_ID');
|
||||
if (botId === undefined) {
|
||||
process.stdout.write(
|
||||
`${GBAdminService.GB_PROMPT}Choose a unique bot Id containing lowercase letters, digits or
|
||||
dashes (cannot use dash as the first two or last one characters),
|
||||
cannot start or end with or contain consecutive dashes and having 4 to 42 characters long.\n`
|
||||
);
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}BOT_ID:`);
|
||||
botId = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return botId;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Update Manifest in Azure: "signInAudience": "AzureADandPersonalMicrosoftAccount" and "accessTokenAcceptedVersion": 2.
|
||||
*/
|
||||
private static retrieveAppId () {
|
||||
let appId = GBConfigService.get('MARKETPLACE_ID');
|
||||
if (appId === undefined) {
|
||||
process.stdout.write(
|
||||
`Sorry, this part cannot be automated yet due to Microsoft schedule,
|
||||
please go to https://apps.dev.microsoft.com/portal/register-app to
|
||||
generate manually an App ID and App Secret.\n`
|
||||
);
|
||||
|
||||
process.stdout.write('Generated Application Id (MARKETPLACE_ID):');
|
||||
appId = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return appId;
|
||||
}
|
||||
|
||||
private static retrieveAppPassword () {
|
||||
let appPassword = GBConfigService.get('MARKETPLACE_SECRET');
|
||||
if (appPassword === undefined) {
|
||||
process.stdout.write('Generated Password (MARKETPLACE_SECRET):');
|
||||
appPassword = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return appPassword;
|
||||
}
|
||||
|
||||
private static retrieveSubscriptionId (list) {
|
||||
let subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
if (subscriptionId){
|
||||
|
||||
return subscriptionId;
|
||||
}
|
||||
const map = {};
|
||||
let index = 1;
|
||||
list.forEach(element => {
|
||||
GBLog.info(`${index}: ${element.displayName} (${element.subscriptionId})`);
|
||||
map[index++] = element;
|
||||
});
|
||||
let subscriptionIndex;
|
||||
if (!subscriptionIndex && subscriptionId === undefined) {
|
||||
process.stdout.write('CLOUD_SUBSCRIPTIONID (type a number):');
|
||||
subscriptionIndex = scanf('%d');
|
||||
subscriptionId = map[subscriptionIndex].subscriptionId;
|
||||
}
|
||||
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
private static retrieveLocation () {
|
||||
let location = GBConfigService.get('CLOUD_LOCATION');
|
||||
if (location === undefined) {
|
||||
process.stdout.write('CLOUD_LOCATION (eg. westus):');
|
||||
location = scanf('%s');
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
}
|
||||
68
packages/azuredeployer.gbapp/index.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
|
||||
/**
|
||||
* Package for Azure Deployer.
|
||||
*/
|
||||
export class GBAzureDeployerPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
public async getDialogs (min: GBMinInstance) {
|
||||
GBLog.verbose(`getDialogs called.`);
|
||||
}
|
||||
public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
GBLog.verbose(`loadPackage called.`);
|
||||
}
|
||||
public async unloadPackage (core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async loadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`loadBot called.`);
|
||||
}
|
||||
public async unloadBot (min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLog.verbose(`onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData (min: GBMinInstance, kind: string, data: any) {
|
||||
GBLog.verbose(`onExchangeData called.`);
|
||||
}
|
||||
}
|
||||
990
packages/azuredeployer.gbapp/services/AzureDeployerService.ts
Normal file
|
|
@ -0,0 +1,990 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 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 { 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';
|
||||
|
||||
const WebSiteResponseTimeout = 900;
|
||||
const iconUrl = 'https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png';
|
||||
/**
|
||||
* Deployer for Microsoft cloud.
|
||||
*/
|
||||
export class AzureDeployerService implements IGBInstallationDeployer {
|
||||
public apiVersion = '2017-12-01';
|
||||
public defaultEndPoint = 'http://localhost:4242';
|
||||
public instance: IGBInstance;
|
||||
public cloud: ResourceManagementClient;
|
||||
public webSiteClient: WebSiteManagementClient;
|
||||
public storageClient: SqlManagementClient;
|
||||
public cognitiveClient: CognitiveServicesManagementClient;
|
||||
public searchClient: SearchManagementClient;
|
||||
public provider = 'Microsoft.BotService';
|
||||
public subscriptionClient: SubscriptionClient;
|
||||
public accessToken: string;
|
||||
public location: string;
|
||||
public subscriptionId: string;
|
||||
public farmName: any;
|
||||
public deployer: IGBDeployer;
|
||||
public core: IGBCoreService;
|
||||
private freeTier: boolean;
|
||||
|
||||
public async runSearch(instance: IGBInstance) {
|
||||
await this.deployer.rebuildIndex(instance, this.getKBSearchSchema(instance.searchIndex));
|
||||
}
|
||||
|
||||
|
||||
public static async createInstance(deployer: GBDeployer, freeTier: boolean = true): Promise<AzureDeployerService> {
|
||||
const username = GBConfigService.get('CLOUD_USERNAME');
|
||||
const password = GBConfigService.get('CLOUD_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();
|
||||
|
||||
service.core = deployer.core;
|
||||
service.deployer = deployer;
|
||||
service.freeTier = freeTier;
|
||||
|
||||
const token = credentials['tokenCache']._entries[0];
|
||||
|
||||
await service.initServices(token.accessToken, token.expiresOn, subscriptionId);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
public static async createInstanceWithCredentials(deployer: GBDeployer, freeTier: boolean = true,
|
||||
subscriptionId: string, username: string, password: string): Promise<AzureDeployerService> {
|
||||
const service = new 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;
|
||||
req.url = url;
|
||||
req.headers.set('Content-Type', 'application/json');
|
||||
req.headers.set('accept-language', '*');
|
||||
req.headers.set('Authorization', `Bearer ${accessToken}`);
|
||||
req.body = body;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
public async getSubscriptions(credentials) {
|
||||
const subscriptionClient = new SubscriptionClient(credentials);
|
||||
|
||||
return subscriptionClient.subscriptions.list();
|
||||
}
|
||||
|
||||
public getKBSearchSchema(indexName: any) {
|
||||
return {
|
||||
name: indexName,
|
||||
fields: [
|
||||
{
|
||||
name: 'questionId',
|
||||
type: 'Edm.String',
|
||||
searchable: false,
|
||||
filterable: false,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: true
|
||||
},
|
||||
{
|
||||
name: 'subject1',
|
||||
type: 'Edm.String',
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'subject2',
|
||||
type: 'Edm.String',
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'subject3',
|
||||
type: 'Edm.String',
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'subject4',
|
||||
type: 'Edm.String',
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'Edm.String',
|
||||
searchable: true,
|
||||
filterable: false,
|
||||
retrievable: false,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'answerId',
|
||||
type: 'Edm.Int32',
|
||||
searchable: false,
|
||||
filterable: false,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'instanceId',
|
||||
type: 'Edm.Int32',
|
||||
searchable: false,
|
||||
filterable: true,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'skipIndex',
|
||||
type: 'Edm.Boolean',
|
||||
searchable: false,
|
||||
filterable: true,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
},
|
||||
{
|
||||
name: 'packageId',
|
||||
type: 'Edm.Int32',
|
||||
searchable: false,
|
||||
filterable: true,
|
||||
retrievable: true,
|
||||
sortable: false,
|
||||
facetable: false,
|
||||
key: false
|
||||
}
|
||||
],
|
||||
scoringProfiles: [],
|
||||
defaultScoringProfile: undefined,
|
||||
corsOptions: undefined
|
||||
};
|
||||
}
|
||||
|
||||
public async botExists(botId: string) {
|
||||
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 url = urlJoin(baseUrl, query);
|
||||
const body = {
|
||||
name: botId,
|
||||
type: 'botServices'
|
||||
};
|
||||
|
||||
const req = AzureDeployerService.createRequestObject(url, accessToken, 'POST', JSON.stringify(body));
|
||||
const res = await httpClient.sendRequest(req);
|
||||
|
||||
return !res.parsedBody.valid;
|
||||
}
|
||||
|
||||
public async updateBotProxy(botId: string, group: string, endpoint: string) {
|
||||
const baseUrl = `https://management.azure.com/`;
|
||||
const username = GBConfigService.get('CLOUD_USERNAME');
|
||||
const password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
|
||||
const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
|
||||
const httpClient = new ServiceClient();
|
||||
|
||||
const parameters = {
|
||||
properties: {
|
||||
endpoint: endpoint
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
// CHECK
|
||||
if (!JSON.parse(res.bodyAsText).id) {
|
||||
throw res.bodyAsText;
|
||||
}
|
||||
GBLog.info(`Bot proxy updated at: ${endpoint}.`);
|
||||
}
|
||||
|
||||
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');
|
||||
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
|
||||
const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
|
||||
const httpClient = new ServiceClient();
|
||||
|
||||
const parameters = {
|
||||
properties: {
|
||||
description: `${description}`,
|
||||
displayName: name,
|
||||
endpoint: endpoint,
|
||||
iconUrl: iconUrl
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
// CHECK
|
||||
if (!JSON.parse(res.bodyAsText).id) {
|
||||
throw res.bodyAsText;
|
||||
}
|
||||
GBLog.info(`Bot updated at: ${endpoint}.`);
|
||||
}
|
||||
|
||||
public async deleteBot(botId: string, group: string) {
|
||||
const baseUrl = `https://management.azure.com/`;
|
||||
const username = GBConfigService.get('CLOUD_USERNAME');
|
||||
const password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
|
||||
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 url = urlJoin(baseUrl, query);
|
||||
const req = AzureDeployerService.createRequestObject(url, accessToken, 'DELETE', undefined);
|
||||
const res = await httpClient.sendRequest(req);
|
||||
|
||||
if (res.bodyAsText !== '') {
|
||||
throw res.bodyAsText;
|
||||
}
|
||||
GBLog.info(`Bot ${botId} was deleted from the provider.`);
|
||||
}
|
||||
|
||||
public async openStorageFirewall(groupName: string, serverName: string) {
|
||||
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
|
||||
const ip = await publicIp.publicIpv4();
|
||||
let params = {
|
||||
startIpAddress: ip,
|
||||
endIpAddress: ip
|
||||
};
|
||||
await this.storageClient.firewallRules.createOrUpdate(groupName, serverName, 'gb', params);
|
||||
}
|
||||
|
||||
public async deployFarm(
|
||||
proxyAddress: string,
|
||||
instance: IGBInstance,
|
||||
credentials: any,
|
||||
subscriptionId: string
|
||||
): Promise<IGBInstance> {
|
||||
const culture = 'en-us';
|
||||
|
||||
const token = credentials['tokenCache']._entries[0];
|
||||
|
||||
await this.initServices(token.accessToken, token.expiresOn, subscriptionId);
|
||||
|
||||
const spinner = new Spinner('%s');
|
||||
spinner.start();
|
||||
spinner.setSpinnerString('|/-\\');
|
||||
let keys: any;
|
||||
const name = instance.botId;
|
||||
|
||||
GBLog.info(`Enabling resource providers...`);
|
||||
await this.enableResourceProviders('Microsoft.BotService');
|
||||
await this.enableResourceProviders('Microsoft.Web');
|
||||
await this.enableResourceProviders('Microsoft.Sql');
|
||||
|
||||
GBLog.info(`Deploying Deploy Group (It may take a few minutes)...`);
|
||||
await this.createDeployGroup(name, instance.cloudLocation);
|
||||
|
||||
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);
|
||||
|
||||
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.createStorage(name, storageServer, storageName, instance.cloudLocation);
|
||||
instance.storageUsername = administratorLogin;
|
||||
instance.storagePassword = administratorPassword;
|
||||
instance.storageName = storageName;
|
||||
instance.storageDialect = 'mssql';
|
||||
instance.storageServer = `${storageServer}.database.windows.net`;
|
||||
|
||||
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;
|
||||
|
||||
// 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.properties.endpoint;
|
||||
// instance.speechKey = keys.key1;
|
||||
|
||||
// GBLog.info(`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 SpellChecker...`);
|
||||
const spellChecker = await this.createSpellChecker(name, `${name}-spellchecker`);
|
||||
instance.spellcheckerEndpoint = spellChecker.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);
|
||||
// instance.nlpEndpoint = nlp.properties.endpoint;
|
||||
|
||||
const sleep = ms => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
};
|
||||
|
||||
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.cloudSubscriptionId
|
||||
);
|
||||
|
||||
GBLog.info(`Waiting one minute to finish NLP service and keys creation...`);
|
||||
await 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;
|
||||
|
||||
// instance.nlpAuthoringKey = authoringKeys.key1;
|
||||
// const nlpAppId = await this.createNLPService(name, name, instance.cloudLocation, culture, instance.nlpAuthoringKey);
|
||||
// instance.nlpAppId = nlpAppId;
|
||||
|
||||
GBLog.info('Updating server environment variables...');
|
||||
await this.updateWebisteConfig(name, serverName, serverFarm.id, instance);
|
||||
|
||||
spinner.stop();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public async deployToCloud(
|
||||
title: string,
|
||||
username: string,
|
||||
password: string,
|
||||
cloudLocation: string,
|
||||
authoringKey: string,
|
||||
appId: string,
|
||||
appPassword: string,
|
||||
subscriptionId: string
|
||||
) {
|
||||
const instance = <IGBInstance>{};
|
||||
instance.state = 'active';
|
||||
instance.botId = title;
|
||||
instance.cloudUsername = username;
|
||||
instance.cloudPassword = password;
|
||||
instance.cloudSubscriptionId = subscriptionId;
|
||||
instance.cloudLocation = cloudLocation;
|
||||
instance.nlpAuthoringKey = authoringKey;
|
||||
instance.marketplaceId = appId;
|
||||
instance.marketplacePassword = appPassword;
|
||||
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`;
|
||||
this.deployFarm(url, instance, credentials, subscriptionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/Azure/azure-rest-api-specs/blob/master/specification/botservice/resource-manager/Microsoft.BotService/preview/2017-12-01/botservice.json
|
||||
*/
|
||||
public async internalDeployBot(
|
||||
instance,
|
||||
accessToken: string,
|
||||
botId: string,
|
||||
name: string,
|
||||
group,
|
||||
description: string,
|
||||
endpoint,
|
||||
location,
|
||||
nlpAppId,
|
||||
nlpKey: string,
|
||||
appId: string,
|
||||
appPassword: string,
|
||||
subscriptionId
|
||||
): Promise<IGBInstance> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const baseUrl = `https://management.azure.com/`;
|
||||
await this.registerProviders(subscriptionId, baseUrl, accessToken);
|
||||
|
||||
instance.marketplaceId = appId;
|
||||
instance.marketplacePassword = appPassword;
|
||||
instance.engineName = GBCorePackage['CurrentEngineName'];
|
||||
|
||||
const parameters = {
|
||||
location: location,
|
||||
sku: {
|
||||
name: this.freeTier ? 'F0' : 'S1'
|
||||
},
|
||||
name: botId,
|
||||
kind: 'bot',
|
||||
properties: {
|
||||
description: description,
|
||||
displayName: name,
|
||||
endpoint: endpoint,
|
||||
iconUrl: iconUrl,
|
||||
luisAppIds: [nlpAppId],
|
||||
luisKey: nlpKey,
|
||||
msaAppId: appId,
|
||||
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 url = urlJoin(baseUrl, query);
|
||||
let req = AzureDeployerService.createRequestObject(url, accessToken, 'PUT', JSON.stringify(parameters));
|
||||
const res = await httpClient.sendRequest(req);
|
||||
if (!JSON.parse(res.bodyAsText).id) {
|
||||
reject(res.bodyAsText);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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}`;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
private async createStorageServer(
|
||||
group: string,
|
||||
name: string,
|
||||
administratorLogin: string,
|
||||
administratorPassword: string,
|
||||
serverName: string,
|
||||
location: string
|
||||
) {
|
||||
const params = {
|
||||
location: location,
|
||||
administratorLogin: administratorLogin,
|
||||
administratorLoginPassword: administratorPassword,
|
||||
fullyQualifiedDomainName: serverName,
|
||||
requestOptions: { timeout: 60 * 1000 * 5 }
|
||||
};
|
||||
|
||||
let database: Server;
|
||||
try {
|
||||
database = await this.storageClient.servers.beginCreateOrUpdateAndWait(group, name, params);
|
||||
} catch (error) {
|
||||
// Try again (MSFT issues).
|
||||
GBLog.info('Storage (server) creation failed. Retrying...');
|
||||
database = await this.storageClient.servers.beginCreateOrUpdateAndWait(group, name, params);
|
||||
}
|
||||
|
||||
// AllowAllWindowsAzureIps must be created that way, so the Azure Search can
|
||||
// access SQL Database to index its contents.
|
||||
|
||||
const paramsFirewall = {
|
||||
startIpAddress: '0.0.0.0',
|
||||
endIpAddress: '0.0.0.0'
|
||||
};
|
||||
await this.storageClient.firewallRules.createOrUpdate(group, name, 'AllowAllWindowsAzureIps', paramsFirewall);
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
public async createApplication(token: string, name: string) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
let client = MicrosoftGraph.Client.init({
|
||||
authProvider: done => {
|
||||
done(null, token);
|
||||
}
|
||||
});
|
||||
const app = {
|
||||
displayName: name
|
||||
};
|
||||
|
||||
client.api(`/applications`).post(app, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async createApplicationSecret(token: string, appId: string) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
let client = MicrosoftGraph.Client.init({
|
||||
authProvider: done => {
|
||||
done(null, token);
|
||||
}
|
||||
});
|
||||
const body = {
|
||||
passwordCredential: {
|
||||
displayName: 'General Bots Generated'
|
||||
}
|
||||
};
|
||||
|
||||
client.api(`/applications/${appId}/addPassword`).post(body, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res.secretText);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async registerProviders(subscriptionId: string, baseUrl: string, accessToken: string) {
|
||||
const query = `subscriptions/${subscriptionId}/providers/${this.provider}/register?api-version=2018-02-01`;
|
||||
const requestUrl = urlJoin(baseUrl, query);
|
||||
|
||||
const req = new WebResource();
|
||||
req.method = 'POST';
|
||||
req.url = requestUrl;
|
||||
req.headers = <any>{};
|
||||
req.headers['Content-Type'] = 'application/json; charset=utf-8';
|
||||
req.headers['accept-language'] = '*';
|
||||
(req.headers as any).Authorization = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
private async createNLPService(
|
||||
name: string,
|
||||
description: string,
|
||||
location: string,
|
||||
culture: string,
|
||||
authoringKey: string
|
||||
) {
|
||||
const parameters = {
|
||||
name: name,
|
||||
description: description,
|
||||
culture: culture
|
||||
};
|
||||
|
||||
const body = JSON.stringify(parameters);
|
||||
const apps = await this.makeNlpRequest(location, authoringKey, undefined, 'GET', 'apps');
|
||||
|
||||
let app = null;
|
||||
if (apps.bodyAsText && apps.bodyAsText !== '[]') {
|
||||
const result = JSON.parse(apps.bodyAsText);
|
||||
if (result.error) {
|
||||
if (result.error.code !== '401') {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
} else {
|
||||
app = result.filter(x => x.name === name)[0];
|
||||
}
|
||||
}
|
||||
let id: string;
|
||||
if (!app) {
|
||||
const res = await this.makeNlpRequest(location, authoringKey, body, 'POST', 'apps');
|
||||
id = res.bodyAsText;
|
||||
} else {
|
||||
id = app.id;
|
||||
}
|
||||
|
||||
return id.replace(/\'/gi, '');
|
||||
}
|
||||
|
||||
private async makeNlpRequest(
|
||||
location: string,
|
||||
authoringKey: string,
|
||||
body: string,
|
||||
method: HttpMethods,
|
||||
resource: string
|
||||
) {
|
||||
const req = new WebResource();
|
||||
req.method = method;
|
||||
req.url = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/${resource}`;
|
||||
req.headers.set('Content-Type', 'application/json');
|
||||
req.headers.set('accept-language', '*');
|
||||
req.headers.set('Ocp-Apim-Subscription-Key', authoringKey);
|
||||
req.body = body;
|
||||
const httpClient = new ServiceClient();
|
||||
|
||||
return await httpClient.sendRequest(req);
|
||||
}
|
||||
|
||||
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}`;
|
||||
req.headers.set('Content-Type', 'application/json');
|
||||
req.headers.set('accept-language', '*');
|
||||
req.headers.set('Ocp-Apim-Subscription-Key', nlpKey);
|
||||
req.body = JSON.stringify(data);
|
||||
const httpClient = new ServiceClient();
|
||||
|
||||
return await httpClient.sendRequest(req);
|
||||
}
|
||||
|
||||
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`;
|
||||
req.headers.set('Content-Type', 'application/json');
|
||||
req.headers.set('accept-language', '*');
|
||||
req.headers.set('Ocp-Apim-Subscription-Key', nlpAuthoringKey);
|
||||
const httpClient = new ServiceClient();
|
||||
|
||||
return await httpClient.sendRequest(req);
|
||||
}
|
||||
|
||||
public async publishNLP(location: string, nlpAppId: string, nlpAuthoringKey: string) {
|
||||
const body = {
|
||||
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`;
|
||||
req.headers.set('Content-Type', 'application/json');
|
||||
req.headers.set('accept-language', '*');
|
||||
req.headers.set('Ocp-Apim-Subscription-Key', nlpAuthoringKey);
|
||||
req.body = JSON.stringify(body);
|
||||
const httpClient = new ServiceClient();
|
||||
|
||||
return await httpClient.sendRequest(req);
|
||||
}
|
||||
|
||||
private async createSearch(group: string, name: string, location: string) {
|
||||
const params = {
|
||||
sku: {
|
||||
name: this.freeTier ? 'free' : 'standard'
|
||||
},
|
||||
location: location
|
||||
};
|
||||
|
||||
return await this.searchClient.services.beginCreateOrUpdateAndWait(group, name, params as any);
|
||||
}
|
||||
|
||||
private async createStorage(group: string, serverName: string, name: string, location: string) {
|
||||
const params = {
|
||||
sku: { name: 'Basic' },
|
||||
createMode: 'Default',
|
||||
location: location
|
||||
};
|
||||
|
||||
let database;
|
||||
try {
|
||||
database = await this.storageClient.databases.beginCreateOrUpdateAndWait(group, serverName, name, params);
|
||||
} catch (error) {
|
||||
|
||||
// Try again (MSFT issues).
|
||||
GBLog.info('Storage (database) creation failed. Retrying...');
|
||||
database = await this.storageClient.databases.beginCreateOrUpdateAndWait(group, serverName, name, params);
|
||||
}
|
||||
return database;
|
||||
}
|
||||
|
||||
private async createCognitiveServices(group: string, name: string, location: string, kind: string): Promise<Account> {
|
||||
const params = {
|
||||
sku: {
|
||||
name: name
|
||||
},
|
||||
createMode: 'Default',
|
||||
location: location,
|
||||
kind: kind,
|
||||
properties: {}
|
||||
};
|
||||
|
||||
if (kind === 'LUIS.Authoring' || kind === 'LUIS') {
|
||||
params.sku.name = this.freeTier ? 'F0' : 'S0';
|
||||
} else if (kind === 'TextAnalytics') {
|
||||
params.sku.name = this.freeTier ? 'F0' : 'S0';
|
||||
} else if (kind === 'Bing.SpellCheck.v7') {
|
||||
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);
|
||||
}
|
||||
|
||||
private async createSpeech(group: string, name: string, location: string): Promise<Account> {
|
||||
return await this.createCognitiveServices(group, name, location, 'SpeechServices');
|
||||
}
|
||||
|
||||
private async createNLP(group: string, name: string, location: string): Promise<Account> {
|
||||
return await this.createCognitiveServices(group, name, location, 'LUIS');
|
||||
}
|
||||
|
||||
private async createNLPAuthoring(group: string, name: string, location: string): Promise<Account> {
|
||||
return await this.createCognitiveServices(group, name, location, 'LUIS.Authoring');
|
||||
}
|
||||
|
||||
private async createSpellChecker(group: string, name: string): Promise<Account> {
|
||||
return await this.createCognitiveServices(group, name, 'westus', 'CognitiveServices');
|
||||
}
|
||||
|
||||
private async createTextAnalytics(group: string, name: string, location: string): Promise<Account> {
|
||||
return await this.createCognitiveServices(group, name, location, 'TextAnalytics');
|
||||
}
|
||||
|
||||
private async createDeployGroup(name: string, location: string) {
|
||||
const params = { location: location };
|
||||
|
||||
return await this.cloud.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> {
|
||||
const params = {
|
||||
serverFarmWithRichSkuName: name,
|
||||
location: location,
|
||||
sku: {
|
||||
name: this.freeTier ? 'F1' : 'S1',
|
||||
capacity: 1,
|
||||
tier: this.freeTier ? 'Free' : 'Standard'
|
||||
}
|
||||
};
|
||||
|
||||
return await this.webSiteClient.appServicePlans.beginCreateOrUpdateAndWait(group, name, params);
|
||||
}
|
||||
|
||||
private async createServer(farmId: string, group: string, name: string, location: string) {
|
||||
let tryed = false;
|
||||
const create = async () => {
|
||||
const parameters: Site = {
|
||||
location: location,
|
||||
serverFarmId: farmId,
|
||||
|
||||
siteConfig: {
|
||||
nodeVersion: GBAdminService.getNodeVersion(),
|
||||
detailedErrorLoggingEnabled: true,
|
||||
requestTracingEnabled: true
|
||||
}
|
||||
};
|
||||
const server = await this.webSiteClient.webApps.beginCreateOrUpdateAndWait(group, name, parameters);
|
||||
|
||||
const siteLogsConfig: SiteLogsConfig = {
|
||||
applicationLogs: {
|
||||
fileSystem: { level: 'Error' }
|
||||
}
|
||||
};
|
||||
await this.webSiteClient.webApps.updateDiagnosticLogsConfig(group, name, siteLogsConfig);
|
||||
|
||||
const souceControlConfig: SiteSourceControl = {
|
||||
repoUrl: 'https://github.com/GeneralBots/BotServer.git',
|
||||
branch: 'master',
|
||||
isManualIntegration: true,
|
||||
isMercurial: false,
|
||||
deploymentRollbackEnabled: false
|
||||
};
|
||||
|
||||
await this.webSiteClient.webApps.beginCreateOrUpdateSourceControlAndWait(group, name, souceControlConfig);
|
||||
return server;
|
||||
};
|
||||
|
||||
try {
|
||||
return await create();
|
||||
} catch (e) {
|
||||
if (!tryed) {
|
||||
tryed = true;
|
||||
GBLog.info('Retrying Deploying Bot Server...');
|
||||
try {
|
||||
return await create();
|
||||
} catch (error) {
|
||||
GBLog.info('Server creation failed at all on MSAzure, stopping...');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async updateWebisteConfig(group: string, name: string, serverFarmId: string, 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: 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}` },
|
||||
{ name: 'MARKETPLACE_SECRET', value: `${instance.marketplacePassword}` },
|
||||
{ name: 'STORAGE_DIALECT', value: `${instance.storageDialect}` },
|
||||
{ name: 'STORAGE_SERVER', value: `${instance.storageServer}.database.windows.net` },
|
||||
{ name: 'STORAGE_NAME', value: `${instance.storageName}` },
|
||||
{ name: 'STORAGE_USERNAME', value: `${instance.storageUsername}` },
|
||||
{ name: 'STORAGE_PASSWORD', value: `${instance.storagePassword}` },
|
||||
{ name: 'STORAGE_SYNC', value: `true` }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
return await this.webSiteClient.webApps.beginCreateOrUpdateAndWait(group, name, parameters);
|
||||
}
|
||||
}
|
||||
8
packages/azuredeployer.gbapp/strings.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export const Messages = {
|
||||
'en-US': {
|
||||
about_suggestions: 'Suggestions are welcomed and improve my quality...'
|
||||
},
|
||||
'pt-BR': {
|
||||
about_suggestions: 'Sugestões melhoram muito minha qualidade...'
|
||||
}
|
||||
};
|
||||
7
packages/basic.gblib/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
*This is a General Bots open core package, more information can be found on the [BotServer](https://github.com/pragmatismo-io/BotServer) repository.*
|
||||
|
||||
This alpha version is using a hack in form of converter to
|
||||
translate BASIC to TS and string replacements to emulate await code.
|
||||
See http://jsfiddle.net/roderick/dym05hsy for more info on vb2ts, so
|
||||
http://stevehanov.ca/blog/index.php?id=92 should be used to run it without
|
||||
translation and enhance classic BASIC experience.
|
||||
113
packages/basic.gblib/index.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
import { GuaribasSchedule } from '../core.gbapp/models/GBModel.js';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import Koa from 'koa';
|
||||
import cors from '@koa/cors';
|
||||
import { createHttpKoaMiddleware } from '@push-rpc/http';
|
||||
import { HttpServerOptions } from '@push-rpc/http/dist/server.js';
|
||||
import { GBServer } from '../../src/app.js';
|
||||
import { SocketServer } from '@push-rpc/core';
|
||||
import * as koaBody from 'koa-body';
|
||||
|
||||
export function createKoaHttpServer(
|
||||
port: number,
|
||||
getRemoteId: (ctx: Koa.Context) => string,
|
||||
opts: Partial<HttpServerOptions> = {}
|
||||
): SocketServer {
|
||||
const { onError, onConnection, middleware } =
|
||||
createHttpKoaMiddleware(getRemoteId, opts);
|
||||
|
||||
const app = new Koa();
|
||||
app.use(cors({ origin: '*' }));
|
||||
app.use(koaBody.koaBody({ multipart: true }));
|
||||
app.use(middleware);
|
||||
const server = app.listen(port);
|
||||
const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set .
|
||||
server.timeout = SERVER_TIMEOUT;
|
||||
|
||||
return {
|
||||
onError,
|
||||
onConnection,
|
||||
close(cb) {
|
||||
server.close(cb);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Package for core.gbapp.
|
||||
*/
|
||||
|
||||
export class GBBasicPackage implements IGBPackage {
|
||||
public sysPackages: IGBPackage[];
|
||||
public CurrentEngineName = 'guaribas-1.0.0';
|
||||
|
||||
public async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||
core.sequelize.addModels([GuaribasSchedule]);
|
||||
}
|
||||
|
||||
public async getDialogs(min: GBMinInstance) {
|
||||
GBLog.verbose(`getDialogs called.`);
|
||||
}
|
||||
public async unloadPackage(core: IGBCoreService): Promise<void> {
|
||||
GBLog.verbose(`unloadPackage called.`);
|
||||
}
|
||||
public async unloadBot(min: GBMinInstance): Promise<void> {
|
||||
GBLog.verbose(`unloadBot called.`);
|
||||
}
|
||||
public async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||
GBLog.verbose(`onNewSession called.`);
|
||||
}
|
||||
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
|
||||
GBLog.verbose(`onExchangeData called.`);
|
||||
}
|
||||
public async loadBot(min: GBMinInstance): Promise<void> {
|
||||
const botId = min.botId;
|
||||
GBServer.globals.debuggers[botId] = {};
|
||||
GBServer.globals.debuggers[botId].state = 0;
|
||||
GBServer.globals.debuggers[botId].breaks = [];
|
||||
GBServer.globals.debuggers[botId].stateInfo = 'Stopped';
|
||||
GBServer.globals.debuggers[botId].childProcess = null;
|
||||
GBServer.globals.debuggers[botId].client = null;
|
||||
GBServer.globals.debuggers[botId].conversationId = null;
|
||||
GBServer.globals.debuggers[botId].watermarkMap = {};
|
||||
}
|
||||
}
|
||||
77
packages/basic.gblib/models/Model.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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 {
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
Column,
|
||||
CreatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasInstance } from '../../core.gbapp/models/GBModel.js';
|
||||
|
||||
@Table
|
||||
//tslint:disable-next-line:max-classes-per-file
|
||||
export class GuaribasSchedule extends Model<GuaribasSchedule> {
|
||||
@Column(DataType.STRING(255))
|
||||
name: string;
|
||||
|
||||
@Column(DataType.STRING(255))
|
||||
schedule: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column(DataType.INTEGER)
|
||||
instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@CreatedAt
|
||||
declare createdAt: Date;
|
||||
|
||||
@Column(DataType.DATE)
|
||||
@UpdatedAt
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
63
packages/basic.gblib/services/ChartServices.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'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();
|
||||
}
|
||||
}
|
||||
310
packages/basic.gblib/services/DebuggerService.ts
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBLog, GBMinInstance } from 'botlib';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import Fs from 'fs';
|
||||
import SwaggerClient from 'swagger-client';
|
||||
import { spawn } from 'child_process';
|
||||
import { CodeServices } from '../../gpt.gblib/services/CodeServices.js';
|
||||
|
||||
/**
|
||||
* Web Automation services of conversation to be called by BASIC.
|
||||
*/
|
||||
export class DebuggerService {
|
||||
static 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'
|
||||
];
|
||||
|
||||
public async setBreakpoint({ botId, line }) {
|
||||
GBLog.info(`BASIC: 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 });
|
||||
GBLog.info(`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) {
|
||||
GBLog.info(`BASIC: Releasing execution ${botId} in DEBUG mode.`);
|
||||
await this.resume({ botId });
|
||||
return { status: 'OK' };
|
||||
} else {
|
||||
GBLog.info(`BASIC: 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 new SwaggerClient({
|
||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
||||
requestInterceptor: req => {
|
||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
||||
}
|
||||
});
|
||||
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' };
|
||||
}
|
||||
|
||||
}
|
||||
1291
packages/basic.gblib/services/DialogKeywords.ts
Normal file
509
packages/basic.gblib/services/GBVMService.ts
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBMinInstance, GBService, IGBCoreService, GBDialogStep } from 'botlib';
|
||||
import * as Fs from 'fs';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||
import { ScheduleServices } from './ScheduleServices.js';
|
||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService.js';
|
||||
import urlJoin from 'url-join';
|
||||
import { NodeVM, VMScript } from 'vm2';
|
||||
import { createVm2Pool } from './vm2-process/index.js';
|
||||
import textract from 'textract';
|
||||
import walkPromise from 'walk-promise';
|
||||
import child_process from 'child_process';
|
||||
import Path from 'path';
|
||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||
import { DialogKeywords } from './DialogKeywords.js';
|
||||
import { KeywordsExpressions } from './KeywordsExpressions.js';
|
||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||
import { SystemKeywords } from './SystemKeywords.js';
|
||||
import lineReplace from 'line-replace';
|
||||
|
||||
/**
|
||||
* @fileoverview Decision was to priorize security(isolation) and debugging,
|
||||
* over a beautiful BASIC transpiler (to be done).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Basic services for BASIC manipulation.
|
||||
*/
|
||||
export class GBVMService extends GBService {
|
||||
private static DEBUGGER_PORT = 9222;
|
||||
public static API_PORT = 1111;
|
||||
|
||||
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
||||
const files = await walkPromise(folder);
|
||||
|
||||
await CollectionUtil.asyncForEach(files, async file => {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
let filename: string = file.name;
|
||||
|
||||
if (filename.endsWith('.docx')) {
|
||||
filename = await this.loadDialog(filename, folder, min);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async loadDialog(filename: string, folder: string, min: GBMinInstance) {
|
||||
const wordFile = filename;
|
||||
const vbsFile = filename.substr(0, filename.indexOf('docx')) + 'vbs';
|
||||
const fullVbsFile = urlJoin(folder, vbsFile);
|
||||
const docxStat = Fs.statSync(urlJoin(folder, wordFile));
|
||||
const interval = 3000; // If compiled is older 30 seconds, then recompile.
|
||||
let writeVBS = true;
|
||||
if (Fs.existsSync(fullVbsFile)) {
|
||||
const vbsStat = Fs.statSync(fullVbsFile);
|
||||
if (docxStat['mtimeMs'] < vbsStat['mtimeMs'] + interval) {
|
||||
writeVBS = false;
|
||||
}
|
||||
}
|
||||
filename = vbsFile;
|
||||
let mainName = GBVMService.getMethodNameFromVBSFilename(filename);
|
||||
min.scriptMap[filename] = mainName;
|
||||
|
||||
if (writeVBS) {
|
||||
let text = await this.getTextFromWord(folder, wordFile);
|
||||
|
||||
const schedule = GBVMService.getSetScheduleKeywordArgs(text);
|
||||
const s = new ScheduleServices();
|
||||
if (schedule) {
|
||||
await s.createOrUpdateSchedule(min, schedule, mainName);
|
||||
} else {
|
||||
await s.deleteScheduleIfAny(min, mainName);
|
||||
}
|
||||
text = text.replace(/^\s*SET SCHEDULE (.*)/gim, '');
|
||||
Fs.writeFileSync(urlJoin(folder, vbsFile), text);
|
||||
}
|
||||
|
||||
// Process node_modules install.
|
||||
const node_modules = urlJoin(process.env.PWD, folder, 'node_modules');
|
||||
if (!Fs.existsSync(node_modules)) {
|
||||
const packageJson = `
|
||||
{
|
||||
"name": "${min.botId}.gbdialog",
|
||||
"version": "1.0.0",
|
||||
"description": "${min.botId} transpiled .gbdialog",
|
||||
"author": "${min.botId} owner.",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"encoding": "0.1.13",
|
||||
"isomorphic-fetch": "3.0.0",
|
||||
"punycode": "2.1.1",
|
||||
"@push-rpc/core": "1.1.5",
|
||||
"@push-rpc/http": "1.1.5",
|
||||
"vm2": "3.9.11"
|
||||
}
|
||||
}`;
|
||||
Fs.writeFileSync(urlJoin(folder, 'package.json'), packageJson);
|
||||
|
||||
GBLogEx.info(min, `BASIC: Installing .gbdialog node_modules for ${min.botId}...`);
|
||||
const npmPath = urlJoin(process.env.PWD, 'node_modules', '.bin', 'npm');
|
||||
child_process.execSync(`${npmPath} install`, { cwd: folder });
|
||||
}
|
||||
|
||||
// Hot swap for .vbs files.
|
||||
const fullFilename = urlJoin(folder, filename);
|
||||
if (process.env.DEV_HOTSWAP) {
|
||||
Fs.watchFile(fullFilename, async () => {
|
||||
await this.translateBASIC(fullFilename, min);
|
||||
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
||||
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
||||
});
|
||||
}
|
||||
|
||||
const compiledAt = Fs.statSync(fullFilename);
|
||||
const jsfile = urlJoin(folder, `${filename}.js`);
|
||||
|
||||
if (Fs.existsSync(jsfile)) {
|
||||
const jsStat = Fs.statSync(jsfile);
|
||||
const interval = 30000; // If compiled is older 30 seconds, then recompile.
|
||||
if (compiledAt.isFile() && compiledAt['mtimeMs'] > jsStat['mtimeMs'] + interval) {
|
||||
await this.translateBASIC(fullFilename, min);
|
||||
}
|
||||
} else {
|
||||
await this.translateBASIC(fullFilename, min);
|
||||
}
|
||||
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
||||
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
||||
return filename;
|
||||
}
|
||||
|
||||
public async translateBASIC(filename: any, min: GBMinInstance) {
|
||||
// Converts General Bots BASIC into regular VBS
|
||||
|
||||
let basicCode: string = Fs.readFileSync(filename, 'utf8');
|
||||
|
||||
// Process INCLUDE keyword to include another
|
||||
// dialog inside the dialog.
|
||||
|
||||
let include = null;
|
||||
do {
|
||||
include = /^include\b(.*)$/gim.exec(basicCode);
|
||||
|
||||
if (include) {
|
||||
let includeName = include[1].trim();
|
||||
includeName = Path.join(Path.dirname(filename), includeName);
|
||||
includeName = includeName.substr(0, includeName.lastIndexOf('.')) + '.vbs';
|
||||
|
||||
// To use include, two /publish will be necessary (for now)
|
||||
// because of alphabet order may raise not found errors.
|
||||
|
||||
let includeCode: string = Fs.readFileSync(includeName, 'utf8');
|
||||
basicCode = basicCode.replace(/^include\b.*$/gim, includeCode);
|
||||
}
|
||||
} while (include);
|
||||
|
||||
let { code, jsonMap } = await this.convert(basicCode);
|
||||
const mapFile = `${filename}.map`;
|
||||
|
||||
Fs.writeFileSync(mapFile, JSON.stringify(jsonMap));
|
||||
|
||||
// Run JS into the GB context.
|
||||
|
||||
const jsfile: string = `${filename}.js`;
|
||||
|
||||
code = `
|
||||
return (async () => {
|
||||
|
||||
// Imports npm packages for this .gbdialog conversational application.
|
||||
|
||||
require('isomorphic-fetch');
|
||||
const createRpcClient = require("@push-rpc/core").createRpcClient;
|
||||
const createHttpClient = require("@push-rpc/http").createHttpClient;
|
||||
|
||||
// Unmarshalls Local variables from server VM.
|
||||
|
||||
let pid = this.pid;
|
||||
let id = this.id;
|
||||
let username = this.username;
|
||||
let mobile = this.mobile;
|
||||
let from = this.from;
|
||||
let channel = this.channel;
|
||||
let ENTER = this.ENTER;
|
||||
let headers = this.headers;
|
||||
let data = this.data;
|
||||
let list = this.list;
|
||||
let httpUsername = this.httpUsername;
|
||||
let httpPs = this.httpPs;
|
||||
let today = this.today;
|
||||
let now = this.now;
|
||||
let page = null;
|
||||
let files = [];
|
||||
let col = 1;
|
||||
let index = 1
|
||||
|
||||
// Makes objects in BASIC insensitive.
|
||||
|
||||
const caseInsensitive = (listOrRow) => {
|
||||
|
||||
if (!listOrRow) {
|
||||
|
||||
return listOrRow
|
||||
};
|
||||
|
||||
const lowercase = (oldKey) => typeof oldKey === 'string' ? oldKey.toLowerCase() : oldKey;
|
||||
|
||||
const createCaseInsensitiveProxy = (obj) => {
|
||||
const propertiesMap = new Map(Object.keys(obj).map(propKey => [lowercase(propKey), obj[propKey]]));
|
||||
const caseInsensitiveGetHandler = {
|
||||
get: (target, property) => propertiesMap.get(lowercase(property))
|
||||
};
|
||||
return new Proxy(obj, caseInsensitiveGetHandler);
|
||||
};
|
||||
|
||||
if (listOrRow.length) {
|
||||
return listOrRow.map(row => createCaseInsensitiveProxy(row));
|
||||
} else {
|
||||
return createCaseInsensitiveProxy(listOrRow);
|
||||
}
|
||||
};
|
||||
|
||||
// Transfers NLP auto variables into global object.
|
||||
|
||||
for(i in this.variables) {
|
||||
global[i] = this.variables[i];
|
||||
}
|
||||
|
||||
// Defines local utility BASIC functions.
|
||||
|
||||
const ubound = (gbarray) => {return gbarray.length - 1};
|
||||
const isarray = (gbarray) => {return Array.isArray(gbarray) };
|
||||
|
||||
// Proxies remote functions as BASIC functions.
|
||||
|
||||
const weekday = (v) => { return (async () => { return await dk.getWeekFromDate({v}) })(); };
|
||||
const hour = (v) => { return (async () => { return await dk.getHourFromDate({v}) })(); };
|
||||
const base64 = (v) => { return (async () => { return await dk.getCoded({v}) })(); };
|
||||
const tolist = (v) => { return (async () => { return await dk.getToLst({v}) })(); };
|
||||
|
||||
// Setups interprocess communication from .gbdialog run-time to the BotServer API.
|
||||
|
||||
const optsRPC = {callTimeout: this.callTimeout};
|
||||
let url;
|
||||
|
||||
url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/dk';
|
||||
const dk = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote;
|
||||
url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/sys';
|
||||
const sys = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote;
|
||||
url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/wa';
|
||||
const wa = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote;
|
||||
url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/img';
|
||||
const img = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote;
|
||||
|
||||
${code}
|
||||
|
||||
// Closes handles if any.
|
||||
|
||||
await wa.closeHandles({pid: pid});
|
||||
|
||||
})();
|
||||
`;
|
||||
Fs.writeFileSync(jsfile, code);
|
||||
GBLogEx.info(min, `[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${code}`);
|
||||
}
|
||||
|
||||
public static getMethodNameFromVBSFilename(filename: string) {
|
||||
let mainName = filename.replace(/\s*|\-/gim, '').split('.')[0];
|
||||
return mainName.toLowerCase();
|
||||
}
|
||||
|
||||
public static getSetScheduleKeywordArgs(code: string) {
|
||||
if (!code) return null;
|
||||
const keyword = /^\s*SET SCHEDULE (.*)/gim;
|
||||
const result = keyword.exec(code);
|
||||
return result ? result[1] : null;
|
||||
}
|
||||
|
||||
private async getTextFromWord(folder: string, filename: string) {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
const path = urlJoin(folder, filename);
|
||||
textract.fromFileWithPath(path, { preserveLineBreaks: true }, (error, text) => {
|
||||
if (error) {
|
||||
if (error.message.startsWith('File not correctly recognized as zip file')) {
|
||||
text = Fs.readFileSync(path, 'utf8');
|
||||
} else {
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (text) {
|
||||
text = GBVMService.normalizeQuotes(text);
|
||||
}
|
||||
resolve(text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static normalizeQuotes(text: any) {
|
||||
text = text.replace(/\¨/gm, '"');
|
||||
text = text.replace(/\“/gm, '"');
|
||||
text = text.replace(/\”/gm, '"');
|
||||
text = text.replace(/\‘/gm, "'");
|
||||
text = text.replace(/\’/gm, "'");
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts General Bots BASIC
|
||||
*
|
||||
*
|
||||
* @param code General Bots BASIC
|
||||
*/
|
||||
public async convert(code: string) {
|
||||
// Start and End of VB2TS tags of processing.
|
||||
|
||||
code = process.env.ENABLE_AUTH ? `hear GBLogExin as login\n${code}` : code;
|
||||
var lines = code.split('\n');
|
||||
const keywords = KeywordsExpressions.getKeywords();
|
||||
let current = 41;
|
||||
const map = {};
|
||||
|
||||
for (let i = 1; i <= lines.length; i++) {
|
||||
let line = lines[i - 1];
|
||||
|
||||
// Remove lines before statments.
|
||||
|
||||
line = line.replace(/^\s*\d+\s*/gi,'');
|
||||
|
||||
for (let j = 0; j < keywords.length; j++) {
|
||||
line = line.replace(keywords[j][0], keywords[j][1]);
|
||||
}
|
||||
|
||||
// Add additional lines returned from replacement.
|
||||
|
||||
let add = line.split(/\r\n|\r|\n/).length;
|
||||
current = current + (add ? add : 0);
|
||||
map[i] = current;
|
||||
lines[i - 1] = line;
|
||||
}
|
||||
|
||||
code = `${lines.join('\n')}\n`;
|
||||
return { code, jsonMap: map };
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the converted JavaScript from BASIC code inside execution context.
|
||||
*/
|
||||
public static async callVM(
|
||||
text: string,
|
||||
min: GBMinInstance,
|
||||
step,
|
||||
user: GuaribasUser,
|
||||
deployer: GBDeployer,
|
||||
debug: boolean = false
|
||||
) {
|
||||
// Creates a class DialogKeywords which is the *this* pointer
|
||||
// in BASIC.
|
||||
|
||||
const sandbox = {};
|
||||
const contentLocale = min.core.getParam<string>(
|
||||
min.instance,
|
||||
'Default Content Language',
|
||||
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
||||
);
|
||||
|
||||
// Auto-NLP generates BASIC variables related to entities.
|
||||
|
||||
let variables = [];
|
||||
if (step ? step.context.activity.originalText : null && min['nerEngine']) {
|
||||
const result = await min['nerEngine'].process(step.context.activity.originalText);
|
||||
|
||||
for (let i = 0; i < result.entities.length; i++) {
|
||||
const v = result.entities[i];
|
||||
const variableName = `${v.entity}`;
|
||||
variables[variableName] = v.option ? v.option : v.sourceText;
|
||||
}
|
||||
}
|
||||
|
||||
const botId = min.botId;
|
||||
const path = DialogKeywords.getGBAIPath(min.botId, `gbdialog`);
|
||||
const gbdialogPath = urlJoin(process.cwd(), 'work', path);
|
||||
const scriptPath = urlJoin(gbdialogPath, `${text}.js`);
|
||||
|
||||
let code = min.sandBoxMap[text];
|
||||
const channel = step? step.context.activity.channelId : 'web';
|
||||
const pid = GBVMService.createProcessInfo(user, min, channel);
|
||||
const dk = new DialogKeywords();
|
||||
const sys = new SystemKeywords();
|
||||
await dk.setFilter ({pid: pid, value: null });
|
||||
|
||||
sandbox['variables'] = variables;
|
||||
sandbox['id'] = sys.getRandomId();
|
||||
sandbox['username'] = await dk.userName({ pid });
|
||||
sandbox['mobile'] = await dk.userMobile({ pid });
|
||||
sandbox['from'] = await dk.userMobile({ pid });
|
||||
sandbox['ENTER'] = String.fromCharCode(13);
|
||||
sandbox['headers'] = {};
|
||||
sandbox['data'] = {};
|
||||
sandbox['list'] = [];
|
||||
sandbox['httpUsername'] = '';
|
||||
sandbox['httpPs'] = '';
|
||||
sandbox['pid'] = pid;
|
||||
sandbox['contentLocale'] = contentLocale;
|
||||
sandbox['callTimeout'] = 60 * 60 * 24 * 1000;
|
||||
sandbox['channel'] = channel;
|
||||
sandbox['today'] = await dk.getToday({ pid });
|
||||
sandbox['now'] = await dk.getNow({ pid });
|
||||
let result;
|
||||
|
||||
try {
|
||||
if (GBConfigService.get('GBVM') === 'false') {
|
||||
const vm1 = new NodeVM({
|
||||
allowAsync: true,
|
||||
sandbox: sandbox,
|
||||
console: 'inherit',
|
||||
wrapper: 'commonjs',
|
||||
require: {
|
||||
builtin: ['stream', 'http', 'https', 'url', 'zlib', 'net', 'tls', 'crypto'],
|
||||
root: ['./'],
|
||||
external: true,
|
||||
context: 'sandbox'
|
||||
}
|
||||
});
|
||||
const s = new VMScript(code, { filename: scriptPath });
|
||||
result = vm1.run(s);
|
||||
} else {
|
||||
const runnerPath = urlJoin(
|
||||
process.cwd(),
|
||||
'dist',
|
||||
'packages',
|
||||
'basic.gblib',
|
||||
'services',
|
||||
'vm2-process',
|
||||
'vm2ProcessRunner.js'
|
||||
);
|
||||
|
||||
const { run } = createVm2Pool({
|
||||
min: 0,
|
||||
max: 0,
|
||||
debug: debug,
|
||||
debuggerport: GBVMService.DEBUGGER_PORT,
|
||||
botId: botId,
|
||||
cpu: 100,
|
||||
memory: 50000,
|
||||
time: 60 * 60 * 24 * 14,
|
||||
cwd: gbdialogPath,
|
||||
script: runnerPath
|
||||
});
|
||||
|
||||
result = await run(code, { filename: scriptPath, sandbox: sandbox });
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
||||
} finally {
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static createProcessInfo(user: GuaribasUser, min: GBMinInstance, channel: any) {
|
||||
const pid = GBAdminService.getNumberIdentifier();
|
||||
GBServer.globals.processes[pid] = {
|
||||
pid: pid,
|
||||
userId: user ? user.userId : 0,
|
||||
instanceId: min.instance.instanceId,
|
||||
channel: channel,
|
||||
roles: 'everyone'
|
||||
};
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
123
packages/basic.gblib/services/ImageProcessingServices.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import Path from 'path';
|
||||
import { GBLog, GBMinInstance } from 'botlib';
|
||||
import { DialogKeywords } from './DialogKeywords.js';
|
||||
import sharp from 'sharp';
|
||||
import joinImages from 'join-images-updated';
|
||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||
import urlJoin from 'url-join';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
|
||||
/**
|
||||
* 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 }) {
|
||||
GBLog.info(`BASIC: Image Processing SHARPEN ${file}.`);
|
||||
|
||||
const gbfile = DialogKeywords.getFileByHandle(file);
|
||||
const data = await sharp(gbfile.data)
|
||||
.sharpen({
|
||||
sigma: 2,
|
||||
m1: 0,
|
||||
m2: 3,
|
||||
x1: 3,
|
||||
y2: 15,
|
||||
y3: 15
|
||||
})
|
||||
.toBuffer();
|
||||
|
||||
const newFile = {
|
||||
filename: gbfile.filename,
|
||||
data: data
|
||||
|
||||
};
|
||||
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 path = DialogKeywords.getGBAIPath(min.botId);
|
||||
const img = await joinImages(paths);
|
||||
const localName = Path.join('work', path, '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 }) {
|
||||
GBLog.info(`BASIC: Image Processing SHARPEN ${file}.`);
|
||||
|
||||
const gbfile = DialogKeywords.getFileByHandle(file);
|
||||
const data = await sharp(gbfile.data)
|
||||
.blur()
|
||||
.toBuffer();
|
||||
|
||||
const newFile = {
|
||||
filename: gbfile.filename,
|
||||
data: data
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
1031
packages/basic.gblib/services/KeywordsExpressions.ts
Normal file
154
packages/basic.gblib/services/ScheduleServices.ts
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBLog, GBMinInstance, GBService } from 'botlib';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
|
||||
import { GuaribasSchedule } from '../../core.gbapp/models/GBModel.js';
|
||||
|
||||
import cron from 'node-cron';
|
||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||
|
||||
/**
|
||||
* @fileoverview Schedule Services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Basic services for BASIC manipulation.
|
||||
*/
|
||||
export class ScheduleServices extends GBService {
|
||||
public async deleteScheduleIfAny (min: GBMinInstance, name: string) {
|
||||
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
|
||||
}
|
||||
});
|
||||
|
||||
if (count > 0) {
|
||||
GBLogEx.info(min,`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> {
|
||||
let record = await GuaribasSchedule.findOne({
|
||||
where: {
|
||||
instanceId: min.instance.instanceId,
|
||||
name: name
|
||||
}
|
||||
});
|
||||
|
||||
if (record === null) {
|
||||
record = await GuaribasSchedule.create(<GuaribasSchedule>{
|
||||
instanceId: min.instance.instanceId,
|
||||
name: name,
|
||||
schedule: schedule
|
||||
});
|
||||
} else {
|
||||
record.schedule = schedule;
|
||||
await record.save();
|
||||
}
|
||||
|
||||
this.ScheduleItem(record, min);
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all cached schedule from BASIC SET SCHEDULE keyword.
|
||||
*/
|
||||
public async scheduleAll () {
|
||||
let schedules;
|
||||
try {
|
||||
schedules = await GuaribasSchedule.findAll();
|
||||
await CollectionUtil.asyncForEach(schedules, async item => {
|
||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(
|
||||
p => p.instance.instanceId === item.instanceId
|
||||
)[0];
|
||||
|
||||
if (min) {
|
||||
this.ScheduleItem(item, min);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Cannot schedule: ${error.message}.`);
|
||||
}
|
||||
return schedules;
|
||||
}
|
||||
|
||||
private ScheduleItem (item: GuaribasSchedule, min: GBMinInstance) {
|
||||
GBLogEx.info(min,`Scheduling ${item.name} on ${min.botId}...`);
|
||||
try {
|
||||
const options = {
|
||||
scheduled: true,
|
||||
timezone: 'America/Sao_Paulo'
|
||||
};
|
||||
|
||||
const task = min['scheduleMap'][item.name];
|
||||
if (task) {
|
||||
task.stop();
|
||||
min['scheduleMap'][item.name] = null;
|
||||
}
|
||||
|
||||
min['scheduleMap'][item.name] = cron.schedule(
|
||||
item.schedule,
|
||||
function () {
|
||||
const finalData = async () => {
|
||||
let script = item.name;
|
||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(
|
||||
p => p.instance.instanceId === item.instanceId
|
||||
)[0];
|
||||
await GBVMService.callVM(script, min, null, null, null, false);
|
||||
};
|
||||
(async () => {
|
||||
await finalData();
|
||||
})();
|
||||
},
|
||||
options
|
||||
);
|
||||
GBLogEx.info(min,`Running .gbdialog word ${item.name} on:${item.schedule}...`);
|
||||
} catch (error) {}
|
||||
}
|
||||
}
|
||||
2048
packages/basic.gblib/services/SystemKeywords.ts
Normal file
490
packages/basic.gblib/services/WebAutomationServices.ts
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import urlJoin from 'url-join';
|
||||
import Fs from 'fs';
|
||||
import Path from 'path';
|
||||
import url from 'url';
|
||||
|
||||
import { GBLog, GBMinInstance } 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 { GuaribasUser } from '../../security.gbapp/models/index.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';
|
||||
|
||||
/**
|
||||
* Web Automation services of conversation to be called by BASIC.
|
||||
*/
|
||||
export class WebAutomationServices {
|
||||
static isSelector(name: any) {
|
||||
return name.startsWith('.') || name.startsWith('#') || name.startsWith('[');
|
||||
}
|
||||
private debugWeb: boolean;
|
||||
private lastDebugWeb: Date;
|
||||
|
||||
public static cyrb53 = (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, `BASIC: 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(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, `BASIC: 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({ handle, frame, selector }) {
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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 page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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 page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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 refresh = true;
|
||||
if (this.lastDebugWeb) {
|
||||
refresh = new Date().getTime() - this.lastDebugWeb.getTime() > 5000;
|
||||
}
|
||||
|
||||
if (this.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' });
|
||||
}
|
||||
this.lastDebugWeb = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Press ENTER in a web page,useful for logins.
|
||||
*
|
||||
* @example PRESS ENTER ON page
|
||||
*/
|
||||
public async pressKey({ handle, char, frame }) {
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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 page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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 page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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);
|
||||
GBLog.info(`BASIC: Web Automation SCREENSHOT ${selector}.`);
|
||||
|
||||
const gbaiName = DialogKeywords.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));
|
||||
GBLog.info(`BASIC: 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 }) {
|
||||
text = `${text}`;
|
||||
const page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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(';');
|
||||
GBLog.info(`BASIC: 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 = Fs.readFileSync(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 path = DialogKeywords.getGBAIPath(min.botId, `gbdrive`);
|
||||
const root = path;
|
||||
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') {
|
||||
GBLog.info(`BASIC: 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 page = WebAutomationServices.getPageByHandle(handle);
|
||||
GBLog.info(`BASIC: 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;
|
||||
}
|
||||
}
|
||||
}
|
||||