fix(config): TSLint parsed on all files.
new(config): Several CI integrations.
This commit is contained in:
parent
6f868c5178
commit
ea978f7d65
47 changed files with 11509 additions and 1839 deletions
|
@ -6,4 +6,4 @@ tmp
|
||||||
.env
|
.env
|
||||||
.coveralls.yml
|
.coveralls.yml
|
||||||
coverage
|
coverage
|
||||||
{YOUR_LIB}-*.tgz
|
BotServer-*.tgz
|
||||||
|
|
12
.travis.yml
12
.travis.yml
|
@ -7,7 +7,7 @@ notifications:
|
||||||
email: false
|
email: false
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- npm install --global nyc mocha typescript rimraf shx
|
- npm install --global nyc mocha typescript shx
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
|
@ -17,7 +17,6 @@ before_script:
|
||||||
|
|
||||||
script:
|
script:
|
||||||
#- npm run build-docs
|
#- npm run build-docs
|
||||||
#- npm run tslint
|
|
||||||
#- npm run coveralls
|
#- npm run coveralls
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
|
@ -29,10 +28,17 @@ after_success:
|
||||||
- npm pack
|
- npm pack
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
- provider: pages
|
||||||
|
skip_cleanup: true
|
||||||
|
local_dir: docs/reference
|
||||||
|
github_token: $GITHUB_TOKEN
|
||||||
|
on:
|
||||||
|
tags: false
|
||||||
|
|
||||||
- provider: releases
|
- provider: releases
|
||||||
api_key: $GITHUB_TOKEN
|
api_key: $GITHUB_TOKEN
|
||||||
file_glob: true
|
file_glob: true
|
||||||
file: "{YOURLIB}-*.tgz"
|
file: "BotServer-*.tgz"
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
on:
|
on:
|
||||||
tags: false
|
tags: false
|
||||||
|
|
9654
package-lock.json
generated
9654
package-lock.json
generated
File diff suppressed because it is too large
Load diff
50
package.json
50
package.json
|
@ -18,15 +18,29 @@
|
||||||
"url": "https://github.com/pragmatismo-io/BotServer.git"
|
"url": "https://github.com/pragmatismo-io/BotServer.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf dist",
|
"clean": "shx rm -rf node_modules/ dist/ docs/reference",
|
||||||
"tslint": "tslint ./src ./packages/**/*.ts -t verbose",
|
"tslint": "tslint --fix ./src/*.ts ./packages/**/*.ts -t verbose",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"build-docs": "typedoc --options typedoc.json src/",
|
"build-docs": "typedoc --options typedoc.json src/",
|
||||||
"test": "nyc --reporter=html --reporter=text mocha -r ts-node/register packages/**/*.test.ts ",
|
"test": "nyc --reporter=html --reporter=text mocha -r ts-node/register packages/**/*.test.ts ",
|
||||||
|
"pretest": "npm run build",
|
||||||
"coveralls": "npm run test && nyc report --reporter=text-lcov | coveralls",
|
"coveralls": "npm run test && nyc report --reporter=text-lcov | coveralls",
|
||||||
"start": "node ./dist/src/app.js",
|
"start": "node ./dist/src/app.js",
|
||||||
"watch:build": "tsc --watch",
|
"watch:build": "tsc --watch",
|
||||||
"watch:server": "nodemon './dist/index.js' --watch './dist'"
|
"watch:server": "nodemon './dist/index.js' --watch './dist'",
|
||||||
|
"posttypedoc": "shx cp .nojekyll docs/reference/.nojekyll",
|
||||||
|
"ban": "ban",
|
||||||
|
"issues": "git-issues",
|
||||||
|
"license": "license-checker --production --onlyunknown --csv",
|
||||||
|
"lint": "standard --verbose --fix 'src/*.js' 'cypress/**/*.js'",
|
||||||
|
"prelint": "npm run pretty",
|
||||||
|
"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",
|
||||||
|
"semantic-release": "semantic-release",
|
||||||
|
"commit": "commit-wizard"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "=10.13.0"
|
"node": "=10.13.0"
|
||||||
|
@ -81,7 +95,7 @@
|
||||||
"reflect-metadata": "0.1.12",
|
"reflect-metadata": "0.1.12",
|
||||||
"request-promise-native": "1.0.5",
|
"request-promise-native": "1.0.5",
|
||||||
"scanf": "^1.0.2",
|
"scanf": "^1.0.2",
|
||||||
"sequelize": "4.41.1",
|
"sequelize": "4.41.2",
|
||||||
"sequelize-typescript": "0.6.6",
|
"sequelize-typescript": "0.6.6",
|
||||||
"simple-git": "^1.107.0",
|
"simple-git": "^1.107.0",
|
||||||
"sqlite3": "4.0.4",
|
"sqlite3": "4.0.4",
|
||||||
|
@ -99,14 +113,25 @@
|
||||||
"winston": "3.1.0"
|
"winston": "3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^2.2.47",
|
"@types/mocha": "^5.2.5",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"coveralls": "^3.0.2",
|
"coveralls": "^3.0.2",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
"shx": "^0.3.2",
|
"shx": "^0.3.2",
|
||||||
"ts-loader": "^5.3.0",
|
"ts-loader": "^5.3.0",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
"tslint-microsoft-contrib": "^5.2.1"
|
"tslint-microsoft-contrib": "^5.2.1",
|
||||||
|
"ban-sensitive-files": "1.9.2",
|
||||||
|
"dependency-check": "3.2.1",
|
||||||
|
"deps-ok": "1.4.1",
|
||||||
|
"git-issues": "1.3.1",
|
||||||
|
"license-checker": "24.0.1",
|
||||||
|
"nsp": "3.2.1",
|
||||||
|
"pre-git": "3.17.1",
|
||||||
|
"prettier-standard": "8.0.1",
|
||||||
|
"standard": "12.0.1",
|
||||||
|
"travis-deploy-once": "5.0.9",
|
||||||
|
"semantic-release": "15.10.8"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"env": {
|
"env": {
|
||||||
|
@ -152,5 +177,18 @@
|
||||||
"warn"
|
"warn"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"analyzeCommits": "simple-commit-message"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"pre-git": {
|
||||||
|
"commit-msg": "simple",
|
||||||
|
"pre-commit": [],
|
||||||
|
"pre-push": [],
|
||||||
|
"post-commit": [],
|
||||||
|
"post-checkout": [],
|
||||||
|
"post-merge": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,36 +36,36 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require('url-join');
|
||||||
import { GBMinInstance } from "botlib";
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { IGBDialog } from "botlib";
|
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import { GBDeployer } from "../../core.gbapp/services/GBDeployer";
|
import { GBMinInstance } from 'botlib';
|
||||||
import { GBImporter } from "../../core.gbapp/services/GBImporter";
|
import { IGBDialog } from 'botlib';
|
||||||
import { GBConfigService } from "../../core.gbapp/services/GBConfigService";
|
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
||||||
import { BotAdapter } from "botbuilder";
|
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
||||||
import { GBAdminService } from "../services/GBAdminService";
|
import { GBImporter } from '../../core.gbapp/services/GBImporter';
|
||||||
import { Messages } from "../strings";
|
import { GBAdminService } from '../services/GBAdminService';
|
||||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
import { Messages } from '../strings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialogs for administration tasks.
|
* Dialogs for administration tasks.
|
||||||
*/
|
*/
|
||||||
export class AdminDialog extends IGBDialog {
|
export class AdminDialog extends IGBDialog {
|
||||||
static async createFarmCommand(text: any, min: GBMinInstance) {}
|
public static async createFarmCommand(text: any, min: GBMinInstance) {}
|
||||||
|
|
||||||
static async undeployPackageCommand(text: any, min: GBMinInstance) {
|
public static async undeployPackageCommand(text: any, min: GBMinInstance) {
|
||||||
let packageName = text.split(" ")[1];
|
const packageName = text.split(' ')[1];
|
||||||
let importer = new GBImporter(min.core);
|
const importer = new GBImporter(min.core);
|
||||||
let deployer = new GBDeployer(min.core, importer);
|
const deployer = new GBDeployer(min.core, importer);
|
||||||
await deployer.undeployPackageFromLocalPath(
|
await deployer.undeployPackageFromLocalPath(
|
||||||
min.instance,
|
min.instance,
|
||||||
UrlJoin("packages", packageName)
|
UrlJoin('packages', packageName)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async deployPackageCommand(text: string, deployer: GBDeployer) {
|
public static async deployPackageCommand(text: string, deployer: GBDeployer) {
|
||||||
let packageName = text.split(" ")[1];
|
const packageName = text.split(' ')[1];
|
||||||
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
|
||||||
await deployer.deployPackageFromLocalPath(
|
await deployer.deployPackageFromLocalPath(
|
||||||
UrlJoin(additionalPath, packageName)
|
UrlJoin(additionalPath, packageName)
|
||||||
);
|
);
|
||||||
|
@ -76,59 +76,59 @@ export class AdminDialog extends IGBDialog {
|
||||||
* @param bot The bot adapter.
|
* @param bot The bot adapter.
|
||||||
* @param min The minimal bot instance data.
|
* @param min The minimal bot instance data.
|
||||||
*/
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
// Setup services.
|
// Setup services.
|
||||||
|
|
||||||
let importer = new GBImporter(min.core);
|
const importer = new GBImporter(min.core);
|
||||||
let deployer = new GBDeployer(min.core, importer);
|
const deployer = new GBDeployer(min.core, importer);
|
||||||
|
|
||||||
min.dialogs.add(
|
min.dialogs.add(
|
||||||
new WaterfallDialog("/admin", [
|
new WaterfallDialog('/admin', [
|
||||||
async step => {
|
async step => {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
const prompt = Messages[locale].authenticate;
|
const prompt = Messages[locale].authenticate;
|
||||||
await step.prompt("textPrompt", prompt);
|
await step.prompt('textPrompt', prompt);
|
||||||
return await step.next();
|
return await step.next();
|
||||||
},
|
},
|
||||||
async step => {
|
async step => {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
let password = step.result;
|
const password = step.result;
|
||||||
if (
|
if (
|
||||||
password === GBConfigService.get("ADMIN_PASS") &&
|
password === GBConfigService.get('ADMIN_PASS') &&
|
||||||
GBAdminService.StrongRegex.test(password)
|
GBAdminService.StrongRegex.test(password)
|
||||||
) {
|
) {
|
||||||
await step.context.sendActivity(Messages[locale].welcome);
|
await step.context.sendActivity(Messages[locale].welcome);
|
||||||
await step.prompt("textPrompt", Messages[locale].which_task);
|
await step.prompt('textPrompt', Messages[locale].which_task);
|
||||||
} else {
|
} else {
|
||||||
await step.prompt("textPrompt", Messages[locale].wrong_password);
|
await step.prompt('textPrompt', Messages[locale].wrong_password);
|
||||||
await step.endDialog();
|
await step.endDialog();
|
||||||
}
|
}
|
||||||
return await step.next();
|
return await step.next();
|
||||||
},
|
},
|
||||||
async step => {
|
async step => {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
var text = step.result;
|
const text = step.result;
|
||||||
let cmdName = text.split(" ")[0];
|
const cmdName = text.split(' ')[0];
|
||||||
|
|
||||||
step.context.sendActivity(Messages[locale].working(cmdName));
|
step.context.sendActivity(Messages[locale].working(cmdName));
|
||||||
let unknownCommand = false;
|
let unknownCommand = false;
|
||||||
|
|
||||||
if (text === "quit") {
|
if (text === 'quit') {
|
||||||
await step.replaceDialog("/");
|
await step.replaceDialog('/');
|
||||||
} else if (cmdName === "createFarm") {
|
} else if (cmdName === 'createFarm') {
|
||||||
await AdminDialog.createFarmCommand(text, deployer);
|
await AdminDialog.createFarmCommand(text, deployer);
|
||||||
await step.replaceDialog("/admin", { firstRun: false });
|
await step.replaceDialog('/admin', { firstRun: false });
|
||||||
} else if (cmdName === "deployPackage") {
|
} else if (cmdName === 'deployPackage') {
|
||||||
await AdminDialog.deployPackageCommand(text, deployer);
|
await AdminDialog.deployPackageCommand(text, deployer);
|
||||||
await step.replaceDialog("/admin", { firstRun: false });
|
await step.replaceDialog('/admin', { firstRun: false });
|
||||||
} else if (cmdName === "redeployPackage") {
|
} else if (cmdName === 'redeployPackage') {
|
||||||
await AdminDialog.undeployPackageCommand(text, min);
|
await AdminDialog.undeployPackageCommand(text, min);
|
||||||
await AdminDialog.deployPackageCommand(text, deployer);
|
await AdminDialog.deployPackageCommand(text, deployer);
|
||||||
await step.replaceDialog("/admin", { firstRun: false });
|
await step.replaceDialog('/admin', { firstRun: false });
|
||||||
} else if (cmdName === "undeployPackage") {
|
} else if (cmdName === 'undeployPackage') {
|
||||||
await AdminDialog.undeployPackageCommand(text, min);
|
await AdminDialog.undeployPackageCommand(text, min);
|
||||||
await step.replaceDialog("/admin", { firstRun: false });
|
await step.replaceDialog('/admin', { firstRun: false });
|
||||||
} else if (cmdName === "setupSecurity") {
|
} else if (cmdName === 'setupSecurity') {
|
||||||
await AdminDialog.setupSecurity(min, step);
|
await AdminDialog.setupSecurity(min, step);
|
||||||
} else {
|
} else {
|
||||||
unknownCommand = true;
|
unknownCommand = true;
|
||||||
|
@ -142,7 +142,7 @@ export class AdminDialog extends IGBDialog {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await step.endDialog();
|
await step.endDialog();
|
||||||
await step.replaceDialog("/answer", { query: text });
|
await step.replaceDialog('/answer', { query: text });
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
@ -151,15 +151,15 @@ export class AdminDialog extends IGBDialog {
|
||||||
|
|
||||||
private static async setupSecurity(min: any, step: any) {
|
private static async setupSecurity(min: any, step: any) {
|
||||||
const locale = step.activity.locale;
|
const locale = step.activity.locale;
|
||||||
let state = `${min.instance.instanceId}${Math.floor(
|
const state = `${min.instance.instanceId}${Math.floor(
|
||||||
Math.random() * 1000000000
|
Math.random() * 1000000000
|
||||||
)}`;
|
)}`;
|
||||||
await min.adminService.setValue(
|
await min.adminService.setValue(
|
||||||
min.instance.instanceId,
|
min.instance.instanceId,
|
||||||
"AntiCSRFAttackState",
|
'AntiCSRFAttackState',
|
||||||
state
|
state
|
||||||
);
|
);
|
||||||
let url = `https://login.microsoftonline.com/${
|
const url = `https://login.microsoftonline.com/${
|
||||||
min.instance.authenticatorTenant
|
min.instance.authenticatorTenant
|
||||||
}/oauth2/authorize?client_id=${
|
}/oauth2/authorize?client_id=${
|
||||||
min.instance.authenticatorClientId
|
min.instance.authenticatorClientId
|
||||||
|
|
|
@ -37,32 +37,30 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Table,
|
|
||||||
Column,
|
Column,
|
||||||
Model,
|
|
||||||
CreatedAt,
|
CreatedAt,
|
||||||
UpdatedAt,
|
Model,
|
||||||
} from "sequelize-typescript";
|
Table,
|
||||||
|
UpdatedAt
|
||||||
|
} from 'sequelize-typescript';
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
export class GuaribasAdmin extends Model<GuaribasAdmin>
|
export class GuaribasAdmin extends Model<GuaribasAdmin> {
|
||||||
{
|
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
instanceId: number;
|
public instanceId: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
key: string;
|
public key: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
value: string;
|
public value: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
public createdAt: Date;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
public updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,116 +36,41 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { GuaribasAdmin } from "../models/AdminModel";
|
import { AuthenticationContext, TokenResponse } from 'adal-node';
|
||||||
import { IGBCoreService } from "botlib";
|
import { IGBCoreService } from 'botlib';
|
||||||
import { AuthenticationContext, TokenResponse } from "adal-node";
|
import { GuaribasAdmin } from '../models/AdminModel';
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require('url-join');
|
||||||
const msRestAzure = require("ms-rest-azure");
|
const msRestAzure = require('ms-rest-azure');
|
||||||
const PasswordGenerator = require("strict-password-generator").default;
|
const PasswordGenerator = require('strict-password-generator').default;
|
||||||
|
|
||||||
export class GBAdminService {
|
export class GBAdminService {
|
||||||
|
|
||||||
static GB_PROMPT: string = "GeneralBots: "
|
public static GB_PROMPT: string = 'GeneralBots: ';
|
||||||
|
public static masterBotInstanceId = 0;
|
||||||
static generateUuid(): string {
|
|
||||||
return msRestAzure.generateUuid();
|
|
||||||
}
|
|
||||||
static masterBotInstanceId = 0;
|
|
||||||
|
|
||||||
public static StrongRegex = new RegExp(
|
public static StrongRegex = new RegExp(
|
||||||
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})"
|
'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})'
|
||||||
);
|
);
|
||||||
|
|
||||||
core: IGBCoreService;
|
public core: IGBCoreService;
|
||||||
|
|
||||||
constructor(core: IGBCoreService) {
|
constructor(core: IGBCoreService) {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setValue(
|
public static generateUuid(): string {
|
||||||
instanceId: number,
|
return msRestAzure.generateUuid();
|
||||||
key: string,
|
|
||||||
value: string
|
|
||||||
): Promise<GuaribasAdmin> {
|
|
||||||
let options = { where: {} };
|
|
||||||
options.where = { key: key };
|
|
||||||
let admin = await GuaribasAdmin.findOne(options);
|
|
||||||
if (admin == null) {
|
|
||||||
admin = new GuaribasAdmin();
|
|
||||||
admin.key = key;
|
|
||||||
}
|
|
||||||
admin.value = value;
|
|
||||||
admin.instanceId = instanceId;
|
|
||||||
return admin.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getValue(instanceId: number, key: string) {
|
|
||||||
let options = { where: {} };
|
|
||||||
options.where = { key: key, instanceId: instanceId };
|
|
||||||
let obj = await GuaribasAdmin.findOne(options);
|
|
||||||
return Promise.resolve(obj.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async acquireElevatedToken(instanceId): Promise<string> {
|
|
||||||
return new Promise<string>(async (resolve, reject) => {
|
|
||||||
let instance = await this.core.loadInstanceById(instanceId);
|
|
||||||
|
|
||||||
let expiresOn = new Date(await this.getValue(instanceId, "expiresOn"));
|
|
||||||
if (expiresOn.getTime() > new Date().getTime()) {
|
|
||||||
let accessToken = await this.getValue(instanceId, "accessToken");
|
|
||||||
resolve(accessToken);
|
|
||||||
} else {
|
|
||||||
let authorizationUrl = UrlJoin(
|
|
||||||
instance.authenticatorAuthorityHostUrl,
|
|
||||||
instance.authenticatorTenant,
|
|
||||||
"/oauth2/authorize"
|
|
||||||
);
|
|
||||||
|
|
||||||
let refreshToken = await this.getValue(instanceId, "refreshToken");
|
|
||||||
let resource = "https://graph.microsoft.com";
|
|
||||||
var authenticationContext = new AuthenticationContext(authorizationUrl);
|
|
||||||
authenticationContext.acquireTokenWithRefreshToken(
|
|
||||||
refreshToken,
|
|
||||||
instance.authenticatorClientId,
|
|
||||||
instance.authenticatorClientSecret,
|
|
||||||
resource,
|
|
||||||
async (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
let token = res as TokenResponse;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async getADALTokenFromUsername(
|
public static async getADALTokenFromUsername(
|
||||||
username: string,
|
username: string,
|
||||||
password: string
|
password: string
|
||||||
) {
|
) {
|
||||||
let credentials = await GBAdminService.getADALCredentialsFromUsername(
|
const credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||||
username,
|
username,
|
||||||
password
|
password
|
||||||
);
|
);
|
||||||
let accessToken = credentials.tokenCache._entries[0].accessToken;
|
const accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||||
return accessToken;
|
return accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +78,7 @@ export class GBAdminService {
|
||||||
username: string,
|
username: string,
|
||||||
password: string
|
password: string
|
||||||
) {
|
) {
|
||||||
let credentials = await msRestAzure.loginWithUsernamePassword(
|
const credentials = await msRestAzure.loginWithUsernamePassword(
|
||||||
username,
|
username,
|
||||||
password
|
password
|
||||||
);
|
);
|
||||||
|
@ -171,7 +96,7 @@ export class GBAdminService {
|
||||||
maximumLength: 14
|
maximumLength: 14
|
||||||
};
|
};
|
||||||
let password = passwordGenerator.generatePassword(options);
|
let password = passwordGenerator.generatePassword(options);
|
||||||
password = password.replace(/@[=:;\?]/g, "#");
|
password = password.replace(/@[=:;\?]/g, '#');
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,8 +110,83 @@ export class GBAdminService {
|
||||||
minimumLength: 12,
|
minimumLength: 12,
|
||||||
maximumLength: 14
|
maximumLength: 14
|
||||||
};
|
};
|
||||||
let name = passwordGenerator.generatePassword(options);
|
const name = passwordGenerator.generatePassword(options);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setValue(
|
||||||
|
instanceId: number,
|
||||||
|
key: string,
|
||||||
|
value: string
|
||||||
|
): Promise<GuaribasAdmin> {
|
||||||
|
const options = { where: {} };
|
||||||
|
options.where = { key: key };
|
||||||
|
let admin = await GuaribasAdmin.findOne(options);
|
||||||
|
if (admin == null) {
|
||||||
|
admin = new GuaribasAdmin();
|
||||||
|
admin.key = key;
|
||||||
|
}
|
||||||
|
admin.value = value;
|
||||||
|
admin.instanceId = instanceId;
|
||||||
|
return admin.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getValue(instanceId: number, key: string) {
|
||||||
|
const options = { where: {} };
|
||||||
|
options.where = { key: key, instanceId: instanceId };
|
||||||
|
const obj = await GuaribasAdmin.findOne(options);
|
||||||
|
return Promise.resolve(obj.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async acquireElevatedToken(instanceId): Promise<string> {
|
||||||
|
return new Promise<string>(async (resolve, reject) => {
|
||||||
|
const instance = await this.core.loadInstanceById(instanceId);
|
||||||
|
|
||||||
|
const expiresOn = new Date(await this.getValue(instanceId, 'expiresOn'));
|
||||||
|
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.authenticatorClientId,
|
||||||
|
instance.authenticatorClientSecret,
|
||||||
|
resource,
|
||||||
|
async (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
const token = res as TokenResponse;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
export const Messages = {
|
export const Messages = {
|
||||||
"en-US": {
|
'en-US': {
|
||||||
authenticate: "Please, authenticate:",
|
authenticate: 'Please, authenticate:',
|
||||||
welcome: "Welcome to Pragmatismo.io GeneralBots Administration.",
|
welcome: 'Welcome to Pragmatismo.io GeneralBots Administration.',
|
||||||
which_task: "Which task do you wanna run now?",
|
which_task: 'Which task do you wanna run now?',
|
||||||
working: (command) => `I'm working on ${command}...`,
|
working: (command) => `I'm working on ${command}...`,
|
||||||
finshed_working:"Done.",
|
finshed_working: 'Done.',
|
||||||
unknown_command: text =>
|
unknown_command: text =>
|
||||||
`Well, but ${text} is not a administrative General Bots command, I will try to search for it.`,
|
`Well, but ${text} is not a administrative General Bots command, I will try to search for it.`,
|
||||||
hi: text => `Hello, ${text}.`,
|
hi: text => `Hello, ${text}.`,
|
||||||
|
@ -13,10 +13,10 @@ export const Messages = {
|
||||||
redeployPackage: text => `Redeploying package ${text}...`,
|
redeployPackage: text => `Redeploying package ${text}...`,
|
||||||
packageUndeployed: text => `Package ${text} undeployed...`,
|
packageUndeployed: text => `Package ${text} undeployed...`,
|
||||||
consent: (url) => `Please, consent access to this app at: [Microsoft Online](${url}).`,
|
consent: (url) => `Please, consent access to this app at: [Microsoft Online](${url}).`,
|
||||||
wrong_password: "Sorry, wrong password. Please, try again."
|
wrong_password: 'Sorry, wrong password. Please, try again.'
|
||||||
},
|
},
|
||||||
"pt-BR": {
|
'pt-BR': {
|
||||||
show_video: "Vou te mostrar um vídeo. Por favor, aguarde...",
|
show_video: 'Vou te mostrar um vídeo. Por favor, aguarde...',
|
||||||
hi: msg => `Oi, ${msg}.`
|
hi: msg => `Oi, ${msg}.`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,33 +34,31 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
|
|
||||||
|
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||||
|
|
||||||
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
|
||||||
|
|
||||||
import { Sequelize } from "sequelize-typescript"
|
|
||||||
|
|
||||||
export class GBAnalyticsPackage implements IGBPackage {
|
export class GBAnalyticsPackage implements IGBPackage {
|
||||||
|
|
||||||
sysPackages: IGBPackage[] = null
|
public sysPackages: IGBPackage[] = null;
|
||||||
|
|
||||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
unloadPackage(core: IGBCoreService): void {
|
public unloadPackage(core: IGBCoreService): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
loadBot(min: GBMinInstance): void {
|
public loadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
unloadBot(min: GBMinInstance): void {
|
public unloadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
onNewSession(min: GBMinInstance, step: any): void {
|
public onNewSession(min: GBMinInstance, step: any): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,36 +34,36 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DataTypes,
|
|
||||||
DataTypeUUIDv4,
|
|
||||||
DataTypeDate,
|
DataTypeDate,
|
||||||
DataTypeDecimal
|
DataTypeDecimal,
|
||||||
} from "sequelize"
|
DataTypes,
|
||||||
|
DataTypeUUIDv4
|
||||||
|
} from 'sequelize';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Sequelize,
|
AutoIncrement,
|
||||||
Table,
|
|
||||||
Column,
|
|
||||||
Model,
|
|
||||||
HasMany,
|
|
||||||
BelongsTo,
|
BelongsTo,
|
||||||
BelongsToMany,
|
BelongsToMany,
|
||||||
Length,
|
Column,
|
||||||
ForeignKey,
|
|
||||||
CreatedAt,
|
CreatedAt,
|
||||||
UpdatedAt,
|
|
||||||
DataType,
|
DataType,
|
||||||
|
ForeignKey,
|
||||||
|
HasMany,
|
||||||
IsUUID,
|
IsUUID,
|
||||||
|
Length,
|
||||||
|
Model,
|
||||||
PrimaryKey,
|
PrimaryKey,
|
||||||
AutoIncrement
|
Sequelize,
|
||||||
} from "sequelize-typescript"
|
Table,
|
||||||
|
UpdatedAt
|
||||||
|
} from 'sequelize-typescript';
|
||||||
|
|
||||||
import { GuaribasSubject } from "../../kb.gbapp/models"
|
import { GuaribasChannel, GuaribasInstance } from '../../core.gbapp/models/GBModel';
|
||||||
import { GuaribasUser } from "../../security.gblib/models"
|
import { GuaribasSubject } from '../../kb.gbapp/models';
|
||||||
import { GuaribasChannel, GuaribasInstance } from "../../core.gbapp/models/GBModel"
|
import { GuaribasUser } from '../../security.gblib/models';
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
export class GuaribasConversation extends Model<GuaribasConversation> {
|
export class GuaribasConversation extends Model<GuaribasConversation> {
|
||||||
|
@ -71,40 +71,40 @@ export class GuaribasConversation extends Model<GuaribasConversation> {
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
conversationId: number
|
public conversationId: number;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasSubject)
|
@ForeignKey(() => GuaribasSubject)
|
||||||
@Column
|
@Column
|
||||||
startSubjectId: number
|
public startSubjectId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasSubject)
|
@BelongsTo(() => GuaribasSubject)
|
||||||
startSubject: GuaribasSubject
|
public startSubject: GuaribasSubject;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasChannel)
|
@ForeignKey(() => GuaribasChannel)
|
||||||
@Column
|
@Column
|
||||||
channelId: string
|
public channelId: string;
|
||||||
|
|
||||||
@Column rateDate: Date
|
@Column public rateDate: Date;
|
||||||
|
|
||||||
@Column(DataType.FLOAT)
|
@Column(DataType.FLOAT)
|
||||||
@Column
|
@Column
|
||||||
rate: number
|
public rate: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date
|
public createdAt: Date;
|
||||||
|
|
||||||
@Column text: string
|
@Column public text: string;
|
||||||
|
|
||||||
@HasMany(() => GuaribasConversationMessage)
|
@HasMany(() => GuaribasConversationMessage)
|
||||||
conversationMessage: GuaribasConversationMessage[]
|
public conversationMessage: GuaribasConversationMessage[];
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasUser)
|
@ForeignKey(() => GuaribasUser)
|
||||||
@Column
|
@Column
|
||||||
startedByUserId: number
|
public startedByUserId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasUser)
|
@BelongsTo(() => GuaribasUser)
|
||||||
startedBy: GuaribasUser
|
public startedBy: GuaribasUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
|
@ -113,38 +113,38 @@ export class GuaribasConversationMessage extends Model<GuaribasConversationMessa
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
conversationMessageId: number
|
public conversationMessageId: number;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasSubject)
|
@ForeignKey(() => GuaribasSubject)
|
||||||
@Column
|
@Column
|
||||||
subjectId: number
|
public subjectId: number;
|
||||||
|
|
||||||
@Column(DataType.TEXT)
|
@Column(DataType.TEXT)
|
||||||
content: string
|
public content: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date
|
public createdAt: Date;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date
|
public updatedAt: Date;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasConversation)
|
@ForeignKey(() => GuaribasConversation)
|
||||||
@Column
|
@Column
|
||||||
conversationId: number
|
public conversationId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasConversation)
|
@BelongsTo(() => GuaribasConversation)
|
||||||
conversation: GuaribasConversation
|
public conversation: GuaribasConversation;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
instanceId: number
|
public instanceId: number;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasUser)
|
@ForeignKey(() => GuaribasUser)
|
||||||
@Column
|
@Column
|
||||||
userId: number
|
public userId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasUser)
|
@BelongsTo(() => GuaribasUser)
|
||||||
user: GuaribasUser
|
public user: GuaribasUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,38 +34,38 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { GuaribasUser } from "../../security.gblib/models"
|
import { GuaribasUser } from '../../security.gblib/models';
|
||||||
import { GuaribasConversation, GuaribasConversationMessage } from "../models"
|
import { GuaribasConversation, GuaribasConversationMessage } from '../models';
|
||||||
|
|
||||||
export class AnalyticsService {
|
export class AnalyticsService {
|
||||||
async createConversation(
|
public async createConversation(
|
||||||
user: GuaribasUser
|
user: GuaribasUser
|
||||||
): Promise<GuaribasConversation> {
|
): Promise<GuaribasConversation> {
|
||||||
return new Promise<GuaribasConversation>(
|
return new Promise<GuaribasConversation>(
|
||||||
(resolve, reject) => {
|
(resolve, reject) => {
|
||||||
let conversation = new GuaribasConversation()
|
const conversation = new GuaribasConversation();
|
||||||
conversation.startedBy = user
|
conversation.startedBy = user;
|
||||||
conversation.startedByUserId = user.userId
|
conversation.startedByUserId = user.userId;
|
||||||
conversation.save().then((value: GuaribasConversation) => {
|
conversation.save().then((value: GuaribasConversation) => {
|
||||||
resolve(value)
|
resolve(value);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createMessage(
|
public createMessage(
|
||||||
conversation: GuaribasConversation,
|
conversation: GuaribasConversation,
|
||||||
user: GuaribasUser,
|
user: GuaribasUser,
|
||||||
content: string
|
content: string
|
||||||
): Promise<GuaribasConversationMessage> {
|
): Promise<GuaribasConversationMessage> {
|
||||||
return new Promise<GuaribasConversationMessage>(
|
return new Promise<GuaribasConversationMessage>(
|
||||||
(resolve, reject) => {
|
(resolve, reject) => {
|
||||||
let message = GuaribasConversationMessage.build()
|
const message = GuaribasConversationMessage.build();
|
||||||
message.conversation = conversation
|
message.conversation = conversation;
|
||||||
message.user = user
|
message.user = user;
|
||||||
message.content = content
|
message.content = content;
|
||||||
message.save().then((value: GuaribasConversationMessage) => {
|
message.save().then((value: GuaribasConversationMessage) => {
|
||||||
resolve(value)
|
resolve(value);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,13 +57,13 @@ export class BotFarmDialog extends IGBDialog {
|
||||||
'2',
|
'2',
|
||||||
'3',
|
'3',
|
||||||
'4',
|
'4',
|
||||||
'5',
|
'5'
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
async step => {
|
async step => {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
await step.context.sendActivity(Messages[locale].thanks);
|
await step.context.sendActivity(Messages[locale].thanks);
|
||||||
},
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
||||||
export const Messages = {
|
export const Messages = {
|
||||||
"en-US": {
|
'en-US': {
|
||||||
about_suggestions: "Suggestions are welcomed and improve my quality...",
|
about_suggestions: 'Suggestions are welcomed and improve my quality...'
|
||||||
},
|
},
|
||||||
"pt-BR": {
|
'pt-BR': {
|
||||||
about_suggestions: "Sugestões melhoram muito minha qualidade...",
|
about_suggestions: 'Sugestões melhoram muito minha qualidade...'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,32 +34,32 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
|
|
||||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||||
|
|
||||||
import { Sequelize } from 'sequelize-typescript'
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
import { ConsoleDirectLine } from "./services/ConsoleDirectLine"
|
import { ConsoleDirectLine } from './services/ConsoleDirectLine';
|
||||||
|
|
||||||
export class GBConsolePackage implements IGBPackage {
|
export class GBConsolePackage implements IGBPackage {
|
||||||
sysPackages: IGBPackage[] = null
|
public sysPackages: IGBPackage[] = null;
|
||||||
channel: ConsoleDirectLine
|
public channel: ConsoleDirectLine;
|
||||||
|
|
||||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadPackage(core: IGBCoreService): void {
|
public unloadPackage(core: IGBCoreService): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBot(min: GBMinInstance): void {
|
public loadBot(min: GBMinInstance): void {
|
||||||
this.channel = new ConsoleDirectLine(min.instance.webchatKey)
|
this.channel = new ConsoleDirectLine(min.instance.webchatKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadBot(min: GBMinInstance): void {
|
public unloadBot(min: GBMinInstance): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewSession(min: GBMinInstance, step: any): void {
|
public onNewSession(min: GBMinInstance, step: any): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,76 +30,75 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
const Path = require("path")
|
const Path = require('path');
|
||||||
const Fs = require("fs")
|
const Fs = require('fs');
|
||||||
const _ = require("lodash")
|
const _ = require('lodash');
|
||||||
const Parse = require("csv-parse")
|
const Parse = require('csv-parse');
|
||||||
const Async = require("async")
|
const Async = require('async');
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
const Walk = require("fs-walk")
|
const Walk = require('fs-walk');
|
||||||
const logger = require("../../../src/logger")
|
const logger = require('../../../src/logger');
|
||||||
const Swagger = require('swagger-client')
|
const Swagger = require('swagger-client');
|
||||||
const rp = require('request-promise')
|
const rp = require('request-promise');
|
||||||
import { GBService } from "botlib"
|
import { GBService } from 'botlib';
|
||||||
|
|
||||||
export class ConsoleDirectLine extends GBService {
|
export class ConsoleDirectLine extends GBService {
|
||||||
|
|
||||||
pollInterval = 1000
|
public pollInterval = 1000;
|
||||||
directLineSecret = ''
|
public directLineSecret = '';
|
||||||
directLineClientName = 'DirectLineClient'
|
public directLineClientName = 'DirectLineClient';
|
||||||
directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json'
|
public directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json';
|
||||||
|
|
||||||
constructor(directLineSecret) {
|
constructor(directLineSecret) {
|
||||||
super()
|
super();
|
||||||
|
|
||||||
this.directLineSecret = directLineSecret
|
|
||||||
|
|
||||||
|
this.directLineSecret = directLineSecret;
|
||||||
|
|
||||||
// TODO: Migrate to Swagger 3.
|
// TODO: Migrate to Swagger 3.
|
||||||
let directLineClient = rp(this.directLineSpecUrl)
|
const directLineClient = rp(this.directLineSpecUrl)
|
||||||
.then(function (spec) {
|
.then(function (spec) {
|
||||||
return new Swagger({
|
return new Swagger({
|
||||||
spec: JSON.parse(spec.trim()),
|
spec: JSON.parse(spec.trim()),
|
||||||
usePromise: true
|
usePromise: true
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.then(function (client) {
|
.then(function (client) {
|
||||||
client.clientAuthorizations.add('AuthorizationBotConnector',
|
client.clientAuthorizations.add('AuthorizationBotConnector',
|
||||||
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + directLineSecret, 'header'))
|
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + directLineSecret, 'header'));
|
||||||
return client
|
return client;
|
||||||
})
|
})
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
console.error('Error initializing DirectLine client', err)
|
console.error('Error initializing DirectLine client', err);
|
||||||
})
|
});
|
||||||
|
|
||||||
// TODO: Remove *this* issue.
|
// TODO: Remove *this* issue.
|
||||||
let _this_ = this
|
const _this_ = this;
|
||||||
directLineClient.then((client) => {
|
directLineClient.then((client) => {
|
||||||
client.Conversations.Conversations_StartConversation()
|
client.Conversations.Conversations_StartConversation()
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
return response.obj.conversationId
|
return response.obj.conversationId;
|
||||||
})
|
})
|
||||||
.then(function (conversationId) {
|
.then(function (conversationId) {
|
||||||
_this_.sendMessagesFromConsole(client, conversationId)
|
_this_.sendMessagesFromConsole(client, conversationId);
|
||||||
_this_.pollMessages(client, conversationId)
|
_this_.pollMessages(client, conversationId);
|
||||||
})
|
})
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
console.error('Error starting conversation', err)
|
console.error('Error starting conversation', err);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessagesFromConsole(client, conversationId) {
|
public sendMessagesFromConsole(client, conversationId) {
|
||||||
let _this_ = this
|
const _this_ = this;
|
||||||
process.stdin.resume()
|
process.stdin.resume();
|
||||||
var stdin = process.stdin
|
const stdin = process.stdin;
|
||||||
process.stdout.write('Command> ')
|
process.stdout.write('Command> ');
|
||||||
stdin.addListener('data', function (e) {
|
stdin.addListener('data', function (e) {
|
||||||
var input = e.toString().trim()
|
const input = e.toString().trim();
|
||||||
if (input) {
|
if (input) {
|
||||||
// exit
|
// exit
|
||||||
if (input.toLowerCase() === 'exit') {
|
if (input.toLowerCase() === 'exit') {
|
||||||
return process.exit()
|
return process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
client.Conversations.Conversations_PostActivity(
|
client.Conversations.Conversations_PostActivity(
|
||||||
|
@ -115,80 +114,80 @@ export class ConsoleDirectLine extends GBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
console.error('Error sending message:', err)
|
console.error('Error sending message:', err);
|
||||||
})
|
});
|
||||||
|
|
||||||
process.stdout.write('Command> ')
|
process.stdout.write('Command> ');
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** TBD: Poll Messages from conversation using DirectLine client */
|
/** TBD: Poll Messages from conversation using DirectLine client */
|
||||||
pollMessages(client, conversationId) {
|
public pollMessages(client, conversationId) {
|
||||||
let _this_ = this
|
const _this_ = this;
|
||||||
console.log('Starting polling message for conversationId: ' + conversationId)
|
console.log('Starting polling message for conversationId: ' + conversationId);
|
||||||
var watermark = null
|
let watermark = null;
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
client.Conversations.Conversations_GetActivities({ conversationId: conversationId, watermark: watermark })
|
client.Conversations.Conversations_GetActivities({ conversationId: conversationId, watermark: watermark })
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
watermark = response.obj.watermark // use watermark so subsequent requests skip old messages
|
watermark = response.obj.watermark; // use watermark so subsequent requests skip old messages
|
||||||
return response.obj.activities
|
return response.obj.activities;
|
||||||
})
|
})
|
||||||
.then(_this_.printMessages, _this_.directLineClientName)
|
.then(_this_.printMessages, _this_.directLineClientName);
|
||||||
}, this.pollInterval)
|
}, this.pollInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
printMessages(activities, directLineClientName) {
|
public printMessages(activities, directLineClientName) {
|
||||||
|
|
||||||
if (activities && activities.length) {
|
if (activities && activities.length) {
|
||||||
// ignore own messages
|
// ignore own messages
|
||||||
activities = activities.filter(function (m) { return m.from.id !== directLineClientName })
|
activities = activities.filter(function (m) { return m.from.id !== directLineClientName; });
|
||||||
|
|
||||||
if (activities.length) {
|
if (activities.length) {
|
||||||
|
|
||||||
// print other messages
|
// print other messages
|
||||||
activities.forEach(activity => {
|
activities.forEach(activity => {
|
||||||
console.log(activity.text)
|
console.log(activity.text);
|
||||||
}, this)
|
}, this);
|
||||||
|
|
||||||
process.stdout.write('Command> ')
|
process.stdout.write('Command> ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printMessage(activity) {
|
public printMessage(activity) {
|
||||||
if (activity.text) {
|
if (activity.text) {
|
||||||
console.log(activity.text)
|
console.log(activity.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.attachments) {
|
if (activity.attachments) {
|
||||||
activity.attachments.forEach(function (attachment) {
|
activity.attachments.forEach(function (attachment) {
|
||||||
switch (attachment.contentType) {
|
switch (attachment.contentType) {
|
||||||
case "application/vnd.microsoft.card.hero":
|
case 'application/vnd.microsoft.card.hero':
|
||||||
this.renderHeroCard(attachment)
|
this.renderHeroCard(attachment);
|
||||||
break
|
break;
|
||||||
|
|
||||||
case "image/png":
|
case 'image/png':
|
||||||
console.log('Opening the requested image ' + attachment.contentUrl)
|
console.log('Opening the requested image ' + attachment.contentUrl);
|
||||||
open(attachment.contentUrl)
|
open(attachment.contentUrl);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHeroCard(attachment) {
|
public renderHeroCard(attachment) {
|
||||||
var width = 70
|
const width = 70;
|
||||||
var contentLine = function (content) {
|
const contentLine = function (content) {
|
||||||
return ' '.repeat((width - content.length) / 2) +
|
return ' '.repeat((width - content.length) / 2) +
|
||||||
content +
|
content +
|
||||||
' '.repeat((width - content.length) / 2)
|
' '.repeat((width - content.length) / 2);
|
||||||
}
|
};
|
||||||
|
|
||||||
console.log('/' + '*'.repeat(width + 1))
|
console.log('/' + '*'.repeat(width + 1));
|
||||||
console.log('*' + contentLine(attachment.content.title) + '*')
|
console.log('*' + contentLine(attachment.content.title) + '*');
|
||||||
console.log('*' + ' '.repeat(width) + '*')
|
console.log('*' + ' '.repeat(width) + '*');
|
||||||
console.log('*' + contentLine(attachment.content.text) + '*')
|
console.log('*' + contentLine(attachment.content.text) + '*');
|
||||||
console.log('*'.repeat(width + 1) + '/')
|
console.log('*'.repeat(width + 1) + '/');
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,11 +36,11 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { IGBDialog } from "botlib";
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { GBMinInstance } from "botlib";
|
import {WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import { BotAdapter } from "botbuilder";
|
import { IGBDialog } from 'botlib';
|
||||||
import {WaterfallDialog } from "botbuilder-dialogs";
|
import { GBMinInstance } from 'botlib';
|
||||||
import { Messages } from "../strings";
|
import { Messages } from '../strings';
|
||||||
|
|
||||||
export class WelcomeDialog extends IGBDialog {
|
export class WelcomeDialog extends IGBDialog {
|
||||||
/**
|
/**
|
||||||
|
@ -49,9 +49,9 @@ export class WelcomeDialog extends IGBDialog {
|
||||||
* @param bot The bot adapter.
|
* @param bot The bot adapter.
|
||||||
* @param min The minimal bot instance data.
|
* @param min The minimal bot instance data.
|
||||||
*/
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
min.dialogs.add(new WaterfallDialog("/", [
|
min.dialogs.add(new WaterfallDialog('/', [
|
||||||
async step => {
|
async step => {
|
||||||
|
|
||||||
const user = await min.userProfile.get(context, {});
|
const user = await min.userProfile.get(context, {});
|
||||||
|
@ -60,9 +60,9 @@ export class WelcomeDialog extends IGBDialog {
|
||||||
if (!user.once) {
|
if (!user.once) {
|
||||||
user.once = true;
|
user.once = true;
|
||||||
await min.userProfile.set(step.context, user);
|
await min.userProfile.set(step.context, user);
|
||||||
var a = new Date();
|
const a = new Date();
|
||||||
const date = a.getHours();
|
const date = a.getHours();
|
||||||
var msg =
|
const msg =
|
||||||
date < 12
|
date < 12
|
||||||
? Messages[locale].good_morning
|
? Messages[locale].good_morning
|
||||||
: date < 18
|
: date < 18
|
||||||
|
@ -70,18 +70,18 @@ export class WelcomeDialog extends IGBDialog {
|
||||||
: Messages[locale].good_night;
|
: Messages[locale].good_night;
|
||||||
|
|
||||||
await step.context.sendActivity(Messages[locale].hi(msg));
|
await step.context.sendActivity(Messages[locale].hi(msg));
|
||||||
await step.replaceDialog("/ask", { firstTime: true });
|
await step.replaceDialog('/ask', { firstTime: true });
|
||||||
|
|
||||||
if (
|
if (
|
||||||
step.context.activity &&
|
step.context.activity &&
|
||||||
step.context.activity.type == "message" &&
|
step.context.activity.type == 'message' &&
|
||||||
step.context.activity.text != ""
|
step.context.activity.text != ''
|
||||||
) {
|
) {
|
||||||
await step.replaceDialog("/answer", { query: step.context.activity.text });
|
await step.replaceDialog('/answer', { query: step.context.activity.text });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
]))
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,11 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { IGBDialog } from "botlib";
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { GBMinInstance } from "botlib";
|
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import { BotAdapter } from "botbuilder";
|
import { IGBDialog } from 'botlib';
|
||||||
import { Messages } from "../strings";
|
import { GBMinInstance } from 'botlib';
|
||||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
import { Messages } from '../strings';
|
||||||
|
|
||||||
export class WhoAmIDialog extends IGBDialog {
|
export class WhoAmIDialog extends IGBDialog {
|
||||||
/**
|
/**
|
||||||
|
@ -49,21 +49,21 @@ export class WhoAmIDialog extends IGBDialog {
|
||||||
* @param bot The bot adapter.
|
* @param bot The bot adapter.
|
||||||
* @param min The minimal bot instance data.
|
* @param min The minimal bot instance data.
|
||||||
*/
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
min.dialogs.add(new WaterfallDialog("/whoAmI", [
|
min.dialogs.add(new WaterfallDialog('/whoAmI', [
|
||||||
async step => {
|
async step => {
|
||||||
let locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
await step.context.sendActivity(`${min.instance.description}`);
|
await step.context.sendActivity(`${min.instance.description}`);
|
||||||
|
|
||||||
if (min.instance.whoAmIVideo) {
|
if (min.instance.whoAmIVideo) {
|
||||||
await step.context.sendActivity(Messages[locale].show_video);
|
await step.context.sendActivity(Messages[locale].show_video);
|
||||||
await min.conversationalService.sendEvent(step, "play", {
|
await min.conversationalService.sendEvent(step, 'play', {
|
||||||
playerType: "video",
|
playerType: 'video',
|
||||||
data: min.instance.whoAmIVideo.trim()
|
data: min.instance.whoAmIVideo.trim()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await step.replaceDialog("/ask", { isReturning: true });
|
await step.replaceDialog('/ask', { isReturning: true });
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
]));
|
]));
|
||||||
|
|
|
@ -34,44 +34,44 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
|
|
||||||
import { GBMinInstance, IGBPackage } from "botlib"
|
import { GBMinInstance, IGBPackage } from 'botlib';
|
||||||
|
|
||||||
import { WelcomeDialog } from "./dialogs/WelcomeDialog"
|
import { IGBCoreService} from 'botlib';
|
||||||
import { WhoAmIDialog } from "./dialogs/WhoAmIDialog"
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
import { IGBCoreService} from "botlib"
|
import { WelcomeDialog } from './dialogs/WelcomeDialog';
|
||||||
import { Sequelize } from "sequelize-typescript"
|
import { WhoAmIDialog } from './dialogs/WhoAmIDialog';
|
||||||
import { GuaribasInstance, GuaribasException, GuaribasPackage, GuaribasChannel } from "./models/GBModel"
|
import { GuaribasChannel, GuaribasException, GuaribasInstance, GuaribasPackage } from './models/GBModel';
|
||||||
|
|
||||||
export class GBCorePackage implements IGBPackage {
|
export class GBCorePackage implements IGBPackage {
|
||||||
sysPackages: IGBPackage[] = null
|
public static CurrentEngineName = 'guaribas-1.0.0';
|
||||||
public static CurrentEngineName = "guaribas-1.0.0";
|
public sysPackages: IGBPackage[] = null;
|
||||||
|
|
||||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||||
core.sequelize.addModels([
|
core.sequelize.addModels([
|
||||||
GuaribasInstance,
|
GuaribasInstance,
|
||||||
GuaribasPackage,
|
GuaribasPackage,
|
||||||
GuaribasChannel,
|
GuaribasChannel,
|
||||||
GuaribasException,
|
GuaribasException
|
||||||
])
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadPackage(core: IGBCoreService): void {
|
public unloadPackage(core: IGBCoreService): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBot(min: GBMinInstance): void {
|
public loadBot(min: GBMinInstance): void {
|
||||||
WelcomeDialog.setup(min.bot, min)
|
WelcomeDialog.setup(min.bot, min);
|
||||||
WhoAmIDialog.setup(min.bot, min)
|
WhoAmIDialog.setup(min.bot, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadBot(min: GBMinInstance): void {
|
public unloadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
onNewSession(min: GBMinInstance, step: any): void {
|
public onNewSession(min: GBMinInstance, step: any): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,21 +36,20 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Table,
|
AutoIncrement,
|
||||||
Column,
|
|
||||||
Model,
|
|
||||||
BelongsTo,
|
BelongsTo,
|
||||||
ForeignKey,
|
Column,
|
||||||
CreatedAt,
|
CreatedAt,
|
||||||
UpdatedAt,
|
|
||||||
DataType,
|
DataType,
|
||||||
|
ForeignKey,
|
||||||
|
Model,
|
||||||
PrimaryKey,
|
PrimaryKey,
|
||||||
AutoIncrement
|
Table,
|
||||||
} from "sequelize-typescript";
|
UpdatedAt
|
||||||
|
} from 'sequelize-typescript';
|
||||||
|
|
||||||
import { IGBInstance } from "botlib";
|
import { IGBInstance } from 'botlib';
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
export class GuaribasInstance extends Model<GuaribasInstance>
|
export class GuaribasInstance extends Model<GuaribasInstance>
|
||||||
|
@ -58,185 +57,185 @@ export class GuaribasInstance extends Model<GuaribasInstance>
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
instanceId: number;
|
public instanceId: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
botEndpoint: string;
|
public botEndpoint: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
whoAmIVideo: string;
|
public whoAmIVideo: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
botId: string;
|
public botId: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
title: string;
|
public title: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
description: string;
|
public description: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
version: string;
|
public version: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
enabledAdmin: boolean;
|
public enabledAdmin: boolean;
|
||||||
|
|
||||||
/* Services section on bot.json */
|
/* Services section on bot.json */
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
engineName: string;
|
public engineName: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
marketplaceId: string;
|
public marketplaceId: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
textAnalyticsKey: string;
|
public textAnalyticsKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
textAnalyticsEndpoint: string;
|
public textAnalyticsEndpoint: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
marketplacePassword: string;
|
public marketplacePassword: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
webchatKey: string;
|
public webchatKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
authenticatorTenant: string;
|
public authenticatorTenant: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
authenticatorAuthorityHostUrl: string;
|
public authenticatorAuthorityHostUrl: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
authenticatorClientId: string;
|
public authenticatorClientId: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
authenticatorClientSecret: string;
|
public authenticatorClientSecret: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
cloudSubscriptionId: string;
|
public cloudSubscriptionId: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
cloudUsername: string;
|
public cloudUsername: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
cloudPassword: string;
|
public cloudPassword: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
cloudLocation: string;
|
public cloudLocation: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
whatsappBotKey: string;
|
public whatsappBotKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
whatsappServiceKey: string;
|
public whatsappServiceKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
whatsappServiceNumber: string;
|
public whatsappServiceNumber: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
whatsappServiceUrl: string;
|
public whatsappServiceUrl: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
whatsappServiceWebhookUrl: string;
|
public whatsappServiceWebhookUrl: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
smsKey: string;
|
public smsKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
smsSecret: string;
|
public smsSecret: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
smsServiceNumber: string;
|
public smsServiceNumber: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
speechKey: string;
|
public speechKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
speechKeyEndpoint: string;
|
public speechKeyEndpoint: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
spellcheckerKey: string;
|
public spellcheckerKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
spellcheckerEndpoint: string;
|
public spellcheckerEndpoint: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
theme: string;
|
public theme: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
ui: string;
|
public ui: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
kb: string;
|
public kb: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
nlpAppId: string;
|
public nlpAppId: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
nlpKey: string;
|
public nlpKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@Column({ type: DataType.STRING(512) })
|
@Column({ type: DataType.STRING(512) })
|
||||||
nlpEndpoint: string;
|
public nlpEndpoint: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
nlpAuthoringKey: string;
|
public nlpAuthoringKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
deploymentPaths: string;
|
public deploymentPaths: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
searchHost: string;
|
public searchHost: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
searchKey: string;
|
public searchKey: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
searchIndex: string;
|
public searchIndex: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
searchIndexer: string;
|
public searchIndexer: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
storageUsername: string;
|
public storageUsername: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
storagePassword: string;
|
public storagePassword: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
storageName: string;
|
public storageName: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
storageServer: string;
|
public storageServer: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
storageDialect: string;
|
public storageDialect: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
storagePath: string;
|
public storagePath: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
adminPass: string;
|
public adminPass: string;
|
||||||
|
|
||||||
/* Settings section of bot.json */
|
/* Settings section of bot.json */
|
||||||
|
|
||||||
@Column(DataType.FLOAT)
|
@Column(DataType.FLOAT)
|
||||||
nlpVsSearch: number;
|
public nlpVsSearch: number;
|
||||||
|
|
||||||
@Column(DataType.FLOAT)
|
@Column(DataType.FLOAT)
|
||||||
searchScore: number;
|
public searchScore: number;
|
||||||
|
|
||||||
@Column(DataType.FLOAT)
|
@Column(DataType.FLOAT)
|
||||||
nlpScore: number;
|
public nlpScore: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
public createdAt: Date;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
public updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
|
@ -244,25 +243,25 @@ export class GuaribasPackage extends Model<GuaribasPackage> {
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
packageId: number;
|
public packageId: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
packageName: string;
|
public packageName: string;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
instanceId: number;
|
public instanceId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasInstance)
|
@BelongsTo(() => GuaribasInstance)
|
||||||
instance: GuaribasInstance;
|
public instance: GuaribasInstance;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
public createdAt: Date;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
public updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
|
@ -270,18 +269,18 @@ export class GuaribasChannel extends Model<GuaribasChannel> {
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
channelId: number;
|
public channelId: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
title: string;
|
public title: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
public createdAt: Date;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
public updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
|
@ -289,23 +288,23 @@ export class GuaribasException extends Model<GuaribasException> {
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
exceptionId: number;
|
public exceptionId: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
message: string;
|
public message: string;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
instanceId: number;
|
public instanceId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasInstance)
|
@BelongsTo(() => GuaribasInstance)
|
||||||
instance: GuaribasInstance;
|
public instance: GuaribasInstance;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
public createdAt: Date;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
public updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,20 +30,20 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require('../../../src/logger');
|
||||||
import * as fs from "fs";
|
import * as fs from 'fs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
export class GBConfigService {
|
export class GBConfigService {
|
||||||
static init(): any {
|
public static init(): any {
|
||||||
try {
|
try {
|
||||||
require("dotenv-extended").load({
|
require('dotenv-extended').load({
|
||||||
path: ".env",
|
path: '.env',
|
||||||
errorOnMissing: true,
|
errorOnMissing: true,
|
||||||
errorOnExtra: false,
|
errorOnExtra: false,
|
||||||
overrideProcessEnv: true
|
overrideProcessEnv: true
|
||||||
|
@ -54,52 +54,52 @@ export class GBConfigService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get(key: string): string | undefined {
|
public static get(key: string): string | undefined {
|
||||||
let value = GBConfigService.tryGet(key);
|
let value = GBConfigService.tryGet(key);
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "CLOUD_USERNAME":
|
case 'CLOUD_USERNAME':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "BOT_ID":
|
case 'BOT_ID':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "CLOUD_PASSWORD":
|
case 'CLOUD_PASSWORD':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "CLOUD_SUBSCRIPTIONID":
|
case 'CLOUD_SUBSCRIPTIONID':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "CLOUD_LOCATION":
|
case 'CLOUD_LOCATION':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "NLP_AUTHORING_KEY":
|
case 'NLP_AUTHORING_KEY':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "STORAGE_DIALECT":
|
case 'STORAGE_DIALECT':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "STORAGE_STORAGE":
|
case 'STORAGE_STORAGE':
|
||||||
value = "./guaribas.sqlite";
|
value = './guaribas.sqlite';
|
||||||
break;
|
break;
|
||||||
case "ADDITIONAL_DEPLOY_PATH":
|
case 'ADDITIONAL_DEPLOY_PATH':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "STORAGE_SYNC":
|
case 'STORAGE_SYNC':
|
||||||
value = "false";
|
value = 'false';
|
||||||
break;
|
break;
|
||||||
case "STORAGE_SYNC_ALTER":
|
case 'STORAGE_SYNC_ALTER':
|
||||||
value = "false";
|
value = 'false';
|
||||||
break;
|
break;
|
||||||
case "STORAGE_SYNC_FORCE":
|
case 'STORAGE_SYNC_FORCE':
|
||||||
value = "false";
|
value = 'false';
|
||||||
break;
|
break;
|
||||||
case "STORAGE_LOGGING":
|
case 'STORAGE_LOGGING':
|
||||||
value = "false";
|
value = 'false';
|
||||||
break;
|
break;
|
||||||
case "STORAGE_ENCRYPT":
|
case 'STORAGE_ENCRYPT':
|
||||||
value = "true";
|
value = 'true';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.warn(`Invalid key on .env file: '${key}'`);
|
logger.warn(`Invalid key on .env file: '${key}'`);
|
||||||
|
@ -110,7 +110,7 @@ export class GBConfigService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static tryGet(key: string) {
|
public static tryGet(key: string) {
|
||||||
let value = process.env["container:" + key];
|
let value = process.env['container:' + key];
|
||||||
if (!value) {
|
if (!value) {
|
||||||
value = process.env[key];
|
value = process.env[key];
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,17 +36,17 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require('../../../src/logger');
|
||||||
|
|
||||||
import { GBCoreService } from "./GBCoreService";
|
import { any } from 'bluebird';
|
||||||
import { IGBConversationalService } from "botlib";
|
import { MessageFactory } from 'botbuilder';
|
||||||
import { GBMinInstance } from "botlib";
|
import { LuisRecognizer } from 'botbuilder-ai';
|
||||||
import { LuisRecognizer } from "botbuilder-ai";
|
import { IGBConversationalService } from 'botlib';
|
||||||
import { MessageFactory } from "botbuilder";
|
import { GBMinInstance } from 'botlib';
|
||||||
import { Messages } from "../strings";
|
import { AzureText } from 'pragmatismo-io-framework';
|
||||||
import { AzureText } from "pragmatismo-io-framework";
|
import { Messages } from '../strings';
|
||||||
import { any } from "bluebird";
|
import { GBCoreService } from './GBCoreService';
|
||||||
const Nexmo = require("nexmo");
|
const Nexmo = require('nexmo');
|
||||||
|
|
||||||
export interface LanguagePickerSettings {
|
export interface LanguagePickerSettings {
|
||||||
defaultLocale?: string;
|
defaultLocale?: string;
|
||||||
|
@ -54,27 +54,27 @@ export interface LanguagePickerSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GBConversationalService implements IGBConversationalService {
|
export class GBConversationalService implements IGBConversationalService {
|
||||||
coreService: GBCoreService;
|
public coreService: GBCoreService;
|
||||||
|
|
||||||
constructor(coreService: GBCoreService) {
|
constructor(coreService: GBCoreService) {
|
||||||
this.coreService = coreService;
|
this.coreService = coreService;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentLanguage(step: any) {
|
public getCurrentLanguage(step: any) {
|
||||||
return step.context.activity.locale;
|
return step.context.activity.locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendEvent(step: any, name: string, value: any): Promise<any> {
|
public async sendEvent(step: any, name: string, value: any): Promise<any> {
|
||||||
if (step.context.activity.channelId === "webchat") {
|
if (step.context.activity.channelId === 'webchat') {
|
||||||
const msg = MessageFactory.text("");
|
const msg = MessageFactory.text('');
|
||||||
msg.value = value;
|
msg.value = value;
|
||||||
msg.type = "event";
|
msg.type = 'event';
|
||||||
msg.name = name;
|
msg.name = name;
|
||||||
return step.context.sendActivity(msg);
|
return step.context.sendActivity(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendSms(
|
public async sendSms(
|
||||||
min: GBMinInstance,
|
min: GBMinInstance,
|
||||||
mobile: string,
|
mobile: string,
|
||||||
text: string
|
text: string
|
||||||
|
@ -99,7 +99,7 @@ export class GBConversationalService implements IGBConversationalService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async routeNLP(step: any, min: GBMinInstance, text: string): Promise<boolean> {
|
public async routeNLP(step: any, min: GBMinInstance, text: string): Promise<boolean> {
|
||||||
// Invokes LUIS.
|
// Invokes LUIS.
|
||||||
|
|
||||||
const model = new LuisRecognizer({
|
const model = new LuisRecognizer({
|
||||||
|
@ -113,12 +113,11 @@ export class GBConversationalService implements IGBConversationalService {
|
||||||
nlp = await model.recognize(step.context);
|
nlp = await model.recognize(step.context);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.statusCode == 404) {
|
if (error.statusCode == 404) {
|
||||||
logger.warn ('NLP application still not publish and there are no other options for answering.')
|
logger.warn ('NLP application still not publish and there are no other options for answering.');
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
} else {
|
||||||
else{
|
const msg = `Error calling NLP server, check if you have a published model and assigned keys on the service. Error: ${
|
||||||
let msg = `Error calling NLP server, check if you have a published model and assigned keys on the service. Error: ${
|
error.statusCode ? error.statusCode : ''
|
||||||
error.statusCode ? error.statusCode : ""
|
|
||||||
} ${error.message}`;
|
} ${error.message}`;
|
||||||
return Promise.reject(new Error(msg)); }
|
return Promise.reject(new Error(msg)); }
|
||||||
|
|
||||||
|
@ -126,25 +125,25 @@ export class GBConversationalService implements IGBConversationalService {
|
||||||
|
|
||||||
// Resolves intents returned from LUIS.
|
// Resolves intents returned from LUIS.
|
||||||
|
|
||||||
let topIntent = LuisRecognizer.topIntent(nlp);
|
const topIntent = LuisRecognizer.topIntent(nlp);
|
||||||
if (topIntent) {
|
if (topIntent) {
|
||||||
var intent = topIntent;
|
const intent = topIntent;
|
||||||
var entity =
|
const entity =
|
||||||
nlp.entities && nlp.entities.length > 0
|
nlp.entities && nlp.entities.length > 0
|
||||||
? nlp.entities[0].entity.toUpperCase()
|
? nlp.entities[0].entity.toUpperCase()
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (intent === "None") {
|
if (intent === 'None') {
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("NLP called:" + intent + ", " + entity);
|
logger.info('NLP called:' + intent + ', ' + entity);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await step.replace("/" + intent, nlp.entities);
|
await step.replace('/' + intent, nlp.entities);
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let msg = `Error finding dialog associated to NLP event: ${intent}: ${
|
const msg = `Error finding dialog associated to NLP event: ${intent}: ${
|
||||||
error.message
|
error.message
|
||||||
}`;
|
}`;
|
||||||
return Promise.reject(new Error(msg));
|
return Promise.reject(new Error(msg));
|
||||||
|
@ -153,20 +152,20 @@ export class GBConversationalService implements IGBConversationalService {
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkLanguage(step, min, text) {
|
public async checkLanguage(step, min, text) {
|
||||||
let locale = await AzureText.getLocale(
|
const locale = await AzureText.getLocale(
|
||||||
min.instance.textAnalyticsKey,
|
min.instance.textAnalyticsKey,
|
||||||
min.instance.textAnalyticsEndpoint,
|
min.instance.textAnalyticsEndpoint,
|
||||||
text
|
text
|
||||||
);
|
);
|
||||||
if (locale != step.context.activity.locale.split("-")[0]) {
|
if (locale != step.context.activity.locale.split('-')[0]) {
|
||||||
switch (locale) {
|
switch (locale) {
|
||||||
case "pt":
|
case 'pt':
|
||||||
step.context.activity.locale = "pt-BR";
|
step.context.activity.locale = 'pt-BR';
|
||||||
await step.context.sendActivity(Messages[locale].changing_language);
|
await step.context.sendActivity(Messages[locale].changing_language);
|
||||||
break;
|
break;
|
||||||
case "en":
|
case 'en':
|
||||||
step.context.activity.locale = "en-US";
|
step.context.activity.locale = 'en-US';
|
||||||
await step.context.sendActivity(Messages[locale].changing_language);
|
await step.context.sendActivity(Messages[locale].changing_language);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -70,7 +70,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
private createTableQuery: (
|
private createTableQuery: (
|
||||||
tableName: string,
|
tableName: string,
|
||||||
attributes: any,
|
attributes: any,
|
||||||
options: any,
|
options: any
|
||||||
) => string;
|
) => string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,15 +136,15 @@ export class GBCoreService implements IGBCoreService {
|
||||||
dialect: this.dialect,
|
dialect: this.dialect,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
dialectOptions: {
|
dialectOptions: {
|
||||||
encrypt: encrypt,
|
encrypt: encrypt
|
||||||
},
|
},
|
||||||
pool: {
|
pool: {
|
||||||
max: 32,
|
max: 32,
|
||||||
min: 8,
|
min: 8,
|
||||||
idle: 40000,
|
idle: 40000,
|
||||||
evict: 40000,
|
evict: 40000,
|
||||||
acquire: 40000,
|
acquire: 40000
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.dialect === 'mssql') {
|
if (this.dialect === 'mssql') {
|
||||||
|
@ -153,7 +153,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
this.queryGenerator.createTableQuery = (
|
this.queryGenerator.createTableQuery = (
|
||||||
tableName,
|
tableName,
|
||||||
attributes,
|
attributes,
|
||||||
options,
|
options
|
||||||
) => this.createTableQueryOverride(tableName, attributes, options);
|
) => this.createTableQueryOverride(tableName, attributes, options);
|
||||||
this.changeColumnQuery = this.queryGenerator.changeColumnQuery;
|
this.changeColumnQuery = this.queryGenerator.changeColumnQuery;
|
||||||
this.queryGenerator.changeColumnQuery = (tableName, attributes) =>
|
this.queryGenerator.changeColumnQuery = (tableName, attributes) =>
|
||||||
|
@ -163,7 +163,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
logger.info('Syncing database...');
|
logger.info('Syncing database...');
|
||||||
return this.sequelize.sync({
|
return this.sequelize.sync({
|
||||||
alter: alter,
|
alter: alter,
|
||||||
force: force,
|
force: force
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const msg = 'Database synchronization is disabled.';
|
const msg = 'Database synchronization is disabled.';
|
||||||
|
@ -257,7 +257,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
let sql: string = this.createTableQuery.apply(this.queryGenerator, [
|
let sql: string = this.createTableQuery.apply(this.queryGenerator, [
|
||||||
tableName,
|
tableName,
|
||||||
attributes,
|
attributes,
|
||||||
options,
|
options
|
||||||
]);
|
]);
|
||||||
const re1 = /CREATE\s+TABLE\s+\[([^\]]*)\]/;
|
const re1 = /CREATE\s+TABLE\s+\[([^\]]*)\]/;
|
||||||
const matches = re1.exec(sql);
|
const matches = re1.exec(sql);
|
||||||
|
@ -268,7 +268,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
re2,
|
re2,
|
||||||
(match: string, ...args: any[]): string => {
|
(match: string, ...args: any[]): string => {
|
||||||
return 'CONSTRAINT [' + table + '_pk] ' + match;
|
return 'CONSTRAINT [' + table + '_pk] ' + match;
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
const re3 = /FOREIGN\s+KEY\s+\((\[[^\]]*\](?:,\s*\[[^\]]*\])*)\)/g;
|
const re3 = /FOREIGN\s+KEY\s+\((\[[^\]]*\](?:,\s*\[[^\]]*\])*)\)/g;
|
||||||
const re4 = /\[([^\]]*)\]/g;
|
const re4 = /\[([^\]]*)\]/g;
|
||||||
|
@ -283,7 +283,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
matches = re4.exec(fkcols);
|
matches = re4.exec(fkcols);
|
||||||
}
|
}
|
||||||
return 'CONSTRAINT [' + fkname + '_fk] FOREIGN KEY (' + fkcols + ')';
|
return 'CONSTRAINT [' + fkname + '_fk] FOREIGN KEY (' + fkcols + ')';
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return sql;
|
return sql;
|
||||||
|
@ -300,7 +300,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
private changeColumnQueryOverride(tableName, attributes): string {
|
private changeColumnQueryOverride(tableName, attributes): string {
|
||||||
let sql: string = this.changeColumnQuery.apply(this.queryGenerator, [
|
let sql: string = this.changeColumnQuery.apply(this.queryGenerator, [
|
||||||
tableName,
|
tableName,
|
||||||
attributes,
|
attributes
|
||||||
]);
|
]);
|
||||||
const re1 = /ALTER\s+TABLE\s+\[([^\]]*)\]/;
|
const re1 = /ALTER\s+TABLE\s+\[([^\]]*)\]/;
|
||||||
const matches = re1.exec(sql);
|
const matches = re1.exec(sql);
|
||||||
|
@ -326,7 +326,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
fkcols +
|
fkcols +
|
||||||
')'
|
')'
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return sql;
|
return sql;
|
||||||
|
|
|
@ -36,35 +36,45 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require('../../../src/logger');
|
||||||
const Path = require("path");
|
const Path = require('path');
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require('url-join');
|
||||||
const Fs = require("fs");
|
const Fs = require('fs');
|
||||||
const WaitUntil = require("wait-until");
|
const WaitUntil = require('wait-until');
|
||||||
const express = require("express");
|
const express = require('express');
|
||||||
|
|
||||||
import { KBService } from "./../../kb.gbapp/services/KBService";
|
import { IGBCoreService, IGBInstance } from 'botlib';
|
||||||
import { GBImporter } from "./GBImporter";
|
import { GBError } from 'botlib';
|
||||||
import { IGBCoreService, IGBInstance } from "botlib";
|
import { IGBPackage } from 'botlib';
|
||||||
import { GBConfigService } from "./GBConfigService";
|
import { AzureSearch } from 'pragmatismo-io-framework';
|
||||||
import { GBError } from "botlib";
|
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
|
||||||
import { GuaribasPackage, GuaribasInstance } from "../models/GBModel";
|
import { GuaribasInstance, GuaribasPackage } from '../models/GBModel';
|
||||||
import { IGBPackage } from "botlib";
|
import { KBService } from './../../kb.gbapp/services/KBService';
|
||||||
import { AzureSearch } from "pragmatismo-io-framework";
|
import { GBConfigService } from './GBConfigService';
|
||||||
import { AzureDeployerService } from "../../azuredeployer.gbapp/services/AzureDeployerService";
|
import { GBImporter } from './GBImporter';
|
||||||
|
|
||||||
/** Deployer service for bots, themes, ai and more. */
|
/** Deployer service for bots, themes, ai and more. */
|
||||||
export class GBDeployer {
|
export class GBDeployer {
|
||||||
core: IGBCoreService;
|
public static deployFolder = 'packages';
|
||||||
importer: GBImporter;
|
public core: IGBCoreService;
|
||||||
workDir: string = "./work";
|
public importer: GBImporter;
|
||||||
static deployFolder = "packages";
|
public workDir: string = './work';
|
||||||
|
|
||||||
constructor(core: IGBCoreService, importer: GBImporter) {
|
constructor(core: IGBCoreService, importer: GBImporter) {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
this.importer = importer;
|
this.importer = importer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static getConnectionStringFromInstance(instance: GuaribasInstance) {
|
||||||
|
return `Server=tcp:${
|
||||||
|
instance.storageServer
|
||||||
|
}.database.windows.net,1433;Database=${instance.storageName};User ID=${
|
||||||
|
instance.storageUsername
|
||||||
|
};Password=${
|
||||||
|
instance.storagePassword
|
||||||
|
};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Performs package deployment in all .gbai or default.
|
* Performs package deployment in all .gbai or default.
|
||||||
|
@ -73,18 +83,18 @@ export class GBDeployer {
|
||||||
public deployPackages(
|
public deployPackages(
|
||||||
core: IGBCoreService,
|
core: IGBCoreService,
|
||||||
server: any,
|
server: any,
|
||||||
appPackages: Array<IGBPackage>
|
appPackages: IGBPackage[]
|
||||||
) {
|
) {
|
||||||
let _this = this;
|
const _this = this;
|
||||||
return new Promise((resolve: any, reject: any): any => {
|
return new Promise((resolve: any, reject: any): any => {
|
||||||
let totalPackages = 0;
|
let totalPackages = 0;
|
||||||
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
|
||||||
let paths = [GBDeployer.deployFolder];
|
let paths = [GBDeployer.deployFolder];
|
||||||
if (additionalPath) {
|
if (additionalPath) {
|
||||||
paths = paths.concat(additionalPath.toLowerCase().split(";"));
|
paths = paths.concat(additionalPath.toLowerCase().split(';'));
|
||||||
}
|
}
|
||||||
let botPackages = new Array<string>();
|
const botPackages = new Array<string>();
|
||||||
let gbappPackages = new Array<string>();
|
const gbappPackages = new Array<string>();
|
||||||
let generalPackages = new Array<string>();
|
let generalPackages = new Array<string>();
|
||||||
|
|
||||||
function doIt(path) {
|
function doIt(path) {
|
||||||
|
@ -94,14 +104,14 @@ export class GBDeployer {
|
||||||
.map(name => Path.join(source, name))
|
.map(name => Path.join(source, name))
|
||||||
.filter(isDirectory);
|
.filter(isDirectory);
|
||||||
|
|
||||||
let dirs = getDirectories(path);
|
const dirs = getDirectories(path);
|
||||||
dirs.forEach(element => {
|
dirs.forEach(element => {
|
||||||
if (element.startsWith(".")) {
|
if (element.startsWith('.')) {
|
||||||
logger.info(`Ignoring ${element}...`);
|
logger.info(`Ignoring ${element}...`);
|
||||||
} else {
|
} else {
|
||||||
if (element.endsWith(".gbot")) {
|
if (element.endsWith('.gbot')) {
|
||||||
botPackages.push(element);
|
botPackages.push(element);
|
||||||
} else if (element.endsWith(".gbapp")) {
|
} else if (element.endsWith('.gbapp')) {
|
||||||
gbappPackages.push(element);
|
gbappPackages.push(element);
|
||||||
} else {
|
} else {
|
||||||
generalPackages.push(element);
|
generalPackages.push(element);
|
||||||
|
@ -124,11 +134,11 @@ export class GBDeployer {
|
||||||
|
|
||||||
gbappPackages.forEach(e => {
|
gbappPackages.forEach(e => {
|
||||||
// Skips .gbapp inside deploy folder.
|
// Skips .gbapp inside deploy folder.
|
||||||
if (!e.startsWith("packages")) {
|
if (!e.startsWith('packages')) {
|
||||||
logger.info(`Deploying app: ${e}...`);
|
logger.info(`Deploying app: ${e}...`);
|
||||||
import(e)
|
import(e)
|
||||||
.then(m => {
|
.then(m => {
|
||||||
let p = new m.Package();
|
const p = new m.Package();
|
||||||
p.loadPackage(core, core.sequelize);
|
p.loadPackage(core, core.sequelize);
|
||||||
appPackages.push(p);
|
appPackages.push(p);
|
||||||
logger.info(`App (.gbapp) deployed: ${e}.`);
|
logger.info(`App (.gbapp) deployed: ${e}.`);
|
||||||
|
@ -169,40 +179,40 @@ export class GBDeployer {
|
||||||
|
|
||||||
/** Then all remaining generalPackages are loaded. */
|
/** Then all remaining generalPackages are loaded. */
|
||||||
|
|
||||||
generalPackages = generalPackages.filter(p => !p.endsWith(".git"));
|
generalPackages = generalPackages.filter(p => !p.endsWith('.git'));
|
||||||
|
|
||||||
generalPackages.forEach(filename => {
|
generalPackages.forEach(filename => {
|
||||||
let filenameOnly = Path.basename(filename);
|
const filenameOnly = Path.basename(filename);
|
||||||
logger.info(`Deploying package: ${filename}...`);
|
logger.info(`Deploying package: ${filename}...`);
|
||||||
|
|
||||||
/** Handles apps for general bots - .gbapp must stay out of deploy folder. */
|
/** Handles apps for general bots - .gbapp must stay out of deploy folder. */
|
||||||
|
|
||||||
if (
|
if (
|
||||||
Path.extname(filename) === ".gbapp" ||
|
Path.extname(filename) === '.gbapp' ||
|
||||||
Path.extname(filename) === ".gblib"
|
Path.extname(filename) === '.gblib'
|
||||||
) {
|
) {
|
||||||
/** Themes for bots. */
|
/** Themes for bots. */
|
||||||
} else if (Path.extname(filename) === ".gbtheme") {
|
} else if (Path.extname(filename) === '.gbtheme') {
|
||||||
server.use("/themes/" + filenameOnly, express.static(filename));
|
server.use('/themes/' + filenameOnly, express.static(filename));
|
||||||
logger.info(
|
logger.info(
|
||||||
`Theme (.gbtheme) assets accessible at: ${"/themes/" +
|
`Theme (.gbtheme) assets accessible at: ${'/themes/' +
|
||||||
filenameOnly}.`
|
filenameOnly}.`
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Knowledge base for bots. */
|
/** Knowledge base for bots. */
|
||||||
} else if (Path.extname(filename) === ".gbkb") {
|
} else if (Path.extname(filename) === '.gbkb') {
|
||||||
server.use(
|
server.use(
|
||||||
"/kb/" + filenameOnly + "/subjects",
|
'/kb/' + filenameOnly + '/subjects',
|
||||||
express.static(UrlJoin(filename, "subjects"))
|
express.static(UrlJoin(filename, 'subjects'))
|
||||||
);
|
);
|
||||||
logger.info(
|
logger.info(
|
||||||
`KB (.gbkb) assets accessible at: ${"/kb/" + filenameOnly}.`
|
`KB (.gbkb) assets accessible at: ${'/kb/' + filenameOnly}.`
|
||||||
);
|
);
|
||||||
} else if (Path.extname(filename) === ".gbui") {
|
} else if (Path.extname(filename) === '.gbui') {
|
||||||
// Already Handled
|
// Already Handled
|
||||||
} else {
|
} else {
|
||||||
/** Unknown package format. */
|
/** Unknown package format. */
|
||||||
let err = new Error(`Package type not handled: ${filename}.`);
|
const err = new Error(`Package type not handled: ${filename}.`);
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
totalPackages++;
|
totalPackages++;
|
||||||
|
@ -218,7 +228,7 @@ export class GBDeployer {
|
||||||
.done(function(result) {
|
.done(function(result) {
|
||||||
if (botPackages.length === 0) {
|
if (botPackages.length === 0) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"No external packages to load, please use ADDITIONAL_DEPLOY_PATH to point to a .gbai package folder."
|
'No external packages to load, please use ADDITIONAL_DEPLOY_PATH to point to a .gbai package folder.'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.info(`Package deployment done.`);
|
logger.info(`Package deployment done.`);
|
||||||
|
@ -233,17 +243,17 @@ export class GBDeployer {
|
||||||
* Deploys a bot to the storage.
|
* Deploys a bot to the storage.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async deployBot(localPath: string): Promise<IGBInstance> {
|
public async deployBot(localPath: string): Promise<IGBInstance> {
|
||||||
let packageType = Path.extname(localPath);
|
const packageType = Path.extname(localPath);
|
||||||
let packageName = Path.basename(localPath);
|
const packageName = Path.basename(localPath);
|
||||||
let instance = await this.importer.importIfNotExistsBotPackage(
|
const instance = await this.importer.importIfNotExistsBotPackage(
|
||||||
packageName,
|
packageName,
|
||||||
localPath
|
localPath
|
||||||
);
|
);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deployPackageToStorage(
|
public async deployPackageToStorage(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
packageName: string
|
packageName: string
|
||||||
): Promise<GuaribasPackage> {
|
): Promise<GuaribasPackage> {
|
||||||
|
@ -253,7 +263,7 @@ export class GBDeployer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deployTheme(localPath: string) {
|
public deployTheme(localPath: string) {
|
||||||
// DISABLED: Until completed, "/ui/public".
|
// DISABLED: Until completed, "/ui/public".
|
||||||
// FsExtra.copy(localPath, this.workDir + packageName)
|
// FsExtra.copy(localPath, this.workDir + packageName)
|
||||||
// .then(() => {
|
// .then(() => {
|
||||||
|
@ -265,26 +275,26 @@ export class GBDeployer {
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
async deployPackageFromLocalPath(localPath: string) {
|
public async deployPackageFromLocalPath(localPath: string) {
|
||||||
let packageType = Path.extname(localPath);
|
const packageType = Path.extname(localPath);
|
||||||
|
|
||||||
switch (packageType) {
|
switch (packageType) {
|
||||||
case ".gbot":
|
case '.gbot':
|
||||||
return this.deployBot(localPath);
|
return this.deployBot(localPath);
|
||||||
|
|
||||||
case ".gbtheme":
|
case '.gbtheme':
|
||||||
return this.deployTheme(localPath);
|
return this.deployTheme(localPath);
|
||||||
|
|
||||||
// PACKAGE: Put in package logic.
|
// PACKAGE: Put in package logic.
|
||||||
case ".gbkb":
|
case '.gbkb':
|
||||||
let service = new KBService(this.core.sequelize);
|
const service = new KBService(this.core.sequelize);
|
||||||
return service.deployKb(this.core, this, localPath);
|
return service.deployKb(this.core, this, localPath);
|
||||||
|
|
||||||
case ".gbui":
|
case '.gbui':
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var err = GBError.create(
|
const err = GBError.create(
|
||||||
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
||||||
);
|
);
|
||||||
Promise.reject(err);
|
Promise.reject(err);
|
||||||
|
@ -292,30 +302,30 @@ export class GBDeployer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async undeployPackageFromLocalPath(instance: IGBInstance, localPath: string) {
|
public async undeployPackageFromLocalPath(instance: IGBInstance, localPath: string) {
|
||||||
let packageType = Path.extname(localPath);
|
const packageType = Path.extname(localPath);
|
||||||
let packageName = Path.basename(localPath);
|
const packageName = Path.basename(localPath);
|
||||||
|
|
||||||
let p = await this.getPackageByName(instance.instanceId, packageName);
|
const p = await this.getPackageByName(instance.instanceId, packageName);
|
||||||
|
|
||||||
switch (packageType) {
|
switch (packageType) {
|
||||||
case ".gbot":
|
case '.gbot':
|
||||||
// TODO: this.undeployBot(packageName, localPath)
|
// TODO: this.undeployBot(packageName, localPath)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ".gbtheme":
|
case '.gbtheme':
|
||||||
// TODO: this.undeployTheme(packageName, localPath)
|
// TODO: this.undeployTheme(packageName, localPath)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ".gbkb":
|
case '.gbkb':
|
||||||
let service = new KBService(this.core.sequelize);
|
const service = new KBService(this.core.sequelize);
|
||||||
return service.undeployKbFromStorage(instance, this, p.packageId);
|
return service.undeployKbFromStorage(instance, this, p.packageId);
|
||||||
|
|
||||||
case ".gbui":
|
case '.gbui':
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var err = GBError.create(
|
const err = GBError.create(
|
||||||
`GuaribasBusinessError: Unknown package type: ${packageType}.`
|
`GuaribasBusinessError: Unknown package type: ${packageType}.`
|
||||||
);
|
);
|
||||||
Promise.reject(err);
|
Promise.reject(err);
|
||||||
|
@ -323,27 +333,17 @@ export class GBDeployer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getConnectionStringFromInstance(instance: GuaribasInstance) {
|
|
||||||
return `Server=tcp:${
|
|
||||||
instance.storageServer
|
|
||||||
}.database.windows.net,1433;Database=${instance.storageName};User ID=${
|
|
||||||
instance.storageUsername
|
|
||||||
};Password=${
|
|
||||||
instance.storagePassword
|
|
||||||
};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async rebuildIndex(instance: GuaribasInstance) {
|
public async rebuildIndex(instance: GuaribasInstance) {
|
||||||
let search = new AzureSearch(
|
const search = new AzureSearch(
|
||||||
instance.searchKey,
|
instance.searchKey,
|
||||||
instance.searchHost,
|
instance.searchHost,
|
||||||
instance.searchIndex,
|
instance.searchIndex,
|
||||||
instance.searchIndexer
|
instance.searchIndexer
|
||||||
);
|
);
|
||||||
|
|
||||||
let connectionString = GBDeployer.getConnectionStringFromInstance(instance);
|
const connectionString = GBDeployer.getConnectionStringFromInstance(instance);
|
||||||
|
|
||||||
const dsName = "gb";
|
const dsName = 'gb';
|
||||||
try {
|
try {
|
||||||
await search.deleteDataSource(dsName);
|
await search.deleteDataSource(dsName);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -356,8 +356,8 @@ export class GBDeployer {
|
||||||
await search.createDataSource(
|
await search.createDataSource(
|
||||||
dsName,
|
dsName,
|
||||||
dsName,
|
dsName,
|
||||||
"GuaribasQuestion",
|
'GuaribasQuestion',
|
||||||
"azuresql",
|
'azuresql',
|
||||||
connectionString
|
connectionString
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -375,11 +375,11 @@ export class GBDeployer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPackageByName(
|
public async getPackageByName(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
packageName: string
|
packageName: string
|
||||||
): Promise<GuaribasPackage> {
|
): Promise<GuaribasPackage> {
|
||||||
var where = { packageName: packageName, instanceId: instanceId };
|
const where = { packageName: packageName, instanceId: instanceId };
|
||||||
return GuaribasPackage.findOne({
|
return GuaribasPackage.findOne({
|
||||||
where: where
|
where: where
|
||||||
});
|
});
|
||||||
|
@ -390,11 +390,11 @@ export class GBDeployer {
|
||||||
* Hot deploy processing.
|
* Hot deploy processing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async scanBootPackage() {
|
public async scanBootPackage() {
|
||||||
const deployFolder = "packages";
|
const deployFolder = 'packages';
|
||||||
let bootPackage = GBConfigService.get("BOOT_PACKAGE");
|
const bootPackage = GBConfigService.get('BOOT_PACKAGE');
|
||||||
|
|
||||||
if (bootPackage === "none") {
|
if (bootPackage === 'none') {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
} else {
|
} else {
|
||||||
return this.deployPackageFromLocalPath(
|
return this.deployPackageFromLocalPath(
|
||||||
|
|
|
@ -30,42 +30,41 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
import Fs = require("fs")
|
import { IGBCoreService, IGBInstance } from 'botlib';
|
||||||
import Path = require("path")
|
import fs = require('fs');
|
||||||
import { IGBCoreService, IGBInstance } from "botlib"
|
import path = require('path');
|
||||||
import { SecService } from "../../security.gblib/services/SecService"
|
import { SecService } from '../../security.gblib/services/SecService';
|
||||||
import { GuaribasInstance } from "../models/GBModel"
|
import { GuaribasInstance } from '../models/GBModel';
|
||||||
|
|
||||||
export class GBImporter {
|
export class GBImporter {
|
||||||
core: IGBCoreService
|
public core: IGBCoreService;
|
||||||
|
|
||||||
constructor(core: IGBCoreService) {
|
constructor(core: IGBCoreService) {
|
||||||
this.core = core
|
this.core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
async importIfNotExistsBotPackage(
|
public async importIfNotExistsBotPackage(
|
||||||
packageName: string,
|
packageName: string,
|
||||||
localPath: string) {
|
localPath: string) {
|
||||||
|
|
||||||
let packageJson = JSON.parse(
|
const packageJson = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, 'package.json'), 'utf8')
|
||||||
)
|
);
|
||||||
|
|
||||||
let botId = packageJson.botId
|
const botId = packageJson.botId;
|
||||||
|
|
||||||
let instance = await this.core.loadInstance(botId)
|
const instance = await this.core.loadInstance(botId);
|
||||||
if (instance) {
|
if (instance) {
|
||||||
return Promise.resolve(instance)
|
return Promise.resolve(instance);
|
||||||
} else {
|
} else {
|
||||||
return this.createInstanceInternal(packageName, localPath, packageJson)
|
return this.createInstanceInternal(packageName, localPath, packageJson);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,20 +74,20 @@ export class GBImporter {
|
||||||
packageJson: any
|
packageJson: any
|
||||||
) {
|
) {
|
||||||
const settings = JSON.parse(
|
const settings = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "settings.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, 'settings.json'), 'utf8')
|
||||||
)
|
);
|
||||||
const servicesJson = JSON.parse(
|
const servicesJson = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "services.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, 'services.json'), 'utf8')
|
||||||
)
|
);
|
||||||
|
|
||||||
packageJson = Object.assign(packageJson, settings, servicesJson)
|
packageJson = {...packageJson, ...settings, ...servicesJson};
|
||||||
|
|
||||||
GuaribasInstance.create(packageJson).then((instance: IGBInstance) => {
|
GuaribasInstance.create(packageJson).then((instance: IGBInstance) => {
|
||||||
|
|
||||||
let service = new SecService()
|
const service = new SecService();
|
||||||
// TODO: service.importSecurityFile(localPath, instance)
|
// TODO: service.importSecurityFile(localPath, instance)
|
||||||
|
|
||||||
Promise.resolve(instance)
|
Promise.resolve(instance);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,48 +36,48 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { DialogSet, TextPrompt } = require("botbuilder-dialogs");
|
const { DialogSet, TextPrompt } = require('botbuilder-dialogs');
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require('url-join');
|
||||||
const express = require("express");
|
const express = require('express');
|
||||||
const logger = require("../../../src/logger");
|
const logger = require('../../../src/logger');
|
||||||
const request = require("request-promise-native");
|
const request = require('request-promise-native');
|
||||||
var AuthenticationContext = require("adal-node").AuthenticationContext;
|
const AuthenticationContext = require('adal-node').AuthenticationContext;
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AutoSaveStateMiddleware,
|
||||||
BotFrameworkAdapter,
|
BotFrameworkAdapter,
|
||||||
BotStateSet,
|
BotStateSet,
|
||||||
ConversationState,
|
ConversationState,
|
||||||
MemoryStorage,
|
MemoryStorage,
|
||||||
UserState,
|
UserState
|
||||||
AutoSaveStateMiddleware
|
} from 'botbuilder';
|
||||||
} from "botbuilder";
|
|
||||||
|
|
||||||
import { GBMinInstance, IGBPackage } from "botlib";
|
import { GBMinInstance, IGBPackage } 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";
|
|
||||||
import { GBWhatsappPackage } from "../../whatsapp.gblib";
|
|
||||||
import {
|
import {
|
||||||
IGBAdminService,
|
IGBAdminService,
|
||||||
IGBCoreService,
|
IGBConversationalService,
|
||||||
IGBConversationalService
|
IGBCoreService
|
||||||
} from "botlib";
|
} from 'botlib';
|
||||||
import { GuaribasInstance } from "../models/GBModel";
|
import { GBAnalyticsPackage } from '../../analytics.gblib';
|
||||||
import { Messages } from "../strings";
|
import { GBCorePackage } from '../../core.gbapp';
|
||||||
|
import { GBCustomerSatisfactionPackage } from '../../customer-satisfaction.gbapp';
|
||||||
|
import { GBKBPackage } from '../../kb.gbapp';
|
||||||
|
import { GBSecurityPackage } from '../../security.gblib';
|
||||||
|
import { GBWhatsappPackage } from '../../whatsapp.gblib';
|
||||||
|
import { GuaribasInstance } from '../models/GBModel';
|
||||||
|
import { Messages } from '../strings';
|
||||||
|
import { GBAdminPackage } from './../../admin.gbapp/index';
|
||||||
|
import { GBDeployer } from './GBDeployer';
|
||||||
|
|
||||||
/** Minimal service layer for a bot. */
|
/** Minimal service layer for a bot. */
|
||||||
|
|
||||||
export class GBMinService {
|
export class GBMinService {
|
||||||
core: IGBCoreService;
|
public core: IGBCoreService;
|
||||||
conversationalService: IGBConversationalService;
|
public conversationalService: IGBConversationalService;
|
||||||
adminService: IGBAdminService;
|
public adminService: IGBAdminService;
|
||||||
deployer: GBDeployer;
|
public deployer: GBDeployer;
|
||||||
|
|
||||||
corePackage = "core.gbai";
|
public corePackage = 'core.gbai';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static initialization of minimal instance.
|
* Static initialization of minimal instance.
|
||||||
|
@ -107,40 +107,40 @@ export class GBMinService {
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
|
|
||||||
async buildMin(
|
public async buildMin(
|
||||||
server: any,
|
server: any,
|
||||||
appPackages: Array<IGBPackage>,
|
appPackages: IGBPackage[],
|
||||||
instances: GuaribasInstance[]
|
instances: GuaribasInstance[]
|
||||||
): Promise<GBMinInstance> {
|
): Promise<GBMinInstance> {
|
||||||
// Serves default UI on root address '/'.
|
// Serves default UI on root address '/'.
|
||||||
|
|
||||||
let uiPackage = "default.gbui";
|
const uiPackage = 'default.gbui';
|
||||||
server.use(
|
server.use(
|
||||||
"/",
|
'/',
|
||||||
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, "build"))
|
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, 'build'))
|
||||||
);
|
);
|
||||||
|
|
||||||
Promise.all(
|
Promise.all(
|
||||||
instances.map(async instance => {
|
instances.map(async instance => {
|
||||||
// Gets the authorization key for each instance from Bot Service.
|
// Gets the authorization key for each instance from Bot Service.
|
||||||
|
|
||||||
let webchatToken = await this.getWebchatToken(instance);
|
const webchatToken = await this.getWebchatToken(instance);
|
||||||
|
|
||||||
// Serves the bot information object via HTTP so clients can get
|
// Serves the bot information object via HTTP so clients can get
|
||||||
// instance information stored on server.
|
// instance information stored on server.
|
||||||
|
|
||||||
server.get("/instances/:botId", (req, res) => {
|
server.get('/instances/:botId', (req, res) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
// Returns the instance object to clients requesting bot info.
|
// Returns the instance object to clients requesting bot info.
|
||||||
|
|
||||||
let botId = req.params.botId;
|
const botId = req.params.botId;
|
||||||
let instance = await this.core.loadInstance(botId);
|
const instance = await this.core.loadInstance(botId);
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
let speechToken = await this.getSTSToken(instance);
|
const speechToken = await this.getSTSToken(instance);
|
||||||
let theme = instance.theme;
|
let theme = instance.theme;
|
||||||
if (!theme) {
|
if (!theme) {
|
||||||
theme = "default.gbtheme";
|
theme = 'default.gbtheme';
|
||||||
}
|
}
|
||||||
|
|
||||||
res.send(
|
res.send(
|
||||||
|
@ -156,7 +156,7 @@ export class GBMinService {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let error = `Instance not found: ${botId}.`;
|
const error = `Instance not found: ${botId}.`;
|
||||||
res.sendStatus(error);
|
res.sendStatus(error);
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ export class GBMinService {
|
||||||
|
|
||||||
// Build bot adapter.
|
// Build bot adapter.
|
||||||
|
|
||||||
var { min, adapter, conversationState } = await this.buildBotAdapter(
|
const { min, adapter, conversationState } = await this.buildBotAdapter(
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ export class GBMinService {
|
||||||
|
|
||||||
// Serves individual URL for each bot conversational interface...
|
// Serves individual URL for each bot conversational interface...
|
||||||
|
|
||||||
let url = `/api/messages/${instance.botId}`;
|
const url = `/api/messages/${instance.botId}`;
|
||||||
server.post(url, async (req, res) => {
|
server.post(url, async (req, res) => {
|
||||||
return this.receiver(
|
return this.receiver(
|
||||||
adapter,
|
adapter,
|
||||||
|
@ -193,14 +193,14 @@ export class GBMinService {
|
||||||
|
|
||||||
// Serves individual URL for each bot user interface.
|
// Serves individual URL for each bot user interface.
|
||||||
|
|
||||||
let uiUrl = `/${instance.botId}`;
|
const uiUrl = `/${instance.botId}`;
|
||||||
server.use(
|
server.use(
|
||||||
uiUrl,
|
uiUrl,
|
||||||
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, "build"))
|
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, 'build'))
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info(`Bot UI ${uiPackage} accessible at: ${uiUrl}.`);
|
logger.info(`Bot UI ${uiPackage} accessible at: ${uiUrl}.`);
|
||||||
let state = `${instance.instanceId}${Math.floor(
|
const state = `${instance.instanceId}${Math.floor(
|
||||||
Math.random() * 1000000000
|
Math.random() * 1000000000
|
||||||
)}`;
|
)}`;
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ export class GBMinService {
|
||||||
let authorizationUrl = UrlJoin(
|
let authorizationUrl = UrlJoin(
|
||||||
min.instance.authenticatorAuthorityHostUrl,
|
min.instance.authenticatorAuthorityHostUrl,
|
||||||
min.instance.authenticatorTenant,
|
min.instance.authenticatorTenant,
|
||||||
"/oauth2/authorize"
|
'/oauth2/authorize'
|
||||||
);
|
);
|
||||||
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${
|
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${
|
||||||
min.instance.authenticatorClientId
|
min.instance.authenticatorClientId
|
||||||
|
@ -227,57 +227,57 @@ export class GBMinService {
|
||||||
// access token that can be used to access the user owned resource.
|
// access token that can be used to access the user owned resource.
|
||||||
|
|
||||||
server.get(`/${min.instance.botId}/token`, async (req, res) => {
|
server.get(`/${min.instance.botId}/token`, async (req, res) => {
|
||||||
let state = await min.adminService.getValue(
|
const state = await min.adminService.getValue(
|
||||||
min.instance.instanceId,
|
min.instance.instanceId,
|
||||||
"AntiCSRFAttackState"
|
'AntiCSRFAttackState'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (req.query.state != state) {
|
if (req.query.state != state) {
|
||||||
let msg =
|
const msg =
|
||||||
"WARNING: state field was not provided as anti-CSRF token";
|
'WARNING: state field was not provided as anti-CSRF token';
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
throw new Error(msg);
|
throw new Error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
var authenticationContext = new AuthenticationContext(
|
const authenticationContext = new AuthenticationContext(
|
||||||
UrlJoin(
|
UrlJoin(
|
||||||
min.instance.authenticatorAuthorityHostUrl,
|
min.instance.authenticatorAuthorityHostUrl,
|
||||||
min.instance.authenticatorTenant
|
min.instance.authenticatorTenant
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
let resource = "https://graph.microsoft.com";
|
const resource = 'https://graph.microsoft.com';
|
||||||
|
|
||||||
authenticationContext.acquireTokenWithAuthorizationCode(
|
authenticationContext.acquireTokenWithAuthorizationCode(
|
||||||
req.query.code,
|
req.query.code,
|
||||||
UrlJoin(instance.botEndpoint, min.instance.botId, "/token"),
|
UrlJoin(instance.botEndpoint, min.instance.botId, '/token'),
|
||||||
resource,
|
resource,
|
||||||
instance.authenticatorClientId,
|
instance.authenticatorClientId,
|
||||||
instance.authenticatorClientSecret,
|
instance.authenticatorClientSecret,
|
||||||
async (err, token) => {
|
async (err, token) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
let msg = `Error acquiring token: ${err}`;
|
const msg = `Error acquiring token: ${err}`;
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
res.send(msg);
|
res.send(msg);
|
||||||
} else {
|
} else {
|
||||||
await this.adminService.setValue(
|
await this.adminService.setValue(
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
"refreshToken",
|
'refreshToken',
|
||||||
token.refreshToken
|
token.refreshToken
|
||||||
);
|
);
|
||||||
await this.adminService.setValue(
|
await this.adminService.setValue(
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
"accessToken",
|
'accessToken',
|
||||||
token.accessToken
|
token.accessToken
|
||||||
);
|
);
|
||||||
await this.adminService.setValue(
|
await this.adminService.setValue(
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
"expiresOn",
|
'expiresOn',
|
||||||
token.expiresOn.toString()
|
token.expiresOn.toString()
|
||||||
);
|
);
|
||||||
await this.adminService.setValue(
|
await this.adminService.setValue(
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
"AntiCSRFAttackState",
|
'AntiCSRFAttackState',
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -305,8 +305,57 @@ export class GBMinService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Webchat key from Bot Service.
|
||||||
|
*
|
||||||
|
* @param instance The Bot instance.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public async getWebchatToken(instance: any) {
|
||||||
|
const options = {
|
||||||
|
url: 'https://directline.botframework.com/v3/directline/tokens/generate',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${instance.webchatKey}`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const json = await request(options);
|
||||||
|
return Promise.resolve(JSON.parse(json));
|
||||||
|
} catch (error) {
|
||||||
|
const msg = `[botId:${instance.botId}] Error calling Direct Line client, verify Bot endpoint on the cloud. Error is: ${error}.`;
|
||||||
|
return Promise.reject(new Error(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a Speech to Text / Text to Speech token from the provider.
|
||||||
|
*
|
||||||
|
* @param instance The general bot instance.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public async getSTSToken(instance: any) {
|
||||||
|
// TODO: Make dynamic: https://CHANGE.api.cognitive.microsoft.com/sts/v1.0
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
url: 'https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken',
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Ocp-Apim-Subscription-Key': instance.speechKey
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await request(options);
|
||||||
|
} catch (error) {
|
||||||
|
const msg = `Error calling Speech to Text client. Error is: ${error}.`;
|
||||||
|
return Promise.reject(new Error(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async buildBotAdapter(instance: any) {
|
private async buildBotAdapter(instance: any) {
|
||||||
let adapter = new BotFrameworkAdapter({
|
const adapter = new BotFrameworkAdapter({
|
||||||
appId: instance.marketplaceId,
|
appId: instance.marketplaceId,
|
||||||
appPassword: instance.marketplacePassword
|
appPassword: instance.marketplacePassword
|
||||||
});
|
});
|
||||||
|
@ -318,7 +367,7 @@ export class GBMinService {
|
||||||
|
|
||||||
// The minimal bot is built here.
|
// The minimal bot is built here.
|
||||||
|
|
||||||
let min = new GBMinInstance();
|
const min = new GBMinInstance();
|
||||||
min.botId = instance.botId;
|
min.botId = instance.botId;
|
||||||
min.bot = adapter;
|
min.bot = adapter;
|
||||||
min.userState = userState;
|
min.userState = userState;
|
||||||
|
@ -326,16 +375,16 @@ export class GBMinService {
|
||||||
min.conversationalService = this.conversationalService;
|
min.conversationalService = this.conversationalService;
|
||||||
min.adminService = this.adminService;
|
min.adminService = this.adminService;
|
||||||
min.instance = await this.core.loadInstance(min.botId);
|
min.instance = await this.core.loadInstance(min.botId);
|
||||||
min.userProfile = conversationState.createProperty("userProfile");
|
min.userProfile = conversationState.createProperty('userProfile');
|
||||||
const dialogState = conversationState.createProperty("dialogState");
|
const dialogState = conversationState.createProperty('dialogState');
|
||||||
min.dialogs = new DialogSet(dialogState);
|
min.dialogs = new DialogSet(dialogState);
|
||||||
min.dialogs.add(new TextPrompt("textPrompt"));
|
min.dialogs.add(new TextPrompt('textPrompt'));
|
||||||
|
|
||||||
return { min, adapter, conversationState };
|
return { min, adapter, conversationState };
|
||||||
}
|
}
|
||||||
|
|
||||||
private invokeLoadBot(appPackages: any[], min: any, server: any) {
|
private invokeLoadBot(appPackages: any[], min: any, server: any) {
|
||||||
let sysPackages = new Array<IGBPackage>();
|
const sysPackages = new Array<IGBPackage>();
|
||||||
// NOTE: A semicolon is necessary before this line.
|
// NOTE: A semicolon is necessary before this line.
|
||||||
[
|
[
|
||||||
GBCorePackage,
|
GBCorePackage,
|
||||||
|
@ -346,13 +395,13 @@ export class GBMinService {
|
||||||
GBCustomerSatisfactionPackage,
|
GBCustomerSatisfactionPackage,
|
||||||
GBWhatsappPackage
|
GBWhatsappPackage
|
||||||
].forEach(sysPackage => {
|
].forEach(sysPackage => {
|
||||||
let p = Object.create(sysPackage.prototype) as IGBPackage;
|
const p = Object.create(sysPackage.prototype) as IGBPackage;
|
||||||
p.loadBot(min);
|
p.loadBot(min);
|
||||||
sysPackages.push(p);
|
sysPackages.push(p);
|
||||||
if (sysPackage.name === "GBWhatsappPackage") {
|
if (sysPackage.name === 'GBWhatsappPackage') {
|
||||||
let url = "/instances/:botId/whatsapp";
|
const url = '/instances/:botId/whatsapp';
|
||||||
server.post(url, (req, res) => {
|
server.post(url, (req, res) => {
|
||||||
p["channel"].received(req, res);
|
p.channel.received(req, res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
@ -378,16 +427,16 @@ export class GBMinService {
|
||||||
return adapter.processActivity(req, res, async context => {
|
return adapter.processActivity(req, res, async context => {
|
||||||
const state = conversationState.get(context);
|
const state = conversationState.get(context);
|
||||||
const step = await min.dialogs.createContext(context, state);
|
const step = await min.dialogs.createContext(context, state);
|
||||||
step.context.activity.locale = "en-US"; // TODO: Make dynamic.
|
step.context.activity.locale = 'en-US'; // TODO: Make dynamic.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const user = await min.userProfile.get(context, {});
|
const user = await min.userProfile.get(context, {});
|
||||||
|
|
||||||
if (!user.loaded) {
|
if (!user.loaded) {
|
||||||
await min.conversationalService.sendEvent(step, "loadInstance", {
|
await min.conversationalService.sendEvent(step, 'loadInstance', {
|
||||||
instanceId: instance.instanceId,
|
instanceId: instance.instanceId,
|
||||||
botId: instance.botId,
|
botId: instance.botId,
|
||||||
theme: instance.theme?instance.theme:"default.gbtheme" ,
|
theme: instance.theme ? instance.theme : 'default.gbtheme' ,
|
||||||
secret: instance.webchatKey
|
secret: instance.webchatKey
|
||||||
});
|
});
|
||||||
user.loaded = true;
|
user.loaded = true;
|
||||||
|
@ -401,32 +450,32 @@ export class GBMinService {
|
||||||
}, ${context.activity.channelId}, {context.activity.value})`
|
}, ${context.activity.channelId}, {context.activity.value})`
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
context.activity.type === "conversationUpdate" &&
|
context.activity.type === 'conversationUpdate' &&
|
||||||
context.activity.membersAdded.length > 0
|
context.activity.membersAdded.length > 0
|
||||||
) {
|
) {
|
||||||
let member = context.activity.membersAdded[0];
|
const member = context.activity.membersAdded[0];
|
||||||
if (member.name === "GeneralBots") {
|
if (member.name === 'GeneralBots') {
|
||||||
logger.info(`Bot added to conversation, starting chat...`);
|
logger.info(`Bot added to conversation, starting chat...`);
|
||||||
appPackages.forEach(e => {
|
appPackages.forEach(e => {
|
||||||
e.onNewSession(min, step);
|
e.onNewSession(min, step);
|
||||||
});
|
});
|
||||||
// Processes the root dialog.
|
// Processes the root dialog.
|
||||||
|
|
||||||
await step.beginDialog("/");
|
await step.beginDialog('/');
|
||||||
} else {
|
} else {
|
||||||
logger.info(`Member added to conversation: ${member.name}`);
|
logger.info(`Member added to conversation: ${member.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes messages.
|
// Processes messages.
|
||||||
} else if (context.activity.type === "message") {
|
} else if (context.activity.type === 'message') {
|
||||||
// Checks for /admin request.
|
// Checks for /admin request.
|
||||||
|
|
||||||
if (context.activity.text === "admin") {
|
if (context.activity.text === 'admin') {
|
||||||
await step.beginDialog("/admin");
|
await step.beginDialog('/admin');
|
||||||
|
|
||||||
// Checks for /menu JSON signature.
|
// Checks for /menu JSON signature.
|
||||||
} else if (context.activity.text.startsWith('{"title"')) {
|
} else if (context.activity.text.startsWith('{"title"')) {
|
||||||
await step.beginDialog("/menu", {
|
await step.beginDialog('/menu', {
|
||||||
data: JSON.parse(context.activity.text)
|
data: JSON.parse(context.activity.text)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -435,102 +484,53 @@ export class GBMinService {
|
||||||
if (step.activeDialog) {
|
if (step.activeDialog) {
|
||||||
await step.continueDialog();
|
await step.continueDialog();
|
||||||
} else {
|
} else {
|
||||||
await step.beginDialog("/answer", {
|
await step.beginDialog('/answer', {
|
||||||
query: context.activity.text
|
query: context.activity.text
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes events.
|
// Processes events.
|
||||||
} else if (context.activity.type === "event") {
|
} else if (context.activity.type === 'event') {
|
||||||
// Empties dialog stack before going to the target.
|
// Empties dialog stack before going to the target.
|
||||||
|
|
||||||
await step.endAll();
|
await step.endAll();
|
||||||
|
|
||||||
if (context.activity.name === "whoAmI") {
|
if (context.activity.name === 'whoAmI') {
|
||||||
await step.beginDialog("/whoAmI");
|
await step.beginDialog('/whoAmI');
|
||||||
} else if (context.activity.name === "showSubjects") {
|
} else if (context.activity.name === 'showSubjects') {
|
||||||
await step.beginDialog("/menu");
|
await step.beginDialog('/menu');
|
||||||
} else if (context.activity.name === "giveFeedback") {
|
} else if (context.activity.name === 'giveFeedback') {
|
||||||
await step.beginDialog("/feedback", {
|
await step.beginDialog('/feedback', {
|
||||||
fromMenu: true
|
fromMenu: true
|
||||||
});
|
});
|
||||||
} else if (context.activity.name === "showFAQ") {
|
} else if (context.activity.name === 'showFAQ') {
|
||||||
await step.beginDialog("/faq");
|
await step.beginDialog('/faq');
|
||||||
} else if (context.activity.name === "answerEvent") {
|
} else if (context.activity.name === 'answerEvent') {
|
||||||
await step.beginDialog("/answerEvent", {
|
await step.beginDialog('/answerEvent', {
|
||||||
questionId: (context.activity as any).data,
|
questionId: (context.activity as any).data,
|
||||||
fromFaq: true
|
fromFaq: true
|
||||||
});
|
});
|
||||||
} else if (context.activity.name === "quality") {
|
} else if (context.activity.name === 'quality') {
|
||||||
await step.beginDialog("/quality", {
|
await step.beginDialog('/quality', {
|
||||||
score: (context.activity as any).data
|
score: (context.activity as any).data
|
||||||
});
|
});
|
||||||
} else if (context.activity.name === "updateToken") {
|
} else if (context.activity.name === 'updateToken') {
|
||||||
let token = (context.activity as any).data;
|
const token = (context.activity as any).data;
|
||||||
await step.beginDialog("/adminUpdateToken", { token: token });
|
await step.beginDialog('/adminUpdateToken', { token: token });
|
||||||
} else {
|
} else {
|
||||||
await step.continueDialog();
|
await step.continueDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let msg = `ERROR: ${error.message} ${error.stack ? error.stack : ""}`;
|
const msg = `ERROR: ${error.message} ${error.stack ? error.stack : ''}`;
|
||||||
logger.error(msg);
|
logger.error(msg);
|
||||||
|
|
||||||
await step.context.sendActivity(
|
await step.context.sendActivity(
|
||||||
Messages[step.context.activity.locale].very_sorry_about_error
|
Messages[step.context.activity.locale].very_sorry_about_error
|
||||||
);
|
);
|
||||||
await step.beginDialog("/ask", { isReturning: true });
|
await step.beginDialog('/ask', { isReturning: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Webchat key from Bot Service.
|
|
||||||
*
|
|
||||||
* @param instance The Bot instance.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
async getWebchatToken(instance: any) {
|
|
||||||
let options = {
|
|
||||||
url: "https://directline.botframework.com/v3/directline/tokens/generate",
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${instance.webchatKey}`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
let json = await request(options);
|
|
||||||
return Promise.resolve(JSON.parse(json));
|
|
||||||
} catch (error) {
|
|
||||||
let msg = `[botId:${instance.botId}] Error calling Direct Line client, verify Bot endpoint on the cloud. Error is: ${error}.`;
|
|
||||||
return Promise.reject(new Error(msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a Speech to Text / Text to Speech token from the provider.
|
|
||||||
*
|
|
||||||
* @param instance The general bot instance.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
async getSTSToken(instance: any) {
|
|
||||||
// TODO: Make dynamic: https://CHANGE.api.cognitive.microsoft.com/sts/v1.0
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
url: "https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken",
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Ocp-Apim-Subscription-Key": instance.speechKey
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await request(options);
|
|
||||||
} catch (error) {
|
|
||||||
let msg = `Error calling Speech to Text client. Error is: ${error}.`;
|
|
||||||
return Promise.reject(new Error(msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
|
||||||
export const Messages = {
|
export const Messages = {
|
||||||
"en-US": {
|
'en-US': {
|
||||||
show_video: "I will show you a video, please wait...",
|
show_video: 'I will show you a video, please wait...',
|
||||||
good_morning: "good morning",
|
good_morning: 'good morning',
|
||||||
good_evening: "good evening",
|
good_evening: 'good evening',
|
||||||
good_night: "good night",
|
good_night: 'good night',
|
||||||
hi: (msg) => `Hello, ${msg}.`,
|
hi: (msg) => `Hello, ${msg}.`,
|
||||||
very_sorry_about_error: `I'm sorry to inform that there was an error which was recorded to be solved.`
|
very_sorry_about_error: `I'm sorry to inform that there was an error which was recorded to be solved.`
|
||||||
|
|
||||||
},
|
},
|
||||||
"pt-BR": {
|
'pt-BR': {
|
||||||
show_video: "Vou te mostrar um vídeo. Por favor, aguarde...",
|
show_video: 'Vou te mostrar um vídeo. Por favor, aguarde...',
|
||||||
good_morning: "bom dia",
|
good_morning: 'bom dia',
|
||||||
good_evening: "boa tarde",
|
good_evening: 'boa tarde',
|
||||||
good_night: "boa noite",
|
good_night: 'boa noite',
|
||||||
hi: (msg) => `Oi, ${msg}.`,
|
hi: (msg) => `Oi, ${msg}.`,
|
||||||
very_sorry_about_error: `Lamento, ocorreu um erro que já foi registrado para ser tratado.`
|
very_sorry_about_error: `Lamento, ocorreu um erro que já foi registrado para ser tratado.`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai';
|
||||||
import 'mocha'
|
import 'mocha';
|
||||||
import {GBImporter} from '../services/GBImporter'
|
import {GBImporter} from '../services/GBImporter';
|
||||||
|
|
||||||
describe('Hello function', () => {
|
describe('Hello function', () => {
|
||||||
|
|
||||||
it('should return empty test', () => {
|
it('should return empty test', () => {
|
||||||
let service = new GBImporter(null);
|
const service = new GBImporter(null);
|
||||||
//service.importIfNotExistsBotPackage(null, null);
|
//service.importIfNotExistsBotPackage(null, null);
|
||||||
const result = 0;
|
const result = 0;
|
||||||
expect(result).to.equal(0);
|
expect(result).to.equal(0);
|
||||||
|
|
|
@ -36,13 +36,13 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { CSService } from "../services/CSService";
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { AzureText } from "pragmatismo-io-framework";
|
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import { GBMinInstance } from "botlib";
|
import { GBMinInstance } from 'botlib';
|
||||||
import { IGBDialog } from "botlib";
|
import { IGBDialog } from 'botlib';
|
||||||
import { BotAdapter } from "botbuilder";
|
import { AzureText } from 'pragmatismo-io-framework';
|
||||||
import { Messages } from "../strings";
|
import { CSService } from '../services/CSService';
|
||||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
import { Messages } from '../strings';
|
||||||
|
|
||||||
export class FeedbackDialog extends IGBDialog {
|
export class FeedbackDialog extends IGBDialog {
|
||||||
/**
|
/**
|
||||||
|
@ -51,13 +51,13 @@ export class FeedbackDialog extends IGBDialog {
|
||||||
* @param bot The bot adapter.
|
* @param bot The bot adapter.
|
||||||
* @param min The minimal bot instance data.
|
* @param min The minimal bot instance data.
|
||||||
*/
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
const service = new CSService();
|
const service = new CSService();
|
||||||
|
|
||||||
min.dialogs.add(
|
min.dialogs.add(
|
||||||
new WaterfallDialog("/feedbackNumber", [
|
new WaterfallDialog('/feedbackNumber', [
|
||||||
async step => {
|
async step => {
|
||||||
let locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
// TODO: Migrate to 4.*+ await step.prompt("choicePrompt", Messages[locale].what_about_me, [
|
// TODO: Migrate to 4.*+ await step.prompt("choicePrompt", Messages[locale].what_about_me, [
|
||||||
// "1",
|
// "1",
|
||||||
// "2",
|
// "2",
|
||||||
|
@ -68,8 +68,8 @@ export class FeedbackDialog extends IGBDialog {
|
||||||
return await step.next();
|
return await step.next();
|
||||||
},
|
},
|
||||||
async step => {
|
async step => {
|
||||||
let locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
let rate = step.result.entity;
|
const rate = step.result.entity;
|
||||||
const user = await min.userProfile.get(context, {});
|
const user = await min.userProfile.get(context, {});
|
||||||
await service.updateConversationRate(user.conversation, rate);
|
await service.updateConversationRate(user.conversation, rate);
|
||||||
await step.context.sendActivity(Messages[locale].thanks);
|
await step.context.sendActivity(Messages[locale].thanks);
|
||||||
|
@ -78,19 +78,19 @@ export class FeedbackDialog extends IGBDialog {
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
min.dialogs.add(new WaterfallDialog("/feedback", [
|
min.dialogs.add(new WaterfallDialog('/feedback', [
|
||||||
async step => {
|
async step => {
|
||||||
let locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
if (step.result.fromMenu) {
|
if (step.result.fromMenu) {
|
||||||
await step.context.sendActivity(Messages[locale].about_suggestions);
|
await step.context.sendActivity(Messages[locale].about_suggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
await step.prompt("textPrompt", Messages[locale].what_about_service);
|
await step.prompt('textPrompt', Messages[locale].what_about_service);
|
||||||
return await step.next();
|
return await step.next();
|
||||||
},
|
},
|
||||||
async step => {
|
async step => {
|
||||||
let locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
let rate = await AzureText.getSentiment(
|
const rate = await AzureText.getSentiment(
|
||||||
min.instance.textAnalyticsKey,
|
min.instance.textAnalyticsKey,
|
||||||
min.instance.textAnalyticsEndpoint,
|
min.instance.textAnalyticsEndpoint,
|
||||||
min.conversationalService.getCurrentLanguage(step),
|
min.conversationalService.getCurrentLanguage(step),
|
||||||
|
@ -104,7 +104,7 @@ export class FeedbackDialog extends IGBDialog {
|
||||||
|
|
||||||
// TODO: Record.
|
// TODO: Record.
|
||||||
}
|
}
|
||||||
await step.replaceDialog("/ask", { isReturning: true });
|
await step.replaceDialog('/ask', { isReturning: true });
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
]));
|
]));
|
||||||
|
|
|
@ -36,14 +36,14 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { IGBDialog } from "botlib";
|
import { IGBDialog } from 'botlib';
|
||||||
|
|
||||||
import { GBMinInstance } from "botlib";
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { CSService } from "../services/CSService";
|
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import { BotAdapter } from "botbuilder";
|
import { GBMinInstance } from 'botlib';
|
||||||
import { Messages } from "../strings";
|
import { CSService } from '../services/CSService';
|
||||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
import { Messages } from '../strings';
|
||||||
const logger = require("../../../src/logger");
|
const logger = require('../../../src/logger');
|
||||||
|
|
||||||
export class QualityDialog extends IGBDialog {
|
export class QualityDialog extends IGBDialog {
|
||||||
/**
|
/**
|
||||||
|
@ -52,18 +52,18 @@ export class QualityDialog extends IGBDialog {
|
||||||
* @param bot The bot adapter.
|
* @param bot The bot adapter.
|
||||||
* @param min The minimal bot instance data.
|
* @param min The minimal bot instance data.
|
||||||
*/
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
const service = new CSService();
|
const service = new CSService();
|
||||||
|
|
||||||
min.dialogs.add( new WaterfallDialog("/quality", [
|
min.dialogs.add(new WaterfallDialog('/quality', [
|
||||||
async step => {
|
async step => {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
const user = await min.userProfile.get(context, {});
|
const user = await min.userProfile.get(context, {});
|
||||||
|
|
||||||
var score = step.result;
|
const score = step.result;
|
||||||
|
|
||||||
setTimeout(
|
setTimeout(
|
||||||
() => min.conversationalService.sendEvent(step, "stop", null),
|
() => min.conversationalService.sendEvent(step, 'stop', null),
|
||||||
400
|
400
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ export class QualityDialog extends IGBDialog {
|
||||||
user.lastQuestion,
|
user.lastQuestion,
|
||||||
user.lastQuestionId
|
user.lastQuestionId
|
||||||
);
|
);
|
||||||
await step.replaceDialog("/ask", { isReturning: true });
|
await step.replaceDialog('/ask', { isReturning: true });
|
||||||
}
|
}
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,34 +34,34 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
import { GuaribasQuestionAlternate } from './models/index'
|
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||||
import { QualityDialog } from './dialogs/QualityDialog'
|
import { FeedbackDialog } from './dialogs/FeedbackDialog';
|
||||||
import { FeedbackDialog } from './dialogs/FeedbackDialog'
|
import { QualityDialog } from './dialogs/QualityDialog';
|
||||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
import { GuaribasQuestionAlternate } from './models/index';
|
||||||
|
|
||||||
import { Sequelize } from 'sequelize-typescript'
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
|
|
||||||
export class GBCustomerSatisfactionPackage implements IGBPackage {
|
export class GBCustomerSatisfactionPackage implements IGBPackage {
|
||||||
sysPackages: IGBPackage[] = null
|
public sysPackages: IGBPackage[] = null;
|
||||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||||
core.sequelize.addModels([
|
core.sequelize.addModels([
|
||||||
GuaribasQuestionAlternate
|
GuaribasQuestionAlternate
|
||||||
])
|
]);
|
||||||
}
|
}
|
||||||
unloadPackage(core: IGBCoreService): void {
|
public unloadPackage(core: IGBCoreService): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
loadBot(min: GBMinInstance): void {
|
public loadBot(min: GBMinInstance): void {
|
||||||
FeedbackDialog.setup(min.bot, min)
|
FeedbackDialog.setup(min.bot, min);
|
||||||
QualityDialog.setup(min.bot, min)
|
QualityDialog.setup(min.bot, min);
|
||||||
}
|
}
|
||||||
unloadBot(min: GBMinInstance): void {
|
public unloadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
onNewSession(min: GBMinInstance, step: any): void {
|
public onNewSession(min: GBMinInstance, step: any): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,34 +34,34 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DataTypes,
|
|
||||||
DataTypeUUIDv4,
|
|
||||||
DataTypeDate,
|
DataTypeDate,
|
||||||
DataTypeDecimal
|
DataTypeDecimal,
|
||||||
} from "sequelize"
|
DataTypes,
|
||||||
|
DataTypeUUIDv4
|
||||||
|
} from 'sequelize';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Sequelize,
|
AutoIncrement,
|
||||||
Table,
|
|
||||||
Column,
|
|
||||||
Model,
|
|
||||||
HasMany,
|
|
||||||
BelongsTo,
|
BelongsTo,
|
||||||
BelongsToMany,
|
BelongsToMany,
|
||||||
Length,
|
Column,
|
||||||
ForeignKey,
|
|
||||||
CreatedAt,
|
CreatedAt,
|
||||||
UpdatedAt,
|
|
||||||
DataType,
|
DataType,
|
||||||
|
ForeignKey,
|
||||||
|
HasMany,
|
||||||
IsUUID,
|
IsUUID,
|
||||||
|
Length,
|
||||||
|
Model,
|
||||||
PrimaryKey,
|
PrimaryKey,
|
||||||
AutoIncrement
|
Sequelize,
|
||||||
} from "sequelize-typescript"
|
Table,
|
||||||
|
UpdatedAt
|
||||||
|
} from 'sequelize-typescript';
|
||||||
|
|
||||||
import { GuaribasInstance } from "../../core.gbapp/models/GBModel"
|
import { GuaribasInstance } from '../../core.gbapp/models/GBModel';
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
export class GuaribasQuestionAlternate extends Model<GuaribasQuestionAlternate> {
|
export class GuaribasQuestionAlternate extends Model<GuaribasQuestionAlternate> {
|
||||||
|
@ -69,16 +69,16 @@ export class GuaribasQuestionAlternate extends Model<GuaribasQuestionAlternate>
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
quickAnswerId: number
|
public quickAnswerId: number;
|
||||||
|
|
||||||
@Column questionTyped: string
|
@Column public questionTyped: string;
|
||||||
|
|
||||||
@Column questionText: string
|
@Column public questionText: string;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
instanceId: number
|
public instanceId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasInstance)
|
@BelongsTo(() => GuaribasInstance)
|
||||||
instance: GuaribasInstance
|
public instance: GuaribasInstance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,12 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
import { GuaribasQuestionAlternate } from '../models'
|
import { GuaribasConversation } from '../../analytics.gblib/models';
|
||||||
import { GuaribasConversation } from '../../analytics.gblib/models'
|
import { GuaribasQuestionAlternate } from '../models';
|
||||||
|
|
||||||
export class CSService {
|
export class CSService {
|
||||||
|
|
||||||
async resolveQuestionAlternate(
|
public async resolveQuestionAlternate(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
questionTyped: string): Promise<GuaribasQuestionAlternate> {
|
questionTyped: string): Promise<GuaribasQuestionAlternate> {
|
||||||
|
|
||||||
|
@ -44,24 +44,24 @@ export class CSService {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
questionTyped: questionTyped
|
questionTyped: questionTyped
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async insertQuestionAlternate(
|
public async insertQuestionAlternate(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
questionTyped: string,
|
questionTyped: string,
|
||||||
questionText: string): Promise<GuaribasQuestionAlternate> {
|
questionText: string): Promise<GuaribasQuestionAlternate> {
|
||||||
return GuaribasQuestionAlternate.create({
|
return GuaribasQuestionAlternate.create({
|
||||||
questionTyped: questionTyped,
|
questionTyped: questionTyped,
|
||||||
questionText: questionText
|
questionText: questionText
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateConversationRate(
|
public async updateConversationRate(
|
||||||
conversation: GuaribasConversation,
|
conversation: GuaribasConversation,
|
||||||
rate: number
|
rate: number
|
||||||
): Promise<GuaribasConversation> {
|
): Promise<GuaribasConversation> {
|
||||||
conversation.rate = rate
|
conversation.rate = rate;
|
||||||
return conversation.save()
|
return conversation.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
export const Messages = {
|
export const Messages = {
|
||||||
"en-US": {
|
'en-US': {
|
||||||
about_suggestions: "Suggestions are welcomed and improve my quality...",
|
about_suggestions: 'Suggestions are welcomed and improve my quality...',
|
||||||
what_about_service: "What about my service?",
|
what_about_service: 'What about my service?',
|
||||||
glad_you_liked: "I'm glad you liked. I'm here for you.",
|
glad_you_liked: 'I\'m glad you liked. I\'m here for you.',
|
||||||
we_will_improve: "Let's take note of that, thanks for sharing.",
|
we_will_improve: 'Let\'s take note of that, thanks for sharing.',
|
||||||
what_about_me: "What about the service, please rate between 1 and 5.",
|
what_about_me: 'What about the service, please rate between 1 and 5.',
|
||||||
thanks: "Thanks!",
|
thanks: 'Thanks!',
|
||||||
im_sorry_lets_try: "I'm sorry. Let's try again...",
|
im_sorry_lets_try: 'I\'m sorry. Let\'s try again...',
|
||||||
great_thanks: "Great, thanks for sharing your thoughts."
|
great_thanks: 'Great, thanks for sharing your thoughts.'
|
||||||
},
|
},
|
||||||
"pt-BR": {
|
'pt-BR': {
|
||||||
about_suggestions: "Sugestões melhoram muito minha qualidade...",
|
about_suggestions: 'Sugestões melhoram muito minha qualidade...',
|
||||||
what_about_service:"O que achou do meu atendimento?",
|
what_about_service: 'O que achou do meu atendimento?',
|
||||||
glad_you_liked: "Bom saber que você gostou. Conte comigo.",
|
glad_you_liked: 'Bom saber que você gostou. Conte comigo.',
|
||||||
we_will_improve: "Vamos registrar sua questão, obrigado pela sinceridade.",
|
we_will_improve: 'Vamos registrar sua questão, obrigado pela sinceridade.',
|
||||||
what_about_me: "O que achou do meu atendimento, de 1 a 5?",
|
what_about_me: 'O que achou do meu atendimento, de 1 a 5?',
|
||||||
thanks: "Obrigado!",
|
thanks: 'Obrigado!',
|
||||||
im_sorry_lets_try: "Desculpe-me, vamos tentar novamente.",
|
im_sorry_lets_try: 'Desculpe-me, vamos tentar novamente.',
|
||||||
great_thanks: "Ótimo, obrigado por contribuir com sua resposta."
|
great_thanks: 'Ótimo, obrigado por contribuir com sua resposta.'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,15 +36,15 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { IGBDialog } from "botlib";
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { AzureText } from "pragmatismo-io-framework";
|
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import { GBMinInstance } from "botlib";
|
import { IGBDialog } from 'botlib';
|
||||||
import { KBService } from "./../services/KBService";
|
import { GBMinInstance } from 'botlib';
|
||||||
import { BotAdapter } from "botbuilder";
|
import { AzureText } from 'pragmatismo-io-framework';
|
||||||
import { Messages } from "../strings";
|
import { Messages } from '../strings';
|
||||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
import { KBService } from './../services/KBService';
|
||||||
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require('../../../src/logger');
|
||||||
|
|
||||||
export class AskDialog extends IGBDialog {
|
export class AskDialog extends IGBDialog {
|
||||||
/**
|
/**
|
||||||
|
@ -53,18 +53,18 @@ export class AskDialog extends IGBDialog {
|
||||||
* @param bot The bot adapter.
|
* @param bot The bot adapter.
|
||||||
* @param min The minimal bot instance data.
|
* @param min The minimal bot instance data.
|
||||||
*/
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
const service = new KBService(min.core.sequelize);
|
const service = new KBService(min.core.sequelize);
|
||||||
|
|
||||||
min.dialogs.add(
|
min.dialogs.add(
|
||||||
new WaterfallDialog("/answerEvent", [
|
new WaterfallDialog('/answerEvent', [
|
||||||
async step => {
|
async step => {
|
||||||
if (step.options && step.options["questionId"]) {
|
if (step.options && step.options.questionId) {
|
||||||
let question = await service.getQuestionById(
|
const question = await service.getQuestionById(
|
||||||
min.instance.instanceId,
|
min.instance.instanceId,
|
||||||
step.options["questionId"]
|
step.options.questionId
|
||||||
);
|
);
|
||||||
let answer = await service.getAnswerById(
|
const answer = await service.getAnswerById(
|
||||||
min.instance.instanceId,
|
min.instance.instanceId,
|
||||||
question.answerId
|
question.answerId
|
||||||
);
|
);
|
||||||
|
@ -73,7 +73,7 @@ export class AskDialog extends IGBDialog {
|
||||||
|
|
||||||
await service.sendAnswer(min.conversationalService, step, answer);
|
await service.sendAnswer(min.conversationalService, step, answer);
|
||||||
|
|
||||||
await step.replaceDialog("/ask", { isReturning: true });
|
await step.replaceDialog('/ask', { isReturning: true });
|
||||||
}
|
}
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
|
@ -81,32 +81,32 @@ export class AskDialog extends IGBDialog {
|
||||||
);
|
);
|
||||||
|
|
||||||
min.dialogs.add(
|
min.dialogs.add(
|
||||||
new WaterfallDialog("/answer", [
|
new WaterfallDialog('/answer', [
|
||||||
async step => {
|
async step => {
|
||||||
const user = await min.userProfile.get(step.context, {});
|
const user = await min.userProfile.get(step.context, {});
|
||||||
let text = step.options["query"];
|
let text = step.options.query;
|
||||||
if (!text) {
|
if (!text) {
|
||||||
throw new Error(`/answer being called with no args.query text.`);
|
throw new Error(`/answer being called with no args.query text.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
|
|
||||||
// Stops any content on projector.
|
// Stops any content on projector.
|
||||||
|
|
||||||
await min.conversationalService.sendEvent(step, "stop", null);
|
await min.conversationalService.sendEvent(step, 'stop', null);
|
||||||
|
|
||||||
// Handle extra text from FAQ.
|
// Handle extra text from FAQ.
|
||||||
|
|
||||||
if (step.options && step.options["query"]) {
|
if (step.options && step.options.query) {
|
||||||
text = step.options["query"];
|
text = step.options.query;
|
||||||
} else if (step.options && step.options["fromFaq"]) {
|
} else if (step.options && step.options.fromFaq) {
|
||||||
await step.context.sendActivity(Messages[locale].going_answer);
|
await step.context.sendActivity(Messages[locale].going_answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spells check the input text before sending Search or NLP.
|
// Spells check the input text before sending Search or NLP.
|
||||||
|
|
||||||
if (min.instance.spellcheckerKey) {
|
if (min.instance.spellcheckerKey) {
|
||||||
let data = await AzureText.getSpelledText(
|
const data = await AzureText.getSpelledText(
|
||||||
min.instance.spellcheckerKey,
|
min.instance.spellcheckerKey,
|
||||||
text
|
text
|
||||||
);
|
);
|
||||||
|
@ -121,7 +121,7 @@ export class AskDialog extends IGBDialog {
|
||||||
|
|
||||||
user.lastQuestion = text;
|
user.lastQuestion = text;
|
||||||
await min.userProfile.set(step.context, user);
|
await min.userProfile.set(step.context, user);
|
||||||
let resultsA = await service.ask(
|
const resultsA = await service.ask(
|
||||||
min.instance,
|
min.instance,
|
||||||
text,
|
text,
|
||||||
min.instance.searchScore,
|
min.instance.searchScore,
|
||||||
|
@ -147,11 +147,11 @@ export class AskDialog extends IGBDialog {
|
||||||
|
|
||||||
// Goes to ask loop, again.
|
// Goes to ask loop, again.
|
||||||
|
|
||||||
return await step.replaceDialog("/ask", { isReturning: true });
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
} else {
|
} else {
|
||||||
// Second time running Search, now with no filter.
|
// Second time running Search, now with no filter.
|
||||||
|
|
||||||
let resultsB = await service.ask(
|
const resultsB = await service.ask(
|
||||||
min.instance,
|
min.instance,
|
||||||
text,
|
text,
|
||||||
min.instance.searchScore,
|
min.instance.searchScore,
|
||||||
|
@ -172,7 +172,7 @@ export class AskDialog extends IGBDialog {
|
||||||
// Informs user that a broader search will be used.
|
// Informs user that a broader search will be used.
|
||||||
|
|
||||||
if (user.subjects.length > 0) {
|
if (user.subjects.length > 0) {
|
||||||
let subjectText = `${KBService.getSubjectItemsSeparatedBySpaces(
|
const subjectText = `${KBService.getSubjectItemsSeparatedBySpaces(
|
||||||
user.subjects
|
user.subjects
|
||||||
)}`;
|
)}`;
|
||||||
await step.context.sendActivity(Messages[locale].wider_answer);
|
await step.context.sendActivity(Messages[locale].wider_answer);
|
||||||
|
@ -185,13 +185,13 @@ export class AskDialog extends IGBDialog {
|
||||||
step,
|
step,
|
||||||
resultsB.answer
|
resultsB.answer
|
||||||
);
|
);
|
||||||
return await step.replaceDialog("/ask", { isReturning: true });
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
!(await min.conversationalService.routeNLP(step, min, text))
|
!(await min.conversationalService.routeNLP(step, min, text))
|
||||||
) {
|
) {
|
||||||
await step.context.sendActivity(Messages[locale].did_not_find);
|
await step.context.sendActivity(Messages[locale].did_not_find);
|
||||||
return await step.replaceDialog("/ask", { isReturning: true });
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ export class AskDialog extends IGBDialog {
|
||||||
);
|
);
|
||||||
|
|
||||||
min.dialogs.add(
|
min.dialogs.add(
|
||||||
new WaterfallDialog("/ask", [
|
new WaterfallDialog('/ask', [
|
||||||
async step => {
|
async step => {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
const user = await min.userProfile.get(step.context, {});
|
const user = await min.userProfile.get(step.context, {});
|
||||||
|
@ -212,23 +212,23 @@ export class AskDialog extends IGBDialog {
|
||||||
|
|
||||||
// Three forms of asking.
|
// Three forms of asking.
|
||||||
|
|
||||||
if (step.options && step.options["firstTime"]) {
|
if (step.options && step.options.firstTime) {
|
||||||
text = Messages[locale].ask_first_time;
|
text = Messages[locale].ask_first_time;
|
||||||
} else if (step.options && step.options["isReturning"]) {
|
} else if (step.options && step.options.isReturning) {
|
||||||
text = Messages[locale].anything_else;
|
text = Messages[locale].anything_else;
|
||||||
} else if (user.subjects.length > 0) {
|
} else if (user.subjects.length > 0) {
|
||||||
text = Messages[locale].which_question;
|
text = Messages[locale].which_question;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Invalid use of /ask");
|
throw new Error('Invalid use of /ask');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.length > 0) {
|
if (text.length > 0) {
|
||||||
return await step.prompt("textPrompt", text);
|
return await step.prompt('textPrompt', text);
|
||||||
}
|
}
|
||||||
return await step.next();
|
return await step.next();
|
||||||
},
|
},
|
||||||
async step => {
|
async step => {
|
||||||
return await step.replaceDialog("/answer", { query: step.result });
|
return await step.replaceDialog('/answer', { query: step.result });
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,14 +34,14 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
import { KBService } from './../services/KBService'
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { IGBDialog } from "botlib"
|
|
||||||
import { BotAdapter } from "botbuilder"
|
|
||||||
import { Messages } from "../strings";
|
|
||||||
import { GBMinInstance } from "botlib"
|
|
||||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
|
import { IGBDialog } from 'botlib';
|
||||||
|
import { GBMinInstance } from 'botlib';
|
||||||
|
import { Messages } from '../strings';
|
||||||
|
import { KBService } from './../services/KBService';
|
||||||
|
|
||||||
export class FaqDialog extends IGBDialog {
|
export class FaqDialog extends IGBDialog {
|
||||||
/**
|
/**
|
||||||
|
@ -50,25 +50,25 @@ export class FaqDialog extends IGBDialog {
|
||||||
* @param bot The bot adapter.
|
* @param bot The bot adapter.
|
||||||
* @param min The minimal bot instance data.
|
* @param min The minimal bot instance data.
|
||||||
*/
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
const service = new KBService(min.core.sequelize)
|
const service = new KBService(min.core.sequelize);
|
||||||
|
|
||||||
min.dialogs.add(new WaterfallDialog("/faq", [
|
min.dialogs.add(new WaterfallDialog('/faq', [
|
||||||
async step => {
|
async step => {
|
||||||
let data = await service.getFaqBySubjectArray("faq", null)
|
const data = await service.getFaqBySubjectArray('faq', null);
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
if (data) {
|
if (data) {
|
||||||
await min.conversationalService.sendEvent(step, "play", {
|
await min.conversationalService.sendEvent(step, 'play', {
|
||||||
playerType: "bullet",
|
playerType: 'bullet',
|
||||||
data: data.slice(0, 10)
|
data: data.slice(0, 10)
|
||||||
})
|
});
|
||||||
|
|
||||||
await step.context.sendActivity(Messages[locale].see_faq) // TODO: RND messages.
|
await step.context.sendActivity(Messages[locale].see_faq); // TODO: RND messages.
|
||||||
await step.endDialog()
|
await step.endDialog();
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]))
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ export class MenuDialog extends IGBDialog {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
let rootSubjectId = null;
|
let rootSubjectId = null;
|
||||||
|
|
||||||
if (step.options && step.options['data']) {
|
if (step.options && step.options.data) {
|
||||||
const subject = step.result.data;
|
const subject = step.result.data;
|
||||||
|
|
||||||
// If there is a shortcut specified as subject destination, go there.
|
// If there is a shortcut specified as subject destination, go there.
|
||||||
|
|
|
@ -34,45 +34,45 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
|
|
||||||
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from './models/index'
|
import { GBMinInstance, IGBPackage } from 'botlib';
|
||||||
import { GBMinInstance, IGBPackage } from "botlib"
|
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from './models/index';
|
||||||
|
|
||||||
import { AskDialog } from "./dialogs/AskDialog"
|
import { IGBCoreService } from 'botlib';
|
||||||
import { FaqDialog } from "./dialogs/FaqDialog"
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
import { MenuDialog } from "./dialogs/MenuDialog"
|
import { AskDialog } from './dialogs/AskDialog';
|
||||||
import { Sequelize } from 'sequelize-typescript'
|
import { FaqDialog } from './dialogs/FaqDialog';
|
||||||
import { IGBCoreService } from 'botlib'
|
import { MenuDialog } from './dialogs/MenuDialog';
|
||||||
|
|
||||||
export class GBKBPackage implements IGBPackage {
|
export class GBKBPackage implements IGBPackage {
|
||||||
|
|
||||||
sysPackages: IGBPackage[] = null
|
public sysPackages: IGBPackage[] = null;
|
||||||
|
|
||||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||||
core.sequelize.addModels([
|
core.sequelize.addModels([
|
||||||
GuaribasAnswer,
|
GuaribasAnswer,
|
||||||
GuaribasQuestion,
|
GuaribasQuestion,
|
||||||
GuaribasSubject
|
GuaribasSubject
|
||||||
])
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
unloadPackage(core: IGBCoreService): void {
|
public unloadPackage(core: IGBCoreService): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
loadBot(min: GBMinInstance): void {
|
public loadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
AskDialog.setup(min.bot, min)
|
AskDialog.setup(min.bot, min);
|
||||||
FaqDialog.setup(min.bot, min)
|
FaqDialog.setup(min.bot, min);
|
||||||
MenuDialog.setup(min.bot, min)
|
MenuDialog.setup(min.bot, min);
|
||||||
|
|
||||||
}
|
}
|
||||||
unloadBot(min: GBMinInstance): void {
|
public unloadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
onNewSession(min: GBMinInstance, step: any): void {
|
public onNewSession(min: GBMinInstance, step: any): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,40 +30,57 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
const logger = require("../../../src/logger")
|
const logger = require('../../../src/logger');
|
||||||
const Path = require("path")
|
const Path = require('path');
|
||||||
const Fs = require("fs")
|
const Fs = require('fs');
|
||||||
const promise = require('bluebird')
|
const promise = require('bluebird');
|
||||||
const parse = promise.promisify(require('csv-parse'))
|
const parse = promise.promisify(require('csv-parse'));
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
const marked = require("marked")
|
const marked = require('marked');
|
||||||
const path = require("path")
|
const path = require('path');
|
||||||
const asyncPromise = require('async-promises')
|
const asyncPromise = require('async-promises');
|
||||||
const walkPromise = require('walk-promise')
|
const walkPromise = require('walk-promise');
|
||||||
import { Messages } from "../strings";
|
import { Messages } from '../strings';
|
||||||
|
|
||||||
import { Sequelize } from 'sequelize-typescript'
|
import { IGBConversationalService, IGBCoreService, IGBInstance } from 'botlib';
|
||||||
import { GBConfigService } from './../../core.gbapp/services/GBConfigService'
|
import { AzureSearch } from 'pragmatismo-io-framework';
|
||||||
import { GuaribasQuestion, GuaribasAnswer, GuaribasSubject } from "../models"
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
import { IGBCoreService, IGBConversationalService, IGBInstance } from "botlib"
|
import { GuaribasPackage } from '../../core.gbapp/models/GBModel';
|
||||||
import { AzureSearch } from "pragmatismo-io-framework"
|
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
||||||
import { GBDeployer } from "../../core.gbapp/services/GBDeployer"
|
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from '../models';
|
||||||
import { GuaribasPackage } from "../../core.gbapp/models/GBModel"
|
import { GBConfigService } from './../../core.gbapp/services/GBConfigService';
|
||||||
|
|
||||||
export class KBServiceSearchResults {
|
export class KBServiceSearchResults {
|
||||||
answer: GuaribasAnswer
|
public answer: GuaribasAnswer;
|
||||||
questionId: number
|
public questionId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KBService {
|
export class KBService {
|
||||||
|
|
||||||
sequelize: Sequelize
|
public sequelize: Sequelize;
|
||||||
|
|
||||||
constructor(sequelize: Sequelize) {
|
constructor(sequelize: Sequelize) {
|
||||||
this.sequelize = sequelize
|
this.sequelize = sequelize;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getQuestionById(
|
public static getFormattedSubjectItems(subjects: GuaribasSubject[]) {
|
||||||
|
if (!subjects) { return ''; }
|
||||||
|
const out = [];
|
||||||
|
subjects.forEach(subject => {
|
||||||
|
out.push(subject.title);
|
||||||
|
});
|
||||||
|
return out.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getSubjectItemsSeparatedBySpaces(subjects: GuaribasSubject[]) {
|
||||||
|
const out = [];
|
||||||
|
subjects.forEach(subject => {
|
||||||
|
out.push(subject.internalId);
|
||||||
|
});
|
||||||
|
return out.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getQuestionById(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
questionId: number
|
questionId: number
|
||||||
): Promise<GuaribasQuestion> {
|
): Promise<GuaribasQuestion> {
|
||||||
|
@ -72,10 +89,10 @@ export class KBService {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
questionId: questionId
|
questionId: questionId
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAnswerById(
|
public async getAnswerById(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
answerId: number
|
answerId: number
|
||||||
): Promise<GuaribasAnswer> {
|
): Promise<GuaribasAnswer> {
|
||||||
|
@ -84,47 +101,47 @@ export class KBService {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
answerId: answerId
|
answerId: answerId
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAnswerByText(
|
public async getAnswerByText(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
text: string
|
text: string
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
|
|
||||||
const Op = Sequelize.Op
|
const Op = Sequelize.Op;
|
||||||
|
|
||||||
let question = await GuaribasQuestion.findOne({
|
const question = await GuaribasQuestion.findOne({
|
||||||
where: {
|
where: {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
content: { [Op.like]: `%${text.trim()}%` }
|
content: { [Op.like]: `%${text.trim()}%` }
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
if (question) {
|
if (question) {
|
||||||
let answer = await GuaribasAnswer.findOne({
|
const answer = await GuaribasAnswer.findOne({
|
||||||
where: {
|
where: {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
answerId: question.answerId
|
answerId: question.answerId
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return Promise.resolve({ question: question, answer: answer })
|
return Promise.resolve({ question: question, answer: answer });
|
||||||
}
|
}
|
||||||
return Promise.resolve(null)
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addAnswer(obj: GuaribasAnswer): Promise<GuaribasAnswer> {
|
public async addAnswer(obj: GuaribasAnswer): Promise<GuaribasAnswer> {
|
||||||
return new Promise<GuaribasAnswer>(
|
return new Promise<GuaribasAnswer>(
|
||||||
(resolve, reject) => {
|
(resolve, reject) => {
|
||||||
GuaribasAnswer.create(obj).then(item => {
|
GuaribasAnswer.create(obj).then(item => {
|
||||||
resolve(item)
|
resolve(item);
|
||||||
}).error((reason) => {
|
}).error((reason) => {
|
||||||
reject(reason)
|
reject(reason);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async ask(
|
public async ask(
|
||||||
instance: IGBInstance,
|
instance: IGBInstance,
|
||||||
query: string,
|
query: string,
|
||||||
searchScore: number,
|
searchScore: number,
|
||||||
|
@ -133,185 +150,165 @@ export class KBService {
|
||||||
|
|
||||||
// Builds search query.
|
// Builds search query.
|
||||||
|
|
||||||
query = query.toLowerCase()
|
query = query.toLowerCase();
|
||||||
query = query.replace("?", " ")
|
query = query.replace('?', ' ');
|
||||||
query = query.replace("!", " ")
|
query = query.replace('!', ' ');
|
||||||
query = query.replace(".", " ")
|
query = query.replace('.', ' ');
|
||||||
query = query.replace("/", " ")
|
query = query.replace('/', ' ');
|
||||||
query = query.replace("\\", " ")
|
query = query.replace('\\', ' ');
|
||||||
|
|
||||||
if (subjects) {
|
if (subjects) {
|
||||||
let text = KBService.getSubjectItemsSeparatedBySpaces(subjects)
|
const text = KBService.getSubjectItemsSeparatedBySpaces(subjects);
|
||||||
if (text) {
|
if (text) {
|
||||||
query = `${query} ${text}`
|
query = `${query} ${text}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Filter by instance. what = `${what}&$filter=instanceId eq ${instanceId}`
|
// TODO: Filter by instance. what = `${what}&$filter=instanceId eq ${instanceId}`
|
||||||
try {
|
try {
|
||||||
if (instance.searchKey && GBConfigService.get("STORAGE_DIALECT") == "mssql") {
|
if (instance.searchKey && GBConfigService.get('STORAGE_DIALECT') == 'mssql') {
|
||||||
let service = new AzureSearch(
|
const service = new AzureSearch(
|
||||||
instance.searchKey,
|
instance.searchKey,
|
||||||
instance.searchHost,
|
instance.searchHost,
|
||||||
instance.searchIndex,
|
instance.searchIndex,
|
||||||
instance.searchIndexer
|
instance.searchIndexer
|
||||||
)
|
);
|
||||||
let results = await service.search(query)
|
const results = await service.search(query);
|
||||||
if (results && results.length > 0 &&
|
if (results && results.length > 0 &&
|
||||||
results[0]["@search.score"] >= searchScore) {
|
results[0]['@search.score'] >= searchScore) {
|
||||||
let value = await this.getAnswerById(
|
const value = await this.getAnswerById(
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
results[0].answerId)
|
results[0].answerId);
|
||||||
if (value) {
|
if (value) {
|
||||||
return Promise.resolve({ answer: value, questionId: results[0].questionId })
|
return Promise.resolve({ answer: value, questionId: results[0].questionId });
|
||||||
}
|
} else {
|
||||||
else {
|
return Promise.resolve({ answer: null, questionId: 0 });
|
||||||
return Promise.resolve({ answer: null, questionId: 0 })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let data = await this.getAnswerByText(instance.instanceId, query)
|
const data = await this.getAnswerByText(instance.instanceId, query);
|
||||||
if (data) {
|
if (data) {
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
{ answer: data.answer, questionId: data.question.questionId })
|
{ answer: data.answer, questionId: data.question.questionId });
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve({ answer: null, questionId: 0 })
|
return Promise.resolve({ answer: null, questionId: 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (reason) {
|
||||||
catch (reason) {
|
|
||||||
return Promise.reject(new Error(reason));
|
return Promise.reject(new Error(reason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getSubjectItems(
|
||||||
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.internalId)
|
|
||||||
})
|
|
||||||
return out.join(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSubjectItems(
|
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
parentId: number
|
parentId: number
|
||||||
): Promise<GuaribasSubject[]> {
|
): Promise<GuaribasSubject[]> {
|
||||||
var where = { parentSubjectId: parentId, instanceId: instanceId }
|
const where = { parentSubjectId: parentId, instanceId: instanceId };
|
||||||
return GuaribasSubject.findAll({
|
return GuaribasSubject.findAll({
|
||||||
where: where
|
where: where
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFaqBySubjectArray(from: string, subjects: any): Promise<GuaribasQuestion[]> {
|
public async getFaqBySubjectArray(from: string, subjects: any): Promise<GuaribasQuestion[]> {
|
||||||
let where = {
|
const where = {
|
||||||
from: from
|
from: from
|
||||||
}
|
};
|
||||||
|
|
||||||
if (subjects) {
|
if (subjects) {
|
||||||
if (subjects[0]) {
|
if (subjects[0]) {
|
||||||
where["subject1"] = subjects[0].internalId
|
where.subject1 = subjects[0].internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subjects[1]) {
|
if (subjects[1]) {
|
||||||
where["subject2"] = subjects[1].internalId
|
where.subject2 = subjects[1].internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subjects[2]) {
|
if (subjects[2]) {
|
||||||
where["subject3"] = subjects[2].internalId
|
where.subject3 = subjects[2].internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subjects[3]) {
|
if (subjects[3]) {
|
||||||
where["subject4"] = subjects[3].internalId
|
where.subject4 = subjects[3].internalId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await GuaribasQuestion.findAll({
|
return await GuaribasQuestion.findAll({
|
||||||
where: where
|
where: where
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async importKbTabularFile(
|
public async importKbTabularFile(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
packageId: number
|
packageId: number
|
||||||
): Promise<GuaribasQuestion[]> {
|
): Promise<GuaribasQuestion[]> {
|
||||||
|
|
||||||
let file = Fs.readFileSync(filePath, "UCS-2")
|
const file = Fs.readFileSync(filePath, 'UCS-2');
|
||||||
let opts = {
|
const opts = {
|
||||||
delimiter: "\t"
|
delimiter: '\t'
|
||||||
}
|
};
|
||||||
|
|
||||||
let lastQuestion: GuaribasQuestion;
|
let lastQuestion: GuaribasQuestion;
|
||||||
let lastAnswer: GuaribasAnswer;
|
let lastAnswer: GuaribasAnswer;
|
||||||
|
|
||||||
let data = await parse(file, opts)
|
const data = await parse(file, opts);
|
||||||
return asyncPromise.eachSeries(data, async line => {
|
return asyncPromise.eachSeries(data, async line => {
|
||||||
|
|
||||||
// Extracts values from columns in the current line.
|
// Extracts values from columns in the current line.
|
||||||
|
|
||||||
let subjectsText = line[0]
|
const subjectsText = line[0];
|
||||||
var from = line[1]
|
const from = line[1];
|
||||||
var to = line[2]
|
const to = line[2];
|
||||||
var question = line[3]
|
const question = line[3];
|
||||||
var answer = line[4]
|
let answer = line[4];
|
||||||
|
|
||||||
// Skips the first line.
|
// Skips the first line.
|
||||||
|
|
||||||
if (!(subjectsText === "subjects" && from == "from")) {
|
if (!(subjectsText === 'subjects' && from == 'from')) {
|
||||||
let format = ".txt"
|
let format = '.txt';
|
||||||
|
|
||||||
// Extracts answer from external media if any.
|
// Extracts answer from external media if any.
|
||||||
|
|
||||||
if (answer.indexOf(".md") > -1) {
|
if (answer.indexOf('.md') > -1) {
|
||||||
let mediaFilename = UrlJoin(path.dirname(filePath), "..", "articles", answer)
|
const mediaFilename = UrlJoin(path.dirname(filePath), '..', 'articles', answer);
|
||||||
if (Fs.existsSync(mediaFilename)) {
|
if (Fs.existsSync(mediaFilename)) {
|
||||||
answer = Fs.readFileSync(mediaFilename, "utf8")
|
answer = Fs.readFileSync(mediaFilename, 'utf8');
|
||||||
format = ".md"
|
format = '.md';
|
||||||
} else {
|
} else {
|
||||||
logger.info(`[GBImporter] File not found: ${mediaFilename}.`)
|
logger.info(`[GBImporter] File not found: ${mediaFilename}.`);
|
||||||
answer = ""
|
answer = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes subjects hierarchy splitting by dots.
|
// Processes subjects hierarchy splitting by dots.
|
||||||
|
|
||||||
let subjectArray = subjectsText.split(".")
|
const subjectArray = subjectsText.split('.');
|
||||||
let subject1: string, subject2: string, subject3: string,
|
let subject1: string, subject2: string, subject3: string,
|
||||||
subject4: string
|
subject4: string;
|
||||||
var indexer = 0
|
let indexer = 0;
|
||||||
|
|
||||||
subjectArray.forEach(element => {
|
subjectArray.forEach(element => {
|
||||||
if (indexer == 0) {
|
if (indexer == 0) {
|
||||||
subject1 = subjectArray[indexer].substring(0, 63)
|
subject1 = subjectArray[indexer].substring(0, 63);
|
||||||
} else if (indexer == 1) {
|
} else if (indexer == 1) {
|
||||||
subject2 = subjectArray[indexer].substring(0, 63)
|
subject2 = subjectArray[indexer].substring(0, 63);
|
||||||
} else if (indexer == 2) {
|
} else if (indexer == 2) {
|
||||||
subject3 = subjectArray[indexer].substring(0, 63)
|
subject3 = subjectArray[indexer].substring(0, 63);
|
||||||
} else if (indexer == 3) {
|
} else if (indexer == 3) {
|
||||||
subject4 = subjectArray[indexer].substring(0, 63)
|
subject4 = subjectArray[indexer].substring(0, 63);
|
||||||
}
|
}
|
||||||
indexer++
|
indexer++;
|
||||||
})
|
});
|
||||||
|
|
||||||
// Now with all the data ready, creates entities in the store.
|
// Now with all the data ready, creates entities in the store.
|
||||||
|
|
||||||
let answer1 = await GuaribasAnswer.create({
|
const answer1 = await GuaribasAnswer.create({
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
content: answer,
|
content: answer,
|
||||||
format: format,
|
format: format,
|
||||||
packageId: packageId,
|
packageId: packageId,
|
||||||
prevId: lastQuestion ? lastQuestion.questionId : 0,
|
prevId: lastQuestion ? lastQuestion.questionId : 0
|
||||||
})
|
});
|
||||||
|
|
||||||
let question1 = await GuaribasQuestion.create({
|
const question1 = await GuaribasQuestion.create({
|
||||||
from: from,
|
from: from,
|
||||||
to: to,
|
to: to,
|
||||||
subject1: subject1,
|
subject1: subject1,
|
||||||
|
@ -322,41 +319,41 @@ export class KBService {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
answerId: answer1.answerId,
|
answerId: answer1.answerId,
|
||||||
packageId: packageId
|
packageId: packageId
|
||||||
})
|
});
|
||||||
|
|
||||||
if (lastAnswer && lastQuestion) {
|
if (lastAnswer && lastQuestion) {
|
||||||
await lastAnswer.updateAttributes({ nextId: lastQuestion.questionId })
|
await lastAnswer.updateAttributes({ nextId: lastQuestion.questionId });
|
||||||
}
|
}
|
||||||
lastAnswer = answer1
|
lastAnswer = answer1;
|
||||||
lastQuestion = question1
|
lastQuestion = question1;
|
||||||
|
|
||||||
return Promise.resolve(lastQuestion)
|
return Promise.resolve(lastQuestion);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Skips the header.
|
// Skips the header.
|
||||||
|
|
||||||
return Promise.resolve(null)
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendAnswer(conversationalService: IGBConversationalService,
|
public async sendAnswer(conversationalService: IGBConversationalService,
|
||||||
step: any, answer: GuaribasAnswer) {
|
step: any, answer: GuaribasAnswer) {
|
||||||
|
|
||||||
if (answer.content.endsWith('.mp4')) {
|
if (answer.content.endsWith('.mp4')) {
|
||||||
await conversationalService.sendEvent(step, "play", {
|
await conversationalService.sendEvent(step, 'play', {
|
||||||
playerType: "video",
|
playerType: 'video',
|
||||||
data: answer.content
|
data: answer.content
|
||||||
})
|
});
|
||||||
} else if (answer.content.length > 140 &&
|
} else if (answer.content.length > 140 &&
|
||||||
step.context._activity.channelId === "webchat") {
|
step.context._activity.channelId === 'webchat') {
|
||||||
const locale = step.context.activity.locale;
|
const locale = step.context.activity.locale;
|
||||||
|
|
||||||
await step.context.sendActivity(Messages[locale].will_answer_projector) // TODO: Handle rnd.
|
await step.context.sendActivity(Messages[locale].will_answer_projector); // TODO: Handle rnd.
|
||||||
var html = answer.content
|
let html = answer.content;
|
||||||
|
|
||||||
if (answer.format === ".md") {
|
if (answer.format === '.md') {
|
||||||
marked.setOptions({
|
marked.setOptions({
|
||||||
renderer: new marked.Renderer(),
|
renderer: new marked.Renderer(),
|
||||||
gfm: true,
|
gfm: true,
|
||||||
|
@ -367,23 +364,23 @@ export class KBService {
|
||||||
smartLists: true,
|
smartLists: true,
|
||||||
smartypants: false,
|
smartypants: false,
|
||||||
xhtml: false
|
xhtml: false
|
||||||
})
|
});
|
||||||
html = marked(answer.content)
|
html = marked(answer.content);
|
||||||
}
|
}
|
||||||
await conversationalService.sendEvent(step, "play",
|
await conversationalService.sendEvent(step, 'play',
|
||||||
{
|
{
|
||||||
playerType: "markdown", data: {
|
playerType: 'markdown', data: {
|
||||||
content: html, answer: answer,
|
content: html, answer: answer,
|
||||||
prevId: answer.prevId, nextId: answer.nextId
|
prevId: answer.prevId, nextId: answer.nextId
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
await step.context.sendActivity(answer.content)
|
await step.context.sendActivity(answer.content);
|
||||||
await conversationalService.sendEvent(step, "stop", null)
|
await conversationalService.sendEvent(step, 'stop', null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async importKbPackage(
|
public async importKbPackage(
|
||||||
localPath: string,
|
localPath: string,
|
||||||
packageStorage: GuaribasPackage,
|
packageStorage: GuaribasPackage,
|
||||||
instance: IGBInstance
|
instance: IGBInstance
|
||||||
|
@ -393,8 +390,8 @@ export class KBService {
|
||||||
|
|
||||||
await this.importSubjectFile(
|
await this.importSubjectFile(
|
||||||
packageStorage.packageId,
|
packageStorage.packageId,
|
||||||
UrlJoin(localPath, "subjects.json"),
|
UrlJoin(localPath, 'subjects.json'),
|
||||||
instance)
|
instance);
|
||||||
|
|
||||||
// Import all .tsv files in the tabular directory.
|
// Import all .tsv files in the tabular directory.
|
||||||
|
|
||||||
|
@ -402,41 +399,40 @@ export class KBService {
|
||||||
localPath,
|
localPath,
|
||||||
instance,
|
instance,
|
||||||
packageStorage.packageId
|
packageStorage.packageId
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async importKbTabularDirectory(
|
||||||
async importKbTabularDirectory(
|
|
||||||
localPath: string,
|
localPath: string,
|
||||||
instance: IGBInstance,
|
instance: IGBInstance,
|
||||||
packageId: number
|
packageId: number
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
|
|
||||||
let files = await walkPromise(UrlJoin(localPath, "tabular"))
|
const files = await walkPromise(UrlJoin(localPath, 'tabular'));
|
||||||
|
|
||||||
return Promise.all(files.map(async file => {
|
return Promise.all(files.map(async file => {
|
||||||
if (file.name.endsWith(".tsv")) {
|
if (file.name.endsWith('.tsv')) {
|
||||||
return this.importKbTabularFile(
|
return this.importKbTabularFile(
|
||||||
UrlJoin(file.root, file.name),
|
UrlJoin(file.root, file.name),
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
packageId)
|
packageId);
|
||||||
}
|
}
|
||||||
}))
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async importSubjectFile(
|
public async importSubjectFile(
|
||||||
packageId: number,
|
packageId: number,
|
||||||
filename: string,
|
filename: string,
|
||||||
instance: IGBInstance
|
instance: IGBInstance
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
var subjects = JSON.parse(Fs.readFileSync(filename, "utf8"))
|
const subjects = JSON.parse(Fs.readFileSync(filename, 'utf8'));
|
||||||
|
|
||||||
const doIt = async (subjects: GuaribasSubject[], parentSubjectId: number) => {
|
const doIt = async (subjects: GuaribasSubject[], parentSubjectId: number) => {
|
||||||
return asyncPromise.eachSeries(subjects, async item => {
|
return asyncPromise.eachSeries(subjects, async item => {
|
||||||
let mediaFilename = item.id + ".png"
|
const mediaFilename = item.id + '.png';
|
||||||
|
|
||||||
let value = await GuaribasSubject.create({
|
const value = await GuaribasSubject.create({
|
||||||
internalId: item.id,
|
internalId: item.id,
|
||||||
parentSubjectId: parentSubjectId,
|
parentSubjectId: parentSubjectId,
|
||||||
instanceId: instance.instanceId,
|
instanceId: instance.instanceId,
|
||||||
|
@ -445,20 +441,19 @@ export class KBService {
|
||||||
title: item.title,
|
title: item.title,
|
||||||
description: item.description,
|
description: item.description,
|
||||||
packageId: packageId
|
packageId: packageId
|
||||||
})
|
});
|
||||||
|
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
return Promise.resolve(doIt(item.children, value.subjectId))
|
return Promise.resolve(doIt(item.children, value.subjectId));
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(item);
|
||||||
}
|
}
|
||||||
else {
|
});
|
||||||
return Promise.resolve(item)
|
};
|
||||||
}
|
return doIt(subjects.children, null);
|
||||||
})
|
|
||||||
}
|
|
||||||
return doIt(subjects.children, null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async undeployKbFromStorage(
|
public async undeployKbFromStorage(
|
||||||
instance: IGBInstance,
|
instance: IGBInstance,
|
||||||
deployer: GBDeployer,
|
deployer: GBDeployer,
|
||||||
packageId: number
|
packageId: number
|
||||||
|
@ -466,18 +461,18 @@ export class KBService {
|
||||||
|
|
||||||
await GuaribasQuestion.destroy({
|
await GuaribasQuestion.destroy({
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
})
|
});
|
||||||
await GuaribasAnswer.destroy({
|
await GuaribasAnswer.destroy({
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
})
|
});
|
||||||
await GuaribasSubject.destroy({
|
await GuaribasSubject.destroy({
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
})
|
});
|
||||||
await GuaribasPackage.destroy({
|
await GuaribasPackage.destroy({
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
})
|
});
|
||||||
|
|
||||||
await deployer.rebuildIndex(instance)
|
await deployer.rebuildIndex(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -485,22 +480,22 @@ export class KBService {
|
||||||
*
|
*
|
||||||
* @param localPath Path to the .gbkb folder.
|
* @param localPath Path to the .gbkb folder.
|
||||||
*/
|
*/
|
||||||
async deployKb(core: IGBCoreService, deployer: GBDeployer, localPath: string) {
|
public async deployKb(core: IGBCoreService, deployer: GBDeployer, localPath: string) {
|
||||||
let packageType = Path.extname(localPath)
|
const packageType = Path.extname(localPath);
|
||||||
let packageName = Path.basename(localPath)
|
const packageName = Path.basename(localPath);
|
||||||
logger.info(`[GBDeployer] Opening package: ${localPath}`)
|
logger.info(`[GBDeployer] Opening package: ${localPath}`);
|
||||||
let packageObject = JSON.parse(
|
const packageObject = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, 'package.json'), 'utf8')
|
||||||
)
|
);
|
||||||
|
|
||||||
let instance = await core.loadInstance(packageObject.botId)
|
const instance = await core.loadInstance(packageObject.botId);
|
||||||
logger.info(`[GBDeployer] Importing: ${localPath}`)
|
logger.info(`[GBDeployer] Importing: ${localPath}`);
|
||||||
let p = await deployer.deployPackageToStorage(
|
const p = await deployer.deployPackageToStorage(
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
packageName)
|
packageName);
|
||||||
await this.importKbPackage(localPath, p, instance)
|
await this.importKbPackage(localPath, p, instance);
|
||||||
|
|
||||||
deployer.rebuildIndex(instance)
|
deployer.rebuildIndex(instance);
|
||||||
logger.info(`[GBDeployer] Finished import of ${localPath}`)
|
logger.info(`[GBDeployer] Finished import of ${localPath}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
export const Messages = {
|
export const Messages = {
|
||||||
"en-US": {
|
'en-US': {
|
||||||
did_not_find: "I'm sorry I didn't find anything.",
|
did_not_find: 'I\'m sorry I didn\'t find anything.',
|
||||||
changing_language: "OK, changing language to English...",
|
changing_language: 'OK, changing language to English...',
|
||||||
going_answer: "Great choice, now looking for your answer...",
|
going_answer: 'Great choice, now looking for your answer...',
|
||||||
wider_answer: subjectText =>
|
wider_answer: subjectText =>
|
||||||
`Answering to you in a broader way... Not just about ${subjectText}.`,
|
`Answering to you in a broader way... Not just about ${subjectText}.`,
|
||||||
which_question: "What's your question?",
|
which_question: 'What\'s your question?',
|
||||||
anything_else: "So, may I help with anything else?",
|
anything_else: 'So, may I help with anything else?',
|
||||||
here_is_subjects: "Here are some subjects to choose from...",
|
here_is_subjects: 'Here are some subjects to choose from...',
|
||||||
menu_select: "Select",
|
menu_select: 'Select',
|
||||||
lets_search: query =>
|
lets_search: query =>
|
||||||
`Vamos pesquisar sobre ${query}... O que deseja saber?`,
|
`Vamos pesquisar sobre ${query}... O que deseja saber?`,
|
||||||
see_faq:
|
see_faq:
|
||||||
"Please take a look at the FAQ I've prepared for you. You can click on them to get the answer.",
|
'Please take a look at the FAQ I\'ve prepared for you. You can click on them to get the answer.',
|
||||||
will_answer_projector:
|
will_answer_projector:
|
||||||
"I'll answer on the projector to a better experience...",
|
'I\'ll answer on the projector to a better experience...',
|
||||||
ask_first_time: "What are you looking for?"
|
ask_first_time: 'What are you looking for?'
|
||||||
},
|
},
|
||||||
"pt-BR": {
|
'pt-BR': {
|
||||||
did_not_find: "Desculpe-me, não encontrei nada a respeito.",
|
did_not_find: 'Desculpe-me, não encontrei nada a respeito.',
|
||||||
changing_language: "OK, mundando de idioma para o Português...",
|
changing_language: 'OK, mundando de idioma para o Português...',
|
||||||
going_answer: "Ótima escolha, procurando resposta para sua questão...",
|
going_answer: 'Ótima escolha, procurando resposta para sua questão...',
|
||||||
wider_answer: subjectText =>
|
wider_answer: subjectText =>
|
||||||
`Vou te responder de modo mais abrangente... Não apenas sobre ${subjectText}`,
|
`Vou te responder de modo mais abrangente... Não apenas sobre ${subjectText}`,
|
||||||
which_question: "Qual a pergunta?",
|
which_question: 'Qual a pergunta?',
|
||||||
anything_else: "Então, posso ajudar em algo a mais?",
|
anything_else: 'Então, posso ajudar em algo a mais?',
|
||||||
here_is_subjects: "Aqui estão algumas categorias de assuntos...",
|
here_is_subjects: 'Aqui estão algumas categorias de assuntos...',
|
||||||
menu_select: "Selecionar",
|
menu_select: 'Selecionar',
|
||||||
lets_search: query =>
|
lets_search: query =>
|
||||||
`Let's search about ${query}... What do you want to know?`,
|
`Let's search about ${query}... What do you want to know?`,
|
||||||
see_faq:
|
see_faq:
|
||||||
"Veja algumas perguntas mais frequentes logo na tela. Clique numa delas para eu responder.",
|
'Veja algumas perguntas mais frequentes logo na tela. Clique numa delas para eu responder.',
|
||||||
will_answer_projector:
|
will_answer_projector:
|
||||||
"Vou te responder na tela para melhor visualização...",
|
'Vou te responder na tela para melhor visualização...',
|
||||||
ask_first_time: "Sobre como eu poderia ajudar?"
|
ask_first_time: 'Sobre como eu poderia ajudar?'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,40 +34,39 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
|
|
||||||
|
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||||
|
|
||||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
|
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from './models';
|
||||||
import { Sequelize } from "sequelize-typescript"
|
|
||||||
import { GuaribasUser, GuaribasGroup, GuaribasUserGroup } from "./models"
|
|
||||||
|
|
||||||
export class GBSecurityPackage implements IGBPackage {
|
export class GBSecurityPackage implements IGBPackage {
|
||||||
sysPackages: IGBPackage[] = null
|
public sysPackages: IGBPackage[] = null;
|
||||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||||
core.sequelize.addModels([
|
core.sequelize.addModels([
|
||||||
GuaribasGroup,
|
GuaribasGroup,
|
||||||
GuaribasUser,
|
GuaribasUser,
|
||||||
GuaribasUserGroup
|
GuaribasUserGroup
|
||||||
])
|
]);
|
||||||
|
|
||||||
core
|
core;
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadPackage(core: IGBCoreService): void {
|
public unloadPackage(core: IGBCoreService): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBot(min: GBMinInstance): void {
|
public loadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadBot(min: GBMinInstance): void {
|
public unloadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
onNewSession(min: GBMinInstance, step: any): void {
|
public onNewSession(min: GBMinInstance, step: any): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,60 +34,60 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DataTypes,
|
|
||||||
DataTypeUUIDv4,
|
|
||||||
DataTypeDate,
|
DataTypeDate,
|
||||||
DataTypeDecimal
|
DataTypeDecimal,
|
||||||
} from "sequelize"
|
DataTypes,
|
||||||
|
DataTypeUUIDv4
|
||||||
|
} from 'sequelize';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Sequelize,
|
AutoIncrement,
|
||||||
Table,
|
|
||||||
Column,
|
|
||||||
Model,
|
|
||||||
HasMany,
|
|
||||||
BelongsTo,
|
BelongsTo,
|
||||||
BelongsToMany,
|
BelongsToMany,
|
||||||
Length,
|
Column,
|
||||||
ForeignKey,
|
|
||||||
CreatedAt,
|
CreatedAt,
|
||||||
UpdatedAt,
|
|
||||||
DataType,
|
DataType,
|
||||||
|
ForeignKey,
|
||||||
|
HasMany,
|
||||||
IsUUID,
|
IsUUID,
|
||||||
|
Length,
|
||||||
|
Model,
|
||||||
PrimaryKey,
|
PrimaryKey,
|
||||||
AutoIncrement
|
Sequelize,
|
||||||
} from "sequelize-typescript"
|
Table,
|
||||||
|
UpdatedAt
|
||||||
|
} from 'sequelize-typescript';
|
||||||
|
|
||||||
import { GuaribasInstance } from "../../core.gbapp/models/GBModel"
|
import { GuaribasInstance } from '../../core.gbapp/models/GBModel';
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
export class GuaribasUser extends Model<GuaribasUser> {
|
export class GuaribasUser extends Model<GuaribasUser> {
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
userId: number
|
public userId: number;
|
||||||
|
|
||||||
@Column displayName: string
|
@Column public displayName: string;
|
||||||
|
|
||||||
@Column userSystemId: string
|
@Column public userSystemId: string;
|
||||||
@Column userName: string
|
@Column public userName: string;
|
||||||
|
|
||||||
@Column defaultChannel: string
|
@Column public defaultChannel: string;
|
||||||
|
|
||||||
@Column email: string
|
@Column public email: string;
|
||||||
|
|
||||||
@Column(DataType.STRING(512))
|
@Column(DataType.STRING(512))
|
||||||
internalAddress: string
|
public internalAddress: string;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
instanceId: number
|
public instanceId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasInstance)
|
@BelongsTo(() => GuaribasInstance)
|
||||||
instance: GuaribasInstance
|
public instance: GuaribasInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
|
@ -95,40 +95,40 @@ export class GuaribasGroup extends Model<GuaribasGroup> {
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
groupId: number
|
public groupId: number;
|
||||||
|
|
||||||
@Length({ min: 0, max: 512 })
|
@Length({ min: 0, max: 512 })
|
||||||
@Column
|
@Column
|
||||||
displayName: string
|
public displayName: string;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
instanceId: number
|
public instanceId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasInstance)
|
@BelongsTo(() => GuaribasInstance)
|
||||||
instance: GuaribasInstance
|
public instance: GuaribasInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
export class GuaribasUserGroup extends Model<GuaribasUserGroup> {
|
export class GuaribasUserGroup extends Model<GuaribasUserGroup> {
|
||||||
@ForeignKey(() => GuaribasUser)
|
@ForeignKey(() => GuaribasUser)
|
||||||
@Column
|
@Column
|
||||||
userId: number
|
public userId: number;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasGroup)
|
@ForeignKey(() => GuaribasGroup)
|
||||||
@Column
|
@Column
|
||||||
groupId: number
|
public groupId: number;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
instanceId: number
|
public instanceId: number;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasInstance)
|
@BelongsTo(() => GuaribasInstance)
|
||||||
instance: GuaribasInstance
|
public instance: GuaribasInstance;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasGroup)
|
@BelongsTo(() => GuaribasGroup)
|
||||||
group: GuaribasGroup
|
public group: GuaribasGroup;
|
||||||
|
|
||||||
@BelongsTo(() => GuaribasUser)
|
@BelongsTo(() => GuaribasUser)
|
||||||
user: GuaribasUser
|
public user: GuaribasUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,48 +30,48 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
const Path = require("path")
|
const Path = require('path');
|
||||||
const Fs = require("fs")
|
const Fs = require('fs');
|
||||||
const _ = require("lodash")
|
const _ = require('lodash');
|
||||||
const Parse = require("csv-parse")
|
const Parse = require('csv-parse');
|
||||||
const Async = require("async")
|
const Async = require('async');
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
const Walk = require("fs-walk")
|
const Walk = require('fs-walk');
|
||||||
const logger = require("../../../src/logger")
|
const logger = require('../../../src/logger');
|
||||||
|
|
||||||
import { GBServiceCallback, GBService, IGBInstance } from "botlib"
|
import { GBService, GBServiceCallback, IGBInstance } from 'botlib';
|
||||||
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from "../models"
|
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from '../models';
|
||||||
|
|
||||||
export class SecService extends GBService {
|
export class SecService extends GBService {
|
||||||
|
|
||||||
async importSecurityFile(localPath: string, instance: IGBInstance) {
|
public async importSecurityFile(localPath: string, instance: IGBInstance) {
|
||||||
let security = JSON.parse(
|
const security = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "security.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, 'security.json'), 'utf8')
|
||||||
)
|
);
|
||||||
security.groups.forEach(group => {
|
security.groups.forEach(group => {
|
||||||
let groupDb = GuaribasGroup.build({
|
const groupDb = GuaribasGroup.build({
|
||||||
instanceId: instance.instanceId,
|
instanceId: instance.instanceId,
|
||||||
displayName: group.displayName
|
displayName: group.displayName
|
||||||
})
|
});
|
||||||
groupDb.save().then(groupDb => {
|
groupDb.save().then(groupDb => {
|
||||||
group.users.forEach(user => {
|
group.users.forEach(user => {
|
||||||
let userDb = GuaribasUser.build({
|
const userDb = GuaribasUser.build({
|
||||||
instanceId: instance.instanceId,
|
instanceId: instance.instanceId,
|
||||||
groupId: groupDb.groupId,
|
groupId: groupDb.groupId,
|
||||||
userName: user.userName
|
userName: user.userName
|
||||||
})
|
});
|
||||||
userDb.save().then(userDb => {
|
userDb.save().then(userDb => {
|
||||||
let userGroup = GuaribasUserGroup.build()
|
const userGroup = GuaribasUserGroup.build();
|
||||||
userGroup.groupId = groupDb.groupId
|
userGroup.groupId = groupDb.groupId;
|
||||||
userGroup.userId = userDb.userId
|
userGroup.userId = userDb.userId;
|
||||||
userGroup.save()
|
userGroup.save();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async ensureUser(
|
public async ensureUser(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
userSystemId: string,
|
userSystemId: string,
|
||||||
userName: string,
|
userName: string,
|
||||||
|
@ -83,24 +83,24 @@ export class SecService extends GBService {
|
||||||
(resolve, reject) => {
|
(resolve, reject) => {
|
||||||
|
|
||||||
GuaribasUser.findOne({
|
GuaribasUser.findOne({
|
||||||
attributes: ["instanceId", "internalAddress"],
|
attributes: ['instanceId', 'internalAddress'],
|
||||||
where: {
|
where: {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
userSystemId: userSystemId
|
userSystemId: userSystemId
|
||||||
}
|
}
|
||||||
}).then(user => {
|
}).then(user => {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
user = GuaribasUser.build()
|
user = GuaribasUser.build();
|
||||||
}
|
}
|
||||||
user.userSystemId = userSystemId
|
user.userSystemId = userSystemId;
|
||||||
user.userName = userName
|
user.userName = userName;
|
||||||
user.displayName = displayName
|
user.displayName = displayName;
|
||||||
user.internalAddress = address
|
user.internalAddress = address;
|
||||||
user.email = userName
|
user.email = userName;
|
||||||
user.defaultChannel = channelName
|
user.defaultChannel = channelName;
|
||||||
user.save()
|
user.save();
|
||||||
resolve(user)
|
resolve(user);
|
||||||
}).error(reason => reject(reason))
|
}).error(reject);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,43 +34,41 @@
|
||||||
* @fileoverview General Bots server core.
|
* @fileoverview General Bots server core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
|
|
||||||
|
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||||
|
|
||||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
|
import { WhatsappDirectLine } from './services/WhatsappDirectLine';
|
||||||
import { Sequelize } from "sequelize-typescript"
|
|
||||||
import { WhatsappDirectLine } from "./services/WhatsappDirectLine"
|
|
||||||
|
|
||||||
|
|
||||||
export class GBWhatsappPackage implements IGBPackage {
|
export class GBWhatsappPackage implements IGBPackage {
|
||||||
|
|
||||||
sysPackages: IGBPackage[] = null
|
public sysPackages: IGBPackage[] = null;
|
||||||
channel: WhatsappDirectLine
|
public channel: WhatsappDirectLine;
|
||||||
|
|
||||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadPackage(core: IGBCoreService): void {
|
public unloadPackage(core: IGBCoreService): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBot(min: GBMinInstance): void {
|
public loadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
// Only loads engine if it is defined on services.json.
|
// Only loads engine if it is defined on services.json.
|
||||||
|
|
||||||
if (min.instance.whatsappBotKey != "") {
|
if (min.instance.whatsappBotKey != '') {
|
||||||
this.channel = new WhatsappDirectLine(min.botId, min.instance.whatsappBotKey, min.instance.whatsappServiceKey,
|
this.channel = new WhatsappDirectLine(min.botId, min.instance.whatsappBotKey, min.instance.whatsappServiceKey,
|
||||||
min.instance.whatsappServiceNumber, min.instance.whatsappServiceUrl, min.instance.whatsappServiceWebhookUrl)
|
min.instance.whatsappServiceNumber, min.instance.whatsappServiceUrl, min.instance.whatsappServiceWebhookUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadBot(min: GBMinInstance): void {
|
public unloadBot(min: GBMinInstance): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
onNewSession(min: GBMinInstance, step: any): void {
|
public onNewSession(min: GBMinInstance, step: any): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,45 +30,45 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
const Path = require("path")
|
const Path = require('path');
|
||||||
const Fs = require("fs")
|
const Fs = require('fs');
|
||||||
const _ = require("lodash")
|
const _ = require('lodash');
|
||||||
const Parse = require("csv-parse")
|
const Parse = require('csv-parse');
|
||||||
const Async = require("async")
|
const Async = require('async');
|
||||||
const UrlJoin = require("url-join")
|
const UrlJoin = require('url-join');
|
||||||
const Walk = require("fs-walk")
|
const Walk = require('fs-walk');
|
||||||
const logger = require("../../../src/logger")
|
const logger = require('../../../src/logger');
|
||||||
const Swagger = require('swagger-client')
|
const Swagger = require('swagger-client');
|
||||||
const rp = require('request-promise')
|
const rp = require('request-promise');
|
||||||
import * as request from "request-promise-native"
|
import * as request from 'request-promise-native';
|
||||||
|
|
||||||
import { GBServiceCallback, GBService, IGBInstance } from "botlib"
|
import { GBService, GBServiceCallback, IGBInstance } from 'botlib';
|
||||||
|
|
||||||
export class WhatsappDirectLine extends GBService {
|
export class WhatsappDirectLine extends GBService {
|
||||||
|
|
||||||
pollInterval = 1000
|
public pollInterval = 1000;
|
||||||
directLineClientName = 'DirectLineClient'
|
public directLineClientName = 'DirectLineClient';
|
||||||
directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json'
|
public directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json';
|
||||||
|
|
||||||
directLineClient: any
|
public directLineClient: any;
|
||||||
whatsappServiceKey: string
|
public whatsappServiceKey: string;
|
||||||
whatsappServiceNumber: string
|
public whatsappServiceNumber: string;
|
||||||
whatsappServiceUrl: string
|
public whatsappServiceUrl: string;
|
||||||
whatsappServiceWebhookUrl: string
|
public whatsappServiceWebhookUrl: string;
|
||||||
botId: string
|
public botId: string;
|
||||||
watermark: string = null
|
public watermark: string = null;
|
||||||
|
|
||||||
conversationIds = {}
|
public conversationIds = {};
|
||||||
|
|
||||||
constructor(botId, directLineSecret, whatsappServiceKey, whatsappServiceNumber, whatsappServiceUrl, whatsappServiceWebhookUrl) {
|
constructor(botId, directLineSecret, whatsappServiceKey, whatsappServiceNumber, whatsappServiceUrl, whatsappServiceWebhookUrl) {
|
||||||
|
|
||||||
super()
|
super();
|
||||||
|
|
||||||
this.botId = botId
|
this.botId = botId;
|
||||||
this.whatsappServiceKey = whatsappServiceKey
|
this.whatsappServiceKey = whatsappServiceKey;
|
||||||
this.whatsappServiceNumber = whatsappServiceNumber
|
this.whatsappServiceNumber = whatsappServiceNumber;
|
||||||
this.whatsappServiceUrl = whatsappServiceUrl
|
this.whatsappServiceUrl = whatsappServiceUrl;
|
||||||
this.whatsappServiceWebhookUrl = whatsappServiceWebhookUrl
|
this.whatsappServiceWebhookUrl = whatsappServiceWebhookUrl;
|
||||||
|
|
||||||
// TODO: Migrate to Swagger 3.
|
// TODO: Migrate to Swagger 3.
|
||||||
this.directLineClient = rp(this.directLineSpecUrl)
|
this.directLineClient = rp(this.directLineSpecUrl)
|
||||||
|
@ -76,16 +76,16 @@ export class WhatsappDirectLine extends GBService {
|
||||||
return new Swagger({
|
return new Swagger({
|
||||||
spec: JSON.parse(spec.trim()),
|
spec: JSON.parse(spec.trim()),
|
||||||
usePromise: true
|
usePromise: true
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.then(async (client) => {
|
.then(async (client) => {
|
||||||
client.clientAuthorizations.add('AuthorizationBotConnector',
|
client.clientAuthorizations.add('AuthorizationBotConnector',
|
||||||
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' +
|
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' +
|
||||||
directLineSecret, 'header'))
|
directLineSecret, 'header'));
|
||||||
|
|
||||||
var options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: UrlJoin(this.whatsappServiceUrl, "webhook"),
|
url: UrlJoin(this.whatsappServiceUrl, 'webhook'),
|
||||||
qs:
|
qs:
|
||||||
{
|
{
|
||||||
token: this.whatsappServiceKey,
|
token: this.whatsappServiceKey,
|
||||||
|
@ -96,67 +96,66 @@ export class WhatsappDirectLine extends GBService {
|
||||||
{
|
{
|
||||||
'cache-control': 'no-cache'
|
'cache-control': 'no-cache'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await request.post(options)
|
const result = await request.post(options);
|
||||||
logger.info(result)
|
logger.info(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error initializing 3rd party Whatsapp provider.', error)
|
logger.error('Error initializing 3rd party Whatsapp provider.', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return client
|
return client;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
logger.error('Error initializing DirectLine client', err)
|
logger.error('Error initializing DirectLine client', err);
|
||||||
})
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
received(req, res) {
|
public received(req, res) {
|
||||||
let text = req.body.messages[0].body
|
const text = req.body.messages[0].body;
|
||||||
let from = req.body.messages[0].author.split('@')[0]
|
const from = req.body.messages[0].author.split('@')[0];
|
||||||
let fromName = req.body.messages[0].senderName
|
const fromName = req.body.messages[0].senderName;
|
||||||
|
|
||||||
if (req.body.messages[0].fromMe) {
|
if (req.body.messages[0].fromMe) {
|
||||||
return // Exit here.
|
return; // Exit here.
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`GBWhatsapp: Hook called. from: ${from}(${fromName}), text: ${text})`)
|
logger.info(`GBWhatsapp: Hook called. from: ${from}(${fromName}), text: ${text})`);
|
||||||
|
|
||||||
let conversationId = this.conversationIds[from]
|
const conversationId = this.conversationIds[from];
|
||||||
|
|
||||||
this.directLineClient.then((client) => {
|
this.directLineClient.then((client) => {
|
||||||
|
|
||||||
if (this.conversationIds[from] == null) {
|
if (this.conversationIds[from] == null) {
|
||||||
|
|
||||||
logger.info(`GBWhatsapp: Starting new conversation on Bot.`)
|
logger.info(`GBWhatsapp: Starting new conversation on Bot.`);
|
||||||
client.Conversations.Conversations_StartConversation()
|
client.Conversations.Conversations_StartConversation()
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
return response.obj.conversationId
|
return response.obj.conversationId;
|
||||||
})
|
})
|
||||||
.then((conversationId) => {
|
.then((conversationId) => {
|
||||||
|
|
||||||
this.conversationIds[from] = conversationId
|
this.conversationIds[from] = conversationId;
|
||||||
this.inputMessage(client, conversationId, text,
|
this.inputMessage(client, conversationId, text,
|
||||||
from, fromName)
|
from, fromName);
|
||||||
|
|
||||||
this.pollMessages(client, conversationId, from, fromName)
|
this.pollMessages(client, conversationId, from, fromName);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error('Error starting conversation', err)
|
console.error('Error starting conversation', err);
|
||||||
})
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.inputMessage(client, conversationId, text,
|
this.inputMessage(client, conversationId, text,
|
||||||
from, fromName)
|
from, fromName);
|
||||||
}
|
}
|
||||||
res.end()
|
res.end();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public inputMessage(client, conversationId, text, from, fromName) {
|
||||||
inputMessage(client, conversationId, text, from, fromName) {
|
|
||||||
|
|
||||||
client.Conversations.Conversations_PostActivity(
|
client.Conversations.Conversations_PostActivity(
|
||||||
{
|
{
|
||||||
|
@ -172,15 +171,15 @@ export class WhatsappDirectLine extends GBService {
|
||||||
replyToId: from
|
replyToId: from
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
logger.error(`GBWhatsapp: Error receiving message: ${err}.`)
|
logger.error(`GBWhatsapp: Error receiving message: ${err}.`);
|
||||||
})
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pollMessages(client, conversationId, from, fromName) {
|
public pollMessages(client, conversationId, from, fromName) {
|
||||||
|
|
||||||
logger.info(`GBWhatsapp: Starting polling message for conversationId:
|
logger.info(`GBWhatsapp: Starting polling message for conversationId:
|
||||||
${conversationId}.`)
|
${conversationId}.`);
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
client.Conversations.Conversations_GetActivities({
|
client.Conversations.Conversations_GetActivities({
|
||||||
|
@ -188,67 +187,67 @@ export class WhatsappDirectLine extends GBService {
|
||||||
conversationId, watermark: this.watermark
|
conversationId, watermark: this.watermark
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.watermark = response.obj.watermark
|
this.watermark = response.obj.watermark;
|
||||||
return response.obj.activities
|
return response.obj.activities;
|
||||||
})
|
})
|
||||||
.then((activities) => {
|
.then((activities) => {
|
||||||
this.printMessages(activities, conversationId, from, fromName)
|
this.printMessages(activities, conversationId, from, fromName);
|
||||||
})
|
});
|
||||||
}, this.pollInterval)
|
}, this.pollInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
printMessages(activities, conversationId, from, fromName) {
|
public printMessages(activities, conversationId, from, fromName) {
|
||||||
|
|
||||||
if (activities && activities.length) {
|
if (activities && activities.length) {
|
||||||
|
|
||||||
// Ignore own messages.
|
// Ignore own messages.
|
||||||
|
|
||||||
activities = activities.filter((m) => { return (m.from.id === "GeneralBots") && m.type === "message" })
|
activities = activities.filter((m) => (m.from.id === 'GeneralBots') && m.type === 'message');
|
||||||
|
|
||||||
if (activities.length) {
|
if (activities.length) {
|
||||||
|
|
||||||
// Print other messages.
|
// Print other messages.
|
||||||
|
|
||||||
activities.forEach(activity => {
|
activities.forEach(activity => {
|
||||||
this.printMessage(activity, conversationId, from, fromName)
|
this.printMessage(activity, conversationId, from, fromName);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printMessage(activity, conversationId, from, fromName) {
|
public printMessage(activity, conversationId, from, fromName) {
|
||||||
|
|
||||||
let output = ""
|
let output = '';
|
||||||
|
|
||||||
if (activity.text) {
|
if (activity.text) {
|
||||||
logger.info(`GBWhatsapp: MSG: ${activity.text}`)
|
logger.info(`GBWhatsapp: MSG: ${activity.text}`);
|
||||||
output = activity.text
|
output = activity.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.attachments) {
|
if (activity.attachments) {
|
||||||
activity.attachments.forEach((attachment) => {
|
activity.attachments.forEach((attachment) => {
|
||||||
switch (attachment.contentType) {
|
switch (attachment.contentType) {
|
||||||
case "application/vnd.microsoft.card.hero":
|
case 'application/vnd.microsoft.card.hero':
|
||||||
output += `\n${this.renderHeroCard(attachment)}`
|
output += `\n${this.renderHeroCard(attachment)}`;
|
||||||
break
|
break;
|
||||||
|
|
||||||
case "image/png":
|
case 'image/png':
|
||||||
logger.info('Opening the requested image ' + attachment.contentUrl)
|
logger.info('Opening the requested image ' + attachment.contentUrl);
|
||||||
output += `\n${attachment.contentUrl}`
|
output += `\n${attachment.contentUrl}`;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendToDevice(conversationId, from, fromName, output)
|
this.sendToDevice(conversationId, from, fromName, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHeroCard(attachment) {
|
public renderHeroCard(attachment) {
|
||||||
return `${attachment.content.title} - ${attachment.content.text}`
|
return `${attachment.content.title} - ${attachment.content.text}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendToDevice(conversationId, to, toName, msg) {
|
public async sendToDevice(conversationId, to, toName, msg) {
|
||||||
var options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: UrlJoin(this.whatsappServiceUrl, 'message'),
|
url: UrlJoin(this.whatsappServiceUrl, 'message'),
|
||||||
qs:
|
qs:
|
||||||
|
@ -261,8 +260,8 @@ export class WhatsappDirectLine extends GBService {
|
||||||
{
|
{
|
||||||
'cache-control': 'no-cache'
|
'cache-control': 'no-cache'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const result = await request.get(options)
|
const result = await request.get(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
98
src/app.ts
98
src/app.ts
|
@ -37,30 +37,30 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const logger = require("./logger");
|
const logger = require('./logger');
|
||||||
const express = require("express");
|
const express = require('express');
|
||||||
const bodyParser = require("body-parser");
|
const bodyParser = require('body-parser');
|
||||||
const opn = require('opn');
|
const opn = require('opn');
|
||||||
|
|
||||||
import { GBConfigService } from "../packages/core.gbapp/services/GBConfigService";
|
import { IGBInstance, IGBPackage } from 'botlib';
|
||||||
import { GBConversationalService } from "../packages/core.gbapp/services/GBConversationalService";
|
import { GBAdminPackage } from '../packages/admin.gbapp/index';
|
||||||
import { GBMinService } from "../packages/core.gbapp/services/GBMinService";
|
import { GBAdminService } from '../packages/admin.gbapp/services/GBAdminService';
|
||||||
import { GBDeployer } from "../packages/core.gbapp/services/GBDeployer";
|
import { GBAnalyticsPackage } from '../packages/analytics.gblib';
|
||||||
import { GBWhatsappPackage } from "./../packages/whatsapp.gblib/index";
|
import { AzureDeployerService } from '../packages/azuredeployer.gbapp/services/AzureDeployerService';
|
||||||
import { GBCoreService } from "../packages/core.gbapp/services/GBCoreService";
|
import { GBCorePackage } from '../packages/core.gbapp';
|
||||||
import { GBImporter } from "../packages/core.gbapp/services/GBImporter";
|
import { GuaribasInstance } from '../packages/core.gbapp/models/GBModel';
|
||||||
import { GBAnalyticsPackage } from "../packages/analytics.gblib";
|
import { GBConfigService } from '../packages/core.gbapp/services/GBConfigService';
|
||||||
import { GBCorePackage } from "../packages/core.gbapp";
|
import { GBConversationalService } from '../packages/core.gbapp/services/GBConversationalService';
|
||||||
import { GBKBPackage } from "../packages/kb.gbapp";
|
import { GBCoreService } from '../packages/core.gbapp/services/GBCoreService';
|
||||||
import { GBSecurityPackage } from "../packages/security.gblib";
|
import { GBDeployer } from '../packages/core.gbapp/services/GBDeployer';
|
||||||
import { GBAdminPackage } from "../packages/admin.gbapp/index";
|
import { GBImporter } from '../packages/core.gbapp/services/GBImporter';
|
||||||
import { GBCustomerSatisfactionPackage } from "../packages/customer-satisfaction.gbapp";
|
import { GBMinService } from '../packages/core.gbapp/services/GBMinService';
|
||||||
import { GBAdminService } from "../packages/admin.gbapp/services/GBAdminService";
|
import { GBCustomerSatisfactionPackage } from '../packages/customer-satisfaction.gbapp';
|
||||||
import { GuaribasInstance } from "../packages/core.gbapp/models/GBModel";
|
import { GBKBPackage } from '../packages/kb.gbapp';
|
||||||
import { AzureDeployerService } from "../packages/azuredeployer.gbapp/services/AzureDeployerService";
|
import { GBSecurityPackage } from '../packages/security.gblib';
|
||||||
import { IGBPackage, IGBInstance } from "botlib";
|
import { GBWhatsappPackage } from './../packages/whatsapp.gblib/index';
|
||||||
|
|
||||||
let appPackages = new Array<IGBPackage>();
|
const appPackages = new Array<IGBPackage>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General Bots open-core entry point.
|
* General Bots open-core entry point.
|
||||||
|
@ -71,7 +71,7 @@ export class GBServer {
|
||||||
* Program entry-point.
|
* Program entry-point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static run() {
|
public static run() {
|
||||||
|
|
||||||
logger.info(`The Bot Server is in STARTING mode...`);
|
logger.info(`The Bot Server is in STARTING mode...`);
|
||||||
|
|
||||||
|
@ -79,8 +79,8 @@ export class GBServer {
|
||||||
// bot instance. This allows the same server to attend multiple Bot on
|
// bot instance. This allows the same server to attend multiple Bot on
|
||||||
// the Marketplace until GB get serverless.
|
// the Marketplace until GB get serverless.
|
||||||
|
|
||||||
let port = process.env.port || process.env.PORT || 4242;
|
const port = process.env.port || process.env.PORT || 4242;
|
||||||
let server = express();
|
const server = express();
|
||||||
|
|
||||||
server.use(bodyParser.json()); // to support JSON-encoded bodies
|
server.use(bodyParser.json()); // to support JSON-encoded bodies
|
||||||
server.use(
|
server.use(
|
||||||
|
@ -99,15 +99,15 @@ export class GBServer {
|
||||||
// Reads basic configuration, initialize minimal services.
|
// Reads basic configuration, initialize minimal services.
|
||||||
|
|
||||||
GBConfigService.init();
|
GBConfigService.init();
|
||||||
let core = new GBCoreService();
|
const core = new GBCoreService();
|
||||||
|
|
||||||
// Ensures cloud / on-premises infrastructure is setup.
|
// Ensures cloud / on-premises infrastructure is setup.
|
||||||
|
|
||||||
logger.info(`Establishing a development local proxy (ngrok)...`);
|
logger.info(`Establishing a development local proxy (ngrok)...`);
|
||||||
let proxyAddress = await core.ensureProxy(port);
|
const proxyAddress = await core.ensureProxy(port);
|
||||||
|
|
||||||
let deployer = new GBDeployer(core, new GBImporter(core));
|
const deployer = new GBDeployer(core, new GBImporter(core));
|
||||||
let azureDeployer = new AzureDeployerService(deployer);
|
const azureDeployer = new AzureDeployerService(deployer);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await core.initDatabase();
|
await core.initDatabase();
|
||||||
|
@ -117,7 +117,7 @@ export class GBServer {
|
||||||
bootInstance = await azureDeployer.deployFarm(proxyAddress);
|
bootInstance = await azureDeployer.deployFarm(proxyAddress);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"In case of error, please cleanup any infrastructure objects created during this procedure and .env before running again."
|
'In case of error, please cleanup any infrastructure objects created during this procedure and .env before running again.'
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
@ -132,13 +132,13 @@ export class GBServer {
|
||||||
|
|
||||||
// Check admin password.
|
// Check admin password.
|
||||||
|
|
||||||
let conversationalService = new GBConversationalService(core);
|
const conversationalService = new GBConversationalService(core);
|
||||||
let adminService = new GBAdminService(core);
|
const adminService = new GBAdminService(core);
|
||||||
let password = GBConfigService.get("ADMIN_PASS");
|
const password = GBConfigService.get('ADMIN_PASS');
|
||||||
|
|
||||||
if (!GBAdminService.StrongRegex.test(password)) {
|
if (!GBAdminService.StrongRegex.test(password)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Please, define a really strong password in ADMIN_PASS environment variable before running the server."
|
'Please, define a really strong password in ADMIN_PASS environment variable before running the server.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ export class GBServer {
|
||||||
GBWhatsappPackage
|
GBWhatsappPackage
|
||||||
].forEach(e => {
|
].forEach(e => {
|
||||||
logger.info(`Loading sys package: ${e.name}...`);
|
logger.info(`Loading sys package: ${e.name}...`);
|
||||||
let p = Object.create(e.prototype) as IGBPackage;
|
const p = Object.create(e.prototype) as IGBPackage;
|
||||||
p.loadPackage(core, core.sequelize);
|
p.loadPackage(core, core.sequelize);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -165,9 +165,9 @@ export class GBServer {
|
||||||
let instances: GuaribasInstance[];
|
let instances: GuaribasInstance[];
|
||||||
try {
|
try {
|
||||||
instances = await core.loadInstances();
|
instances = await core.loadInstances();
|
||||||
let instance = instances[0];
|
const instance = instances[0];
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
logger.info(`Updating bot endpoint to local reverse proxy (ngrok)...`);
|
logger.info(`Updating bot endpoint to local reverse proxy (ngrok)...`);
|
||||||
|
|
||||||
await azureDeployer.updateBotProxy(
|
await azureDeployer.updateBotProxy(
|
||||||
|
@ -177,30 +177,30 @@ export class GBServer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.parent.code === "ELOGIN") {
|
if (error.parent.code === 'ELOGIN') {
|
||||||
let group = GBConfigService.get("CLOUD_GROUP");
|
const group = GBConfigService.get('CLOUD_GROUP');
|
||||||
let serverName = GBConfigService.get("STORAGE_SERVER").split(
|
const serverName = GBConfigService.get('STORAGE_SERVER').split(
|
||||||
".database.windows.net"
|
'.database.windows.net'
|
||||||
)[0];
|
)[0];
|
||||||
await azureDeployer.openStorageFirewall(group, serverName);
|
await azureDeployer.openStorageFirewall(group, serverName);
|
||||||
} else {
|
} else {
|
||||||
// Check if storage is empty and needs formatting.
|
// Check if storage is empty and needs formatting.
|
||||||
|
|
||||||
let isInvalidObject =
|
const isInvalidObject =
|
||||||
error.parent.number == 208 || error.parent.errno == 1; // MSSQL or SQLITE.
|
error.parent.number == 208 || error.parent.errno == 1; // MSSQL or SQLITE.
|
||||||
|
|
||||||
if (isInvalidObject) {
|
if (isInvalidObject) {
|
||||||
if (GBConfigService.get("STORAGE_SYNC") != "true") {
|
if (GBConfigService.get('STORAGE_SYNC') != 'true') {
|
||||||
throw `Operating storage is out of sync or there is a storage connection error. Try setting STORAGE_SYNC to true in .env file. Error: ${
|
throw new Error(`Operating storage is out of sync or there is a storage connection error. Try setting STORAGE_SYNC to true in .env file. Error: ${
|
||||||
error.message
|
error.message
|
||||||
}.`;
|
}.`);
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
|
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw `Cannot connect to operating storage: ${error.message}.`;
|
throw new Error(`Cannot connect to operating storage: ${error.message}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ export class GBServer {
|
||||||
// If instances is undefined here it's because storage has been formatted.
|
// If instances is undefined here it's because storage has been formatted.
|
||||||
// Load all instances from .gbot found on deploy package directory.
|
// Load all instances from .gbot found on deploy package directory.
|
||||||
if (!instances) {
|
if (!instances) {
|
||||||
let saveInstance = new GuaribasInstance(bootInstance);
|
const saveInstance = new GuaribasInstance(bootInstance);
|
||||||
await saveInstance.save();
|
await saveInstance.save();
|
||||||
instances = await core.loadInstances();
|
instances = await core.loadInstances();
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ export class GBServer {
|
||||||
// Setup server dynamic (per bot instance) resources and listeners.
|
// Setup server dynamic (per bot instance) resources and listeners.
|
||||||
|
|
||||||
logger.info(`Publishing instances...`);
|
logger.info(`Publishing instances...`);
|
||||||
let minService = new GBMinService(
|
const minService = new GBMinService(
|
||||||
core,
|
core,
|
||||||
conversationalService,
|
conversationalService,
|
||||||
adminService,
|
adminService,
|
||||||
|
@ -230,13 +230,13 @@ export class GBServer {
|
||||||
await minService.buildMin(server, appPackages, instances);
|
await minService.buildMin(server, appPackages, instances);
|
||||||
logger.info(`The Bot Server is in RUNNING mode...`);
|
logger.info(`The Bot Server is in RUNNING mode...`);
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
opn('http://localhost:4242');
|
opn('http://localhost:4242');
|
||||||
}
|
}
|
||||||
|
|
||||||
return core;
|
return core;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(`STOP: ${err} ${err.stack ? err.stack : ""}`);
|
logger.error(`STOP: ${err} ${err.stack ? err.stack : ''}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
const { createLogger, format, transports } = require('winston')
|
const { createLogger, format, transports } = require('winston');
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
levels: {
|
levels: {
|
||||||
|
@ -53,7 +53,7 @@ const config = {
|
||||||
silly: 'magenta',
|
silly: 'magenta',
|
||||||
custom: 'yellow'
|
custom: 'yellow'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
format: format.combine(
|
format: format.combine(
|
||||||
|
@ -62,11 +62,11 @@ const logger = createLogger({
|
||||||
format.label({ label: 'GeneralBots' }),
|
format.label({ label: 'GeneralBots' }),
|
||||||
format.timestamp(),
|
format.timestamp(),
|
||||||
format.printf(nfo => {
|
format.printf(nfo => {
|
||||||
return `${nfo.timestamp} [${nfo.label}] ${nfo.level}: ${nfo.message}`
|
return `${nfo.timestamp} [${nfo.label}] ${nfo.level}: ${nfo.message}`;
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
levels: config.levels,
|
levels: config.levels,
|
||||||
transports: [new transports.Console()]
|
transports: [new transports.Console()]
|
||||||
})
|
});
|
||||||
|
|
||||||
module.exports=logger
|
module.exports = logger;
|
||||||
|
|
Loading…
Add table
Reference in a new issue