fix(general): tslint being applied in all sources.

This commit is contained in:
Rodrigo Rodriguez 2019-03-08 06:37:13 -03:00
parent a5a5f23ecd
commit 5d08457bef
28 changed files with 459 additions and 592 deletions

6
package-lock.json generated
View file

@ -3166,9 +3166,9 @@
}
},
"botlib": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/botlib/-/botlib-0.1.19.tgz",
"integrity": "sha512-JssUqK0NVwLTvs2zcl42jpKTsB5ocse27aVnFukV+wGuAjCeZu6HZpaTue1jTCHojMXAH1TSLNQnuCOOTxpw/w==",
"version": "0.1.21",
"resolved": "https://registry.npmjs.org/botlib/-/botlib-0.1.21.tgz",
"integrity": "sha512-AF8Sp+SF3xN/jzOCo7tnqJfGaYkeHP0mJKcfYL0iHYbUuIVsCVtNmIottd1WTzDfKhls+ZoqclSAbzzoC0LS+Q==",
"requires": {
"async": "2.6.2",
"botbuilder": "4.1.7",

View file

@ -66,7 +66,7 @@
"botbuilder-choices": "4.0.0-preview1.2",
"botbuilder-dialogs": "4.2.0",
"botbuilder-prompts": "4.0.0-preview1.2",
"botlib": "0.1.19",
"botlib": "^0.1.21",
"chai": "4.2.0",
"child_process": "^1.0.2",
"chokidar": "2.1.2",

View file

@ -38,14 +38,14 @@
const UrlJoin = require('url-join');
import { BotAdapter } from 'botbuilder';
import { WaterfallDialog, WaterfallStep, WaterfallStepContext } from 'botbuilder-dialogs';
import { GBMinInstance } from 'botlib';
import { IGBDialog } from 'botlib';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
import { GBImporter } from '../../core.gbapp/services/GBImporterService';
import { GBAdminService } from '../services/GBAdminService';
import { Messages } from '../strings';
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
/**
* Dialogs for administration tasks.
@ -79,7 +79,10 @@ export class AdminDialog extends IGBDialog {
}
public static async rebuildIndexPackageCommand(min: GBMinInstance, text: string, deployer: GBDeployer) {
await deployer.rebuildIndex(min.instance);
await deployer.rebuildIndex(
min.instance,
new AzureDeployerService(deployer).getKBSearchSchema(min.instance.searchIndex)
);
}
public static async addConnectionCommand(min: GBMinInstance, text: any) {
@ -136,7 +139,7 @@ export class AdminDialog extends IGBDialog {
if (text === 'quit') {
return await step.replaceDialog('/');
} else if (cmdName === 'createFarm') {
await AdminDialog.createFarmCommand(text, deployer);
await AdminDialog.createFarmCommand(text, min);
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'deployPackage') {
@ -224,9 +227,9 @@ export class AdminDialog extends IGBDialog {
await min.adminService.setValue(min.instance.instanceId, 'AntiCSRFAttackState', state);
const url = `https://login.microsoftonline.com/${min.instance.authenticatorTenant}/oauth2/authorize?client_id=${
min.instance.authenticatorClientId
}&response_type=code&redirect_uri=${UrlJoin(
const url = `https://login.microsoftonline.com/${
min.instance.authenticatorTenant
}/oauth2/authorize?client_id=${min.instance.authenticatorClientId}&response_type=code&redirect_uri=${UrlJoin(
min.instance.botEndpoint,
min.instance.botId,
'/token'
@ -239,5 +242,4 @@ export class AdminDialog extends IGBDialog {
])
);
}
}

View file

@ -36,15 +36,18 @@
'use strict';
import urlJoin = require('url-join');
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
import { Sequelize } from 'sequelize-typescript';
import { AdminDialog } from './dialogs/AdminDialog';
import { GuaribasAdmin } from './models/AdminModel';
export class GBAdminPackage implements IGBPackage {
public sysPackages: IGBPackage[] = null;
public sysPackages: IGBPackage[] = undefined;
public unloadPackage(core: IGBCoreService): void {}
public getDialogs(min: GBMinInstance) {}
public unloadBot(min: GBMinInstance): void {}
public onNewSession(min: GBMinInstance, step: any): void {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
core.sequelize.addModels([GuaribasAdmin]);

View file

@ -37,7 +37,7 @@
'use strict';
import { AuthenticationContext, TokenResponse } from 'adal-node';
import { IGBCoreService } from 'botlib';
import { IGBCoreService, IGBAdminService } from 'botlib';
import { GuaribasInstance } from '../../core.gbapp/models/GBModel';
import { GuaribasAdmin } from '../models/AdminModel';
const UrlJoin = require('url-join');
@ -47,7 +47,7 @@ const PasswordGenerator = require('strict-password-generator').default;
/**
* Services for server administration.
*/
export class GBAdminService {
export class GBAdminService implements IGBAdminService {
public static GB_PROMPT: string = 'GeneralBots: ';
public static masterBotInstanceId = 0;
@ -76,7 +76,7 @@ export class GBAdminService {
return credentials;
}
public static getRndPassword() {
public static getRndPassword(): string {
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: true,
@ -105,7 +105,7 @@ export class GBAdminService {
return name;
}
public async setValue(instanceId: number, key: string, value: string): Promise<GuaribasAdmin> {
public async setValue(instanceId: number, key: string, value: string) {
const options = { where: {} };
options.where = { key: key };
let admin = await GuaribasAdmin.findOne(options);
@ -115,8 +115,7 @@ export class GBAdminService {
}
admin.value = value;
admin.instanceId = instanceId;
return admin.save();
await admin.save();
}
public async updateSecurityInfo(

View file

@ -43,8 +43,8 @@ import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
import { Sequelize } from 'sequelize-typescript';
export class GBAnalyticsPackage implements IGBPackage {
public sysPackages: IGBPackage[] = null;
public sysPackages: IGBPackage[] = undefined;
public getDialogs(min: GBMinInstance) {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {}
public unloadPackage(core: IGBCoreService): void {}
public loadBot(min: GBMinInstance): void {}

View file

@ -40,6 +40,7 @@ import { BotAdapter } from 'botbuilder';
import { GBMinInstance } from 'botlib';
import { IGBDialog } from 'botlib';
import { Messages } from '../strings';
import { WaterfallDialog } from 'botlib/node_modules/botbuilder-dialogs';
export class BotFarmDialog extends IGBDialog {
/**
@ -49,21 +50,20 @@ export class BotFarmDialog extends IGBDialog {
* @param min The minimal bot instance data.
*/
public static setup(bot: BotAdapter, min: GBMinInstance) {
min.dialogs.add('/createBotFarm', [
min.dialogs.add(new WaterfallDialog ('/createBotFarm', [
async step => {
const locale = step.context.activity.locale;
await step.prompt('choicePrompt', Messages[locale].what_about_me, [
'1',
'2',
'3',
'4',
'5'
]);
await step.prompt('choicePrompt', Messages[locale].what_about_me);
return step.next();
},
async step => {
const locale = step.context.activity.locale;
await step.context.sendActivity(Messages[locale].thanks);
return step.next();
}
]);
]));
}
}

View file

@ -37,18 +37,18 @@
'use strict';
import { IGBInstance } from 'botlib';
import { IGBInstallationDeployer } from 'botlib';
import * as fs from 'fs';
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService';
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService';
import { AzureDeployerService } from '../services/AzureDeployerService';
import { GuaribasInstance } from '../../../packages/core.gbapp/models/GBModel';
const scanf = require('scanf');
/**
* Handles command-line dialog for getting info for Boot Bot.
*/
export class StartDialog {
public static async createBaseInstance() {
public static async createBaseInstance(installationDeployer: IGBInstallationDeployer) {
// No .env so asks for cloud credentials to start a new farm.
if (!fs.existsSync(`.env`)) {
@ -75,7 +75,7 @@ export class StartDialog {
// Connects to the cloud and retrieves subscriptions.
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
const list = await AzureDeployerService.getSubscriptions(credentials);
const list = await installationDeployer.getSubscriptions(credentials);
let subscriptionId: string;
while (subscriptionId === undefined) {
@ -104,9 +104,8 @@ export class StartDialog {
process.stdout.write(`${GBAdminService.GB_PROMPT}Thank you. That is enough information.\nNow building farm...`);
// Prepares the first instance on bot farm.
const instance: IGBInstance = {};
const instance = <IGBInstance>{};
instance.botId = botId;
instance.cloudUsername = username;
@ -223,7 +222,7 @@ generate manually an App ID and App Secret.\n`
private static retrieveLocation() {
let location = GBConfigService.get('CLOUD_LOCATION');
if (!location) {
process.stdout.write("CLOUD_LOCATION (eg. 'westus'):");
process.stdout.write('CLOUD_LOCATION (eg. \'westus\'):');
location = scanf('%s');
}

View file

@ -40,8 +40,8 @@ import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
import { Sequelize } from 'sequelize-typescript';
export class GBAzureDeployerPackage implements IGBPackage {
public sysPackages: IGBPackage[] = null;
public sysPackages: IGBPackage[] = undefined;
public getDialogs(min: GBMinInstance) {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {}

View file

@ -43,33 +43,29 @@ import { SearchManagementClient } from 'azure-arm-search';
import { SqlManagementClient } from 'azure-arm-sql';
import { WebSiteManagementClient } from 'azure-arm-website';
import { AppServicePlan } from 'azure-arm-website/lib/models';
import { GBService, IGBInstance } from 'botlib';
import { IGBInstance, IGBInstallationDeployer } from 'botlib';
import { HttpMethods, ServiceClient, WebResource } from 'ms-rest-js';
import { GBDeployer } from '../../../packages/core.gbapp/services/GBDeployer';
import * as simplegit from 'simple-git/promise';
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService';
import { GBCorePackage } from '../../../packages/core.gbapp';
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService';
import { GuaribasInstance } from '../../../packages/core.gbapp/models/GBModel';
import { GBDeployer } from '../../../packages/core.gbapp/services/GBDeployer';
const Spinner = require('cli-spinner').Spinner;
const scanf = require('scanf');
const git = simplegit();
const logger = require('../../../src/logger');
const UrlJoin = require('url-join');
const iconUrl = 'https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png';
const publicIp = require('public-ip');
export class AzureDeployerService extends GBService {
public static apiVersion = '2017-12-01';
public static defaultEndPoint = 'http://localhost:4242';
export class AzureDeployerService implements IGBInstallationDeployer {
public apiVersion = '2017-12-01';
public defaultEndPoint = 'http://localhost:4242';
public instance: IGBInstance;
public resourceClient: ResourceManagementClient.ResourceManagementClient;
public webSiteClient: WebSiteManagementClient;
public storageClient: SqlManagementClient;
public cognitiveClient: CognitiveServicesManagementClient;
public searchClient: SearchManagementClient;
public static provider = 'Microsoft.BotService';
public provider = 'Microsoft.BotService';
public subscriptionClient: SubscriptionClient.SubscriptionClient;
public accessToken: string;
public location: string;
@ -78,15 +74,16 @@ export class AzureDeployerService extends GBService {
public deployer: GBDeployer;
constructor(deployer: GBDeployer) {
super();
this.deployer = deployer;
}
public static async getSubscriptions(credentials) {
public async getSubscriptions(credentials) {
const subscriptionClient = new SubscriptionClient.default(credentials);
return subscriptionClient.subscriptions.list();
}
public static getKBSearchSchema(indexName) {
public getKBSearchSchema(indexName) {
return {
name: indexName,
fields: [
@ -187,16 +184,13 @@ export class AzureDeployerService extends GBService {
};
}
public static async updateBotProxy(botId, group, endpoint) {
public async updateBotProxy(botId, group, endpoint) {
const baseUrl = `https://management.azure.com/`;
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
const accessToken = await GBAdminService.getADALTokenFromUsername(
username,
password
);
const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
const httpClient = new ServiceClient();
const parameters = {
@ -207,14 +201,9 @@ export class AzureDeployerService extends GBService {
const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
this.provider
}/botServices/${botId}?api-version=${AzureDeployerService.apiVersion}`;
}/botServices/${botId}?api-version=${this.apiVersion}`;
const url = UrlJoin(baseUrl, query);
const req = this.createRequestObject(
url,
accessToken,
'PATCH',
JSON.stringify(parameters)
);
const req = AzureDeployerService.createRequestObject(url, accessToken, 'PATCH', JSON.stringify(parameters));
const res = await httpClient.sendRequest(req);
if (!(res.bodyAsJson as any).id) {
throw res.bodyAsText;
@ -222,7 +211,7 @@ export class AzureDeployerService extends GBService {
logger.info(`Bot proxy updated at: ${endpoint}.`);
}
public static async openStorageFirewall(groupName, serverName) {
public async openStorageFirewall(groupName, serverName) {
const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD');
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
@ -239,7 +228,7 @@ export class AzureDeployerService extends GBService {
await storageClient.firewallRules.createOrUpdate(groupName, serverName, 'gb', params);
}
public static createRequestObject(url: string, accessToken: string, verb: HttpMethods, body: string) {
private static createRequestObject(url: string, accessToken: string, verb: HttpMethods, body: string) {
const req = new WebResource();
req.method = verb;
req.url = url;
@ -304,19 +293,19 @@ export class AzureDeployerService extends GBService {
instance.searchIndex = 'azuresql-index';
instance.searchIndexer = 'azuresql-indexer';
instance.searchKey = searchKeys.primaryKey;
this.deployer.rebuildIndex(instance);
this.deployer.rebuildIndex(instance, this.deployer);
logger.info(`Deploying Speech...`);
const speech = await this.createSpeech(name, `${name}-speech`, instance.cloudLocation);
keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
instance.speechKeyEndpoint = speech.endpoint;
instance.speechEndpoint = speech.endpoint;
instance.speechKey = keys.key1;
logger.info(`Deploying SpellChecker...`);
const spellChecker = await this.createSpellChecker(name, `${name}-spellchecker`, instance.cloudLocation);
const spellChecker = await this.createSpellChecker(name, `${name}-spellchecker`);
keys = await this.cognitiveClient.accounts.listKeys(name, spellChecker.name);
instance.spellCheckerKey = keys.key1;
instance.spellCheckerEndpoint = spellChecker.endpoint;
instance.spellcheckerKey = keys.key1;
instance.spellcheckerEndpoint = spellChecker.endpoint;
logger.info(`Deploying Text Analytics...`);
const textAnalytics = await this.createTextAnalytics(name, `${name}-textanalytics`, instance.cloudLocation);
@ -336,7 +325,7 @@ export class AzureDeployerService extends GBService {
instance.nlpAppId = nlpAppId;
logger.info(`Deploying Bot...`);
instance.botEndpoint = AzureDeployerService.defaultEndPoint;
instance.botEndpoint = this.defaultEndPoint;
instance = await this.internalDeployBot(
instance,
@ -349,8 +338,8 @@ export class AzureDeployerService extends GBService {
'global',
instance.nlpAppId,
instance.nlpKey,
instance.appId,
instance.appPassword,
instance.marketplaceId,
instance.marketplacePassword,
instance.cloudSubscriptionId
);
@ -359,17 +348,16 @@ export class AzureDeployerService extends GBService {
}
public async deployToCloud(
title,
username,
password,
cloudLocation,
authoringKey,
appId,
appPassword,
subscriptionId
title: string,
username: string,
password: string,
cloudLocation: string,
authoringKey: string,
appId: string,
appPassword: string,
subscriptionId: string
) {
const instance: IGBInstance = {};
const instance = <IGBInstance> {};
instance.botId = title;
instance.cloudUsername = username;
@ -397,18 +385,6 @@ export class AzureDeployerService extends GBService {
this.accessToken = credentials.tokenCache._entries[0].accessToken;
}
private async updateWebisteConfig(group, serverFarmId, name, location) {
const siteConfig = {
location: location,
serverFarmId: serverFarmId,
numberOfWorkers: 1,
phpVersion: '5.5'
};
// TODO: Copy .env to app settings.
return this.webSiteClient.webApps.createOrUpdateConfiguration(group, name, siteConfig);
}
private async createStorageServer(group, name, administratorLogin, administratorPassword, serverName, location) {
const params = {
@ -423,7 +399,7 @@ export class AzureDeployerService extends GBService {
private async registerProviders(subscriptionId, baseUrl, accessToken) {
const query = `subscriptions/${subscriptionId}/providers/${
AzureDeployerService.provider
this.provider
}/register?api-version=2018-02-01`;
const requestUrl = UrlJoin(baseUrl, query);
@ -436,7 +412,6 @@ export class AzureDeployerService extends GBService {
req.headers.Authorization = 'Bearer ' + accessToken;
const httpClient = new ServiceClient();
const res = await httpClient.sendRequest(req);
// TODO: Check res for error.
}
@ -457,7 +432,7 @@ export class AzureDeployerService extends GBService {
appId,
appPassword,
subscriptionId
) {
): Promise<IGBInstance> {
return new Promise(async (resolve, reject) => {
const baseUrl = `https://management.azure.com/`;
await this.registerProviders(subscriptionId, baseUrl, accessToken);
@ -489,8 +464,8 @@ export class AzureDeployerService extends GBService {
const httpClient = new ServiceClient();
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
AzureDeployerService.provider
}/botServices/${botId}?api-version=${AzureDeployerService.apiVersion}`;
this.provider
}/botServices/${botId}?api-version=${this.apiVersion}`;
let url = UrlJoin(baseUrl, query);
let req = AzureDeployerService.createRequestObject(url, accessToken, 'PUT', JSON.stringify(parameters));
const res = await httpClient.sendRequest(req);
@ -502,7 +477,7 @@ export class AzureDeployerService extends GBService {
setTimeout(async () => {
try {
query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/Microsoft.BotService/botServices/${botId}/channels/WebChatChannel/listChannelWithKeys?api-version=${
AzureDeployerService.apiVersion
this.apiVersion
}`;
url = UrlJoin(baseUrl, query);
req = AzureDeployerService.createRequestObject(url, accessToken, 'GET', JSON.stringify(parameters));
@ -603,7 +578,7 @@ export class AzureDeployerService extends GBService {
return await this.createCognitiveServices(group, name, location, 'LUIS');
}
private async createSpellChecker(group, name, location): Promise<CognitiveServicesAccount> {
private async createSpellChecker(group, name): Promise<CognitiveServicesAccount> {
return await this.createCognitiveServices(group, name, 'global', 'Bing.SpellCheck.v7');
}
@ -637,5 +612,4 @@ export class AzureDeployerService extends GBService {
};
return this.webSiteClient.webApps.createOrUpdate(group, name, parameters);
}
}

View file

@ -44,22 +44,20 @@ import { Sequelize } from 'sequelize-typescript';
import { ConsoleDirectLine } from './services/ConsoleDirectLine';
export class GBConsolePackage implements IGBPackage {
public sysPackages: IGBPackage[] = null;
public sysPackages: IGBPackage[] = undefined;
public channel: ConsoleDirectLine;
public getDialogs(min: GBMinInstance) {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {}
public unloadPackage(core: IGBCoreService): void {
}
public unloadPackage(core: IGBCoreService): void {}
public loadBot(min: GBMinInstance): void {
this.channel = new ConsoleDirectLine(min.instance.webchatKey);
}
public unloadBot(min: GBMinInstance): void {
}
public unloadBot(min: GBMinInstance): void {}
public onNewSession(min: GBMinInstance, step: any): void {
}
public onNewSession(min: GBMinInstance, step: any): void {}
}

View file

@ -48,30 +48,20 @@ import { GuaribasChannel, GuaribasException, GuaribasInstance, GuaribasPackage }
export class GBCorePackage implements IGBPackage {
public static CurrentEngineName = 'guaribas-1.0.0';
public sysPackages: IGBPackage[] = null;
public sysPackages: IGBPackage[] = undefined;
public getDialogs(min: GBMinInstance) {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
core.sequelize.addModels([
GuaribasInstance,
GuaribasPackage,
GuaribasChannel,
GuaribasException
]);
core.sequelize.addModels([GuaribasInstance, GuaribasPackage, GuaribasChannel, GuaribasException]);
}
public unloadPackage(core: IGBCoreService): void {
}
public unloadPackage(core: IGBCoreService): void {}
public loadBot(min: GBMinInstance): void {
WelcomeDialog.setup(min.bot, min);
WhoAmIDialog.setup(min.bot, min);
}
public unloadBot(min: GBMinInstance): void {
}
public onNewSession(min: GBMinInstance, step: any): void {
}
public unloadBot(min: GBMinInstance): void {}
public onNewSession(min: GBMinInstance, step: any): void {}
}

View file

@ -54,6 +54,7 @@ import { IGBInstance } from 'botlib';
@Table
export class GuaribasInstance extends Model<GuaribasInstance>
implements IGBInstance {
@PrimaryKey
@AutoIncrement
@Column
@ -152,7 +153,7 @@ export class GuaribasInstance extends Model<GuaribasInstance>
public speechKey: string;
@Column
public speechKeyEndpoint: string;
public speechEndpoint: string;
@Column
public spellcheckerKey: string;

View file

@ -35,22 +35,27 @@
import { TurnContext } from 'botbuilder';
import { WaterfallStepContext } from 'botbuilder-dialogs';
import { GBMinInstance } from 'botlib';
import * as request from 'request-promise-native';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
import { GBDeployer } from './GBDeployer';
const UrlJoin = require('url-join');
/**
* BASIC system class for extra manipulation of bot behaviour.
*/
class SysClass {
public min: GBMinInstance;
private readonly deployer: GBDeployer;
constructor(min: GBMinInstance) {
constructor(min: GBMinInstance, deployer: GBDeployer) {
this.min = min;
this.deployer = deployer;
}
public async wait(seconds: number) {
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
// tslint:disable-next-line no-string-based-set-timeout
const timeout = async (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
await timeout(seconds * 1000);
}
@ -68,7 +73,7 @@ class SysClass {
appPassword,
subscriptionId
) {
const service = new AzureDeployerService(this.min.deployer);
const service = new AzureDeployerService(this.deployer);
await service.deployToCloud(
botId,
username,
@ -80,6 +85,27 @@ class SysClass {
subscriptionId
);
}
/**
* Generic function to call any REST API.
*/
public async sendEmail(to, subject, body) {
// tslint:disable-next-line:no-console
console.log(`[E-mail]: to:${to}, subject: ${subject}, body: ${body}.`);
}
/**
* Generic function to call any REST API.
*/
public async httpGet(url: string, qs) {
const options = {
uri: UrlJoin(url , qs)
};
return await request.get(options);
}
}
/**
* @fileoverview General Bots server core.
@ -92,9 +118,9 @@ export default class DialogClass {
public step: WaterfallStepContext;
public internalSys: SysClass;
constructor(min: GBMinInstance) {
constructor(min: GBMinInstance, deployer: GBDeployer) {
this.min = min;
this.internalSys = new SysClass(min);
this.internalSys = new SysClass(min, deployer);
}
public sys(): SysClass {
@ -102,7 +128,7 @@ export default class DialogClass {
}
public async hear(cb) {
const idCallback = Math.floor(Math.random() * 1000000000000);
const idCallback = crypto.getRandomValues(new Uint32Array(16))[0];
this.min.cbMap[idCallback] = cb;
await this.step.beginDialog('/hear', { id: idCallback });
}
@ -110,17 +136,4 @@ export default class DialogClass {
public async talk(text: string) {
return await this.context.sendActivity(text);
}
/**
* Generic function to call any REST API.
*/
public sendEmail(to, subject, body) {
// tslint:disable-next-line:no-console
console.log(`[E-mail]: to:${to}, subject: ${subject}, body: ${body}.`);
}
/**
* Generic function to call any REST API.
*/
public post(url: string, data) {}
}

View file

@ -39,7 +39,7 @@
const logger = require('../../../src/logger');
import { MessageFactory } from 'botbuilder';
import { LuisRecognizer } from 'botbuilder-ai';
import { GBMinInstance, IGBConversationalService } from 'botlib';
import { GBMinInstance, IGBConversationalService, IGBCoreService } from 'botlib';
import { AzureText } from 'pragmatismo-io-framework';
import { Messages } from '../strings';
import { GBCoreService } from './GBCoreService';
@ -51,9 +51,10 @@ export interface LanguagePickerSettings {
}
export class GBConversationalService implements IGBConversationalService {
public coreService: GBCoreService;
constructor(coreService: GBCoreService) {
public coreService: IGBCoreService;
constructor(coreService: IGBCoreService) {
this.coreService = coreService;
}
@ -93,7 +94,7 @@ export class GBConversationalService implements IGBConversationalService {
public async routeNLP(step: any, min: GBMinInstance, text: string): Promise<boolean> {
// Invokes LUIS.
let endpoint = min.instance.nlpEndpoint.replace('/luis/v2.0', '');
const endpoint = min.instance.nlpEndpoint.replace('/luis/v2.0', '');
const model = new LuisRecognizer({
applicationId: min.instance.nlpAppId,

View file

@ -36,12 +36,13 @@
'use strict';
import { IGBCoreService, IGBInstance, IGBPackage } from 'botlib';
import { IGBCoreService, IGBInstallationDeployer, IGBInstance, IGBPackage } from 'botlib';
import * as fs from 'fs';
import { Sequelize } from 'sequelize-typescript';
import { GBAdminPackage } from '../../admin.gbapp/index';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { GBAnalyticsPackage } from '../../analytics.gblib';
import { StartDialog } from '../../azuredeployer.gbapp/dialogs/StartDialog';
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
import { GBCorePackage } from '../../core.gbapp';
import { GBCustomerSatisfactionPackage } from '../../customer-satisfaction.gbapp';
@ -50,8 +51,6 @@ import { GBSecurityPackage } from '../../security.gblib';
import { GBWhatsappPackage } from '../../whatsapp.gblib/index';
import { GuaribasInstance } from '../models/GBModel';
import { GBConfigService } from './GBConfigService';
import { StartDialog } from '../../azuredeployer.gbapp/dialogs/StartDialog';
import { WaterfallDialog } from 'botbuilder-dialogs';
const logger = require('../../../src/logger');
const opn = require('opn');
@ -60,6 +59,7 @@ const opn = require('opn');
* Core service layer.
*/
export class GBCoreService implements IGBCoreService {
/**
* Data access layer instance.
*/
@ -162,13 +162,13 @@ export class GBCoreService implements IGBCoreService {
}
}
public async checkStorage(azureDeployer: AzureDeployerService) {
public async checkStorage(installationDeployer: IGBInstallationDeployer) {
try {
await this.sequelize.authenticate();
} catch (error) {
logger.info('Opening storage firewall on infrastructure...');
if (error.parent.code === 'ELOGIN') {
await this.openStorageFrontier(azureDeployer);
await this.openStorageFrontier(installationDeployer);
} else {
throw error;
}
@ -193,14 +193,14 @@ export class GBCoreService implements IGBCoreService {
/**
* Loads all items to start several listeners.
*/
public async loadInstances(): Promise<IGBInstance> {
public async loadInstances(): Promise<IGBInstance[]> {
return GuaribasInstance.findAll({});
}
/**
* Loads just one Bot instance by its internal Id.
*/
public async loadInstanceById(instanceId: string): Promise<IGBInstance> {
public async loadInstanceById(instanceId: number): Promise<IGBInstance> {
const options = { where: { instanceId: instanceId } };
return GuaribasInstance.findOne(options);
@ -240,8 +240,15 @@ STORAGE_SYNC=true
public async ensureProxy(port): Promise<string> {
try {
if (fs.existsSync('node_modules/ngrok/bin/ngrok.exe')) {
const ngrok = require('ngrok');
return await ngrok.connect({ port: port });
} else {
logger.warn('ngrok executable not found. Check installation or node_modules folder.');
return 'localhost';
}
} catch (error) {
// There are false positive from ngrok regarding to no memory, but it's just
// lack of connection.
@ -267,15 +274,15 @@ STORAGE_SYNC=true
* @param azureDeployer
* @param proxyAddress
*/
public async loadAllInstances(core: GBCoreService, azureDeployer: AzureDeployerService, proxyAddress: string) {
public async loadAllInstances(core: IGBCoreService, installationDeployer: IGBInstallationDeployer, proxyAddress: string) {
logger.info(`Loading instances from storage...`);
let instances: GuaribasInstance[];
let instances: IGBInstance[];
try {
instances = await core.loadInstances();
const instance = instances[0];
if (process.env.NODE_ENV === 'development') {
logger.info(`Updating bot endpoint to local reverse proxy (ngrok)...`);
await AzureDeployerService.updateBotProxy(
await installationDeployer.updateBotProxy(
instance.botId,
instance.botId,
`${proxyAddress}/api/messages/${instance.botId}`
@ -308,9 +315,9 @@ STORAGE_SYNC=true
* @param bootInstance
* @param core
*/
public async ensureInstances(instances: GuaribasInstance[], bootInstance: any, core: GBCoreService) {
public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) {
if (!instances) {
const instance: IGBInstance = {};
const instance = new GuaribasInstance();
await instance.save();
instances = await core.loadInstances();
}
@ -347,11 +354,12 @@ STORAGE_SYNC=true
}
}
public async createBootInstance(core: GBCoreService, azureDeployer: AzureDeployerService, proxyAddress: string) {
public async createBootInstance(core: GBCoreService, installationDeployer: IGBInstallationDeployer, proxyAddress: string) {
logger.info(`Deploying cognitive infrastructure (on the cloud / on premises)...`);
try {
let { instance, credentials, subscriptionId } = await StartDialog.createBaseInstance();
instance = await azureDeployer.deployFarm(proxyAddress, instance, credentials, subscriptionId);
let { instance, credentials, subscriptionId } = await StartDialog.createBaseInstance(installationDeployer);
instance = await installationDeployer.deployFarm(proxyAddress, instance, credentials, subscriptionId);
core.writeEnv(instance);
logger.info(`File .env written, starting General Bots...`);
GBConfigService.init();
@ -457,9 +465,9 @@ STORAGE_SYNC=true
*
* @param azureDeployer Infrastructure Deployer instance.
*/
private async openStorageFrontier(deployer: AzureDeployerService) {
private async openStorageFrontier(installationDeployer: IGBInstallationDeployer) {
const group = GBConfigService.get('CLOUD_GROUP');
const serverName = GBConfigService.get('STORAGE_SERVER').split('.database.windows.net')[0];
await AzureDeployerService.openStorageFirewall(group, serverName);
await installationDeployer.openStorageFirewall(group, serverName);
}
}

View file

@ -73,7 +73,7 @@ export class GBDeployer {
this.importer = importer;
}
public static getConnectionStringFromInstance(instance: GuaribasInstance) {
public static getConnectionStringFromInstance(instance: IGBInstance) {
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;`;
@ -272,7 +272,7 @@ export class GBDeployer {
}
}
public async rebuildIndex(instance: GuaribasInstance) {
public async rebuildIndex(instance: IGBInstance, searchSchema: any) {
const search = new AzureSearch(
instance.searchKey,
instance.searchHost,
@ -302,7 +302,7 @@ export class GBDeployer {
throw err;
}
}
await search.createIndex(AzureDeployerService.getKBSearchSchema(instance.searchIndex), dsName);
await search.createIndex(searchSchema, dsName);
}
public async getPackageByName(instanceId: number, packageName: string): Promise<GuaribasPackage> {
@ -312,7 +312,7 @@ export class GBDeployer {
});
}
public installDefaultGBUI() {
public runOnce() {
const root = 'packages/default.gbui';
if (!Fs.existsSync(`${root}/build`)) {
logger.info(`Preparing default.gbui (it may take some additional time for the first time)...`);
@ -323,7 +323,7 @@ export class GBDeployer {
}
private async deployDataPackages(
core: GBCoreService,
core: IGBCoreService,
botPackages: string[],
_this: this,
generalPackages: string[],

View file

@ -46,7 +46,7 @@ const AuthenticationContext = require('adal-node').AuthenticationContext;
import { AutoSaveStateMiddleware, BotFrameworkAdapter, ConversationState, MemoryStorage, UserState } from 'botbuilder';
import { ConfirmPrompt, WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBAdminService, IGBConversationalService, IGBCoreService, IGBPackage } from 'botlib';
import { GBMinInstance, IGBAdminService, IGBConversationalService, IGBCoreService, IGBPackage, IGBInstance } from 'botlib';
import { GBAnalyticsPackage } from '../../analytics.gblib';
import { GBCorePackage } from '../../core.gbapp';
import { GBCustomerSatisfactionPackage } from '../../customer-satisfaction.gbapp';
@ -97,12 +97,12 @@ export class GBMinService {
* */
public async buildMin(
bootInstance: GuaribasInstance,
bootInstance: IGBInstance,
server: any,
appPackages: IGBPackage[],
instances: GuaribasInstance[],
instances: IGBInstance[],
deployer: GBDeployer
): Promise<GBMinInstance> {
) {
// Serves default UI on root address '/'.
const uiPackage = 'default.gbui';
@ -166,9 +166,9 @@ export class GBMinService {
);
}
private handleOAuthTokenRequests(server: any, min: GBMinInstance, instance: GuaribasInstance) {
private handleOAuthTokenRequests(server: any, min: GBMinInstance, instance: IGBInstance) {
server.get(`/${min.instance.botId}/token`, async (req, res) => {
const state = await min.adminService.getValue(min.instance.instanceId, 'AntiCSRFAttackState');
const state = await min.adminService.getValue(instance.instanceId, 'AntiCSRFAttackState');
if (req.query.state !== state) {
const msg = 'WARNING: state field was not provided as anti-CSRF token';
logger.error(msg);
@ -218,7 +218,7 @@ export class GBMinService {
/**
* Returns the instance object to clients requesting bot info.
*/
private async sendInstanceToClient(req, bootInstance: GuaribasInstance, res: any, webchatToken: any) {
private async sendInstanceToClient(req, bootInstance: IGBInstance, res: any, webchatToken: any) {
let botId = req.params.botId;
if (botId === '[default]') {
botId = bootInstance.botId;
@ -351,7 +351,7 @@ export class GBMinService {
if (sysPackage.name === 'GBWhatsappPackage') {
const url = '/instances/:botId/whatsapp';
server.post(url, (req, res) => {
p.channel.received(req, res);
p['channel'].received(req, res);
});
}
}, this);
@ -383,7 +383,7 @@ export class GBMinService {
await adapter.processActivity(req, res, async context => {
// Get loaded user state
const state = await conversationState.get(context);
const step = await min.dialogs.createContext(context, state);
const step = await min.dialogs.createContext(context);
step.context.activity.locale = 'en-US'; // TODO: Make dynamic.
try {
@ -481,10 +481,10 @@ export class GBMinService {
if (isVMCall) {
let mainMethod = context.activity.text;
min.sandbox.context = context;
min.sandbox.step = step;
min.sandbox[mainMethod].bind(min.sandbox);
await min.sandbox[mainMethod]();
min.sandBoxMap[mainMethod].context = context;
min.sandBoxMap[mainMethod].step = step;
min.sandBoxMap[mainMethod][mainMethod].bind(min.sandBoxMap[mainMethod]);
await min.sandBoxMap[mainMethod][mainMethod]();
} else if (context.activity.text === 'admin') {
await step.beginDialog('/admin');

View file

@ -33,10 +33,11 @@
'use strict';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBCoreService } from 'botlib';
import { GBMinInstance, IGBCoreService, GBService } from 'botlib';
import * as fs from 'fs';
import { GBDeployer } from './GBDeployer';
import { TSCompiler } from './TSCompiler';
import GBAPIService from './GBAPIService';
import DialogClass from './GBAPIService';
const walkPromise = require('walk-promise');
@ -44,7 +45,7 @@ const logger = require('../../../src/logger');
const vm = require('vm');
const UrlJoin = require('url-join');
const vb2ts = require('vbscript-to-typescript/dist/converter');
var beautify = require('js-beautify').js;
let beautify = require('js-beautify').js;
/**
* @fileoverview Virtualization services for emulation of BASIC.
@ -55,7 +56,7 @@ var beautify = require('js-beautify').js;
* translation and enhance classic BASIC experience.
*/
export class GBVMService implements IGBCoreService {
export class GBVMService extends GBService {
private readonly script = new vm.Script();
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
@ -110,6 +111,10 @@ export class GBVMService implements IGBCoreService {
return 'let password = sys().generatePassword()';
});
code = code.replace(/(get)(\s)(.*)/g, ($0, $1, $2) => {
return `sys().httpGet (${$2})`;
});
code = code.replace(/(create a bot farm using)(\s)(.*)/g, ($0, $1, $2, $3) => {
return `sys().createABotFarmUsing (${$3})`;
});
@ -207,14 +212,14 @@ export class GBVMService implements IGBCoreService {
parsedCode = this.handleThisAndAwait(parsedCode);
parsedCode = beautify(parsedCode, { indent_size: 2, space_in_empty_paren: true })
parsedCode = beautify(parsedCode, { indent_size: 2, space_in_empty_paren: true });
fs.writeFileSync(jsfile, parsedCode);
const sandbox: DialogClass = new DialogClass(min);
const sandbox: DialogClass = new DialogClass(min, deployer);
const context = vm.createContext(sandbox);
vm.runInContext(parsedCode, context);
min.sandbox = sandbox;
await deployer.deployScriptToStorage(min.instanceId, filename);
min.sandBoxMap[mainName] = sandbox;
await deployer.deployScriptToStorage(1, filename); // TODO: Per bot storage.
logger.info(`[GBVMService] Finished loading of ${filename}`);
}
}

View file

@ -45,23 +45,17 @@ import { GuaribasQuestionAlternate } from './models/index';
import { Sequelize } from 'sequelize-typescript';
export class GBCustomerSatisfactionPackage implements IGBPackage {
public sysPackages: IGBPackage[] = null;
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
core.sequelize.addModels([
GuaribasQuestionAlternate
]);
}
public unloadPackage(core: IGBCoreService): void {
public sysPackages: IGBPackage[] = undefined;
public getDialogs(min: GBMinInstance) {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
core.sequelize.addModels([GuaribasQuestionAlternate]);
}
public unloadPackage(core: IGBCoreService): void {}
public loadBot(min: GBMinInstance): void {
FeedbackDialog.setup(min.bot, min);
QualityDialog.setup(min.bot, min);
}
public unloadBot(min: GBMinInstance): void {
}
public onNewSession(min: GBMinInstance, step: any): void {
}
public unloadBot(min: GBMinInstance): void {}
public onNewSession(min: GBMinInstance, step: any): void {}
}

View file

@ -48,31 +48,18 @@ import { FaqDialog } from './dialogs/FaqDialog';
import { MenuDialog } from './dialogs/MenuDialog';
export class GBKBPackage implements IGBPackage {
public sysPackages: IGBPackage[] = null;
public sysPackages: IGBPackage[] = undefined;
public getDialogs(min: GBMinInstance) {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
core.sequelize.addModels([
GuaribasAnswer,
GuaribasQuestion,
GuaribasSubject
]);
}
public unloadPackage(core: IGBCoreService): void {
core.sequelize.addModels([GuaribasAnswer, GuaribasQuestion, GuaribasSubject]);
}
public unloadPackage(core: IGBCoreService): void {}
public loadBot(min: GBMinInstance): void {
AskDialog.setup(min.bot, min);
FaqDialog.setup(min.bot, min);
MenuDialog.setup(min.bot, min);
}
public unloadBot(min: GBMinInstance): void {
}
public onNewSession(min: GBMinInstance, step: any): void {
}
public unloadBot(min: GBMinInstance): void {}
public onNewSession(min: GBMinInstance, step: any): void {}
}

View file

@ -53,6 +53,7 @@ import { GuaribasPackage } from '../../core.gbapp/models/GBModel';
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from '../models';
import { GBConfigService } from './../../core.gbapp/services/GBConfigService';
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
export class KBServiceSearchResults {
public answer: GuaribasAnswer;
@ -326,7 +327,7 @@ export class KBService {
});
if (lastAnswer && lastQuestionId) {
await lastAnswer.updateAttributes({ nextId: lastQuestionId });
await lastAnswer.update({ nextId: lastQuestionId });
}
lastAnswer = answer1;
lastQuestionId = question1.questionId;
@ -449,7 +450,7 @@ export class KBService {
where: { instanceId: instance.instanceId, packageId: packageId }
});
await deployer.rebuildIndex(instance);
await deployer.rebuildIndex(instance, new AzureDeployerService(deployer).getKBSearchSchema(instance.searchIndex));
}
/**
@ -468,7 +469,7 @@ export class KBService {
const p = await deployer.deployPackageToStorage(instance.instanceId, packageName);
await this.importKbPackage(localPath, p, instance);
deployer.rebuildIndex(instance);
deployer.rebuildIndex(instance, new AzureDeployerService(deployer).getKBSearchSchema(instance.searchIndex));
logger.info(`[GBDeployer] Finished import of ${localPath}`);
}
}

View file

@ -44,29 +44,17 @@ import { Sequelize } from 'sequelize-typescript';
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from './models';
export class GBSecurityPackage implements IGBPackage {
public sysPackages: IGBPackage[] = null;
public sysPackages: IGBPackage[] = undefined;
public getDialogs(min: GBMinInstance) {}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
core.sequelize.addModels([
GuaribasGroup,
GuaribasUser,
GuaribasUserGroup
]);
core;
core.sequelize.addModels([GuaribasGroup, GuaribasUser, GuaribasUserGroup]);
}
public unloadPackage(core: IGBCoreService): void {
public unloadPackage(core: IGBCoreService): void {}
}
public loadBot(min: GBMinInstance): void {
}
public unloadBot(min: GBMinInstance): void {
}
public onNewSession(min: GBMinInstance, step: any): void {
}
public loadBot(min: GBMinInstance): void {}
public unloadBot(min: GBMinInstance): void {}
public onNewSession(min: GBMinInstance, step: any): void {}
}

View file

@ -1,52 +1,12 @@
/*****************************************************************************\
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
| under the terms of the GNU Affero General Public License, version 3, |
| or under a proprietary license. |
| |
| The texts of the GNU Affero General Public License with an additional |
| permission and of our proprietary license can be found at and |
| in the LICENSE file you have received along with this program. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of Pragmatismo.io. |
| The licensing of the program under the AGPLv3 does not imply a |
| trademark license. Therefore any rights, title and interest in |
| our trademarks remain entirely with us. |
| |
\*****************************************************************************/
const Path = require('path');
const Fs = require('fs');
const _ = require('lodash');
const Parse = require('csv-parse');
const Async = require('async');
const UrlJoin = require('url-join');
const logger = require('../../../src/logger');
import { GBService, GBServiceCallback, IGBInstance } from 'botlib';
import { GBService, IGBInstance } from 'botlib';
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from '../models';
export class SecService extends GBService {
public async importSecurityFile(localPath: string, instance: IGBInstance) {
const security = JSON.parse(
Fs.readFileSync(UrlJoin(localPath, 'security.json'), 'utf8')
);
const security = JSON.parse(Fs.readFileSync(UrlJoin(localPath, 'security.json'), 'utf8'));
security.groups.forEach(group => {
const groupDb = GuaribasGroup.build({
instanceId: instance.instanceId,
@ -78,16 +38,15 @@ export class SecService extends GBService {
channelName: string,
displayName: string
): Promise<GuaribasUser> {
return new Promise<GuaribasUser>(
(resolve, reject) => {
return new Promise<GuaribasUser>((resolve, reject) => {
GuaribasUser.findOne({
attributes: ['instanceId', 'internalAddress'],
where: {
instanceId: instanceId,
userSystemId: userSystemId
}
}).then(user => {
})
.then(user => {
if (!user) {
user = GuaribasUser.build();
}
@ -99,7 +58,8 @@ export class SecService extends GBService {
user.defaultChannel = channelName;
user.save();
resolve(user);
}).error(reject);
})
.error(reject);
});
}
}

View file

@ -44,31 +44,30 @@ import { Sequelize } from 'sequelize-typescript';
import { WhatsappDirectLine } from './services/WhatsappDirectLine';
export class GBWhatsappPackage implements IGBPackage {
public sysPackages: IGBPackage[] = undefined;
public getDialogs(min: GBMinInstance) {}
public sysPackages: IGBPackage[] = null;
public channel: WhatsappDirectLine;
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
}
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {}
public unloadPackage(core: IGBCoreService): void {
}
public unloadPackage(core: IGBCoreService): void {}
public loadBot(min: GBMinInstance): void {
// Only loads engine if it is defined on services.json.
if (min.instance.whatsappBotKey) {
this.channel = new WhatsappDirectLine(min.botId, min.instance.whatsappBotKey, min.instance.whatsappServiceKey,
min.instance.whatsappServiceNumber, min.instance.whatsappServiceUrl, min.instance.whatsappServiceWebhookUrl);
this.channel = new WhatsappDirectLine(
min.botId,
min.instance.whatsappBotKey,
min.instance.whatsappServiceKey,
min.instance.whatsappServiceNumber,
min.instance.whatsappServiceUrl,
min.instance.whatsappServiceWebhookUrl
);
}
}
public unloadBot(min: GBMinInstance): void {
}
public onNewSession(min: GBMinInstance, step: any): void {
}
public unloadBot(min: GBMinInstance): void {}
public onNewSession(min: GBMinInstance, step: any): void {}
}

View file

@ -1,50 +1,11 @@
/*****************************************************************************\
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | |
| (_) \___/' |
| |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. |
| |
| According to our dual licensing model, this program can be used either |
| under the terms of the GNU Affero General Public License, version 3, |
| or under a proprietary license. |
| |
| The texts of the GNU Affero General Public License with an additional |
| permission and of our proprietary license can be found at and |
| in the LICENSE file you have received along with this program. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| "General Bots" is a registered trademark of Pragmatismo.io. |
| The licensing of the program under the AGPLv3 does not imply a |
| trademark license. Therefore any rights, title and interest in |
| our trademarks remain entirely with us. |
| |
\*****************************************************************************/
const Path = require('path');
const Fs = require('fs');
const _ = require('lodash');
const Parse = require('csv-parse');
const Async = require('async');
const UrlJoin = require('url-join');
const logger = require('../../../src/logger');
const Swagger = require('swagger-client');
const rp = require('request-promise');
import { GBService } from 'botlib';
import * as request from 'request-promise-native';
import { GBService, GBServiceCallback, IGBInstance } from 'botlib';
export class WhatsappDirectLine extends GBService {
public pollInterval = 1000;
public directLineClientName = 'DirectLineClient';
public directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json';
@ -59,8 +20,14 @@ export class WhatsappDirectLine extends GBService {
public conversationIds = {};
constructor(botId, directLineSecret, whatsappServiceKey, whatsappServiceNumber, whatsappServiceUrl, whatsappServiceWebhookUrl) {
constructor(
botId,
directLineSecret,
whatsappServiceKey,
whatsappServiceNumber,
whatsappServiceUrl,
whatsappServiceWebhookUrl
) {
super();
this.botId = botId;
@ -71,28 +38,27 @@ export class WhatsappDirectLine extends GBService {
// TODO: Migrate to Swagger 3.
this.directLineClient = rp(this.directLineSpecUrl)
.then((spec) => {
.then(spec => {
return new Swagger({
spec: JSON.parse(spec.trim()),
usePromise: true
});
})
.then(async (client) => {
client.clientAuthorizations.add('AuthorizationBotConnector',
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' +
directLineSecret, 'header'));
.then(async client => {
client.clientAuthorizations.add(
'AuthorizationBotConnector',
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + directLineSecret, 'header')
);
const options = {
method: 'POST',
url: UrlJoin(this.whatsappServiceUrl, 'webhook'),
qs:
{
qs: {
token: this.whatsappServiceKey,
webhookUrl: `${this.whatsappServiceWebhookUrl}/instances/${this.botId}/whatsapp`,
set: true
},
headers:
{
headers: {
'cache-control': 'no-cache'
}
};
@ -106,10 +72,9 @@ export class WhatsappDirectLine extends GBService {
return client;
})
.catch((err) => {
.catch(err => {
logger.error('Error initializing DirectLine client', err);
});
}
public received(req, res) {
@ -125,39 +90,31 @@ export class WhatsappDirectLine extends GBService {
const conversationId = this.conversationIds[from];
this.directLineClient.then((client) => {
if (this.conversationIds[from] == null) {
this.directLineClient.then(client => {
if (this.conversationIds[from] == undefined) {
logger.info(`GBWhatsapp: Starting new conversation on Bot.`);
client.Conversations.Conversations_StartConversation()
.then((response) => {
.then(response => {
return response.obj.conversationId;
})
.then((conversationId) => {
.then(conversationId => {
this.conversationIds[from] = conversationId;
this.inputMessage(client, conversationId, text,
from, fromName);
this.inputMessage(client, conversationId, text, from, fromName);
this.pollMessages(client, conversationId, from, fromName);
})
.catch((err) => {
.catch(err => {
console.error('Error starting conversation', err);
});
} else {
this.inputMessage(client, conversationId, text,
from, fromName);
this.inputMessage(client, conversationId, text, from, fromName);
}
res.end();
});
}
public inputMessage(client, conversationId, text, from, fromName) {
client.Conversations.Conversations_PostActivity(
{
client.Conversations.Conversations_PostActivity({
conversationId: conversationId,
activity: {
textFormat: 'plain',
@ -169,42 +126,37 @@ export class WhatsappDirectLine extends GBService {
},
replyToId: from
}
}).catch((err) => {
}).catch(err => {
logger.error(`GBWhatsapp: Error receiving message: ${err}.`);
});
}
public pollMessages(client, conversationId, from, fromName) {
logger.info(`GBWhatsapp: Starting polling message for conversationId:
${conversationId}.`);
setInterval(() => {
client.Conversations.Conversations_GetActivities({
conversationId:
conversationId, watermark: this.watermark
conversationId: conversationId,
watermark: this.watermark
})
.then((response) => {
.then(response => {
this.watermark = response.obj.watermark;
return response.obj.activities;
})
.then((activities) => {
.then(activities => {
this.printMessages(activities, conversationId, from, fromName);
});
}, this.pollInterval);
}
public printMessages(activities, conversationId, from, fromName) {
if (activities && activities.length) {
// Ignore own messages.
activities = activities.filter((m) => (m.from.id === 'GeneralBots') && m.type === 'message');
activities = activities.filter(m => m.from.id === 'GeneralBots' && m.type === 'message');
if (activities.length) {
// Print other messages.
activities.forEach(activity => {
@ -215,7 +167,6 @@ export class WhatsappDirectLine extends GBService {
}
public printMessage(activity, conversationId, from, fromName) {
let output = '';
if (activity.text) {
@ -224,7 +175,7 @@ export class WhatsappDirectLine extends GBService {
}
if (activity.attachments) {
activity.attachments.forEach((attachment) => {
activity.attachments.forEach(attachment => {
switch (attachment.contentType) {
case 'application/vnd.microsoft.card.hero':
output += `\n${this.renderHeroCard(attachment)}`;
@ -238,29 +189,25 @@ export class WhatsappDirectLine extends GBService {
});
}
this.sendToDevice(conversationId, from, fromName, output);
this.sendToDevice(from, output);
}
public renderHeroCard(attachment) {
return `${attachment.content.title} - ${attachment.content.text}`;
}
public async sendToDevice(conversationId, to, toName, msg) {
public async sendToDevice(to, msg) {
const options = {
method: 'POST',
url: UrlJoin(this.whatsappServiceUrl, 'message'),
qs:
{
qs: {
token: this.whatsappServiceKey,
phone: to,
body: msg
},
headers:
{
headers: {
'cache-control': 'no-cache'
}
};
const result = await request.get(options);
}
}

View file

@ -40,7 +40,7 @@
const logger = require('./logger');
const express = require('express');
const bodyParser = require('body-parser');
import { IGBInstance, IGBPackage } from 'botlib';
import { IGBInstance, IGBPackage, IGBCoreService } from 'botlib';
import { GBAdminService } from '../packages/admin.gbapp/services/GBAdminService';
import { AzureDeployerService } from '../packages/azuredeployer.gbapp/services/AzureDeployerService';
import { GuaribasInstance } from '../packages/core.gbapp/models/GBModel';
@ -50,8 +50,6 @@ import { GBCoreService } from '../packages/core.gbapp/services/GBCoreService';
import { GBDeployer } from '../packages/core.gbapp/services/GBDeployer';
import { GBImporter } from '../packages/core.gbapp/services/GBImporterService';
import { GBMinService } from '../packages/core.gbapp/services/GBMinService';
import { GBVMService } from '../packages/core.gbapp/services/GBVMService';
import { load } from 'dotenv';
const appPackages = new Array<IGBPackage>();
@ -90,7 +88,7 @@ export class GBServer {
// Reads basic configuration, initialize minimal services.
GBConfigService.init();
const core = new GBCoreService();
const core: IGBCoreService = new GBCoreService();
const importer: GBImporter = new GBImporter(core);
const deployer: GBDeployer = new GBDeployer(core, importer);
@ -103,7 +101,7 @@ export class GBServer {
logger.info(`Establishing a development local proxy (ngrok)...`);
const proxyAddress: string = await core.ensureProxy(port);
// Creates a boot instance or load it frmo storage.
// Creates a boot instance or load it from storage.
let bootInstance: IGBInstance = null;
try {
@ -130,9 +128,9 @@ export class GBServer {
'boot.gbot',
'packages/boot.gbot'
);
const fullInstance = Object.assign(packageInstance, bootInstance);
const fullInstance = { ...packageInstance, ...bootInstance };
await core.saveInstance(fullInstance);
let instances: GuaribasInstance[] = await core.loadAllInstances(core, azureDeployer, proxyAddress);
let instances: IGBInstance[] = await core.loadAllInstances(core, azureDeployer, proxyAddress);
instances = await core.ensureInstances(instances, bootInstance, core);
if (!bootInstance) {
bootInstance = instances[0];
@ -145,14 +143,13 @@ export class GBServer {
// Deployment of local applications for the first time.
deployer.installDefaultGBUI();
deployer.runOnce();
logger.info(`The Bot Server is in RUNNING mode...`);
// Opens Navigator.
core.openBrowserInDevelopment();
} catch (err) {
logger.error(`STOP: ${err} ${err.stack ? err.stack : ''}`);
process.exit(1);

View file

@ -12,6 +12,7 @@
"resolveJsonModule": true,
"outDir": "./dist",
"paths": {
"*": ["types/*"],
"botlib/*": ["node_modules/botlib/*"],
"pragmatismo-io-framework/*": ["node_modules/pragmatismo-io-framework/*"]
},